cucumber-tag-expressions 4.1.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: add075dc395b297351352601837188db90a7e347035845e63e8af7028ecc9d90
4
- data.tar.gz: d9e1ed8d2291b2338c2a64303581e6cfa84854265aff0422d75bf8641f156c5e
3
+ metadata.gz: c0642b9d453a4744506946b51bbde89b079a8db597c0f0f67122340283c98c07
4
+ data.tar.gz: 9a5e50d412b6b352b6ee9c8276941471fa29b183edf76eedc59482671c40a732
5
5
  SHA512:
6
- metadata.gz: 258a7f1a40ba0022491144dba178f8b6ac6a2e9c6180273e2c19244981b463651cb586c9ee6bf4acf4c34c42400f28305165d75571749be6de275fe9fb68d3ed
7
- data.tar.gz: e03fbb76b4a951de7a8f4a1d6a3f60b3d47ed9c79b158e729ec153880b36bb28181bbc95c14125cd6ace08ab3578def4ca68781d90fbee64f455d04e4a6ad232
6
+ metadata.gz: c6dad5df3a70282c263c30ca2c89335752843f34960e89e49ff3d90490a3d15f1574cf14a6e2ac49016f6f682dce0abb66151bc8a45700d48c691864da516907
7
+ data.tar.gz: ce5a050cd9b6c2ae6f907cf5de61ec0a77c724a4361da2d46bfe507f9114bcec3ba2ae271105f41d1fc9a3d1c6684ab19348f6dc4bd5bd393afed8c78be44dfe
@@ -11,7 +11,11 @@ module Cucumber
11
11
  end
12
12
 
13
13
  def to_s
14
- @value.gsub(/\\/, "\\\\\\\\").gsub(/\(/, "\\(").gsub(/\)/, "\\)")
14
+ @value
15
+ .gsub(/\\/, "\\\\\\\\")
16
+ .gsub(/\(/, "\\(")
17
+ .gsub(/\)/, "\\)")
18
+ .gsub(/\s/, "\\ ")
15
19
  end
16
20
  end
17
21
 
@@ -61,5 +65,15 @@ module Cucumber
61
65
  "( #{@left} and #{@right} )"
62
66
  end
63
67
  end
68
+
69
+ class True
70
+ def evaluate(variables)
71
+ true
72
+ end
73
+
74
+ def to_s
75
+ "true"
76
+ end
77
+ end
64
78
  end
65
79
  end
@@ -18,9 +18,21 @@ module Cucumber
18
18
  end
19
19
 
20
20
  def parse(infix_expression)
21
- process_tokens!(infix_expression)
21
+ expected_token_type = :operand
22
+
23
+ tokens = tokenize(infix_expression)
24
+ return True.new if tokens.empty?
25
+
26
+ tokens.each do |token|
27
+ if @operator_types[token]
28
+ expected_token_type = send("handle_#{@operator_types[token][:type]}", infix_expression, token, expected_token_type)
29
+ else
30
+ expected_token_type = handle_literal(infix_expression, token, expected_token_type)
31
+ end
32
+ end
33
+
22
34
  while @operators.any?
