Update initializable

This commit is contained in:
Yehuda Katz + Carl Lerche
2009-10-27 16:48:35 -07:00
parent da62a7c536
commit df95f16570
2 changed files with 150 additions and 67 deletions

View File

@@ -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

View File

@@ -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