2010-01-27 01:08:50 -05:00
|
|
|
require 'tsort'
|
|
|
|
|
2009-10-07 18:21:19 -04:00
|
|
|
module Rails
|
|
|
|
module Initializable
|
2009-11-02 20:19:03 -05:00
|
|
|
def self.included(base)
|
|
|
|
base.extend ClassMethods
|
2009-10-27 19:48:35 -04:00
|
|
|
end
|
2009-10-07 18:21:19 -04:00
|
|
|
|
2009-11-05 17:45:53 -05:00
|
|
|
class Initializer
|
2009-12-14 16:42:48 -05:00
|
|
|
attr_reader :name, :block
|
2009-11-05 17:45:53 -05:00
|
|
|
|
|
|
|
def initialize(name, context, options, &block)
|
|
|
|
@name, @context, @options, @block = name, context, options, block
|
|
|
|
end
|
|
|
|
|
|
|
|
def before
|
|
|
|
@options[:before]
|
|
|
|
end
|
|
|
|
|
|
|
|
def after
|
|
|
|
@options[:after]
|
|
|
|
end
|
|
|
|
|
|
|
|
def run(*args)
|
|
|
|
@context.instance_exec(*args, &block)
|
|
|
|
end
|
|
|
|
|
|
|
|
def bind(context)
|
|
|
|
return self if @context
|
|
|
|
Initializer.new(@name, context, @options, &block)
|
|
|
|
end
|
2009-10-27 19:48:35 -04:00
|
|
|
end
|
2009-10-08 15:14:57 -04:00
|
|
|
|
2009-10-27 19:48:35 -04:00
|
|
|
class Collection < Array
|
2010-01-27 01:08:50 -05:00
|
|
|
include TSort
|
|
|
|
|
|
|
|
alias :tsort_each_node :each
|
|
|
|
def tsort_each_child(initializer, &block)
|
|
|
|
select { |i| i.before == initializer.name || i.name == initializer.after }.each(&block)
|
|
|
|
end
|
|
|
|
|
2009-11-02 20:19:03 -05:00
|
|
|
def +(other)
|
|
|
|
Collection.new(to_a + other.to_a)
|
2009-10-08 15:14:57 -04:00
|
|
|
end
|
2009-10-27 19:48:35 -04:00
|
|
|
end
|
2009-10-08 15:14:57 -04:00
|
|
|
|
2009-11-02 20:19:03 -05:00
|
|
|
def run_initializers(*args)
|
2009-12-14 16:42:48 -05:00
|
|
|
return if instance_variable_defined?(:@ran)
|
2010-06-24 04:37:58 -04:00
|
|
|
initializers.tsort.each do |initializer|
|
2009-11-05 17:45:53 -05:00
|
|
|
initializer.run(*args)
|
2009-11-02 20:19:03 -05:00
|
|
|
end
|
|
|
|
@ran = true
|
2009-10-27 19:48:35 -04:00
|
|
|
end
|
2009-10-08 15:14:57 -04:00
|
|
|
|
2009-11-05 17:45:53 -05:00
|
|
|
def initializers
|
2010-01-25 18:08:08 -05:00
|
|
|
@initializers ||= self.class.initializers_for(self)
|
2009-11-05 17:45:53 -05:00
|
|
|
end
|
|
|
|
|
2009-11-02 20:19:03 -05:00
|
|
|
module ClassMethods
|
|
|
|
def initializers
|
2010-06-24 05:13:08 -04:00
|
|
|
@initializers ||= Collection.new
|
2009-10-08 15:14:57 -04:00
|
|
|
end
|
|
|
|
|
2010-01-22 19:29:29 -05:00
|
|
|
def initializers_chain
|
2009-11-02 20:19:03 -05:00
|
|
|
initializers = Collection.new
|
|
|
|
ancestors.reverse_each do |klass|
|
|
|
|
next unless klass.respond_to?(:initializers)
|
2010-01-22 19:29:29 -05:00
|
|
|
initializers = initializers + klass.initializers
|
2009-11-02 20:19:03 -05:00
|
|
|
end
|
|
|
|
initializers
|
2009-10-07 18:21:19 -04:00
|
|
|
end
|
|
|
|
|
2010-01-25 18:08:08 -05:00
|
|
|
def initializers_for(binding)
|
|
|
|
Collection.new(initializers_chain.map { |i| i.bind(binding) })
|
|
|
|
end
|
|
|
|
|
2009-11-02 20:19:03 -05:00
|
|
|
def initializer(name, opts = {}, &blk)
|
2009-12-23 16:45:55 -05:00
|
|
|
raise ArgumentError, "A block must be passed when defining an initializer" unless blk
|
2010-01-27 01:08:50 -05:00
|
|
|
opts[:after] ||= initializers.last.name unless initializers.empty? || initializers.find { |i| i.name == opts[:before] }
|
2010-01-22 19:29:29 -05:00
|
|
|
initializers << Initializer.new(name, nil, opts, &blk)
|
2009-10-27 19:48:35 -04:00
|
|
|
end
|
|
|
|
end
|
2009-10-07 18:21:19 -04:00
|
|
|
end
|
2010-06-24 04:37:58 -04:00
|
|
|
end
|