# module Crystal # class DependencyResolver # class Dependency # attr_accessor :name, :block, :before, :after # # def initialize name, block # @name, @block = name, block # @before, @after = [], [] # end # # def inspect # "#<#{name} #{before.inspect}, #{after.inspect}>" # end # end # # def dependencies; @dependencies ||= {} end # # # # # Define dependency # # # def run name, options = {}, &block # options = options.to_openobject # # raise "Invalid usage, you must specify :after or :before!" unless options.before? or options.after? # d = Dependency.new name, block # # if options.before? # add_dependency d, :before, options.before.must_be.present # elsif options.after? # add_dependency d, :after, options.after.must_be.present # else # add_dependency d, nil, nil # end # end # # # # # # Call dependencies # # # def call name, &block # return unless dep = dependencies[name] # # # before # callees = [] # dep_lists = [dep.before] # while !dep_lists.empty? # dep_lists.each do |list| # callees << list # end # # dep_lists = next_level dep_lists, :before # end # call_all callees.reverse # # # call # dep.block.call if dep.block # # # after # dep_lists = [dep.after] # while !dep_lists.empty? # call_all dep_lists # # dep_lists = next_level dep_lists, :after # end # end # # protected # def add_dependency dep, type, ref # raise "Dependency '#{dep.name}' already defined!" if dependencies.include? dep.name # dependencies[dep.name] = dep # # # add back reference # if type # catch :found do # dep_lists = [dependencies.values] # while !dep_lists.empty? # dep_lists.each do |list| # list.each do |d| # if d.name == ref # d.send(type) << dep # throw :found # end # end # end # # dep_lists = next_level dep_lists, type # end # # raise "Dependency '#{ref}' referenced from '#{dep.name}' not found!" # end # end # end # # def next_level dep_lists, type # r = [] # dep_lists.each do |list| # list.each do |d| # r << d.send(type) # end # end # r # end # # def call_all list_of_lists # list_of_lists.each{|list| list.each{|d| d.block.call if d.block}} # end # end # end