Class: TestRunner::Cli::FilterExpression

Inherits:
Object
  • Object
show all
Defined in:
lib/test-runner/cli/filter_expression.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(str_filter) ⇒ FilterExpression

Returns a new instance of FilterExpression.



5
6
7
8
9
10
11
12
13
14
# File 'lib/test-runner/cli/filter_expression.rb', line 5

def initialize(str_filter)
  @source = str_filter.to_s
  @tokens = tokenize(@source)
  @pos = 0

  error('empty expression') if @tokens.empty?

  @expr = parse_or
  error("unexpected token #{peek[1].inspect}") if peek
end

Instance Attribute Details

#sourceObject (readonly, protected)

Returns the value of attribute source.



23
24
25
# File 'lib/test-runner/cli/filter_expression.rb', line 23

def source
  @source
end

Instance Method Details

#accept(type) ⇒ Object (protected)



124
125
126
127
128
129
130
# File 'lib/test-runner/cli/filter_expression.rb', line 124

def accept(type)
  token = peek
  return unless token && token[0] == type

  @pos += 1
  token
end

#and_expr(left, right) ⇒ Object (protected)



120
121
122
# File 'lib/test-runner/cli/filter_expression.rb', line 120

def and_expr(left, right)
  proc { |test_script| left.call(test_script) && right.call(test_script) }
end

#error(message) ⇒ Object (protected)

Raises:

  • (GLI::BadCommandLine)


148
149
150
# File 'lib/test-runner/cli/filter_expression.rb', line 148

def error(message)
  raise GLI::BadCommandLine, "Invalid filter expression #{source.inspect}: #{message}"
end

#expect(type) ⇒ Object (protected)



132
133
134
135
136
137
138
139
140
141
142
# File 'lib/test-runner/cli/filter_expression.rb', line 132

def expect(type)
  token = accept(type)
  return token if token

  expected = {
    word: 'identifier',
    rparen: ')'
  }.fetch(type, type.to_s)

  error("expected #{expected}")
end

#or_expr(left, right) ⇒ Object (protected)



116
117
118
# File 'lib/test-runner/cli/filter_expression.rb', line 116

def or_expr(left, right)
  proc { |test_script| left.call(test_script) || right.call(test_script) }
end

#parse_andObject (protected)



77
78
79
80
81
82
83
84
85
86
87
# File 'lib/test-runner/cli/filter_expression.rb', line 77

def parse_and
  expr = parse_factor

  while accept(:and)
    left = expr
    right = parse_factor
    expr = and_expr(left, right)
  end

  expr
end

#parse_comparisonObject (protected)



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/test-runner/cli/filter_expression.rb', line 99

def parse_comparison
  key = expect(:word)[1]
  op = accept(:eq) || accept(:neq)
  error('expected = or !=') unless op
  value = expect(:word)[1]

  proc do |test_script|
    if key == 'tag'
      test_script.tags.include?(value) == (op[0] == :eq)
    elsif op[0] == :eq
      test_script.labels[key].to_s == value
    else
      test_script.labels[key].to_s != value
    end
  end
end

#parse_factorObject (protected)



89
90
91
92
93
94
95
96
97
# File 'lib/test-runner/cli/filter_expression.rb', line 89

def parse_factor
  if accept(:lparen)
    expr = parse_or
    expect(:rparen)
    expr
  else
    parse_comparison
  end
end

#parse_orObject (protected)



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/test-runner/cli/filter_expression.rb', line 65

def parse_or
  expr = parse_and

  while accept(:or)
    left = expr
    right = parse_and
    expr = or_expr(left, right)
  end

  expr
end

#pass?(test_script) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


17
18
19
# File 'lib/test-runner/cli/filter_expression.rb', line 17

def pass?(test_script)
  @expr.call(test_script)
end

#peekObject (protected)



144
145
146
# File 'lib/test-runner/cli/filter_expression.rb', line 144

def peek
  @tokens[@pos]
end

#tokenize(str) ⇒ Object (protected)



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/test-runner/cli/filter_expression.rb', line 25

def tokenize(str)
  tokens = []
  i = 0

  while i < str.length
    c = str[i]

    if c.match?(/\s/)
      i += 1
    elsif str[i, 2] == '&&'
      tokens << [:and, '&&']
      i += 2
    elsif str[i, 2] == '||'
      tokens << [:or, '||']
      i += 2
    elsif str[i, 2] == '!='
      tokens << [:neq, '!=']
      i += 2
    elsif c == '='
      tokens << [:eq, '=']
      i += 1
    elsif c == '('
      tokens << [:lparen, '(']
      i += 1
    elsif c == ')'
      tokens << [:rparen, ')']
      i += 1
    elsif ['&', '|', '!'].include?(c)
      error("unexpected token #{c.inspect}")
    else
      j = i
      j += 1 while j < str.length && str[j] !~ /[\s()&|!=]/
      tokens << [:word, str[i...j]]
      i = j
    end
  end

  tokens
end