cucumber-tag_expressions 1.0.1 → 1.1.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
  SHA1:
3
- metadata.gz: 19bf8f6a97a5f34c6040463bbae25c1a0bfb6666
4
- data.tar.gz: 954221878d37d62109793038d3d0aa41681a7522
3
+ metadata.gz: 2e5a0bcac8bfcc6f2dc1106c1137dc0680230ffb
4
+ data.tar.gz: ca8e096362f13513df653e454ad22978249acece
5
5
  SHA512:
6
- metadata.gz: 4f1c563583f5a5cd596143818b39c598ef42881905563fe7a2cbb8d6cf14287980d7485a920935d50cf9878d602507100f7d03f52e05861a00c8cd9df9240e6f
7
- data.tar.gz: 702f403529dd3b7b014e29750df7a3cde3242f591cf222dfdda677914b979f4be87251538b27337eafc6ffc2c009e0e765465308ce783b209180c5efffa95bbc
6
+ metadata.gz: 62fed4362ef18098c1640e13c73f1f7a241b29abe6e5aa07156871c1ccf596859158684874cb4e8528937fef53a8b54111a288317da32df57591a0fcc5eae1af
7
+ data.tar.gz: cc6d23a76a4d0ea419c01c451509acbfe798648287e49da4e65b9cff2dfa8618a8a900bfecc73c34795e7d1fb2f411488140ccd35ddda9c0112c4dc46fbbb901
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This script reads NDJSON-encoded Cucumber events from STDIN and prints
4
+ # the location of each pickle (scenario) matching a tag expression. If
5
+ # no tag expression is specified, all pickle locations are printed.
6
+ #
7
+ # Example:
8
+ #
9
+ # gherkin features/*.feature | cucumber-tag-expressions "@foo and not @bar"
10
+ #
11
+ require 'json'
12
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__),"../lib"))
13
+ require 'cucumber/tag_expressions'
14
+
15
+ tag_expression_parser = Cucumber::TagExpressions::Parser.new
16
+ tag_expression = ARGV[0] ? tag_expression_parser.parse(ARGV[0]) : nil
17
+
18
+ STDIN.each do |json|
19
+ event = JSON.parse(json)
20
+ if event['type'] == 'pickle'
21
+ tag_names = event['pickle']['tags'].map {|tag| tag['name']}
22
+ if tag_expression.nil? || tag_expression.evaluate(tag_names)
23
+ location = "#{event['uri']}:#{event['pickle']['locations'][0]['line']}"
24
+ puts location
25
+ end
26
+ end
27
+ end
@@ -3,7 +3,7 @@ module Cucumber
3
3
  # Literal expression node
4
4
  class Literal
5
5
  def initialize(value)
6
- @value = value
6
+ @value = value.gsub(/\\\(/, '(').gsub(/\\\)/, ')')
7
7
  end
8
8
 
9
9
  def evaluate(variables)
@@ -11,7 +11,7 @@ module Cucumber
11
11
  end
12
12
 
13
13
  def to_s
14
- @value
14
+ @value.gsub(/\(/, '\\(').gsub(/\)/, '\\)')
15
15
  end
16
16
  end
17
17
 
@@ -6,22 +6,22 @@ module Cucumber
6
6
  class Parser
7
7
  def initialize
8
8
  @expressions = []
9
- @operations = []
10
-
11
- @components = {
12
- 'or' => { type: :operation, precedence: 0, assoc: :left },
13
- 'and' => { type: :operation, precedence: 1, assoc: :left },
14
- 'not' => { type: :operation, precedence: 2, assoc: :right },
15
- ')' => { type: :close_paren, precedence: -1 },
16
- '(' => { type: :open_paren, precedence: 1 }
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
17
  }
18
18
  end
19
19
 
20
20
  def parse(infix_expression)
21
21
  process_tokens!(infix_expression)
22
- while @operations.any?
23
- raise 'Unclosed (' if @operations.last == '('
24
- push_expression(pop(@operations))
22
+ while @operators.any?
23
+ raise 'Syntax error. Unmatched (' if @operators.last == '('
24
+ push_expression(pop(@operators))
25
25
  end
26
26
  expression = pop(@expressions)
27
27
  @expressions.empty? ? expression : raise('Not empty')
@@ -33,34 +33,36 @@ module Cucumber
33
33
  # Helpers
34
34
  #
35
35
  def assoc_of(token, value)
36
- @components[token][:assoc] == value
36
+ @operator_types[token][:assoc] == value
37
37
  end
38
38
 
39
39
  def lower_precedence?(operation)
40
40
  (assoc_of(operation, :left) &&
41
- prec(operation) <= prec(@operations.last)) ||
41
+ precedence(operation) <= precedence(@operators.last)) ||
42
42
  (assoc_of(operation, :right) &&
43
- prec(operation) < prec(@operations.last))
43
+ precedence(operation) < precedence(@operators.last))
44
44
  end
