cucumber-cucumber-expressions 16.1.2 → 17.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 +4 -4
- data/.rubocop.yml +27 -0
- data/.rubocop_todo.yml +524 -0
- data/Gemfile +2 -1
- data/Rakefile +4 -17
- data/VERSION +1 -1
- data/cucumber-cucumber-expressions.gemspec +11 -9
- data/lib/cucumber/cucumber_expressions/argument.rb +6 -3
- data/lib/cucumber/cucumber_expressions/ast.rb +24 -59
- data/lib/cucumber/cucumber_expressions/combinatorial_generated_expression_factory.rb +6 -13
- data/lib/cucumber/cucumber_expressions/cucumber_expression.rb +9 -11
- data/lib/cucumber/cucumber_expressions/cucumber_expression_generator.rb +7 -11
- data/lib/cucumber/cucumber_expressions/cucumber_expression_parser.rb +37 -53
- data/lib/cucumber/cucumber_expressions/cucumber_expression_tokenizer.rb +13 -18
- data/lib/cucumber/cucumber_expressions/errors.rb +119 -101
- data/lib/cucumber/cucumber_expressions/expression_factory.rb +2 -0
- data/lib/cucumber/cucumber_expressions/generated_expression.rb +2 -0
- data/lib/cucumber/cucumber_expressions/group.rb +2 -0
- data/lib/cucumber/cucumber_expressions/group_builder.rb +2 -0
- data/lib/cucumber/cucumber_expressions/parameter_type.rb +13 -23
- data/lib/cucumber/cucumber_expressions/parameter_type_matcher.rb +8 -6
- data/lib/cucumber/cucumber_expressions/parameter_type_registry.rb +23 -20
- data/lib/cucumber/cucumber_expressions/regular_expression.rb +3 -2
- data/lib/cucumber/cucumber_expressions/tree_regexp.rb +5 -4
- data/spec/cucumber/cucumber_expressions/argument_spec.rb +4 -2
- data/spec/cucumber/cucumber_expressions/combinatorial_generated_expression_factory_test.rb +7 -6
- data/spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb +104 -101
- data/spec/cucumber/cucumber_expressions/cucumber_expression_parser_spec.rb +2 -0
- data/spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb +84 -87
- data/spec/cucumber/cucumber_expressions/cucumber_expression_tokenizer_spec.rb +3 -1
- data/spec/cucumber/cucumber_expressions/cucumber_expression_transformation_spec.rb +2 -0
- data/spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb +79 -60
- data/spec/cucumber/cucumber_expressions/expression_factory_spec.rb +2 -0
- data/spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb +43 -48
- data/spec/cucumber/cucumber_expressions/parameter_type_spec.rb +3 -1
- data/spec/cucumber/cucumber_expressions/regular_expression_spec.rb +37 -28
- data/spec/cucumber/cucumber_expressions/tree_regexp_spec.rb +23 -22
- metadata +21 -9
- data/.rspec +0 -1
- data/scripts/update-gemspec +0 -32
- data/spec/capture_warnings.rb +0 -74
@@ -1,23 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cucumber/cucumber_expressions/ast'
|
2
4
|
|
3
5
|
module Cucumber
|
4
6
|
module CucumberExpressions
|
5
7
|
class CucumberExpressionError < StandardError
|
6
|
-
|
7
|
-
|
8
|
-
index
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
m = <<-EOF
|
15
|
-
This Cucumber Expression has a problem at column #{index + 1}:
|
16
|
-
|
17
|
-
#{expression}
|
18
|
-
#{pointer}
|
19
|
-
#{problem}.
|
20
|
-
#{solution}
|
8
|
+
def build_message(index, expression, pointer, problem, solution)
|
9
|
+
m = <<~EOF
|
10
|
+
This Cucumber Expression has a problem at column #{index + 1}:
|
11
|
+
|
12
|
+
#{expression}
|
13
|
+
#{pointer}
|
14
|
+
#{problem}.
|
15
|
+
#{solution}
|
21
16
|
EOF
|
22
17
|
m.strip
|
23
18
|
end
|
@@ -40,86 +35,100 @@ This Cucumber Expression has a problem at column #{index + 1}:
|
|
40
35
|
|
41
36
|
class AlternativeMayNotExclusivelyContainOptionals < CucumberExpressionError
|
42
37
|
def initialize(node, expression)
|
43
|
-
super(
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
38
|
+
super(
|
39
|
+
build_message(
|
40
|
+
node.start,
|
41
|
+
expression,
|
42
|
+
point_at_located(node),
|
43
|
+
'An alternative may not exclusively contain optionals',
|
44
|
+
"If you did not mean to use an optional you can use '\\(' to escape the the '('"
|
45
|
+
)
|
46
|
+
)
|
50
47
|
end
|
51
48
|
end
|
52
49
|
|
53
50
|
class AlternativeMayNotBeEmpty < CucumberExpressionError
|
54
51
|
def initialize(node, expression)
|
55
|
-
super(
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
52
|
+
super(
|
53
|
+
build_message(
|
54
|
+
node.start,
|
55
|
+
expression,
|
56
|
+
point_at_located(node),
|
57
|
+
'Alternative may not be empty',
|
58
|
+
"If you did not mean to use an alternative you can use '\\/' to escape the the '/'"
|
59
|
+
)
|
60
|
+
)
|
62
61
|
end
|
63
62
|
end
|
64
63
|
|
65
64
|
class CantEscape < CucumberExpressionError
|
66
65
|
def initialize(expression, index)
|
67
|
-
super(
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
66
|
+
super(
|
67
|
+
build_message(
|
68
|
+
index,
|
69
|
+
expression,
|
70
|
+
point_at(index),
|
71
|
+
"Only the characters '{', '}', '(', ')', '\\', '/' and whitespace can be escaped",
|
72
|
+
"If you did mean to use an '\\' you can use '\\\\' to escape it"
|
73
|
+
)
|
74
|
+
)
|
74
75
|
end
|
75
76
|
end
|
76
77
|
|
77
78
|
class OptionalMayNotBeEmpty < CucumberExpressionError
|
78
79
|
def initialize(node, expression)
|
79
|
-
super(
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
80
|
+
super(
|
81
|
+
build_message(
|
82
|
+
node.start,
|
83
|
+
expression,
|
84
|
+
point_at_located(node),
|
85
|
+
'An optional must contain some text',
|
86
|
+
"If you did not mean to use an optional you can use '\\(' to escape the the '('"
|
87
|
+
)
|
88
|
+
)
|
86
89
|
end
|
87
90
|
end
|
88
91
|
|
89
92
|
class ParameterIsNotAllowedInOptional < CucumberExpressionError
|
90
93
|
def initialize(node, expression)
|
91
|
-
super(
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
94
|
+
super(
|
95
|
+
build_message(
|
96
|
+
node.start,
|
97
|
+
expression,
|
98
|
+
point_at_located(node),
|
99
|
+
'An optional may not contain a parameter type',
|
100
|
+
"If you did not mean to use an parameter type you can use '\\{' to escape the the '{'"
|
101
|
+
)
|
102
|
+
)
|
98
103
|
end
|
99
104
|
end
|
100
105
|
|
101
106
|
class OptionalIsNotAllowedInOptional < CucumberExpressionError
|
102
107
|
def initialize(node, expression)
|
103
|
-
super(
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
108
|
+
super(
|
109
|
+
build_message(
|
110
|
+
node.start,
|
111
|
+
expression,
|
112
|
+
point_at_located(node),
|
113
|
+
'An optional may not contain an other optional',
|
114
|
+
"If you did not mean to use an optional type you can use '\\(' to escape the the '('. For more complicated expressions consider using a regular expression instead."
|
115
|
+
)
|
116
|
+
)
|
110
117
|
end
|
111
118
|
end
|
112
119
|
|
113
120
|
class TheEndOfLineCannotBeEscaped < CucumberExpressionError
|
114
121
|
def initialize(expression)
|
115
122
|
index = expression.codepoints.length - 1
|
116
|
-
super(
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
+
super(
|
124
|
+
build_message(
|
125
|
+
index,
|
126
|
+
expression,
|
127
|
+
point_at(index),
|
128
|
+
'The end of line can not be escaped',
|
129
|
+
"You can use '\\\\' to escape the the '\\'"
|
130
|
+
)
|
131
|
+
)
|
123
132
|
end
|
124
133
|
end
|
125
134
|
|
@@ -128,45 +137,50 @@ This Cucumber Expression has a problem at column #{index + 1}:
|
|
128
137
|
begin_symbol = Token::symbol_of(begin_token)
|
129
138
|
end_symbol = Token::symbol_of(end_token)
|
130
139
|
purpose = Token::purpose_of(begin_token)
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
140
|
+
|
141
|
+
super(
|
142
|
+
build_message(
|
143
|
+
current.start,
|
144
|
+
expression,
|
145
|
+
point_at_located(current),
|
146
|
+
"The '#{begin_symbol}' does not have a matching '#{end_symbol}'",
|
147
|
+
"If you did not intend to use #{purpose} you can use '\\#{begin_symbol}' to escape the #{purpose}"
|
148
|
+
)
|
149
|
+
)
|
138
150
|
end
|
139
151
|
end
|
140
152
|
|
141
153
|
class AlternationNotAllowedInOptional < CucumberExpressionError
|
142
154
|
def initialize(expression, current)
|
143
|
-
super(
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
155
|
+
super(
|
156
|
+
build_message(
|
157
|
+
current.start,
|
158
|
+
expression,
|
159
|
+
point_at_located(current),
|
160
|
+
'An alternation can not be used inside an optional',
|
161
|
+
"You can use '\\/' to escape the the '/'"
|
162
|
+
)
|
163
|
+
)
|
150
164
|
end
|
151
165
|
end
|
152
166
|
|
153
167
|
class InvalidParameterTypeName < CucumberExpressionError
|
154
168
|
def initialize(type_name)
|
155
|
-
super("Illegal character in parameter name {#{type_name}}. "
|
156
|
-
"Parameter names may not contain '{', '}', '(', ')', '\\' or '/'")
|
169
|
+
super("Illegal character in parameter name {#{type_name}}. Parameter names may not contain '{', '}', '(', ')', '\\' or '/'")
|
157
170
|
end
|
158
171
|
end
|
159
172
|
|
160
|
-
|
161
173
|
class InvalidParameterTypeNameInNode < CucumberExpressionError
|
162
174
|
def initialize(expression, token)
|
163
|
-
super(
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
175
|
+
super(
|
176
|
+
build_message(
|
177
|
+
token.start,
|
178
|
+
expression,
|
179
|
+
point_at_located(token),
|
180
|
+
"Parameter names may not contain '{', '}', '(', ')', '\\' or '/'",
|
181
|
+
'Did you mean to use a regular expression?'
|
182
|
+
)
|
183
|
+
)
|
170
184
|
end
|
171
185
|
end
|
172
186
|
|
@@ -174,28 +188,32 @@ This Cucumber Expression has a problem at column #{index + 1}:
|
|
174
188
|
attr_reader :undefined_parameter_type_name
|
175
189
|
|
176
190
|
def initialize(node, expression, undefined_parameter_type_name)
|
177
|
-
super(
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
191
|
+
super(
|
192
|
+
build_message(
|
193
|
+
node.start,
|
194
|
+
expression,
|
195
|
+
point_at_located(node),
|
196
|
+
"Undefined parameter type '#{undefined_parameter_type_name}'",
|
197
|
+
"Please register a ParameterType for '#{undefined_parameter_type_name}'"
|
198
|
+
)
|
199
|
+
)
|
182
200
|
@undefined_parameter_type_name = undefined_parameter_type_name
|
183
201
|
end
|
184
202
|
end
|
185
203
|
|
186
204
|
class AmbiguousParameterTypeError < CucumberExpressionError
|
187
205
|
def initialize(parameter_type_regexp, expression_regexp, parameter_types, generated_expressions)
|
188
|
-
super(
|
189
|
-
Your Regular Expression /#{expression_regexp.source}/
|
190
|
-
matches multiple parameter types with regexp /#{parameter_type_regexp}/:
|
191
|
-
|
206
|
+
super(<<~EOM)
|
207
|
+
Your Regular Expression /#{expression_regexp.source}/
|
208
|
+
matches multiple parameter types with regexp /#{parameter_type_regexp}/:
|
209
|
+
#{parameter_type_names(parameter_types)}
|
192
210
|
|
193
|
-
I couldn't decide which one to use. You have two options:
|
211
|
+
I couldn't decide which one to use. You have two options:
|
194
212
|
|
195
|
-
1) Use a Cucumber Expression instead of a Regular Expression. Try one of these:
|
196
|
-
|
213
|
+
1) Use a Cucumber Expression instead of a Regular Expression. Try one of these:
|
214
|
+
#{expressions(generated_expressions)}
|
197
215
|
|
198
|
-
2) Make one of the parameter types preferential and continue to use a Regular Expression.
|
216
|
+
2) Make one of the parameter types preferential and continue to use a Regular Expression.
|
199
217
|
|
200
218
|
EOM
|
201
219
|
end
|
@@ -1,17 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cucumber/cucumber_expressions/errors'
|
2
4
|
|
3
5
|
module Cucumber
|
4
6
|
module CucumberExpressions
|
5
7
|
class ParameterType
|
6
|
-
ILLEGAL_PARAMETER_NAME_PATTERN = /([\[\]()$.|?*+])
|
7
|
-
UNESCAPE_PATTERN = /(\\([\[$.|?*+\]]))
|
8
|
+
ILLEGAL_PARAMETER_NAME_PATTERN = /([\[\]()$.|?*+])/.freeze
|
9
|
+
UNESCAPE_PATTERN = /(\\([\[$.|?*+\]]))/.freeze
|
8
10
|
|
9
|
-
attr_reader :name, :type, :regexps
|
11
|
+
attr_reader :name, :type, :transformer, :use_for_snippets, :prefer_for_regexp_match, :regexps
|
10
12
|
|
11
13
|
def self.check_parameter_type_name(type_name)
|
12
|
-
unless is_valid_parameter_type_name(type_name)
|
13
|
-
raise CucumberExpressionError.new("Illegal character in parameter name {#{type_name}}. Parameter names may not contain '[]()$.|?*+'")
|
14
|
-
end
|
14
|
+
raise CucumberExpressionError.new("Illegal character in parameter name {#{type_name}}. Parameter names may not contain '[]()$.|?*+'") unless is_valid_parameter_type_name(type_name)
|
15
15
|
end
|
16
16
|
|
17
17
|
def self.is_valid_parameter_type_name(type_name)
|
@@ -21,14 +21,6 @@ module Cucumber
|
|
21
21
|
!(ILLEGAL_PARAMETER_NAME_PATTERN =~ unescaped_type_name)
|
22
22
|
end
|
23
23
|
|
24
|
-
def prefer_for_regexp_match?
|
25
|
-
@prefer_for_regexp_match
|
26
|
-
end
|
27
|
-
|
28
|
-
def use_for_snippets?
|
29
|
-
@use_for_snippets
|
30
|
-
end
|
31
|
-
|
32
24
|
# Create a new Parameter
|
33
25
|
#
|
34
26
|
# @param name the name of the parameter type
|
@@ -55,14 +47,14 @@ module Cucumber
|
|
55
47
|
end
|
56
48
|
|
57
49
|
def <=>(other)
|
58
|
-
return -1 if prefer_for_regexp_match
|
59
|
-
return 1 if other.prefer_for_regexp_match
|
50
|
+
return -1 if prefer_for_regexp_match && !other.prefer_for_regexp_match
|
51
|
+
return 1 if other.prefer_for_regexp_match && !prefer_for_regexp_match
|
52
|
+
|
60
53
|
return name <=> other.name
|
61
54
|
end
|
62
55
|
|
63
56
|
private
|
64
57
|
|
65
|
-
|
66
58
|
def string_array(regexps)
|
67
59
|
array = regexps.is_a?(Array) ? regexps : [regexps]
|
68
60
|
array.map { |regexp| regexp.is_a?(String) ? regexp : regexp_source(regexp) }
|
@@ -70,14 +62,12 @@ module Cucumber
|
|
70
62
|
|
71
63
|
def regexp_source(regexp)
|
72
64
|
[
|
73
|
-
|
74
|
-
|
75
|
-
|
65
|
+
'EXTENDED',
|
66
|
+
'IGNORECASE',
|
67
|
+
'MULTILINE'
|
76
68
|
].each do |option_name|
|
77
69
|
option = Regexp.const_get(option_name)
|
78
|
-
if regexp.options & option != 0
|
79
|
-
raise CucumberExpressionError.new("ParameterType Regexps can't use option Regexp::#{option_name}")
|
80
|
-
end
|
70
|
+
raise CucumberExpressionError.new("ParameterType Regexps can't use option Regexp::#{option_name}") if regexp.options & option != 0
|
81
71
|
end
|
82
72
|
regexp.source
|
83
73
|
end
|
@@ -1,20 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Cucumber
|
2
4
|
module CucumberExpressions
|
3
5
|
class ParameterTypeMatcher
|
4
6
|
attr_reader :parameter_type
|
5
7
|
|
6
|
-
def initialize(parameter_type, regexp, text, match_position=0)
|
8
|
+
def initialize(parameter_type, regexp, text, match_position = 0)
|
7
9
|
@parameter_type, @regexp, @text = parameter_type, regexp, text
|
8
10
|
@match = @regexp.match(@text, match_position)
|
9
11
|
end
|
10
12
|
|
11
13
|
def advance_to(new_match_position)
|
12
|
-
(new_match_position...@text.length).each
|
14
|
+
(new_match_position...@text.length).each do |advancedPos|
|
13
15
|
matcher = self.class.new(parameter_type, @regexp, @text, advancedPos)
|
14
|
-
if matcher.find && matcher.full_word?
|
15
|
-
|
16
|
-
end
|
17
|
-
}
|
16
|
+
return matcher if matcher.find && matcher.full_word?
|
17
|
+
end
|
18
18
|
|
19
19
|
self.class.new(parameter_type, @regexp, @text, @text.length)
|
20
20
|
end
|
@@ -38,8 +38,10 @@ module Cucumber
|
|
38
38
|
def <=>(other)
|
39
39
|
pos_comparison = start <=> other.start
|
40
40
|
return pos_comparison if pos_comparison != 0
|
41
|
+
|
41
42
|
length_comparison = other.group.length <=> group.length
|
42
43
|
return length_comparison if length_comparison != 0
|
44
|
+
|
43
45
|
0
|
44
46
|
end
|
45
47
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cucumber/cucumber_expressions/parameter_type'
|
2
4
|
require 'cucumber/cucumber_expressions/errors'
|
3
5
|
require 'cucumber/cucumber_expressions/cucumber_expression_generator'
|
@@ -6,27 +8,27 @@ require 'bigdecimal'
|
|
6
8
|
module Cucumber
|
7
9
|
module CucumberExpressions
|
8
10
|
class ParameterTypeRegistry
|
9
|
-
INTEGER_REGEXPS = [/-?\d+/, /\d+/]
|
10
|
-
FLOAT_REGEXP = /(?=.*\d.*)[-+]?\d*(?:\.(?=\d.*))?\d*(?:\d+[E][-+]?\d+)
|
11
|
-
WORD_REGEXP = /[^\s]
|
12
|
-
STRING_REGEXP = /"([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'
|
13
|
-
ANONYMOUS_REGEXP =
|
11
|
+
INTEGER_REGEXPS = [/-?\d+/, /\d+/].freeze
|
12
|
+
FLOAT_REGEXP = /(?=.*\d.*)[-+]?\d*(?:\.(?=\d.*))?\d*(?:\d+[E][-+]?\d+)?/.freeze
|
13
|
+
WORD_REGEXP = /[^\s]+/.freeze
|
14
|
+
STRING_REGEXP = /"([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'/.freeze
|
15
|
+
ANONYMOUS_REGEXP = /.*/.freeze
|
14
16
|
|
15
17
|
def initialize
|
16
18
|
@parameter_type_by_name = {}
|
17
19
|
@parameter_types_by_regexp = Hash.new {|hash, regexp| hash[regexp] = []}
|
18
20
|
|
19
|
-
define_parameter_type(ParameterType.new('int', INTEGER_REGEXPS, Integer,
|
20
|
-
define_parameter_type(ParameterType.new('float', FLOAT_REGEXP, Float,
|
21
|
-
define_parameter_type(ParameterType.new('word', WORD_REGEXP, String,
|
22
|
-
define_parameter_type(ParameterType.new('string', STRING_REGEXP, String,
|
23
|
-
define_parameter_type(ParameterType.new('', ANONYMOUS_REGEXP, String,
|
24
|
-
define_parameter_type(ParameterType.new('bigdecimal', FLOAT_REGEXP, BigDecimal,
|
25
|
-
define_parameter_type(ParameterType.new('biginteger', INTEGER_REGEXPS, Integer,
|
26
|
-
define_parameter_type(ParameterType.new('byte', INTEGER_REGEXPS, Integer,
|
27
|
-
define_parameter_type(ParameterType.new('short', INTEGER_REGEXPS, Integer,
|
28
|
-
define_parameter_type(ParameterType.new('long', INTEGER_REGEXPS, Integer,
|
29
|
-
define_parameter_type(ParameterType.new('double', FLOAT_REGEXP, Float,
|
21
|
+
define_parameter_type(ParameterType.new('int', INTEGER_REGEXPS, Integer, ->(s = nil) { s && s.to_i}, true, true))
|
22
|
+
define_parameter_type(ParameterType.new('float', FLOAT_REGEXP, Float, ->(s = nil) { s && s.to_f}, true, false))
|
23
|
+
define_parameter_type(ParameterType.new('word', WORD_REGEXP, String, ->(s = nil) { s}, false, false))
|
24
|
+
define_parameter_type(ParameterType.new('string', STRING_REGEXP, String, ->(s1, s2) { arg = s1 != nil ? s1 : s2; arg.gsub(/\\"/, '"').gsub(/\\'/, "'")}, true, false))
|
25
|
+
define_parameter_type(ParameterType.new('', ANONYMOUS_REGEXP, String, ->(s = nil) { s}, false, true))
|
26
|
+
define_parameter_type(ParameterType.new('bigdecimal', FLOAT_REGEXP, BigDecimal, ->(s = nil) { BigDecimal(s)}, false, false))
|
27
|
+
define_parameter_type(ParameterType.new('biginteger', INTEGER_REGEXPS, Integer, ->(s = nil) { s && s.to_i}, false, false))
|
28
|
+
define_parameter_type(ParameterType.new('byte', INTEGER_REGEXPS, Integer, ->(s = nil) { s && s.to_i}, false, false))
|
29
|
+
define_parameter_type(ParameterType.new('short', INTEGER_REGEXPS, Integer, ->(s = nil) { s && s.to_i}, false, false))
|
30
|
+
define_parameter_type(ParameterType.new('long', INTEGER_REGEXPS, Integer, ->(s = nil) { s && s.to_i}, false, false))
|
31
|
+
define_parameter_type(ParameterType.new('double', FLOAT_REGEXP, Float, ->(s = nil) { s && s.to_f}, false, false))
|
30
32
|
end
|
31
33
|
|
32
34
|
def lookup_by_type_name(name)
|
@@ -36,7 +38,8 @@ module Cucumber
|
|
36
38
|
def lookup_by_regexp(parameter_type_regexp, expression_regexp, text)
|
37
39
|
parameter_types = @parameter_types_by_regexp[parameter_type_regexp]
|
38
40
|
return nil if parameter_types.nil?
|
39
|
-
|
41
|
+
|
42
|
+
if parameter_types.length > 1 && !parameter_types[0].prefer_for_regexp_match
|
40
43
|
# We don't do this check on insertion because we only want to restrict
|
41
44
|
# ambiguity when we look up by Regexp. Users of CucumberExpression should
|
42
45
|
# not be restricted.
|
@@ -54,7 +57,7 @@ module Cucumber
|
|
54
57
|
if parameter_type.name != nil
|
55
58
|
if @parameter_type_by_name.has_key?(parameter_type.name)
|
56
59
|
if parameter_type.name.length == 0
|
57
|
-
raise CucumberExpressionError.new(
|
60
|
+
raise CucumberExpressionError.new('The anonymous parameter type has already been defined')
|
58
61
|
else
|
59
62
|
raise CucumberExpressionError.new("There is already a parameter with name #{parameter_type.name}")
|
60
63
|
end
|
@@ -64,14 +67,14 @@ module Cucumber
|
|
64
67
|
|
65
68
|
parameter_type.regexps.each do |parameter_type_regexp|
|
66
69
|
parameter_types = @parameter_types_by_regexp[parameter_type_regexp]
|
67
|
-
if parameter_types.any? && parameter_types[0].prefer_for_regexp_match
|
70
|
+
if parameter_types.any? && parameter_types[0].prefer_for_regexp_match && parameter_type.prefer_for_regexp_match
|
68
71
|
raise CucumberExpressionError.new("There can only be one preferential parameter type per regexp. The regexp /#{parameter_type_regexp}/ is used for two preferential parameter types, {#{parameter_types[0].name}} and {#{parameter_type.name}}")
|
69
72
|
end
|
73
|
+
|
70
74
|
parameter_types.push(parameter_type)
|
71
75
|
parameter_types.sort!
|
72
76
|
end
|
73
77
|
end
|
74
|
-
|
75
78
|
end
|
76
79
|
end
|
77
80
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cucumber/cucumber_expressions/argument'
|
2
4
|
require 'cucumber/cucumber_expressions/parameter_type'
|
3
5
|
require 'cucumber/cucumber_expressions/tree_regexp'
|
@@ -5,7 +7,6 @@ require 'cucumber/cucumber_expressions/tree_regexp'
|
|
5
7
|
module Cucumber
|
6
8
|
module CucumberExpressions
|
7
9
|
class RegularExpression
|
8
|
-
|
9
10
|
def initialize(expression_regexp, parameter_type_registry)
|
10
11
|
@expression_regexp = expression_regexp
|
11
12
|
@parameter_type_registry = parameter_type_registry
|
@@ -23,7 +24,7 @@ module Cucumber
|
|
23
24
|
nil,
|
24
25
|
parameter_type_regexp,
|
25
26
|
String,
|
26
|
-
|
27
|
+
->(*s) { s[0]},
|
27
28
|
false,
|
28
29
|
false
|
29
30
|
)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cucumber/cucumber_expressions/group_builder'
|
2
4
|
require 'cucumber/cucumber_expressions/errors'
|
3
5
|
|
@@ -14,6 +16,7 @@ module Cucumber
|
|
14
16
|
def match(s)
|
15
17
|
match = @regexp.match(s)
|
16
18
|
return nil if match.nil?
|
19
|
+
|
17
20
|
group_indices = (0..match.length).to_a.to_enum
|
18
21
|
@group_builder.build(match, group_indices)
|
19
22
|
end
|
@@ -42,7 +45,7 @@ module Cucumber
|
|
42
45
|
end
|
43
46
|
|
44
47
|
# (?<name>X)
|
45
|
-
raise CucumberExpressionError.new(
|
48
|
+
raise CucumberExpressionError.new('Named capture groups are not supported. See https://github.com/cucumber/cucumber/issues/329')
|
46
49
|
end
|
47
50
|
|
48
51
|
private def create_group_builder(regexp)
|
@@ -60,9 +63,7 @@ module Cucumber
|
|
60
63
|
group_start_stack.push(i)
|
61
64
|
group_builder = GroupBuilder.new
|
62
65
|
non_capturing = is_non_capturing(source, i)
|
63
|
-
if non_capturing
|
64
|
-
group_builder.set_non_capturing!
|
65
|
-
end
|
66
|
+
group_builder.set_non_capturing! if non_capturing
|
66
67
|
stack.push(group_builder)
|
67
68
|
elsif c == ')' && !escaping && !char_class
|
68
69
|
gb = stack.pop
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cucumber/cucumber_expressions/argument'
|
2
4
|
require 'cucumber/cucumber_expressions/tree_regexp'
|
3
5
|
require 'cucumber/cucumber_expressions/parameter_type_registry'
|
@@ -8,9 +10,9 @@ module Cucumber
|
|
8
10
|
it 'exposes parameter_type' do
|
9
11
|
tree_regexp = TreeRegexp.new(/three (.*) mice/)
|
10
12
|
parameter_type_registry = ParameterTypeRegistry.new
|
11
|
-
arguments = Argument.build(tree_regexp,
|
13
|
+
arguments = Argument.build(tree_regexp, 'three blind mice', [parameter_type_registry.lookup_by_type_name('string')])
|
12
14
|
argument = arguments[0]
|
13
|
-
expect(argument.parameter_type.name).to eq(
|
15
|
+
expect(argument.parameter_type.name).to eq('string')
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cucumber/cucumber_expressions/parameter_type'
|
2
4
|
require 'cucumber/cucumber_expressions/combinatorial_generated_expression_factory'
|
3
5
|
|
4
6
|
module Cucumber
|
5
7
|
module CucumberExpressions
|
6
|
-
|
7
8
|
class Color; end
|
8
9
|
class CssColor; end
|
9
10
|
class Date; end
|
@@ -14,13 +15,13 @@ module Cucumber
|
|
14
15
|
it 'generates multiple expressions' do
|
15
16
|
parameter_type_combinations = [
|
16
17
|
[
|
17
|
-
ParameterType.new('color', /red|blue|yellow/, Color,
|
18
|
-
ParameterType.new('csscolor', /red|blue|yellow/, CssColor,
|
18
|
+
ParameterType.new('color', /red|blue|yellow/, Color, ->(s) { Color.new}, true, false),
|
19
|
+
ParameterType.new('csscolor', /red|blue|yellow/, CssColor, ->(s) { CssColor.new}, true, false)
|
19
20
|
],
|
20
21
|
[
|
21
|
-
ParameterType.new('date', /\d{4}-\d{2}-\d{2}/, Date,
|
22
|
-
ParameterType.new('datetime', /\d{4}-\d{2}-\d{2}/, DateTime,
|
23
|
-
ParameterType.new('timestamp', /\d{4}-\d{2}-\d{2}/, Timestamp,
|
22
|
+
ParameterType.new('date', /\d{4}-\d{2}-\d{2}/, Date, ->(s) { Date.new}, true, false),
|
23
|
+
ParameterType.new('datetime', /\d{4}-\d{2}-\d{2}/, DateTime, ->(s) { DateTime.new}, true, false),
|
24
|
+
ParameterType.new('timestamp', /\d{4}-\d{2}-\d{2}/, Timestamp, ->(s) { Timestamp.new}, true, false)
|
24
25
|
]
|
25
26
|
]
|
26
27
|
|