cucumber-tag-expressions 6.0.0 → 6.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/cucumber/tag_expressions/expressions.rb +10 -8
- data/lib/cucumber/tag_expressions/parser.rb +59 -64
- data/lib/cucumber/tag_expressions.rb +2 -0
- data/spec/errors_spec.rb +2 -3
- data/spec/evaluations_spec.rb +1 -2
- data/spec/parsing_spec.rb +2 -3
- data/spec/spec_helper.rb +4 -0
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 47563b3d91bae578ee83c3f510081724ba64d4322cb6196beaf0da543d4b21c0
|
4
|
+
data.tar.gz: 5bcf02d2e8b2e0aa0b7b2906ba9aecde5224f967b12fc7deb7f013e6defa5614
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 724e4dc685894201c18998973edd45866ebe13a75799119c847c19209c0f9b6b8c9042d81001d8faf2e6f922b926a5d14053b0672457394f5f6b8096cb2ccf9b
|
7
|
+
data.tar.gz: 64044f10e31c417e6348c02d7f21043e8f0aa223b6a0b892cbfe4a74b266007d85140c66c4b6528075d4cce1340a7292453810ecebfc28142e87df319d2edc16
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Cucumber
|
2
4
|
module TagExpressions
|
3
5
|
# Literal expression node
|
@@ -12,10 +14,10 @@ module Cucumber
|
|
12
14
|
|
13
15
|
def to_s
|
14
16
|
@value
|
15
|
-
.gsub(/\\/,
|
16
|
-
.gsub(/\(/,
|
17
|
-
.gsub(/\)/,
|
18
|
-
.gsub(/\s/,
|
17
|
+
.gsub(/\\/, '\\\\\\\\')
|
18
|
+
.gsub(/\(/, '\\(')
|
19
|
+
.gsub(/\)/, '\\)')
|
20
|
+
.gsub(/\s/, '\\ ')
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
@@ -30,8 +32,8 @@ module Cucumber
|
|
30
32
|
end
|
31
33
|
|
32
34
|
def to_s
|
33
|
-
if @expression.is_a?(And)|| @expression.is_a?(Or)
|
34
|
-
# -- HINT: Binary
|
35
|
+
if @expression.is_a?(And) || @expression.is_a?(Or)
|
36
|
+
# -- HINT: Binary operations already provide "( ... )"
|
35
37
|
"not #{@expression}"
|
36
38
|
else
|
37
39
|
"not ( #{@expression} )"
|
@@ -72,12 +74,12 @@ module Cucumber
|
|
72
74
|
end
|
73
75
|
|
74
76
|
class True
|
75
|
-
def evaluate(
|
77
|
+
def evaluate(_variables)
|
76
78
|
true
|
77
79
|
end
|
78
80
|
|
79
81
|
def to_s
|
80
|
-
|
82
|
+
'true'
|
81
83
|
end
|
82
84
|
end
|
83
85
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cucumber/tag_expressions/expressions'
|
2
4
|
|
3
5
|
module Cucumber
|
4
6
|
module TagExpressions
|
@@ -6,32 +8,19 @@ module Cucumber
|
|
6
8
|
def initialize
|
7
9
|
@expressions = []
|
8
10
|
@operators = []
|
9
|
-
|
10
|
-
@operator_types = {
|
11
|
-
'or' => { type: :binary_operator, precedence: 0, assoc: :left },
|
12
|
-
'and' => { type: :binary_operator, precedence: 1, assoc: :left },
|
13
|
-
'not' => { type: :unary_operator, precedence: 2, assoc: :right },
|
14
|
-
')' => { type: :close_paren, precedence: -1 },
|
15
|
-
'(' => { type: :open_paren, precedence: 1 }
|
16
|
-
}
|
17
11
|
end
|
18
12
|
|
19
13
|
def parse(infix_expression)
|
20
14
|
expected_token_type = :operand
|
21
|
-
|
22
15
|
tokens = tokenize(infix_expression)
|
23
16
|
return True.new if tokens.empty?
|
24
17
|
|
25
18
|
tokens.each do |token|
|
26
|
-
|
27
|
-
expected_token_type = send("handle_#{@operator_types[token][:type]}", infix_expression, token, expected_token_type)
|
28
|
-
else
|
29
|
-
expected_token_type = handle_literal(infix_expression, token, expected_token_type)
|
30
|
-
end
|
19
|
+
expected_token_type = handle_sequential_tokens(token, infix_expression, expected_token_type)
|
31
20
|
end
|
32
21
|
|
33
22
|
while @operators.any?
|
34
|
-
raise %
|
23
|
+
raise %{Tag expression "#{infix_expression}" could not be parsed because of syntax error: Unmatched (.} if @operators.last == '('
|
35
24
|
|
36
25
|
push_expression(pop(@operators))
|
37
26
|
end
|
@@ -42,67 +31,64 @@ module Cucumber
|
|
42
31
|
private
|
43
32
|
|
44
33
|
def assoc_of(token, value)
|
45
|
-
|
34
|
+
operator_types.dig(token, :assoc) == value
|
46
35
|
end
|
47
36
|
|
48
37
|
def lower_precedence?(operation)
|
49
|
-
(assoc_of(operation, :left) &&
|
50
|
-
|
51
|
-
(assoc_of(operation, :right) &&
|
52
|
-
precedence(operation) < precedence(@operators.last))
|
38
|
+
(assoc_of(operation, :left) && precedence(operation) <= precedence(@operators.last)) ||
|
39
|
+
(assoc_of(operation, :right) && precedence(operation) < precedence(@operators.last))
|
53
40
|
end
|
54
41
|
|
55
42
|
def operator?(token)
|
56
|
-
|
57
|
-
@operator_types[token][:type] == :binary_operator
|
43
|
+
%i[unary_operator binary_operator].include?(operator_types.dig(token, :type))
|
58
44
|
end
|
59
45
|
|
60
46
|
def precedence(token)
|
61
|
-
|
47
|
+
operator_types.dig(token, :precedence)
|
62
48
|
end
|
63
49
|
|
64
50
|
def tokenize(infix_expression)
|
65
51
|
tokens = []
|
66
52
|
escaped = false
|
67
|
-
token =
|
68
|
-
infix_expression.chars.each do |
|
53
|
+
token = +''
|
54
|
+
infix_expression.chars.each do |char|
|
69
55
|
if escaped
|
70
|
-
|
71
|
-
|
72
|
-
escaped = false
|
73
|
-
else
|
74
|
-
raise %Q{Tag expression "#{infix_expression}" could not be parsed because of syntax error: Illegal escape before "#{ch}".}
|
56
|
+
unless char == '(' || char == ')' || char == '\\' || whitespace?(char)
|
57
|
+
raise %(Tag expression "#{infix_expression}" could not be parsed because of syntax error: Illegal escape before "#{char}".)
|
75
58
|
end
|
76
|
-
|
59
|
+
|
60
|
+
token += char
|
61
|
+
escaped = false
|
62
|
+
elsif char == '\\'
|
77
63
|
escaped = true
|
78
|
-
elsif
|
79
|
-
if token.length
|
64
|
+
elsif char == '(' || char == ')' || whitespace?(char)
|
65
|
+
if token.length.positive?
|
80
66
|
tokens.push(token)
|
81
|
-
token =
|
82
|
-
end
|
83
|
-
if !ch.match(/\s/)
|
84
|
-
tokens.push(ch)
|
67
|
+
token = +''
|
85
68
|
end
|
69
|
+
tokens.push(char) unless whitespace?(char)
|
86
70
|
else
|
87
|
-
token +=
|
71
|
+
token += char
|
88
72
|
end
|
89
73
|
end
|
90
|
-
if token.length
|
91
|
-
tokens.push(token)
|
92
|
-
end
|
74
|
+
tokens.push(token) if token.length.positive?
|
93
75
|
tokens
|
94
76
|
end
|
95
77
|
|
96
78
|
def push_expression(token)
|
97
79
|
case token
|
98
|
-
when 'and'
|
99
|
-
|
100
|
-
when '
|
101
|
-
|
102
|
-
|
103
|
-
|
80
|
+
when 'and' then @expressions.push(And.new(*pop(@expressions, 2)))
|
81
|
+
when 'or' then @expressions.push(Or.new(*pop(@expressions, 2)))
|
82
|
+
when 'not' then @expressions.push(Not.new(pop(@expressions)))
|
83
|
+
else @expressions.push(Literal.new(token))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def handle_sequential_tokens(token, infix_expression, expected_token_type)
|
88
|
+
if operator_types[token]
|
89
|
+
send("handle_#{operator_types.dig(token, :type)}", infix_expression, token, expected_token_type)
|
104
90
|
else
|
105
|
-
|
91
|
+
handle_literal(infix_expression, token, expected_token_type)
|
106
92
|
end
|
107
93
|
end
|
108
94
|
|
@@ -114,10 +100,7 @@ module Cucumber
|
|
114
100
|
|
115
101
|
def handle_binary_operator(infix_expression, token, expected_token_type)
|
116
102
|
check(infix_expression, expected_token_type, :operator)
|
117
|
-
while @operators.any? && operator?(@operators.last) &&
|
118
|
-
lower_precedence?(token)
|
119
|
-
push_expression(pop(@operators))
|
120
|
-
end
|
103
|
+
push_expression(pop(@operators)) while @operators.any? && operator?(@operators.last) && lower_precedence?(token)
|
121
104
|
@operators.push(token)
|
122
105
|
:operand
|
123
106
|
end
|
@@ -130,10 +113,8 @@ module Cucumber
|
|
130
113
|
|
131
114
|
def handle_close_paren(infix_expression, _token, expected_token_type)
|
132
115
|
check(infix_expression, expected_token_type, :operator)
|
133
|
-
while @operators.any? && @operators.last != '('
|
134
|
-
|
135
|
-
end
|
136
|
-
raise %Q{Tag expression "#{infix_expression}" could not be parsed because of syntax error: Unmatched ).} if @operators.empty?
|
116
|
+
push_expression(pop(@operators)) while @operators.any? && @operators.last != '('
|
117
|
+
raise %{Tag expression "#{infix_expression}" could not be parsed because of syntax error: Unmatched ).} if @operators.empty?
|
137
118
|
|
138
119
|
pop(@operators) if @operators.last == '('
|
139
120
|
:operator
|
@@ -146,16 +127,30 @@ module Cucumber
|
|
146
127
|
end
|
147
128
|
|
148
129
|
def check(infix_expression, expected_token_type, token_type)
|
149
|
-
if expected_token_type
|
150
|
-
|
151
|
-
|
130
|
+
return if expected_token_type == token_type
|
131
|
+
|
132
|
+
raise %(Tag expression "#{infix_expression}" could not be parsed because of syntax error: Expected #{expected_token_type}.)
|
152
133
|
end
|
153
134
|
|
154
|
-
def pop(array,
|
155
|
-
result = array.pop(
|
156
|
-
raise('Empty stack') if result.
|
135
|
+
def pop(array, amount = 1)
|
136
|
+
result = array.pop(amount)
|
137
|
+
raise('Empty stack') if result.length != amount
|
138
|
+
|
139
|
+
amount == 1 ? result.first : result
|
140
|
+
end
|
141
|
+
|
142
|
+
def operator_types
|
143
|
+
{
|
144
|
+
'or' => { type: :binary_operator, precedence: 0, assoc: :left },
|
145
|
+
'and' => { type: :binary_operator, precedence: 1, assoc: :left },
|
146
|
+
'not' => { type: :unary_operator, precedence: 2, assoc: :right },
|
147
|
+
')' => { type: :close_paren, precedence: -1 },
|
148
|
+
'(' => { type: :open_paren, precedence: 1 }
|
149
|
+
}
|
150
|
+
end
|
157
151
|
|
158
|
-
|
152
|
+
def whitespace?(char)
|
153
|
+
char.match(/\s/)
|
159
154
|
end
|
160
155
|
end
|
161
156
|
end
|
data/spec/errors_spec.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
require 'yaml'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
3
|
tests = YAML.load_file('../testdata/errors.yml')
|
5
4
|
|
@@ -7,7 +6,7 @@ describe 'Errors' do
|
|
7
6
|
tests.each do |test|
|
8
7
|
let(:parser) { Cucumber::TagExpressions::Parser.new }
|
9
8
|
|
10
|
-
it
|
9
|
+
it "fails to parse '#{test['expression']}' with '#{test['error']}'" do
|
11
10
|
expect { parser.parse(test['expression']) }.to raise_error(test['error'])
|
12
11
|
end
|
13
12
|
end
|
data/spec/evaluations_spec.rb
CHANGED
data/spec/parsing_spec.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
require 'yaml'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
3
|
tests = YAML.load_file('../testdata/parsing.yml')
|
5
4
|
|
@@ -7,7 +6,7 @@ describe 'Parsing' do
|
|
7
6
|
let(:parser) { Cucumber::TagExpressions::Parser.new }
|
8
7
|
|
9
8
|
tests.each do |test|
|
10
|
-
it
|
9
|
+
it "parses '#{test['expression']}' into '#{test['formatted']}'" do
|
11
10
|
expect(parser.parse(test['expression']).to_s).to eq(test['formatted'])
|
12
11
|
end
|
13
12
|
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cucumber-tag-expressions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrea Nodari
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2024-10-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -72,6 +72,7 @@ files:
|
|
72
72
|
- spec/errors_spec.rb
|
73
73
|
- spec/evaluations_spec.rb
|
74
74
|
- spec/parsing_spec.rb
|
75
|
+
- spec/spec_helper.rb
|
75
76
|
homepage: https://cucumber.io/docs/cucumber/api/#tag-expressions
|
76
77
|
licenses:
|
77
78
|
- MIT
|
@@ -97,11 +98,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
98
|
- !ruby/object:Gem::Version
|
98
99
|
version: 3.0.8
|
99
100
|
requirements: []
|
100
|
-
rubygems_version: 3.4.
|
101
|
+
rubygems_version: 3.4.19
|
101
102
|
signing_key:
|
102
103
|
specification_version: 4
|
103
|
-
summary: cucumber-tag-expressions-6.
|
104
|
+
summary: cucumber-tag-expressions-6.1.1
|
104
105
|
test_files:
|
105
106
|
- spec/errors_spec.rb
|
106
107
|
- spec/evaluations_spec.rb
|
107
108
|
- spec/parsing_spec.rb
|
109
|
+
- spec/spec_helper.rb
|