45
45
 
46
- def operation?(token)
47
- @components[token][:type] == :operation
46
+ def operator?(token)
47
+ @operator_types[token][:type] == :unary_operator ||
48
+ @operator_types[token][:type] == :binary_operator
48
49
  end
49
50
 
50
- def prec(token)
51
- @components[token][:precedence]
51
+ def precedence(token)
52
+ @operator_types[token][:precedence]
52
53
  end
53
54
 
54
55
  def tokens(infix_expression)
55
- infix_expression.gsub(/\(/, ' ( ').gsub(/\)/, ' ) ').strip.split(/\s+/)
56
+ infix_expression.gsub(/(?<!\\)\(/, ' ( ').gsub(/(?<!\\)\)/, ' ) ').strip.split(/\s+/)
56
57
  end
57
58
 
58
59
  def process_tokens!(infix_expression)
60
+ expected_token_type = :operand
59
61
  tokens(infix_expression).each do |token|
60
- if @components[token]
61
- send("handle_#{@components[token][:type]}", token)
62
+ if @operator_types[token]
63
+ expected_token_type = send("handle_#{@operator_types[token][:type]}", token, expected_token_type)
62
64
  else
63
- handle_literal(token)
65
+ expected_token_type = handle_literal(token, expected_token_type)
64
66
  end
65
67
  end
66
68
  end
@@ -81,28 +83,48 @@ module Cucumber
81
83
  ############################################################################
82
84
  # Handlers
83
85
  #
84
- def handle_literal(token)
85
- push_expression(token)
86
+ def handle_unary_operator(token, expected_token_type)
87
+ check(expected_token_type, :operand)
88
+ @operators.push(token)
89
+ :operand
86
90
  end
87
91
 
88
- def handle_operation(token)
89
- while @operations.any? && operation?(@operations.last) &&
92
+ def handle_binary_operator(token, expected_token_type)
93
+ check(expected_token_type, :operator)
94
+ while @operators.any? && operator?(@operators.last) &&
90
95
  lower_precedence?(token)
91
- push_expression(pop(@operations))
96
+ push_expression(pop(@operators))
92
97
  end
93
- @operations.push(token)
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
94
106
  end
95
107
 
96
- def handle_close_paren(_token)
97
- while @operations.any? && @operations.last != '('
98
- push_expression(pop(@operations))
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))
99
112
  end
100
- raise 'Unclosed (' if @operations.empty?
101
- pop(@operations) if @operations.last == '('
113
+ raise 'Syntax error. Unmatched )' if @operators.empty?
114
+ pop(@operators) if @operators.last == '('
115
+ :operator
102
116
  end
103
117
 
104
- def handle_open_paren(token)
105
- @operations.push(token)
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
106
128
  end
107
129
 
108
130
  def pop(array, n = 1)
@@ -3,8 +3,8 @@ require 'cucumber/tag_expressions/parser'
3
3
  describe 'Expression node' do
4
4
  shared_examples 'expression node' do |infix_expression, data|
5
5
  data.each do |tags, result|
6
- expression = Cucumber::TagExpressions::Parser.new.parse(infix_expression)
7
6
  it "#{infix_expression.inspect} with variables: #{tags.inspect}'" do
7
+ expression = Cucumber::TagExpressions::Parser.new.parse(infix_expression)
8
8
  expect(expression.evaluate(tags)).to eq(result)
9
9
  end
10
10
  end
@@ -40,4 +40,16 @@ describe 'Expression node' do
40
40
  include_examples 'expression node', infix_expression, data
41
41
  end
42
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
43
55
  end
@@ -7,15 +7,20 @@ describe Cucumber::TagExpressions::Parser do
7
7
  ['not a', 'not ( a )'],
8
8
  ['( a and b ) or ( c and d )', '( ( a and b ) or ( c and d ) )'],
9
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 ) )']
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 ) )']
11
13
  ]
12
14
 