23
- raise 'Syntax error. Unmatched (' if @operators.last == '('
35
+ raise %Q{Tag expression "#{infix_expression}" could not be parsed because of syntax error: Unmatched (.} if @operators.last == '('
24
36
  push_expression(pop(@operators))
25
37
  end
26
38
  expression = pop(@expressions)
@@ -52,48 +64,36 @@ module Cucumber
52
64
  @operator_types[token][:precedence]
53
65
  end
54
66
 
55
- def tokens(infix_expression)
67
+ def tokenize(infix_expression)
68
+ tokens = []
56
69
  escaped = false
57
70
  token = ""
58
- result = []
59
71
  infix_expression.chars.each do | ch |
60
- if ch == '\\' && !escaped
61
- escaped = true
62
- else
63
- if ch.match(/\s/)
64
- if token.length > 0
65
- result.push(token)
66
- token = ""
67
- end
72
+ if escaped
73
+ if ch == '(' || ch == ')' || ch == '\\' || ch.match(/\s/)
74
+ token += ch
75
+ escaped = false
68
76
  else
69
- if (ch == '(' || ch == ')') && !escaped
70
- if token.length > 0
71
- result.push(token)
72
- token = ""
73
- end
74
- result.push(ch)
75
- else
76
- token = token + ch
77
- end
77
+ raise %Q{Tag expression "#{infix_expression}" could not be parsed because of syntax error: Illegal escape before "#{ch}".}
78
78
  end
79
- escaped = false
79
+ elsif ch == '\\'
80
+ escaped = true
81
+ elsif ch == '(' || ch == ')' || ch.match(/\s/)
82
+ if token.length > 0
83
+ tokens.push(token)
84
+ token = ""
85
+ end
86
+ if !ch.match(/\s/)
87
+ tokens.push(ch)
88
+ end
89
+ else
90
+ token += ch
80
91
  end
81
92
  end
82
93
  if token.length > 0
83
- result.push(token)
84
- end
85
- result
86
- end
87
-
88
- def process_tokens!(infix_expression)
89
- expected_token_type = :operand
90
- tokens(infix_expression).each do |token|
91
- if @operator_types[token]
92
- expected_token_type = send("handle_#{@operator_types[token][:type]}", token, expected_token_type)
93
- else
94
- expected_token_type = handle_literal(token, expected_token_type)
95
- end
94
+ tokens.push(token)
96
95
  end
96
+ tokens
97
97
  end
98
98
 
99
99
  def push_expression(token)
@@ -112,14 +112,14 @@ module Cucumber
112
112
  ############################################################################
113
113
  # Handlers
114
114
  #
115
- def handle_unary_operator(token, expected_token_type)
116
- check(expected_token_type, :operand)
115
+ def handle_unary_operator(infix_expression, token, expected_token_type)
116
+ check(infix_expression, expected_token_type, :operand)
117
117
  @operators.push(token)
118
118
  :operand
119
119
  end
120
120
 
121
- def handle_binary_operator(token, expected_token_type)
122
- check(expected_token_type, :operator)
121
+ def handle_binary_operator(infix_expression, token, expected_token_type)
122
+ check(infix_expression, expected_token_type, :operator)
123
123
  while @operators.any? && operator?(@operators.last) &&
124
124
  lower_precedence?(token)
125
125
  push_expression(pop(@operators))
@@ -128,31 +128,31 @@ module Cucumber
128
128
  :operand
129
129
  end
130
130
 
131
- def handle_open_paren(token, expected_token_type)
132
- check(expected_token_type, :operand)
131
+ def handle_open_paren(infix_expression, token, expected_token_type)
132
+ check(infix_expression, expected_token_type, :operand)
133
133
  @operators.push(token)
134
134
  :operand
135
135
  end
136
136
 
137
- def handle_close_paren(_token, expected_token_type)
138
- check(expected_token_type, :operator)
137
+ def handle_close_paren(infix_expression, _token, expected_token_type)
138
+ check(infix_expression, expected_token_type, :operator)
139
139
  while @operators.any? && @operators.last != '('
140
140
  push_expression(pop(@operators))
141
141
  end
142
- raise 'Syntax error. Unmatched )' if @operators.empty?
142
+ raise %Q{Tag expression "#{infix_expression}" could not be parsed because of syntax error: Unmatched ).} if @operators.empty?
143
143
  pop(@operators) if @operators.last == '('
144
144
  :operator
145
145
  end
146
146
 
147
- def handle_literal(token, expected_token_type)
148
- check(expected_token_type, :operand)
147
+ def handle_literal(infix_expression, token, expected_token_type)
148
+ check(infix_expression, expected_token_type, :operand)
149
149
  push_expression(token)
150
150
  :operator
151
151
  end
152
152
 
153
- def check(expected_token_type, token_type)
153
+ def check(infix_expression, expected_token_type, token_type)
154
154
  if expected_token_type != token_type
