lib/hx.rb in hx-0.15.0 vs lib/hx.rb in hx-0.16.0

- old
+ new

@@ -25,10 +25,11 @@ require 'set' require 'pathname' require 'tempfile' require 'yaml' require 'hx/path' +require 'set' module Hx VERSION = (Pathname.new(__FILE__).parent.parent + 'VERSION').read.strip @@ -335,10 +336,11 @@ def Chain.new(input, options) filters = options[:chain] || [] options = options.dup options.delete(:chain) # prevent inheritance for raw_filter in filters + raw_filter = Hx.expand_chain(raw_filter) input = Hx.build_source(options, input, {}, raw_filter) end input end @@ -407,22 +409,34 @@ end end raw_input end -def self.build_source(options, default_input, sources, raw_source) - raw_source = expand_chain(raw_source) - +def self.get_input_names(raw_source) if raw_source.has_key? 'input' - input_name = raw_source['input'] + return Array(raw_source['input']) + else + [] + end +end + +def self.build_source(options, default_input, sources, raw_source) + input_names = get_input_names(raw_source) + input_sources = input_names.map do |input_name| begin - source = sources.fetch(input_name) + sources.fetch(input_name) rescue IndexError raise NameError, "No source named #{input_name} in scope" end - else + end + case input_sources.length + when 0 source = default_input + when 1 + source = input_sources.first + else + source = Overlay.new(*input_sources) end if raw_source.has_key? 'filter' if raw_source.has_key? 'options' filter_options = options.dup @@ -498,43 +512,51 @@ end end raw_sources_by_name = raw_config.fetch('sources', {}) raw_outputs = raw_config.fetch('output', []) - source_names = raw_sources_by_name.keys + for name, raw_source in raw_sources_by_name + raw_sources_by_name[name] = Hx.expand_chain(raw_source) + end + raw_outputs = raw_outputs.map! do |raw_output| + Hx.expand_chain(raw_output) + end # build input dependency graph - source_dependencies = {} + source_dependencies = Hash.new { |h,k| h[k] = Set.new } source_count_by_dependency = Hash.new(0) for name, raw_source in raw_sources_by_name - raw_source = Hx.expand_chain(raw_source) - if raw_source.has_key? 'input' - input_name = raw_source['input'] - source_dependencies[name] = input_name + for input_name in Hx.get_input_names(raw_source) + source_dependencies[name].add input_name source_count_by_dependency[input_name] += 1 end end for raw_output in raw_outputs - raw_output = Hx.expand_chain(raw_output) - if raw_output.has_key? 'input' - input_name = raw_source['input'] + for input_name in Hx.get_input_names(raw_source) source_count_by_dependency[input_name] += 1 end end + source_names = raw_sources_by_name.keys + # calculate depth for each input in the graph source_depths = Hash.new(0) - for name in source_names - seen = Set[] # for cycle detection - while source_dependencies.has_key? name - if seen.include? name - raise RuntimeError, "cycle in source graph at #{name}" - end - seen.add name + to_process = Set.new(source_names) + until to_process.empty? + need_updating = Set.new + for name in to_process depth = source_depths[name] + 1 - name = source_dependencies[name] - source_depths[name] = depth if depth > source_depths[name] + if depth >= source_names.length + raise "cycle in source graph involving #{name}" + end + for input_name in source_dependencies[name] + if depth > source_depths[input_name] + source_depths[input_name] = depth + need_updating.add input_name + end + end end + to_process = need_updating end # depth-first topological sort depth_first_names = source_names.sort_by { |n| -source_depths[n] }