mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
Update initializable
This commit is contained in:
@@ -1,78 +1,86 @@
|
||||
module Rails
|
||||
module Initializable
|
||||
|
||||
# A collection of initializers
|
||||
class Collection
|
||||
def initialize(context)
|
||||
@context = context
|
||||
@keys = []
|
||||
@values = {}
|
||||
@ran = false
|
||||
def self.included(klass)
|
||||
klass.instance_eval do
|
||||
extend Rails::Initializable
|
||||
extend Rails::Initializable::ClassMethodsWhenIncluded
|
||||
include Rails::Initializable::InstanceMethodsWhenIncluded
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
return self if @ran
|
||||
each do |key, initializer|
|
||||
@context.class_eval(&initializer.block)
|
||||
def self.extended(klass)
|
||||
klass.extend Initializer
|
||||
end
|
||||
|
||||
class Collection < Array
|
||||
def initialize(klasses)
|
||||
klasses.each do |klass|
|
||||
klass.added_initializers.each do |initializer|
|
||||
index = if initializer.before
|
||||
index_for(initializer.before)
|
||||
elsif initializer.after
|
||||
index_for(initializer.after) + 1
|
||||
else
|
||||
length
|
||||
end
|
||||
|
||||
insert(index, initializer)
|
||||
end
|
||||
end
|
||||
@ran = true
|
||||
self
|
||||
end
|
||||
|
||||
def [](key)
|
||||
keys, values = merge_with_parent
|
||||
values[key.to_sym]
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
key = key.to_sym
|
||||
@keys |= [key]
|
||||
@values[key] = value
|
||||
end
|
||||
|
||||
def each
|
||||
keys, values = merge_with_parent
|
||||
keys.each { |k| yield k, values[k] }
|
||||
self
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_reader :keys, :values
|
||||
|
||||
private
|
||||
|
||||
def merge_with_parent
|
||||
keys, values = [], {}
|
||||
|
||||
if @context.is_a?(Class) && @context.superclass.is_a?(Initializable)
|
||||
parent = @context.superclass.initializers
|
||||
keys, values = parent.keys, parent.values
|
||||
end
|
||||
|
||||
values = values.merge(@values)
|
||||
return keys | @keys, values
|
||||
def index_for(name)
|
||||
inst = find {|i| i.name == name }
|
||||
inst && index(inst)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Initializer
|
||||
attr_reader :name, :options, :block
|
||||
attr_reader :added_initializers
|
||||
|
||||
def initialize(name, options = {}, &block)
|
||||
@name, @options, @block = name, options, block
|
||||
# When you include Rails::Initializable, this method will be on instances
|
||||
# of the class included into. When you extend it, it will be on the
|
||||
# class or module itself.
|
||||
#
|
||||
# The #initializers method is set up to return the right list of
|
||||
# initializers for the context in question.
|
||||
def initialize!
|
||||
return if @_initialized
|
||||
|
||||
initializers.each {|initializer| instance_eval(&initializer.block) }
|
||||
|
||||
@_initialized = true
|
||||
end
|
||||
|
||||
module Initializer
|
||||
Initializer = Struct.new(:name, :before, :after, :block, :global)
|
||||
|
||||
def all_initializers
|
||||
klasses = ancestors.select {|klass| klass.is_a?(Initializable) }.reverse
|
||||
initializers = Collection.new(klasses)
|
||||
end
|
||||
|
||||
alias initializers all_initializers
|
||||
|
||||
def initializer(name, options = {}, &block)
|
||||
@added_initializers ||= []
|
||||
@added_initializers <<
|
||||
Initializer.new(name, options[:before], options[:after], block, options[:global])
|
||||
end
|
||||
end
|
||||
|
||||
def initializer(name, options = {}, &block)
|
||||
@initializers ||= Collection.new(self)
|
||||
@initializers[name] = Initializer.new(name, options, &block)
|
||||
module ClassMethodsWhenIncluded
|
||||
def initializers
|
||||
all_initializers.select {|i| i.global == true }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def initializers
|
||||
@initializers ||= Collection.new(self)
|
||||
module InstanceMethodsWhenIncluded
|
||||
def initializers
|
||||
self.class.all_initializers.reject {|i| i.global == true }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
extend Initializable
|
||||
|
||||
@@ -31,38 +31,113 @@ module InitializableTests
|
||||
end
|
||||
end
|
||||
|
||||
class Parent
|
||||
extend Rails::Initializable
|
||||
|
||||
initializer :one do
|
||||
$arr << 1
|
||||
end
|
||||
|
||||
initializer :two do
|
||||
$arr << 2
|
||||
end
|
||||
end
|
||||
|
||||
class Child < Parent
|
||||
extend Rails::Initializable
|
||||
|
||||
initializer :three, :before => :one do
|
||||
$arr << 3
|
||||
end
|
||||
|
||||
initializer :four, :after => :one do
|
||||
$arr << 4
|
||||
end
|
||||
end
|
||||
|
||||
class Parent
|
||||
initializer :five, :before => :one do
|
||||
$arr << 5
|
||||
end
|
||||
end
|
||||
|
||||
class Instance
|
||||
include Rails::Initializable
|
||||
|
||||
initializer :one do
|
||||
$arr << 1
|
||||
end
|
||||
|
||||
initializer :two do
|
||||
$arr << 2
|
||||
end
|
||||
|
||||
initializer :three, :global => true do
|
||||
$arr << 3
|
||||
end
|
||||
|
||||
initializer :four, :global => true do
|
||||
$arr << 4
|
||||
end
|
||||
end
|
||||
|
||||
class Basic < ActiveSupport::TestCase
|
||||
include ActiveSupport::Testing::Isolation
|
||||
|
||||
test "initializers run" do
|
||||
Foo.initializers.run
|
||||
Foo.initialize!
|
||||
assert_equal 1, Foo.foo
|
||||
end
|
||||
|
||||
test "initializers are inherited" do
|
||||
Bar.initializers.run
|
||||
Bar.initialize!
|
||||
assert_equal [1, 1], [Bar.foo, Bar.bar]
|
||||
end
|
||||
|
||||
test "initializers only get run once" do
|
||||
Foo.initializers.run
|
||||
Foo.initializers.run
|
||||
Foo.initialize!
|
||||
Foo.initialize!
|
||||
assert_equal 1, Foo.foo
|
||||
end
|
||||
|
||||
test "running initializers on children does not effect the parent" do
|
||||
Bar.initializers.run
|
||||
Bar.initialize!
|
||||
assert_nil Foo.foo
|
||||
assert_nil Foo.bar
|
||||
end
|
||||
|
||||
test "inherited initializers are the same objects" do
|
||||
assert Foo.initializers[:foo].eql?(Bar.initializers[:foo])
|
||||
end
|
||||
|
||||
test "initializing with modules" do
|
||||
Word.initializers.run
|
||||
Word.initialize!
|
||||
assert_equal "bird", $word
|
||||
end
|
||||
end
|
||||
|
||||
class BeforeAfter < ActiveSupport::TestCase
|
||||
test "running on parent" do
|
||||
$arr = []
|
||||
Parent.initialize!
|
||||
assert_equal [5, 1, 2], $arr
|
||||
end
|
||||
|
||||
test "running on child" do
|
||||
$arr = []
|
||||
Child.initialize!
|
||||
assert_equal [5, 3, 1, 4, 2], $arr
|
||||
end
|
||||
end
|
||||
|
||||
class InstanceTest < ActiveSupport::TestCase
|
||||
test "running locals" do
|
||||
$arr = []
|
||||
instance = Instance.new
|
||||
instance.initialize!
|
||||
assert_equal [1, 2], $arr
|
||||
end
|
||||
|
||||
test "running globals" do
|
||||
$arr = []
|
||||
Instance.initialize!
|
||||
assert_equal [3, 4], $arr
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user