Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #10795: refactor_dispatcher.patch

File refactor_dispatcher.patch, 10.7 kB (added by lifofifo, 6 months ago)
  • a/actionpack/lib/action_controller.rb

    old new  
    5656require 'action_controller/record_identifier' 
    5757require 'action_controller/request_forgery_protection' 
    5858require 'action_controller/headers' 
     59require 'action_controller/dispatcher_callbacks' 
    5960 
    6061require 'action_view' 
    6162ActionController::Base.template_class = ActionView::Base 
  • a/actionpack/lib/action_controller/dispatcher.rb

    old new  
    33  # reloading the app after each request when Dependencies.load? is true. 
    44  class Dispatcher 
    55    @@guard = Mutex.new 
    6  
     6     
     7    include DispatcherCallbacks 
     8     
    79    class << self 
    810      # Backward-compatible class method takes CGI-specific args. Deprecated 
    911      # in favor of Dispatcher.new(output, request, response).dispatch. 
     
    6062          $stderr.puts "(originally #{originating_exception})" if originating_exception 
    6163        end 
    6264      end 
     65       
     66      def define_dispatcher_callbacks(cache_classes = true) 
     67        unless cache_classes  
     68          # Development mode callbacks 
     69          before_dispatch :reload_application 
     70          after_dispatch :cleanup_application 
     71        end 
     72         
     73        # Common callbacks         
     74        to_prepare :load_application_controller do 
     75          begin 
     76            require_dependency 'application' unless defined?(::ApplicationController) 
     77          rescue LoadError => error 
     78            raise unless error.message =~ /application\.rb/ 
     79          end 
     80        end 
     81         
     82        if defined? ActiveRecord 
     83          before_dispatch :active_record_callbacks 
     84          to_prepare :activerecord_instantiate_observers do 
     85            ActiveRecord::Base.instantiate_observers 
     86          end 
     87        end 
     88         
     89        after_dispatch :flush_logger 
     90      end 
    6391 
    6492      private 
    6593        def failsafe_response_body(status) 
     
    93121    cattr_accessor :callbacks 
    94122    self.callbacks = Hash.new { |h, k| h[k] = [] } 
    95123 
    96     cattr_accessor :unprepared 
    97     self.unprepared = true 
    98  
    99  
    100     before_dispatch :reload_application 
    101     before_dispatch :prepare_application 
    102     after_dispatch :flush_logger 
    103     after_dispatch :cleanup_application 
    104  
    105     if defined? ActiveRecord 
    106       to_prepare :activerecord_instantiate_observers do 
    107         ActiveRecord::Base.instantiate_observers 
    108       end 
    109     end 
    110  
    111124    def initialize(output, request = nil, response = nil) 
    112125      @output, @request, @response = output, request, response 
    113126    end 
     
    135148      failsafe_rescue exception 
    136149    end 
    137150 
    138     def reload_application 
    139       if Dependencies.load? 
    140         Routing::Routes.reload 
    141         self.unprepared = true 
    142       end 
    143     end 
    144  
    145     def prepare_application(force = false) 
    146       begin 
    147         require_dependency 'application' unless defined?(::ApplicationController) 
    148       rescue LoadError => error 
    149         raise unless error.message =~ /application\.rb/ 
    150       end 
    151  
    152       ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord) 
    153  
    154       if unprepared || force 
    155         run_callbacks :prepare 
    156         self.unprepared = false 
    157       end 
    158     end 
    159  
    160     # Cleanup the application by clearing out loaded classes so they can 
    161     # be reloaded on the next request without restarting the server. 
    162     def cleanup_application(force = false) 
    163       if Dependencies.load? || force 
    164         ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord) 
    165         Dependencies.clear 
    166         ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord) 
    167       end 
    168     end 
    169  
    170     def flush_logger 
    171       RAILS_DEFAULT_LOGGER.flush if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:flush) 
    172     end 
    173  
    174151    protected 
    175152      def handle_request 
    176153        @controller = Routing::Routes.recognize(@request) 
  • /dev/null

    old new  
     1module ActionController #:nodoc: 
     2  module DispatcherCallbacks #:nodoc: 
     3     
     4    def reload_application 
     5      Routing::Routes.reload 
     6      run_callbacks :prepare 
     7    end 
     8     
     9    def active_record_callbacks 
     10      ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord) 
     11    end 
     12 
     13    # Cleanup the application by clearing out loaded classes so they can 
     14    # be reloaded on the next request without restarting the server. 
     15    def cleanup_application(force = false) 
     16      if Dependencies.load? || force 
     17        ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord) 
     18        Dependencies.clear 
     19        ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord) 
     20      end 
     21    end 
     22 
     23    def flush_logger 
     24      RAILS_DEFAULT_LOGGER.flush if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:flush) 
     25    end 
     26     
     27  end 
     28end 
  • a/actionpack/test/controller/dispatcher_test.rb

    old new  
    1111    @output = StringIO.new 
    1212    ENV['REQUEST_METHOD'] = 'GET' 
    1313 
    14     Dispatcher.callbacks[:prepare].clear 
    15     @dispatcher = Dispatcher.new(@output) 
     14    Dispatcher.stubs(:require_dependency) 
    1615  end 
    1716 
    1817  def teardown 
     18    Dispatcher.callbacks = Hash.new { |h, k| h[k] = [] } 
    1919    ENV.delete 'REQUEST_METHOD' 
    2020  end 
    2121 
    2222  def test_clears_dependencies_after_dispatch_if_in_loading_mode 
     23    prepare_dispatcher 
     24     
    2325    Dependencies.stubs(:load?).returns(true) 
    2426 
    2527    ActionController::Routing::Routes.expects(:reload).once 
    2628    Dependencies.expects(:clear).once 
    27  
     29     
    2830    dispatch 
    2931  end 
    3032 
    3133  def test_leaves_dependencies_after_dispatch_if_not_in_loading_mode 
     34    prepare_dispatcher(true) 
     35 
    3236    Dependencies.stubs(:load?).returns(false) 
    3337 
    3438    ActionController::Routing::Routes.expects(:reload).never 
     
    3842  end 
    3943 
    4044  def test_failsafe_response 
     45    prepare_dispatcher 
     46     
    4147    CGI.expects(:new).raises('some multipart parsing failure') 
    4248 
    4349    ActionController::Routing::Routes.stubs(:reload) 
     
    4854    assert_equal "Status: 400 Bad Request\r\nContent-Type: text/html\r\n\r\n<html><body><h1>400 Bad Request</h1></body></html>", @output.string 
    4955  end 
    5056 
    51   def test_reload_application_sets_unprepared_if_loading_dependencies 
    52     Dependencies.stubs(:load?).returns(false) 
    53     ActionController::Routing::Routes.expects(:reload).never 
    54     @dispatcher.unprepared = false 
    55     @dispatcher.send!(:reload_application) 
    56     assert !@dispatcher.unprepared 
    57  
    58     Dependencies.stubs(:load?).returns(true) 
    59     ActionController::Routing::Routes.expects(:reload).once 
    60     @dispatcher.send!(:reload_application) 
    61     assert @dispatcher.unprepared 
     57  def test_dispatcher_callbacks_if_loading_dependencies 
     58    prepare_dispatcher 
     59     
     60    Dispatcher.any_instance.expects(:reload_application) 
     61    Dispatcher.any_instance.expects(:cleanup_application) 
     62     
     63    dispatch 
     64  end 
     65   
     66  def test_dispatcher_callbacks_if_requiring_dependencies 
     67    prepare_dispatcher(true) 
     68     
     69    Dispatcher.any_instance.expects(:reload_application).never 
     70    Dispatcher.any_instance.expects(:cleanup_application).never 
     71     
     72    dispatch 
    6273  end 
    6374 
    64   def test_prepare_application_runs_callbacks_if_unprepared 
     75  def test_prepare_application_runs_callbacks_when_called 
     76    prepare_dispatcher(false, false) 
     77     
    6578    a = b = c = nil 
    6679    Dispatcher.to_prepare { a = b = c = 1 } 
    6780    Dispatcher.to_prepare { b = c = 2 } 
    6881    Dispatcher.to_prepare { c = 3 } 
    6982 
    70     # Skip the callbacks when already prepared. 
    71     @dispatcher.unprepared = false 
    72     @dispatcher.send! :prepare_application 
    7383    assert_nil a || b || c 
    7484 
    7585    # Perform the callbacks when unprepared. 
    76     @dispatcher.unprepared = true 
    7786    @dispatcher.send! :prepare_application 
    7887    assert_equal 1, a 
    7988    assert_equal 2, b 
    8089    assert_equal 3, c 
    8190 
    82     # But when not :load, make sure they are only run onc
     91    # make sure they are run everytime when cache_classes is fals
    8392    a = b = c = nil 
    84     @dispatcher.send! :prepare_application 
    85     assert_nil a || b || c 
     93     
     94    dispatch 
     95     
     96    assert_equal 1, a 
     97    assert_equal 2, b 
     98    assert_equal 3, c 
    8699  end 
    87100 
    88101  def test_to_prepare_with_identifier_replaces 
     102    prepare_dispatcher 
     103     
    89104    a = b = nil 
    90105    Dispatcher.to_prepare(:unique_id) { a = b = 1 } 
    91106    Dispatcher.to_prepare(:unique_id) { a = 2 } 
    92107 
    93     @dispatcher.unprepared = true 
    94     @dispatcher.send! :prepare_application 
     108    @dispatcher.send! :reload_application 
    95109    assert_equal 2, a 
    96110    assert_equal nil, b 
    97111  end 
    98112 
    99   def test_to_prepare_only_runs_once_if_not_loading_dependencies 
     113  def test_to_prepare_only_runs_once_if_not_loading_dependencies     
    100114    Dependencies.stubs(:load?).returns(false) 
    101115    called = 0 
    102116    Dispatcher.to_prepare(:unprepared_test) { called += 1 } 
     117     
     118    prepare_dispatcher(true) 
    103119    2.times { dispatch } 
    104120    assert_equal 1, called 
    105121  end 
    106122 
    107123  private 
     124   
     125    def prepare_dispatcher(cache_classes = false, prepare = true) 
     126      Dispatcher.define_dispatcher_callbacks(cache_classes) 
     127 
     128      @dispatcher = Dispatcher.new(@output) 
     129      @dispatcher.send(:run_callbacks, :prepare) if prepare 
     130       
     131      class << @dispatcher 
     132        def prepare_application 
     133          run_callbacks :prepare 
     134        end 
     135      end 
     136    end 
     137     
    108138    def dispatch(output = @output) 
    109139      controller = mock 
    110140      controller.stubs(:process).returns(controller) 
  • a/railties/lib/initializer.rb

    old new  
    9797      after_initialize 
    9898 
    9999      load_application_initializers 
     100       
     101      # Prepare dispatcher callbacks and run 'prepare' callbacks 
     102      prepare_dispatcher 
    100103    end 
    101104 
    102105    # Check for valid Ruby version 
     
    338341        load(initializer) 
    339342      end 
    340343    end 
     344     
     345    def prepare_dispatcher 
     346      require 'dispatcher' unless defined?(::Dispatcher) 
     347      Dispatcher.define_dispatcher_callbacks(configuration.cache_classes) 
     348      Dispatcher.new(RAILS_DEFAULT_LOGGER).send :run_callbacks, :prepare 
     349    end 
    341350 
    342351  end 
    343352