155
- raise "Syntax error. Expected #{expected_token_type}"
155
+ raise %Q{Tag expression "#{infix_expression}" could not be parsed because of syntax error: Expected #{expected_token_type}.}
156
156
  end
157
157
  end
158
158
 
@@ -0,0 +1,13 @@
1
+ require 'cucumber/tag_expressions/parser'
2
+ require 'yaml'
3
+
4
+ tests = YAML.load_file('../testdata/errors.yml')
5
+
6
+ describe 'Errors' do
7
+ tests.each do |test|
8
+ it %Q{fails to parse "#{test['expression']}" with "#{test['error']}"} do
9
+ parser = Cucumber::TagExpressions::Parser.new
10
+ expect { parser.parse(test['expression']) }.to raise_error(test['error'])
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ require 'cucumber/tag_expressions/parser'
2
+ require 'yaml'
3
+
4
+ evaluations = YAML.load_file('../testdata/evaluations.yml')
5
+
6
+ describe 'Evaluations' do
7
+ evaluations.each do |evaluation|
8
+ context evaluation['expression'] do
9
+ evaluation['tests'].each do |test|
10
+ it "evaluates [#{test['variables'].join(', ')}] to #{test['result']}" do
11
+ parser = Cucumber::TagExpressions::Parser.new
12
+ expect(parser.parse(evaluation['expression']).evaluate(test['variables'])).to eq(test['result'])
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ require 'cucumber/tag_expressions/parser'
2
+ require 'yaml'
3
+
4
+ tests = YAML.load_file('../testdata/parsing.yml')
5
+
6
+ describe 'Parsing' do
7
+ tests.each do |test|
8
+ it %Q{parses "#{test['expression']}" into "#{test['formatted']}"} do
9
+ parser = Cucumber::TagExpressions::Parser.new
10
+ expression = parser.parse(test['expression'])
11
+ expect(expression.to_s).to eq(test['formatted'])
12
+ end
13
+ end
14
+ end
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: 4.1.0
4
+ version: 5.0.0
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: 2021-10-08 00:00:00.000000000 Z
12
+ date: 2023-01-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -57,23 +57,22 @@ executables: []
57
57
  extensions: []
58
58
  extra_rdoc_files: []
59
59
  files:
60
- - LICENSE
61
60
  - README.md
62
61
  - lib/cucumber/tag_expressions.rb
63
62
  - lib/cucumber/tag_expressions/expressions.rb
64
63
  - lib/cucumber/tag_expressions/parser.rb
65
- - spec/capture_warnings.rb
66
- - spec/expressions_spec.rb
67
- - spec/parser_spec.rb
64
+ - spec/errors_spec.rb
65
+ - spec/evaluations_spec.rb
66
+ - spec/parsing_spec.rb
68
67
  homepage: https://cucumber.io/docs/cucumber/api/#tag-expressions
69
68
  licenses:
70
69
  - MIT
71
70
  metadata:
72
71
  bug_tracker_uri: https://github.com/cucumber/cucumber/issues
73
- changelog_uri: https://github.com/cucumber/common/blob/main/tag-expressions/CHANGELOG.md
72
+ changelog_uri: https://github.com/cucumber/tag-expressions/blob/main/CHANGELOG.md
74
73
  documentation_uri: https://cucumber.io/docs/cucumber/api/#tag-expressions
75
74
  mailing_list_uri: https://groups.google.com/forum/#!forum/cukes
76
- source_code_uri: https://github.com/cucumber/common/blob/main/tag-expressions/ruby
75
+ source_code_uri: https://github.com/cucumber/tag-expressions/tree/main/ruby
77
76
  post_install_message:
78
77
  rdoc_options:
79
78
  - "--charset=UTF-8"
@@ -90,11 +89,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
89
  - !ruby/object:Gem::Version
91
90
  version: '0'
92
91
  requirements: []
93
- rubygems_version: 3.1.2
92
+ rubygems_version: 3.2.22
94
93
  signing_key:
95
94
  specification_version: 4
96
- summary: cucumber-tag-expressions-4.1.0
95
+ summary: cucumber-tag-expressions-5.0.0
97
96
  test_files:
98
- - spec/expressions_spec.rb
99
- - spec/capture_warnings.rb
100
- - spec/parser_spec.rb
97
+ - spec/errors_spec.rb
98
+ - spec/evaluations_spec.rb
99
+ - spec/parsing_spec.rb
data/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) Cucumber Ltd
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
- # With thanks to @myronmarston
3
- # https://github.com/vcr/vcr/blob/master/spec/capture_warnings.rb
4
-
5
- module CaptureWarnings
6
- def report_warnings(&block)
7
- current_dir = Dir.pwd
8
- warnings, errors = capture_error(&block).partition { |line| line.include?('warning') }
9
- project_warnings, other_warnings = warnings.uniq.partition { |line| line.include?(current_dir) }
10
-
11
- if errors.any?
12
- puts errors.join("\n")
13
- end
14
-
15
- if other_warnings.any?
16
- puts "#{ other_warnings.count } warnings detected, set VIEW_OTHER_WARNINGS=true to see them."
17
- print_warnings('other', other_warnings) if ENV['VIEW_OTHER_WARNINGS']
18
- end
19
-
20
- # Until they fix https://bugs.ruby-lang.org/issues/10661
21
- if RUBY_VERSION == "2.2.0"
22
- project_warnings = project_warnings.reject { |w| w =~ /warning: possible reference to past scope/ }
23
- end
24
-
25
- if project_warnings.any?
26
- puts "#{ project_warnings.count } warnings detected"
27
- print_warnings('cucumber-expressions', project_warnings)
28
- fail "Please remove all cucumber-expressions warnings."
29
- end
30
-
31
- ensure_system_exit_if_required
32
- end
33
-
34
- def capture_error(&block)
35
- old_stderr = STDERR.clone
36
- pipe_r, pipe_w = IO.pipe
37
- pipe_r.sync = true
38
- error = String.new
39
- reader = Thread.new do
40
- begin
41
- loop do
42
- error << pipe_r.readpartial(1024)
43
- end
44
- rescue EOFError
45
- end
46
- end
47
- STDERR.reopen(pipe_w)
48
- block.call
49
- ensure
50
- capture_system_exit
51
- STDERR.reopen(old_stderr)
52
- pipe_w.close
53
- reader.join
54
- return error.split("\n")
55
- end
56
-
57
- def print_warnings(type, warnings)
58
- puts
59
- puts "-" * 30 + " #{type} warnings: " + "-" * 30
60
- puts
61
- puts warnings.join("\n")
62
- puts
63
- puts "-" * 75
64
- puts
65
- end
66
-
67
- def ensure_system_exit_if_required
68
- raise @system_exit if @system_exit
69
- end
70
-
71
- def capture_system_exit
72
- @system_exit = $!
73
- end
74
- end
@@ -1,84 +0,0 @@
1
- require 'cucumber/tag_expressions/parser'
2
-
3
- describe 'Expression node' do
4
- shared_examples 'expression node' do |infix_expression, data|
5
- data.each do |tags, result|
6
- it "#{infix_expression.inspect} with variables: #{tags.inspect}'" do
7
- expression = Cucumber::TagExpressions::Parser.new.parse(infix_expression)
8
- expect(expression.evaluate(tags)).to eq(result)
9
- end
10
- end
11
- end
12
-
13
- describe Cucumber::TagExpressions::Not do
14
- context '#evaluate' do
15
- infix_expression = 'not x'
16
- data = [[%w(x), false],
17
- [%w(y), true]]
18
- include_examples 'expression node', infix_expression, data
19
- end
20
- end
21
-
22
- describe Cucumber::TagExpressions::And do
23
- context '#evaluate' do
24
- infix_expression = 'x and y'
25
- data = [[%w(x y), true],
26
- [%w(x), false],
27
- [%w(y), false]]
28
- include_examples 'expression node', infix_expression, data
29
- end
30
- end
31
-
32
- describe Cucumber::TagExpressions::Or do
33
- context '#evaluate' do
34
- infix_expression = 'x or y'
35
- data = [[%w(), false],
36
- [%w(x), true],
37
- [%w(y), true],
38
- [%w(x q), true],
39
- [%w(x y), true]]
40
- include_examples 'expression node', infix_expression, data
41
- end
42
- end
43
-
44
- describe Cucumber::TagExpressions::Or do
45
- context '#evaluate' do
46
- infix_expression = 'x\\(1\\) or (y\\(2\\))'
47
- data = [[%w(), false],
48
- [%w(x), false],
49
- [%w(y), false],
50
- [%w(x(1)), true],
51
- [%w(y(2)), true]]
52
- include_examples 'expression node', infix_expression, data
53
- end
54
- end
55
-
56
- describe Cucumber::TagExpressions::Or do
57
- context '#evaluate' do
58
- infix_expression = 'x\\\\ or (y\\\\\\)) or (z\\\\)'
59
- data = [[%w(), false],
60
- [%w(x), false],
61
- [%w(y\)), false],
62
- [%w(z), false],
63
- [%w(x\\), true],
64
- [%w(y\\\)), true],
65
- [%w(z\\), true]]
66
- include_examples 'expression node', infix_expression, data
67
- end
68
- end
69
-
70
- describe Cucumber::TagExpressions::Or do
71
- context '#evaluate' do
72
- infix_expression = '\\x or y\\ or z\\'
73
- data = [[%w(), false],
74
- [%w(\\x), false],
75
- [%w(y\\), false],
76
- [%w(z\\), false],
77
- [%w(x), true],
78
- [%w(y), true],
79
- [%w(z), true]]
80
- include_examples 'expression node', infix_expression, data
81
- end
82
- end
83
-
84
- end
data/spec/parser_spec.rb DELETED
@@ -1,50 +0,0 @@
1
- require 'cucumber/tag_expressions/parser'
2
-
3
- describe Cucumber::TagExpressions::Parser do
4
- correct_test_data = [
5
- ['a and b', '( a and b )'],
6
- ['a or (b)', '( a or b )'],
7
- ['not a', 'not ( a )'],
8
- ['( a and b ) or ( c and d )', '( ( a and b ) or ( c and d ) )'],
9
- ['not a or b and not c or not d or e and f',
10
- '( ( ( not ( a ) or ( b and not ( c ) ) ) or not ( d ) ) or ( e and f ) )'],
11
- ['not a\\(\\) or b and not c or not d or e and f',
12
- '( ( ( not ( a\\(\\) ) or ( b and not ( c ) ) ) or not ( d ) ) or ( e and f ) )'],
13
- ['a\\\\ and b', '( a\\\\ and b )'],
14
- ['\\a and b\\ and c\\', '( ( a and b ) and c )'],
15
- ['(a and b\\\\)', '( a and b\\\\ )'],
16
- ['a\\\\\\( and b\\\\\\)', '( a\\\\\\( and b\\\\\\) )']
17
- ]
18
-
19
- error_test_data = [
20
- ['@a @b or', 'Syntax error. Expected operator'],
21
- ['@a and (@b not)', 'Syntax error. Expected operator'],
22
- ['@a and (@b @c) or', 'Syntax error. Expected operator'],
23
- ['@a and or', 'Syntax error. Expected operand'],
24
- ['or or', 'Syntax error. Expected operand'],
25
- ['a b', 'Syntax error. Expected operator'],
26
- ['( a and b ) )', 'Syntax error. Unmatched )'],
27
- ['( ( a and b )', 'Syntax error. Unmatched ('],
28
- ]
29
-
30
- context '#parse' do
31
- context 'with correct test data' do
32
- correct_test_data.each do |infix_expression, to_string|
33
- parser = Cucumber::TagExpressions::Parser.new
34
- it "parses correctly #{infix_expression.inspect}" do
35
- expect(parser.parse(infix_expression).to_s).to eq(to_string)
36
- end
37
- end
38
- end
39
-
40
- context 'with error test data' do
41
- error_test_data.each do |infix_expression, message|
42
- parser = Cucumber::TagExpressions::Parser.new
43
- it "raises an error parsing #{infix_expression.inspect}" do
44
- expect { parser.parse(infix_expression) }
45
- .to raise_error(RuntimeError, message)
46
- end
47
- end
48
- end
49
- end
50
- end