cucumber-tag-expressions 4.0.2 → 5.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7d2dc32ca080c6d1a891598da9057b1c648002a770bb271b2836bd13e0c4440d
4
- data.tar.gz: 33f531d5d359782af4f4f0c975c72cbf7a788f2be84a015b7befb31f8a818455
3
+ metadata.gz: c0642b9d453a4744506946b51bbde89b079a8db597c0f0f67122340283c98c07
4
+ data.tar.gz: 9a5e50d412b6b352b6ee9c8276941471fa29b183edf76eedc59482671c40a732
5
5
  SHA512:
6
- metadata.gz: ee2697573e51ccc628b456682814a11bd89652f85d5859b0292e1286eda5403f21fcab77df1b597e5d0a3d8f8b73212665d658f04da8c10843a9e0df862351f4
7
- data.tar.gz: de63fd74e729c530bc383ffed30a1783cf5f4381e9611390418c5259bee04e187f1ecd1c82066b1d5d013a75d6b67a8d3b0cca5db65fa85a7c16c076bbddecfe
6
+ metadata.gz: c6dad5df3a70282c263c30ca2c89335752843f34960e89e49ff3d90490a3d15f1574cf14a6e2ac49016f6f682dce0abb66151bc8a45700d48c691864da516907
7
+ data.tar.gz: ce5a050cd9b6c2ae6f907cf5de61ec0a77c724a4361da2d46bfe507f9114bcec3ba2ae271105f41d1fc9a3d1c6684ab19348f6dc4bd5bd393afed8c78be44dfe
@@ -3,7 +3,7 @@ module Cucumber
3
3
  # Literal expression node
4
4
  class Literal
5
5
  def initialize(value)
6
- @value = value.gsub(/\\\(/, '(').gsub(/\\\)/, ')')
6
+ @value = value
7
7
  end
8
8
 
9
9
  def evaluate(variables)
@@ -11,7 +11,11 @@ module Cucumber
11
11
  end
12
12
 
13
13
  def to_s
14
- @value.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,19 +64,36 @@ module Cucumber
52
64
  @operator_types[token][:precedence]
53
65
  end
54
66
 
55
- def tokens(infix_expression)
56
- infix_expression.gsub(/(?<!\\)\(/, ' ( ').gsub(/(?<!\\)\)/, ' ) ').strip.split(/\s+/)
57
- end
58
-
59
- def process_tokens!(infix_expression)
60
- expected_token_type = :operand
61
- tokens(infix_expression).each do |token|
62
- if @operator_types[token]
63
- expected_token_type = send("handle_#{@operator_types[token][:type]}", token, expected_token_type)
67
+ def tokenize(infix_expression)
68
+ tokens = []
69
+ escaped = false
70
+ token = ""
71
+ infix_expression.chars.each do | ch |
72
+ if escaped
73
+ if ch == '(' || ch == ')' || ch == '\\' || ch.match(/\s/)
74
+ token += ch
75
+ escaped = false
76
+ else
77
+ raise %Q{Tag expression "#{infix_expression}" could not be parsed because of syntax error: Illegal escape before "#{ch}".}
78
+ end
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
64
89
  else
65
- expected_token_type = handle_literal(token, expected_token_type)
90
+ token += ch
66
91
  end
67
92
  end
93
+ if token.length > 0
94
+ tokens.push(token)
95
+ end
96
+ tokens
68
97
  end
69
98
 
70
99
  def push_expression(token)
@@ -83,14 +112,14 @@ module Cucumber
83
112
  ############################################################################
84
113
  # Handlers
85
114
  #
86
- def handle_unary_operator(token, expected_token_type)
87
- check(expected_token_type, :operand)
115
+ def handle_unary_operator(infix_expression, token, expected_token_type)
116
+ check(infix_expression, expected_token_type, :operand)
88
117
  @operators.push(token)
89
118
  :operand
90
119
  end
91
120
 
92
- def handle_binary_operator(token, expected_token_type)
93
- check(expected_token_type, :operator)
121
+ def handle_binary_operator(infix_expression, token, expected_token_type)
122
+ check(infix_expression, expected_token_type, :operator)
94
123
  while @operators.any? && operator?(@operators.last) &&
95
124
  lower_precedence?(token)
96
125
  push_expression(pop(@operators))
@@ -99,31 +128,31 @@ module Cucumber
99
128
  :operand
100
129
  end
101
130
 
102
- def handle_open_paren(token, expected_token_type)
103
- check(expected_token_type, :operand)
131
+ def handle_open_paren(infix_expression, token, expected_token_type)
132
+ check(infix_expression, expected_token_type, :operand)
104
133
  @operators.push(token)
105
134
  :operand
106
135
  end
107
136
 
108
- def handle_close_paren(_token, expected_token_type)
109
- check(expected_token_type, :operator)
137
+ def handle_close_paren(infix_expression, _token, expected_token_type)
138
+ check(infix_expression, expected_token_type, :operator)
110
139
  while @operators.any? && @operators.last != '('
111
140
  push_expression(pop(@operators))
112
141
  end
113
- 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?
114
143
  pop(@operators) if @operators.last == '('
115
144
  :operator
116
145
  end
117
146
 
118
- def handle_literal(token, expected_token_type)
119
- check(expected_token_type, :operand)
147
+ def handle_literal(infix_expression, token, expected_token_type)
148
+ check(infix_expression, expected_token_type, :operand)
120
149
  push_expression(token)
121
150
  :operator
122
151
  end
123
152
 
124
- def check(expected_token_type, token_type)
153
+ def check(infix_expression, expected_token_type, token_type)
125
154
  if expected_token_type != token_type
126
- 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}.}
127
156
  end
128
157
  end
129
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.0.2
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-09-13 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.0.2
95
+ summary: cucumber-tag-expressions-5.0.0
97
96
  test_files:
98
- - spec/parser_spec.rb
99
- - spec/capture_warnings.rb
100
- - spec/expressions_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,55 +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
- end
data/spec/parser_spec.rb DELETED
@@ -1,46 +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
- ]
14
-
15
- error_test_data = [
16
- ['@a @b or', 'Syntax error. Expected operator'],
17
- ['@a and (@b not)', 'Syntax error. Expected operator'],
18
- ['@a and (@b @c) or', 'Syntax error. Expected operator'],
19
- ['@a and or', 'Syntax error. Expected operand'],
20
- ['or or', 'Syntax error. Expected operand'],
21
- ['a b', 'Syntax error. Expected operator'],
22
- ['( a and b ) )', 'Syntax error. Unmatched )'],
23
- ['( ( a and b )', 'Syntax error. Unmatched ('],
24
- ]
25
-
26
- context '#parse' do
27
- context 'with correct test data' do
28
- correct_test_data.each do |infix_expression, to_string|
29
- parser = Cucumber::TagExpressions::Parser.new
30
- it "parses correctly #{infix_expression.inspect}" do
31
- expect(parser.parse(infix_expression).to_s).to eq(to_string)
32
- end
33
- end
34
- end
35
-
36
- context 'with error test data' do
37
- error_test_data.each do |infix_expression, message|
38
- parser = Cucumber::TagExpressions::Parser.new
39
- it "raises an error parsing #{infix_expression.inspect}" do
40
- expect { parser.parse(infix_expression) }
41
- .to raise_error(RuntimeError, message)
42
- end
43
- end
44
- end
45
- end
46
- end