提交 9cfeefb6 编写于 作者: W wycats

Reorganized initializers a bit to enable better hooks for common cases without...

Reorganized initializers a bit to enable better hooks for common cases without the need for Railtie. Specifically, the following hooks were added:

* before_configuration: this hook is run immediately after the Application class 
  comes into existence, but before the user has added any configuration. This is
  the appropriate place to set configuration for your plugin
* before_initialize: This is run after all of the user's configuration has completed,
  but before any initializers have begun (in other words, it runs right after
  config/environments/{development,production,test}.rb)
* after_initialize: This is run after all of the initializers have run. It is an
  appropriate place for forking in a preforking setup

Each of these hooks may be used via ActiveSupport.on_load(name) { }. In all these cases, the context inside the block will be the Application object. This means that for simple cases, you can use these hooks without needing to create a Railtie.
上级 458f5712
......@@ -15,6 +15,12 @@ class Railtie < Rails::Railtie
config.generators.orm :active_record, :migration => true,
:timestamps => true
config.app_middleware.insert_after "::ActionDispatch::Callbacks",
"ActiveRecord::QueryCache"
config.app_middleware.insert_after "::ActionDispatch::Callbacks",
"ActiveRecord::ConnectionAdapters::ConnectionManagement"
rake_tasks do
load "active_record/railties/databases.rake"
end
......@@ -58,16 +64,9 @@ class Railtie < Rails::Railtie
end
end
# Setup database middleware after initializers have run
initializer "active_record.initialize_database_middleware", :after => "action_controller.set_configs" do |app|
middleware = app.config.middleware
middleware.insert_after "::ActionDispatch::Callbacks", ActiveRecord::QueryCache
middleware.insert_after "::ActionDispatch::Callbacks", ActiveRecord::ConnectionAdapters::ConnectionManagement
end
initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app|
ActiveSupport.on_load(:active_record) do
unless app.config.cache_classes
ActiveSupport.on_load(:active_record) do
ActionDispatch::Callbacks.after do
ActiveRecord::Base.reset_subclasses
ActiveRecord::Base.clear_reloadable_connections!
......
......@@ -2,16 +2,26 @@ module ActiveSupport
@load_hooks = Hash.new {|h,k| h[k] = [] }
@loaded = {}
def self.on_load(name, &block)
def self.on_load(name, options = {}, &block)
if base = @loaded[name]
base.instance_eval(&block)
execute_hook(base, options, block)
else
@load_hooks[name] << block
@load_hooks[name] << [block, options]
end
end
def self.execute_hook(base, options, block)
if options[:yield]
block.call(base)
else
base.instance_eval(&block)
end
end
def self.run_load_hooks(name, base = Object)
@load_hooks[name].each { |hook| base.instance_eval(&hook) }
@loaded[name] = base
@load_hooks[name].each do |hook, options|
execute_hook(base, options, hook)
end
end
end
\ No newline at end of file
require 'abstract_unit'
class LazyLoadHooksTest < ActiveSupport::TestCase
def test_basic_hook
i = 0
ActiveSupport.on_load(:basic_hook) { i += 1 }
ActiveSupport.run_load_hooks(:basic_hook)
assert_equal 1, i
end
def test_hook_registered_after_run
i = 0
ActiveSupport.run_load_hooks(:registered_after)
assert_equal 0, i
ActiveSupport.on_load(:registered_after) { i += 1 }
assert_equal 1, i
end
def test_hook_receives_a_context
i = 0
ActiveSupport.on_load(:contextual) { i += incr }
assert_equal 0, i
ActiveSupport.run_load_hooks(:contextual, FakeContext.new(2))
assert_equal 2, i
end
def test_hook_receives_a_context_afterward
i = 0
ActiveSupport.run_load_hooks(:contextual_after, FakeContext.new(2))
assert_equal 0, i
ActiveSupport.on_load(:contextual_after) { i += incr }
assert_equal 2, i
end
def test_hook_with_yield_true
i = 0
ActiveSupport.on_load(:contextual_yield, :yield => true) do |obj|
i += obj.incr + incr_amt
end
assert_equal 0, i
ActiveSupport.run_load_hooks(:contextual_yield, FakeContext.new(2))
assert_equal 7, i
end
def test_hook_with_yield_true_afterward
i = 0
ActiveSupport.run_load_hooks(:contextual_yield_after, FakeContext.new(2))
assert_equal 0, i
ActiveSupport.on_load(:contextual_yield_after, :yield => true) do |obj|
i += obj.incr + incr_amt
end
assert_equal 7, i
end
private
def incr_amt
5
end
class FakeContext
attr_reader :incr
def initialize(incr)
@incr = incr
end
end
end
\ No newline at end of file
......@@ -2379,7 +2379,6 @@ Now that we've referenced that class, it will be required for us. You'll notice
* initialize_subscriber
* set_clear_dependencies_hook
* initialize_dependency_mechanism
* bootstrap_load_path
These are all defined using the +initializer+ method:
......@@ -2930,7 +2929,6 @@ With +@@autoloads+ being
* initialize_subscriber
* set_clear_dependencies_hook
* initialize_dependency_mechanism
* bootstrap_load_path
h4. Active Support Initializers
......
......@@ -69,6 +69,8 @@ def inherited(base)
raise "You cannot have more than one Rails::Application" if Rails.application
super
Rails.application = base.instance
ActiveSupport.run_load_hooks(:before_configuration, base.instance)
end
def respond_to?(*args)
......@@ -82,7 +84,7 @@ def method_missing(*args, &block)
end
end
delegate :metal_loader, :to => :config
delegate :middleware, :metal_loader, :to => :config
def require_environment!
environment = paths.config.environment.to_a.first
......@@ -125,7 +127,7 @@ def load_generators
end
def app
@app ||= middleware.build(routes)
@app ||= config.middleware.build(routes)
end
def call(env)
......
......@@ -10,7 +10,8 @@ module Bootstrap
require environment if environment
end
initializer :load_all_active_support do
initializer :load_active_support do
require 'active_support/dependencies'
require "active_support/all" unless config.active_support.bare
end
......@@ -18,7 +19,6 @@ module Bootstrap
# Used by Passenger to ensure everything's loaded before forking and
# to avoid autoload race conditions in JRuby.
initializer :preload_frameworks do
require 'active_support/dependencies'
ActiveSupport::Autoload.eager_autoload! if config.preload_frameworks
end
......@@ -66,8 +66,8 @@ module Bootstrap
ActiveSupport::Dependencies.mechanism = config.cache_classes ? :require : :load
end
initializer :bootstrap_load_path do
# This is just an initializer used as hook so all load paths are loaded together
initializer :bootstrap_hook do |app|
ActiveSupport.run_load_hooks(:before_initialize, app)
end
end
end
......
......@@ -33,7 +33,7 @@ def encoding=(value)
end
def middleware
@middleware ||= default_middleware_stack
@middleware ||= app_middleware.merge_into(default_middleware_stack)
end
def metal_loader
......
......@@ -35,10 +35,8 @@ module Finisher
app
end
initializer :after_initialize do
config.after_initialize_blocks.each do |block|
block.call(self)
end
initializer :finisher_hook do |app|
ActiveSupport.run_load_hooks(:after_initialize, app)
end
# Disable dependency loading during request cycle
......
......@@ -125,7 +125,7 @@ def find_root_with_flag(flag, default=nil)
end
end
delegate :middleware, :paths, :root, :to => :config
delegate :paths, :root, :to => :config
def load_tasks
super
......@@ -133,7 +133,7 @@ def load_tasks
end
# Add configured load paths to ruby load paths and remove duplicates.
initializer :set_load_path, :before => :bootstrap_load_path do
initializer :set_load_path, :before => :bootstrap_hook do
config.load_paths.reverse_each do |path|
$LOAD_PATH.unshift(path) if File.directory?(path)
end
......@@ -142,7 +142,10 @@ def load_tasks
# Set the paths from which Rails will automatically load source files,
# and the load_once paths.
initializer :set_autoload_paths, :before => :bootstrap_load_path do |app|
#
# This needs to be an initializer, since it needs to run once
# per engine and get the engine as a block parameter
initializer :set_autoload_paths, :before => :bootstrap_hook do |app|
ActiveSupport::Dependencies.load_paths.unshift(*config.load_paths)
if reloadable?(app)
......@@ -200,7 +203,9 @@ def load_tasks
end
end
initializer :load_app_classes do |app|
# This needs to be an initializer, since it needs to run once
# per engine and get the engine as a block parameter
initializer :load_app_classes, :before => :finisher_hook do |app|
next if $rails_rake_task
if app.config.cache_classes
......
......@@ -3,10 +3,50 @@
module Rails
class Railtie
class Configuration
class MiddlewareStackProxy
def initialize
@operations = []
end
def insert_before(*args, &block)
@operations << [:insert_before, args, block]
end
alias insert insert_before
def insert_after(*args, &block)
@operations << [:insert_after, args, block]
end
def swap(*args, &block)
@operations << [:swap, args, block]
end
def use(*args, &block)
@operations << [:use, args, block]
end
def merge_into(other)
@operations.each do |operation, args, block|
other.send(operation, *args, &block)
end
other
end
end
def initialize
@@options ||= {}
end
# This allows you to modify the application's middlewares from Engines.
#
# All operations you run on the app_middleware will be replayed on the
# application once it is defined and the default_middlewares are
# created
def app_middleware
@@app_middleware ||= MiddlewareStackProxy.new
end
# Holds generators configuration:
#
# config.generators do |g|
......@@ -28,12 +68,8 @@ def generators
end
end
def after_initialize_blocks
@@after_initialize_blocks ||= []
end
def after_initialize(&blk)
after_initialize_blocks << blk if blk
def after_initialize(&block)
ActiveSupport.on_load(:after_initialize, :yield => true, &block)
end
def to_prepare_blocks
......
......@@ -28,19 +28,6 @@ def setup
assert_equal "congratulations", $test_after_initialize_block2
end
test "after_initialize block works correctly when no block is passed" do
add_to_config <<-RUBY
config.root = "#{app_path}"
config.after_initialize { $test_after_initialize_block1 = "success" }
config.after_initialize # don't pass a block, this is what we're testing!
config.after_initialize { $test_after_initialize_block2 = "congratulations" }
RUBY
require "#{app_path}/config/environment"
assert_equal "success", $test_after_initialize_block1
assert_equal "congratulations", $test_after_initialize_block2
end
test "after_initialize runs after frameworks have been initialized" do
$activerecord_configurations = nil
add_to_config <<-RUBY
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册