cucumber-tag-expressions 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6ace30f7929f56e9f7fb15e914f1cd2a505f7d8d45c938c26e4bbf02e21fbd5a
4
+ data.tar.gz: 39eeb518cb6cba26529321912bb3f81a889ef33387ee4e0bb4212615f5931872
5
+ SHA512:
6
+ metadata.gz: db6b0596392018944363bd639303c1148ac1063e080f89bbb1d81c99b251a2637f1ef79d16b7c74f949069f974854a71ae75d03f95346497c15e4a5013677f84
7
+ data.tar.gz: e0e5c54580a07129712df9a3f1ae23314640576a34529046d942d6da84de71df73973410b07fc18d64e5cf1b0bfaaa766cf6137485338fdece12101a37617d17
data/LICENSE ADDED
@@ -0,0 +1,21 @@
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.
@@ -0,0 +1,3 @@
1
+ # Cucumber Tag Expressions for Ruby
2
+
3
+ [The docs are here](https://cucumber.io/docs/cucumber/api/#tag-expressions).
@@ -0,0 +1 @@
1
+ require 'cucumber/tag_expressions/parser'
@@ -0,0 +1,65 @@
1
+ module Cucumber
2
+ module TagExpressions
3
+ # Literal expression node
4
+ class Literal
5
+ def initialize(value)
6
+ @value = value.gsub(/\\\(/, '(').gsub(/\\\)/, ')')
7
+ end
8
+
9
+ def evaluate(variables)
10
+ variables.include?(@value)
11
+ end
12
+
13
+ def to_s
14
+ @value.gsub(/\(/, '\\(').gsub(/\)/, '\\)')
15
+ end
16
+ end
17
+
18
+ # Not expression node
19
+ class Not
20
+ def initialize(expression)
21
+ @expression = expression
22
+ end
23
+
24
+ def evaluate(variables)
25
+ !@expression.evaluate(variables)
26
+ end
27
+
28
+ def to_s
29
+ "not ( #{@expression} )"
30
+ end
31
+ end
32
+
33
+ # Or expression node
34
+ class Or
35
+ def initialize(left, right)
36
+ @left = left
37
+ @right = right
38
+ end
39
+
40
+ def evaluate(variables)
41
+ @left.evaluate(variables) || @right.evaluate(variables)
42
+ end
43
+
44
+ def to_s
45
+ "( #{@left} or #{@right} )"
46
+ end
47
+ end
48
+
49
+ # And expression node
50
+ class And
51
+ def initialize(left, right)
52
+ @left = left
53
+ @right = right
54
+ end
55
+
56
+ def evaluate(variables)
57
+ @left.evaluate(variables) && @right.evaluate(variables)
58
+ end
59
+
60
+ def to_s
61
+ "( #{@left} and #{@right} )"
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,137 @@
1
+ require 'cucumber/tag_expressions/expressions.rb'
2
+
3
+ module Cucumber
4
+ module TagExpressions
5
+ # Ruby tag expression parser
6
+ class Parser
7
+ def initialize
8
+ @expressions = []
9
+ @operators = []
10
+
11
+ @operator_types = {
12
+ 'or' => { type: :binary_operator, precedence: 0, assoc: :left },
13
+ 'and' => { type: :binary_operator, precedence: 1, assoc: :left },
14
+ 'not' => { type: :unary_operator, precedence: 2, assoc: :right },
15
+ ')' => { type: :close_paren, precedence: -1 },
16
+ '(' => { type: :open_paren, precedence: 1 }
17
+ }
18
+ end
19
+
20
+ def parse(infix_expression)
21
+ process_tokens!(infix_expression)
22
+ while @operators.any?
23
+ raise 'Syntax error. Unmatched (' if @operators.last == '('
24
+ push_expression(pop(@operators))
25
+ end
26
+ expression = pop(@expressions)
27
+ @expressions.empty? ? expression : raise('Not empty')
28
+ end
29
+
30
+ private
31
+
32
+ ############################################################################
33
+ # Helpers
34
+ #
35
+ def assoc_of(token, value)
36
+ @operator_types[token][:assoc] == value
37
+ end
38
+
39
+ def lower_precedence?(operation)
40
+ (assoc_of(operation, :left) &&
41
+ precedence(operation) <= precedence(@operators.last)) ||
42
+ (assoc_of(operation, :right) &&
43
+ precedence(operation) < precedence(@operators.last))
44
+ end
45
+
46
+ def operator?(token)
47
+ @operator_types[token][:type] == :unary_operator ||
48
+ @operator_types[token][:type] == :binary_operator
49
+ end
50
+
51
+ def precedence(token)
52
+ @operator_types[token][:precedence]
53
+ end
54
+
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)
64
+ else
65
+ expected_token_type = handle_literal(token, expected_token_type)
66
+ end
67
+ end
68
+ end
69
+
70
+ def push_expression(token)
71
+ case token
72
+ when 'and'
73
+ @expressions.push(And.new(*pop(@expressions, 2)))
74
+ when 'or'
75
+ @expressions.push(Or.new(*pop(@expressions, 2)))
76
+ when 'not'
77
+ @expressions.push(Not.new(pop(@expressions)))
78
+ else
79
+ @expressions.push(Literal.new(token))
80
+ end
81
+ end
82
+
83
+ ############################################################################
84
+ # Handlers
85
+ #
86
+ def handle_unary_operator(token, expected_token_type)
87
+ check(expected_token_type, :operand)
88
+ @operators.push(token)
89
+ :operand
90
+ end
91
+
92
+ def handle_binary_operator(token, expected_token_type)
93
+ check(expected_token_type, :operator)
94
+ while @operators.any? && operator?(@operators.last) &&
95
+ lower_precedence?(token)
96
+ push_expression(pop(@operators))
97
+ end
98
+ @operators.push(token)
99
+ :operand
100
+ end
101
+
102
+ def handle_open_paren(token, expected_token_type)
103
+ check(expected_token_type, :operand)
104
+ @operators.push(token)
105
+ :operand
106
+ end
107
+
108
+ def handle_close_paren(_token, expected_token_type)
109
+ check(expected_token_type, :operator)
110
+ while @operators.any? && @operators.last != '('
111
+ push_expression(pop(@operators))
112
+ end
113
+ raise 'Syntax error. Unmatched )' if @operators.empty?
114
+ pop(@operators) if @operators.last == '('
115
+ :operator
116
+ end
117
+
118
+ def handle_literal(token, expected_token_type)
119
+ check(expected_token_type, :operand)
120
+ push_expression(token)
121
+ :operator
122
+ end
123
+
124
+ def check(expected_token_type, token_type)
125
+ if expected_token_type != token_type
126
+ raise "Syntax error. Expected #{expected_token_type}"
127
+ end
128
+ end
129
+
130
+ def pop(array, n = 1)
131
+ result = array.pop(n)
132
+ raise('Empty stack') if result.size != n
133
+ n == 1 ? result.first : result
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,74 @@
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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ require 'simplecov'
3
+ formatters = [ SimpleCov::Formatter::HTMLFormatter ]
4
+
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(*formatters)
6
+ SimpleCov.add_filter 'spec/'
7
+ SimpleCov.start
@@ -0,0 +1,55 @@
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
@@ -0,0 +1,46 @@
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
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cucumber-tag-expressions
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Andrea Nodari
8
+ - Aslak Hellesøy
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-12-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '13.0'
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 13.0.1
24
+ type: :development
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - "~>"
29
+ - !ruby/object:Gem::Version
30
+ version: '13.0'
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 13.0.1
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.9'
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 3.9.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - "~>"
49
+ - !ruby/object:Gem::Version
50
+ version: '3.9'
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 3.9.0
54
+ - !ruby/object:Gem::Dependency
55
+ name: coveralls
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.8'
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 0.8.23
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: '0.8'
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 0.8.23
74
+ description: Cucumber tag expressions for ruby
75
+ email: cukes@googlegroups.com
76
+ executables: []
77
+ extensions: []
78
+ extra_rdoc_files: []
79
+ files:
80
+ - LICENSE
81
+ - README.md
82
+ - lib/cucumber/tag_expressions.rb
83
+ - lib/cucumber/tag_expressions/expressions.rb
84
+ - lib/cucumber/tag_expressions/parser.rb
85
+ - spec/capture_warnings.rb
86
+ - spec/coverage.rb
87
+ - spec/expressions_spec.rb
88
+ - spec/parser_spec.rb
89
+ homepage: https://cucumber.io/docs/cucumber/api/#tag-expressions
90
+ licenses:
91
+ - MIT
92
+ metadata:
93
+ bug_tracker_uri: https://github.com/cucumber/cucumber/issues
94
+ changelog_uri: https://github.com/cucumber/cucumber/blob/master/tag-expressions/CHANGELOG.md
95
+ documentation_uri: https://cucumber.io/docs/cucumber/api/#tag-expressions
96
+ mailing_list_uri: https://groups.google.com/forum/#!forum/cukes
97
+ source_code_uri: https://github.com/cucumber/cucumber/blob/master/tag-expressions/ruby
98
+ post_install_message:
99
+ rdoc_options:
100
+ - "--charset=UTF-8"
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: 1.9.3
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.7.6.2
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: cucumber-tag-expressions-2.0.3
119
+ test_files:
120
+ - spec/capture_warnings.rb
121
+ - spec/parser_spec.rb
122
+ - spec/coverage.rb
123
+ - spec/expressions_spec.rb