13
15
  error_test_data = [
14
- ['( a and b ))', RuntimeError, 'Unclosed ('],
15
- ['a not ( and )', RuntimeError, 'Empty stack'],
16
- ['( ( a and b )', RuntimeError, 'Unclosed ('],
17
- ['a b', RuntimeError, 'Not empty'],
18
- ['or or', RuntimeError, 'Empty stack']
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 ('],
19
24
  ]
20
25
 
21
26
  context '#parse' do
@@ -29,11 +34,11 @@ describe Cucumber::TagExpressions::Parser do
29
34
  end
30
35
 
31
36
  context 'with error test data' do
32
- error_test_data.each do |infix_expression, error_type, message|
37
+ error_test_data.each do |infix_expression, message|
33
38
  parser = Cucumber::TagExpressions::Parser.new
34
39
  it "raises an error parsing #{infix_expression.inspect}" do
35
40
  expect { parser.parse(infix_expression) }
36
- .to raise_error(error_type, message)
41
+ .to raise_error(RuntimeError, message)
37
42
  end
38
43
  end
39
44
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cucumber-tag_expressions
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrea Nodari
8
+ - Aslak Hellesøy
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2017-05-28 00:00:00.000000000 Z
12
+ date: 2017-11-28 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bundler
@@ -44,14 +45,14 @@ dependencies:
44
45
  requirements:
45
46
  - - "~>"
46
47
  - !ruby/object:Gem::Version
47
- version: '3.5'
48
+ version: '3.7'
48
49
  type: :development
49
50
  prerelease: false
50
51
  version_requirements: !ruby/object:Gem::Requirement
51
52
  requirements:
52
53
  - - "~>"
53
54
  - !ruby/object:Gem::Version
54
- version: '3.5'
55
+ version: '3.7'
55
56
  - !ruby/object:Gem::Dependency
56
57
  name: coveralls
57
58
  requirement: !ruby/object:Gem::Requirement
@@ -68,18 +69,14 @@ dependencies:
68
69
  version: '0'
69
70
  description: Cucumber tag expressions for ruby
70
71
  email: cukes@googlegroups.com
71
- executables: []
72
+ executables:
73
+ - cucumber-tag-expressions
72
74
  extensions: []
73
75
  extra_rdoc_files: []
74
76
  files:
75
- - ".rspec"
76
- - ".travis.yml"
77
- - Gemfile
78
77
  - LICENSE
79
- - Makefile
80
78
  - README.md
81
- - Rakefile
82
- - cucumber-tag_expressions.gemspec
79
+ - bin/cucumber-tag-expressions
83
80
  - lib/cucumber/tag_expressions.rb
84
81
  - lib/cucumber/tag_expressions/expressions.rb
85
82
  - lib/cucumber/tag_expressions/parser.rb
@@ -110,8 +107,8 @@ rubyforge_project:
110
107
  rubygems_version: 2.6.8
111
108
  signing_key:
112
109
  specification_version: 4
113
- summary: cucumber-tag_expressions-1.0.1
110
+ summary: cucumber-tag_expressions-1.1.0
114
111
  test_files:
112
+ - spec/parser_spec.rb
115
113
  - spec/coverage.rb
116
114
  - spec/expressions_spec.rb
117
- - spec/parser_spec.rb
data/.rspec DELETED
@@ -1 +0,0 @@
1
- --color
@@ -1,15 +0,0 @@
1
- language: ruby
2
-
3
- rvm:
4
- - 2.4.0
5
- - 2.3.3
6
- - 2.2.6
7
- - jruby-9.1.7.0
8
-
9
- notifications:
10
- webhooks:
11
- urls:
12
- - https://webhooks.gitter.im/e/5373e574ed4e88026838
13
- on_success: change
14
- on_failure: always
15
- on_start: never
data/Gemfile DELETED
@@ -1,3 +0,0 @@
1
- # frozen_string_literal: true
2
- source 'https://rubygems.org'
3
- gemspec
data/Makefile DELETED
@@ -1,8 +0,0 @@
1
- default:
2
- bundle install
3
- bundle exec rake
4
- bundle exec rake install
5
- .PHONY: default
6
-
7
- clean:
8
- .PHONY: clean
data/Rakefile DELETED
@@ -1,13 +0,0 @@
1
- # encoding: utf-8
2
- require 'rubygems'
3
- require 'bundler'
4
- Bundler::GemHelper.install_tasks
5
-
6
- $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
7
-
8
- require 'rspec/core/rake_task'
9
- RSpec::Core::RakeTask.new(:spec) do |t|
10
- t.ruby_opts = %w(-r./spec/coverage -w)
11
- end
12
-
13
- task default: ['spec']
@@ -1,26 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- Gem::Specification.new do |s|
3
- s.name = 'cucumber-tag_expressions'
4
- s.version = '1.0.1'
5
- s.authors = ['Andrea Nodari']
6
- s.description = 'Cucumber tag expressions for ruby'
7
- s.summary = "#{s.name}-#{s.version}"
8
- s.email = 'cukes@googlegroups.com'
9
- s.homepage = 'https://docs.cucumber.io/tag-expressions/'
10
- s.platform = Gem::Platform::RUBY
11
- s.license = 'MIT'
12
- s.required_ruby_version = '>= 1.9.3'
13
-
14
- s.add_development_dependency 'bundler'
15
- s.add_development_dependency 'rake', '~> 10.5'
16
- s.add_development_dependency 'rspec', '~> 3.5'
17
-
18
- # For coverage reports
19
- s.add_development_dependency 'coveralls'
20
-
21
- s.rubygems_version = '>= 1.6.1'
22
- s.files = `git ls-files`.split("\n").reject { |path| path =~ /\.gitignore$/ }
23
- s.test_files = `git ls-files -- spec/*`.split("\n")
24
- s.rdoc_options = ['--charset=UTF-8']
25
- s.require_path = 'lib'
26
- end