mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
69ab3eb57e
The current code base is not uniform. After some discussion, we have chosen to go with double quotes by default.
93 lines
2.3 KiB
Ruby
93 lines
2.3 KiB
Ruby
require "tsort"
|
|
|
|
module Rails
|
|
module Initializable
|
|
def self.included(base) #:nodoc:
|
|
base.extend ClassMethods
|
|
end
|
|
|
|
class Initializer
|
|
attr_reader :name, :block
|
|
|
|
def initialize(name, context, options, &block)
|
|
options[:group] ||= :default
|
|
@name, @context, @options, @block = name, context, options, block
|
|
end
|
|
|
|
def before
|
|
@options[:before]
|
|
end
|
|
|
|
def after
|
|
@options[:after]
|
|
end
|
|
|
|
def belongs_to?(group)
|
|
@options[:group] == group || @options[:group] == :all
|
|
end
|
|
|
|
def run(*args)
|
|
@context.instance_exec(*args, &block)
|
|
end
|
|
|
|
def bind(context)
|
|
return self if @context
|
|
Initializer.new(@name, context, @options, &block)
|
|
end
|
|
|
|
def context_class
|
|
@context.class
|
|
end
|
|
end
|
|
|
|
class Collection < Array
|
|
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
|
|
|
|
def +(other)
|
|
Collection.new(to_a + other.to_a)
|
|
end
|
|
end
|
|
|
|
def run_initializers(group=:default, *args)
|
|
return if instance_variable_defined?(:@ran)
|
|
initializers.tsort_each do |initializer|
|
|
initializer.run(*args) if initializer.belongs_to?(group)
|
|
end
|
|
@ran = true
|
|
end
|
|
|
|
def initializers
|
|
@initializers ||= self.class.initializers_for(self)
|
|
end
|
|
|
|
module ClassMethods
|
|
def initializers
|
|
@initializers ||= Collection.new
|
|
end
|
|
|
|
def initializers_chain
|
|
initializers = Collection.new
|
|
ancestors.reverse_each do |klass|
|
|
next unless klass.respond_to?(:initializers)
|
|
initializers = initializers + klass.initializers
|
|
end
|
|
initializers
|
|
end
|
|
|
|
def initializers_for(binding)
|
|
Collection.new(initializers_chain.map { |i| i.bind(binding) })
|
|
end
|
|
|
|
def initializer(name, opts = {}, &blk)
|
|
raise ArgumentError, "A block must be passed when defining an initializer" unless blk
|
|
opts[:after] ||= initializers.last.name unless initializers.empty? || initializers.find { |i| i.name == opts[:before] }
|
|
initializers << Initializer.new(name, nil, opts, &blk)
|
|
end
|
|
end
|
|
end
|
|
end
|