Class: ATP::Processors::Condition

Inherits:
ATP::Processor show all
Defined in:
lib/atp/processors/condition.rb

Overview

This optimizes the condition nodes such that any adjacent flow nodes that have the same condition, will be grouped together under a single condition wrapper.

For example this AST:

(flow
  (group
    (name "g1")
    (test
      (name "test1"))
    (flow-flag "bitmap" true
      (test
        (name "test2"))))
  (flow-flag "bitmap" true
    (group
      (name "g1")
      (flow-flag "x" true
        (test
          (name "test3")))
      (flow-flag "y" true
        (flow-flag "x" true
          (test
            (name "test4")))))))

Will be optimized to this:

(flow
  (group
    (name "g1")
    (test
      (name "test1"))
    (flow-flag "bitmap" true
      (test
        (name "test2"))
      (flow-flag "x" true
        (test
          (name "test3"))
        (flow-flag "y" true
          (test
            (name "test4")))))))

Constant Summary collapse

CONDITION_NODES =
[:flow_flag, :test_result, :test_executed, :group, :job]

Instance Method Summary collapse

Methods inherited from ATP::Processor

#handler_missing, #n, #n0, #n1, #run

Instance Method Details

#combine(conditions, node) ⇒ Object



163
164
165
166
167
168
169
170
# File 'lib/atp/processors/condition.rb', line 163

def combine(conditions, node)
  if conditions && !conditions.empty?
    conditions.reverse_each do |n|
      node = n.updated(nil, n.children + (node.is_a?(Array) ? node : [node]))
    end
  end
  node
end

#condition?(node) ⇒ Boolean

Returns:

  • (Boolean)


122
123
124
# File 'lib/atp/processors/condition.rb', line 122

def condition?(node)
  node.is_a?(ATP::AST::Node) && CONDITION_NODES.include?(node.type)
end

#condition_to_be_removed?(node) ⇒ Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/atp/processors/condition.rb', line 108

def condition_to_be_removed?(node)
  remove_condition.any? { |c| equal_conditions?(c, node) }
end

#equal_conditions?(node1, node2) ⇒ Boolean

Returns:

  • (Boolean)


112
113
114
115
116
117
118
119
120
# File 'lib/atp/processors/condition.rb', line 112

def equal_conditions?(node1, node2)
  if node1.type == node2.type
    if node1.type == :group
      node1.to_a.take(1) == node2.to_a.take(1)
    else
      node1.to_a.take(2) == node2.to_a.take(2)
    end
  end
end

#extract_common_embedded_conditions(nodes) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/atp/processors/condition.rb', line 132

def extract_common_embedded_conditions(nodes)
  nodes = [nodes] unless nodes.is_a?(Array)
  result = []
  cond_a = nil
  test_a = nil
  ConditionExtractor.new.run(nodes).each do |cond_b, test_b|
    if cond_a
      common = cond_a & cond_b
      if common.empty?
        result << combine(cond_a, extract_common_embedded_conditions(test_a))
        cond_a = cond_b
        test_a = test_b
      else
        a = combine(cond_a - common, test_a)
        b = combine(cond_b - common, test_b)
        cond_a = common
        test_a = [a, b].flatten
      end
    else
      cond_a = cond_b
      test_a = test_b
    end
  end
  if nodes == [test_a]
    nodes
  else
    result << combine(cond_a, extract_common_embedded_conditions(test_a))
    result.flatten
  end
end

#has_condition?(condition, node) ⇒ Boolean

Returns true if the given node contains the given condition within its immediate children

Returns:

  • (Boolean)


100
101
102
103
104
105
106
# File 'lib/atp/processors/condition.rb', line 100

def has_condition?(condition, node)
  ([node] + node.children.to_a).any? do |n|
    if n.is_a?(ATP::AST::Node)
      equal_conditions?(condition, n)
    end
  end
end

#on_boolean_condition(node) ⇒ Object Also known as: on_flow_flag, on_test_result, on_test_executed, on_job



67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/atp/processors/condition.rb', line 67

def on_boolean_condition(node)
  children = node.children.dup
  name = children.shift
  state = children.shift
  remove_condition << node
  children = extract_common_embedded_conditions(n(:temp, children))
  remove_condition.pop
  if condition_to_be_removed?(node)
    process_all(children)
  else
    node.updated(nil, [name, state] + process_all(children))
  end
end

#on_flow(node) ⇒ Object



126
127
128
129
130
# File 'lib/atp/processors/condition.rb', line 126

def on_flow(node)
  name, *nodes = *node
  nodes = extract_common_embedded_conditions(nodes)
  node.updated(nil, [name] + nodes)
end

#on_group(node) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/atp/processors/condition.rb', line 85

def on_group(node)
  children = node.children.dup
  name = children.shift
  remove_condition << node
  children = extract_common_embedded_conditions(n(:temp, children))
  remove_condition.pop
  if condition_to_be_removed?(node)
    process_all(children)
  else
    node.updated(nil, [name] + process_all(children))
  end
end

#process(node) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/atp/processors/condition.rb', line 48

def process(node)
  # Bit of a hack - To get all of the nested conditions optimized away it is necessary
  # to execute this recursively a few times. This guard ensures that the recursion is
  # only performed on the top-level and not on every process operation.
  if @top_level_called
    super
  else
    @top_level_called = true
    ast1 = nil
    ast2 = node
    while ast1 != ast2
      ast1 = super(ast2)
      ast2 = super(ast1)
    end
    @top_level_called = false
    ast1
  end
end

#remove_conditionObject



172
173
174
# File 'lib/atp/processors/condition.rb', line 172

def remove_condition
  @remove_condition ||= []
end