Class: Etcenv::VariableExpander

Inherits:
Object
  • Object
show all
Defined in:
lib/etcenv/variable_expander.rb

Defined Under Namespace

Classes: DepthLimitError, LoopError

Constant Summary collapse

MAX_DEPTH_DEFAULT =
50

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(variables) ⇒ VariableExpander

Returns a new instance of VariableExpander.



14
15
16
# File 'lib/etcenv/variable_expander.rb', line 14

def initialize(variables)
  @variables = variables.dup.freeze
end

Instance Attribute Details

#variablesObject (readonly)

Returns the value of attribute variables.



18
19
20
# File 'lib/etcenv/variable_expander.rb', line 18

def variables
  @variables
end

Class Method Details

.expand(variables, max = MAX_DEPTH_DEFAULT) ⇒ Object



10
11
12
# File 'lib/etcenv/variable_expander.rb', line 10

def self.expand(variables, max = MAX_DEPTH_DEFAULT)
  new(variables).expand(max)
end

Instance Method Details

#dependees_by_variableObject



34
35
36
37
38
39
40
41
42
43
44
# File 'lib/etcenv/variable_expander.rb', line 34

def dependees_by_variable
  @dependees_by_variable ||= variable_with_deps.inject({}) do |r, x|
    k, v, deps = x[0], x[1][0], x[1][1]

    deps.each do |dep|
      r[dep] ||= []
      r[dep] << k
    end
    r
  end.freeze
end

#detect_loop!Object



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/etcenv/variable_expander.rb', line 56

def detect_loop!
  if !variables.empty? && root_variables.empty?
    raise LoopError, "there's no possible root variables (variables which don't have dependee)"
  else
    dependees_by_variable.each do |k, deps|
      deps.each do |dep|
        if (dependees_by_variable[dep] || []).include?(k)
          raise LoopError, "There's a loop between $#{dep} and $#{k}"
        end
      end
    end
  end
end

#expand(max = MAX_DEPTH_DEFAULT) ⇒ Object



20
21
22
23
24
25
26
27
28
# File 'lib/etcenv/variable_expander.rb', line 20

def expand(max = MAX_DEPTH_DEFAULT)
  detect_loop!

  result = {}
  solve_order(max).map do |x|
    result[x] = single_expand(@variables[x], result)
  end
  result
end

#root_variablesObject



46
47
48
49
50
51
52
53
54
# File 'lib/etcenv/variable_expander.rb', line 46

def root_variables
  @root_variables ||= variable_with_deps.inject([]) do |r, x|
    k, v, deps = x[0], x[1][0], x[1][1]
    if deps.empty?
      r << k
    end
    r
  end + (variables.keys - dependees_by_variable.keys)
end

#solve_order(max_depth = 10) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/etcenv/variable_expander.rb', line 70

def solve_order(max_depth = 10)
  order = []
  solve = nil
  solve = ->(vs, depth = 0) do
    raise DepthLimitError if depth.succ > max_depth
    vs.each do |x|
      order.concat solve.call(dependees_by_variable[x] || [], depth.succ) + [x]
    end
  end
  solve.call(root_variables)

  Utils.uniq_with_keeping_first_appearance(order).reverse
end

#variable_with_depsObject



30
31
32
# File 'lib/etcenv/variable_expander.rb', line 30

def variable_with_deps
  @variables.map { |k, v| [k, [v, detect_variables(v)]] }
end