cucumber-cucumber-expressions 8.3.1 → 19.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +2 -2
  3. data/lib/cucumber/cucumber_expressions/argument.rb +8 -4
  4. data/lib/cucumber/cucumber_expressions/ast.rb +166 -0
  5. data/lib/cucumber/cucumber_expressions/combinatorial_generated_expression_factory.rb +6 -13
  6. data/lib/cucumber/cucumber_expressions/cucumber_expression.rb +82 -80
  7. data/lib/cucumber/cucumber_expressions/cucumber_expression_generator.rb +14 -26
  8. data/lib/cucumber/cucumber_expressions/cucumber_expression_parser.rb +203 -0
  9. data/lib/cucumber/cucumber_expressions/cucumber_expression_tokenizer.rb +90 -0
  10. data/lib/cucumber/cucumber_expressions/errors.rb +205 -13
  11. data/lib/cucumber/cucumber_expressions/expression_factory.rb +24 -0
  12. data/lib/cucumber/cucumber_expressions/generated_expression.rb +2 -0
  13. data/lib/cucumber/cucumber_expressions/group.rb +7 -1
  14. data/lib/cucumber/cucumber_expressions/group_builder.rb +9 -2
  15. data/lib/cucumber/cucumber_expressions/parameter_type.rb +14 -21
  16. data/lib/cucumber/cucumber_expressions/parameter_type_matcher.rb +11 -9
  17. data/lib/cucumber/cucumber_expressions/parameter_type_registry.rb +28 -16
  18. data/lib/cucumber/cucumber_expressions/regular_expression.rb +3 -2
  19. data/lib/cucumber/cucumber_expressions/tree_regexp.rb +54 -46
  20. metadata +76 -77
  21. data/.github/ISSUE_TEMPLATE.md +0 -5
  22. data/.github/PULL_REQUEST_TEMPLATE.md +0 -5
  23. data/.rspec +0 -1
  24. data/.rsync +0 -4
  25. data/.subrepo +0 -1
  26. data/Gemfile +0 -3
  27. data/Makefile +0 -1
  28. data/README.md +0 -5
  29. data/Rakefile +0 -27
  30. data/cucumber-cucumber-expressions.gemspec +0 -33
  31. data/default.mk +0 -70
  32. data/examples.txt +0 -31
  33. data/scripts/update-gemspec +0 -32
  34. data/spec/capture_warnings.rb +0 -74
  35. data/spec/coverage.rb +0 -7
  36. data/spec/cucumber/cucumber_expressions/argument_spec.rb +0 -17
  37. data/spec/cucumber/cucumber_expressions/combinatorial_generated_expression_factory_test.rb +0 -43
  38. data/spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb +0 -231
  39. data/spec/cucumber/cucumber_expressions/cucumber_expression_regexp_spec.rb +0 -57
  40. data/spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb +0 -212
  41. data/spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb +0 -202
  42. data/spec/cucumber/cucumber_expressions/expression_examples_spec.rb +0 -30
  43. data/spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb +0 -86
  44. data/spec/cucumber/cucumber_expressions/parameter_type_spec.rb +0 -15
  45. data/spec/cucumber/cucumber_expressions/regular_expression_spec.rb +0 -80
  46. data/spec/cucumber/cucumber_expressions/tree_regexp_spec.rb +0 -133
data/default.mk DELETED
@@ -1,70 +0,0 @@
1
- SHELL := /usr/bin/env bash
2
- RUBY_SOURCE_FILES = $(shell find . -name "*.rb")
3
- GEMSPEC = $(shell find . -name "*.gemspec")
4
- LIBNAME := $(shell basename $$(dirname $$(pwd)))
5
- GEM := cucumber-$(LIBNAME)-$(NEW_VERSION).gem
6
-
7
- default: .tested
8
- .PHONY: default
9
-
10
- .deps: Gemfile.lock
11
- touch $@
12
-
13
- Gemfile.lock: Gemfile $(GEMSPEC)
14
- bundle install
15
- touch $@
16
-
17
- .tested: .deps $(RUBY_SOURCE_FILES)
18
- bundle exec rspec --color
19
- touch $@
20
-
21
- update-dependencies:
22
- ./scripts/update-gemspec
23
- .PHONY: update-dependencies
24
-
25
- ifdef NEW_VERSION
26
- ifneq (,$(GEMSPEC))
27
- gem: $(GEM)
28
- else
29
- gem:
30
- @echo "Not building gem because there is no gemspec"
31
- endif
32
- endif
33
- .PHONY: gem
34
-
35
- $(GEM): clean .tested
36
- gem build $(GEMSPEC)
37
- test -s "$(GEM)" || { echo "Gem not built: $(GEM)"; exit 1; }
38
-
39
- pre-release: update-version update-dependencies gem
40
- .PHONY: pre-release
41
-
42
- update-version:
43
- ifdef NEW_VERSION
44
- ifneq (,$(GEMSPEC))
45
- sed -i "s/\(s\.version *= *'\)[0-9]*\.[0-9]*\.[0-9]*\('\)/\1$(NEW_VERSION)\2/" $(GEMSPEC)
46
- endif
47
- else
48
- @echo -e "\033[0;31mNEW_VERSION is not defined. Can't update version :-(\033[0m"
49
- exit 1
50
- endif
51
- .PHONY: update-version
52
-
53
- publish: gem
54
- ifneq (,$(GEMSPEC))
55
- gem push $(GEM)
56
- else
57
- @echo "Not publishing because there is no gemspec"
58
- endif
59
- .PHONY: publish
60
-
61
- post-release:
62
- @echo "No post-release needed for ruby"
63
- .PHONY: post-release
64
-
65
- clean: clean-ruby
66
- .PHONY: clean
67
-
68
- clean-ruby:
69
- rm -f .deps .linked .tested* Gemfile.lock *.gem
70
- .PHONY: clean-ruby
data/examples.txt DELETED
@@ -1,31 +0,0 @@
1
- I have {int} cuke(s)
2
- I have 22 cukes
3
- [22]
4
- ---
5
- I have {int} cuke(s) and some \[]^$.|?*+
6
- I have 1 cuke and some \[]^$.|?*+
7
- [1]
8
- ---
9
- /I have (\d+) cukes? in my (\w+) now/
10
- I have 22 cukes in my belly now
11
- [22,"belly"]
12
- ---
13
- /I have (-?\d+) cukes? in my (.*) now/
14
- I have 1 cuke in my belly now
15
- [1,"belly"]
16
- ---
17
- /^Something( with an optional argument)?$/
18
- Something
19
- [null]
20
- ---
21
- Привет, {word}!
22
- Привет, Мир!
23
- ["Мир"]
24
- ---
25
- /I have (.*) cukes? in my (.*) now/
26
- I have 22 cukes in my belly now
27
- ["22","belly"]
28
- ---
29
- I have {} cuke(s) in my {} now
30
- I have 22 cukes in my belly now
31
- ["22","belly"]
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # Updates the *.gemspec in the current directory to use the latest releases of gems
4
- #
5
- set -uf -o pipefail
6
- IFS=$'\n'
7
-
8
- gemspec=$(find . -type f -maxdepth 1 -name "*.gemspec")
9
- if [ "${gemspec}" = "" ]; then
10
- exit 0
11
- fi
12
- add_dependency_lines=$(cat ${gemspec} | grep "s.add_[a-z_]*dependency '[^']*'")
13
- if [ $? -ne 0 ]; then
14
- # No add_dependency_lines found - nothing to do
15
- exit 0
16
- fi
17
-
18
- set -e
19
-
20
- gems=$(echo "${add_dependency_lines}" | tr -s ' ' | cut -d ' ' -f3 | cut -d"'" -f 2)
21
- while read -r gem; do
22
- echo "upgrading ${gem}"
23
- if [ "${gem}" = "bundler" ]; then
24
- cat "${gemspec}" | sed "s/\(s.add_[a-z_]*dependency\) '${gem}'.*/\1 '${gem}', '>= 1.16.2'/" > ${gemspec}.tmp
25
- else
26
- gem_line=$(gem list "${gem}" --remote --all --no-prerelease | grep "^${gem}\s")
27
- latest_patch_version=$(echo "${gem_line}" | cut -d'(' -f2 | cut -d')' -f1 | cut -d',' -f1 | cut -d' ' -f1)
28
- latest_minor_version=$(echo "${latest_patch_version}" | cut -d. -f1,2)
29
- cat "${gemspec}" | sed "s/\(s.add_[a-z_]*dependency\) '${gem}'.*/\1 '${gem}', '~> ${latest_minor_version}', '>= ${latest_patch_version}'/" > ${gemspec}.tmp
30
- fi
31
- mv ${gemspec}.tmp ${gemspec}
32
- done <<< "${gems}"
@@ -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
data/spec/coverage.rb DELETED
@@ -1,7 +0,0 @@
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
@@ -1,17 +0,0 @@
1
- require 'cucumber/cucumber_expressions/argument'
2
- require 'cucumber/cucumber_expressions/tree_regexp'
3
- require 'cucumber/cucumber_expressions/parameter_type_registry'
4
-
5
- module Cucumber
6
- module CucumberExpressions
7
- describe Argument do
8
- it 'exposes parameter_type' do
9
- tree_regexp = TreeRegexp.new(/three (.*) mice/)
10
- parameter_type_registry = ParameterTypeRegistry.new
11
- arguments = Argument.build(tree_regexp, "three blind mice", [parameter_type_registry.lookup_by_type_name("string")])
12
- argument = arguments[0]
13
- expect(argument.parameter_type.name).to eq("string")
14
- end
15
- end
16
- end
17
- end
@@ -1,43 +0,0 @@
1
- require 'cucumber/cucumber_expressions/parameter_type'
2
- require 'cucumber/cucumber_expressions/combinatorial_generated_expression_factory'
3
-
4
- module Cucumber
5
- module CucumberExpressions
6
-
7
- class Color; end
8
- class CssColor; end
9
- class Date; end
10
- class DateTime; end
11
- class Timestamp; end
12
-
13
- describe CombinatorialGeneratedExpressionFactory do
14
- it 'generates multiple expressions' do
15
- parameter_type_combinations = [
16
- [
17
- ParameterType.new('color', /red|blue|yellow/, Color, lambda {|s| Color.new}, true, false),
18
- ParameterType.new('csscolor', /red|blue|yellow/, CssColor, lambda {|s| CssColor.new}, true, false)
19
- ],
20
- [
21
- ParameterType.new('date', /\d{4}-\d{2}-\d{2}/, Date, lambda {|s| Date.new}, true, false),
22
- ParameterType.new('datetime', /\d{4}-\d{2}-\d{2}/, DateTime, lambda {|s| DateTime.new}, true, false),
23
- ParameterType.new('timestamp', /\d{4}-\d{2}-\d{2}/, Timestamp, lambda {|s| Timestamp.new}, true, false)
24
- ]
25
- ]
26
-
27
- factory = CombinatorialGeneratedExpressionFactory.new(
28
- 'I bought a {%s} ball on {%s}',
29
- parameter_type_combinations
30
- )
31
- expressions = factory.generate_expressions.map {|ge| ge.source}
32
- expect(expressions).to eq([
33
- 'I bought a {color} ball on {date}',
34
- 'I bought a {color} ball on {datetime}',
35
- 'I bought a {color} ball on {timestamp}',
36
- 'I bought a {csscolor} ball on {date}',
37
- 'I bought a {csscolor} ball on {datetime}',
38
- 'I bought a {csscolor} ball on {timestamp}',
39
- ])
40
- end
41
- end
42
- end
43
- end
@@ -1,231 +0,0 @@
1
- require 'cucumber/cucumber_expressions/cucumber_expression_generator'
2
- require 'cucumber/cucumber_expressions/cucumber_expression'
3
- require 'cucumber/cucumber_expressions/parameter_type'
4
- require 'cucumber/cucumber_expressions/parameter_type_registry'
5
-
6
- module Cucumber
7
- module CucumberExpressions
8
- describe CucumberExpressionGenerator do
9
- class Currency
10
- end
11
-
12
- before do
13
- @parameter_type_registry = ParameterTypeRegistry.new
14
- @generator = CucumberExpressionGenerator.new(@parameter_type_registry)
15
- end
16
-
17
- it "documents expression generation" do
18
- parameter_registry = ParameterTypeRegistry.new
19
- ### [generate-expression]
20
- generator = CucumberExpressionGenerator.new(parameter_registry)
21
- undefined_step_text = "I have 2 cucumbers and 1.5 tomato"
22
- generated_expression = generator.generate_expression(undefined_step_text)
23
- expect(generated_expression.source).to eq("I have {int} cucumbers and {float} tomato")
24
- expect(generated_expression.parameter_types[1].type).to eq(Float)
25
- ### [generate-expression]
26
- end
27
-
28
- it "generates expression for no args" do
29
- assert_expression("hello", [], "hello")
30
- end
31
-
32
- it "generates expression with escaped left parenthesis" do
33
- assert_expression(
34
- "\\(iii)", [],
35
- "(iii)")
36
- end
37
-
38
- it "generates expression with escaped left curly brace" do
39
- assert_expression(
40
- "\\{iii}", [],
41
- "{iii}")
42
- end
43
-
44
- it "generates expression with escaped slashes" do
45
- assert_expression(
46
- "The {int}\\/{int}\\/{int} hey", ["int", "int2", "int3"],
47
- "The 1814/05/17 hey")
48
- end
49
-
50
- it "generates expression for int float arg" do
51
- assert_expression(
52
- "I have {int} cukes and {float} euro", ["int", "float"],
53
- "I have 2 cukes and 1.5 euro")
54
- end
55
-
56
- it "generates expression for strings" do
57
- assert_expression(
58
- "I like {string} and {string}", ["string", "string2"],
59
- 'I like "bangers" and \'mash\'')
60
- end
61
-
62
- it "generates expression with % sign" do
63
- assert_expression(
64
- "I am {int}% foobar", ["int"],
65
- 'I am 20% foobar')
66
- end
67
-
68
- it "generates expression for just int" do
69
- assert_expression(
70
- "{int}", ["int"],
71
- "99999")
72
- end
73
-
74
- it "numbers only second argument when builtin type is not reserved keyword" do
75
- assert_expression(
76
- "I have {int} cukes and {int} euro", ["int", "int2"],
77
- "I have 2 cukes and 5 euro")
78
- end
79
-
80
- it "numbers only second argument when type is not reserved keyword" do
81
- @parameter_type_registry.define_parameter_type(ParameterType.new(
82
- 'currency',
83
- '[A-Z]{3}',
84
- Currency,
85
- lambda {|s| Currency.new(s)},
86
- true,
87
- true
88
- ))
89
-
90
- assert_expression(
91
- "I have a {currency} account and a {currency} account", ["currency", "currency2"],
92
- "I have a EUR account and a GBP account")
93
- end
94
-
95
- it "exposes parameters in generated expression" do
96
- expression = @generator.generate_expression("I have 2 cukes and 1.5 euro")
97
- types = expression.parameter_types.map(&:type)
98
- expect(types).to eq([Integer, Float])
99
- end
100
-
101
- it "matches parameter types with optional capture groups" do
102
- @parameter_type_registry.define_parameter_type(ParameterType.new(
103
- 'optional-flight',
104
- /(1st flight)?/,
105
- String,
106
- lambda {|s| s},
107
- true,
108
- false
109
- ))
110
- @parameter_type_registry.define_parameter_type(ParameterType.new(
111
- 'optional-hotel',
112
- /(1 hotel)?/,
113
- String,
114
- lambda {|s| s},
115
- true,
116
- false
117
- ))
118
-
119
- expression = @generator.generate_expressions("I reach Stage 4: 1st flight -1 hotel")[0]
120
- # While you would expect this to be `I reach Stage {int}: {optional-flight} -{optional-hotel}`
121
- # the `-1` causes {int} to match just before {optional-hotel}.
122
- expect(expression.source).to eq("I reach Stage {int}: {optional-flight} {int} hotel")
123
- end
124
-
125
- it "generates at most 256 expressions" do
126
- for i in 0..3
127
- @parameter_type_registry.define_parameter_type(ParameterType.new(
128
- "my-type-#{i}",
129
- /([a-z] )*?[a-z]/,
130
- String,
131
- lambda {|s| s},
132
- true,
133
- false
134
- ))
135
- end
136
- # This would otherwise generate 4^11=4194300 expressions and consume just shy of 1.5GB.
137
- expressions = @generator.generate_expressions("a s i m p l e s t e p")
138
- expect(expressions.length).to eq(256)
139
- end
140
-
141
- it "prefers expression with longest non empty match" do
142
- @parameter_type_registry.define_parameter_type(ParameterType.new(
143
- 'zero-or-more',
144
- /[a-z]*/,
145
- String,
146
- lambda {|s| s},
147
- true,
148
- false
149
- ))
150
- @parameter_type_registry.define_parameter_type(ParameterType.new(
151
- 'exactly-one',
152
- /[a-z]/,
153
- String,
154
- lambda {|s| s},
155
- true,
156
- false
157
- ))
158
-
159
- expressions = @generator.generate_expressions("a simple step")
160
- expect(expressions.length).to eq(2)
161
- expect(expressions[0].source).to eq("{exactly-one} {zero-or-more} {zero-or-more}")
162
- expect(expressions[1].source).to eq("{zero-or-more} {zero-or-more} {zero-or-more}")
163
- end
164
-
165
- context "does not suggest parameter when match is" do
166
- before do
167
- @parameter_type_registry.define_parameter_type(ParameterType.new(
168
- 'direction',
169
- /(up|down)/,
170
- String,
171
- lambda {|s| s},
172
- true,
173
- false
174
- ))
175
- end
176
-
177
- it "at the beginning of a word" do
178
- expect(@generator.generate_expression("When I download a picture").source).not_to eq("When I {direction}load a picture")
179
- expect(@generator.generate_expression("When I download a picture").source).to eq("When I download a picture")
180
- end
181
-
182
- it "inside a word" do
183
- expect(@generator.generate_expression("When I watch the muppet show").source).not_to eq("When I watch the m{direction}pet show")
184
- expect(@generator.generate_expression("When I watch the muppet show").source).to eq("When I watch the muppet show")
185
- end
186
-
187
- it "at the end of a word" do
188
- expect(@generator.generate_expression("When I create a group").source).not_to eq("When I create a gro{direction}")
189
- expect(@generator.generate_expression("When I create a group").source).to eq("When I create a group")
190
- end
191
- end
192
-
193
- context "does suggest parameter when match is" do
194
- before do
195
- @parameter_type_registry.define_parameter_type(ParameterType.new(
196
- 'direction',
197
- /(up|down)/,
198
- String,
199
- lambda {|s| s},
200
- true,
201
- false
202
- ))
203
- end
204
-
205
- it "a full word" do
206
- expect(@generator.generate_expression("When I go down the road").source).to eq("When I go {direction} the road")
207
- expect(@generator.generate_expression("When I walk up the hill").source).to eq("When I walk {direction} the hill")
208
- expect(@generator.generate_expression("up the hill, the road goes down").source).to eq("{direction} the hill, the road goes {direction}")
209
- end
210
-
211
- it 'wrapped around punctuation characters' do
212
- expect(@generator.generate_expression("When direction is:down").source).to eq("When direction is:{direction}")
213
- expect(@generator.generate_expression("Then direction is down.").source).to eq("Then direction is {direction}.")
214
- end
215
- end
216
-
217
- def assert_expression(expected_expression, expected_argument_names, text)
218
- generated_expression = @generator.generate_expression(text)
219
- expect(generated_expression.parameter_names).to eq(expected_argument_names)
220
- expect(generated_expression.source).to eq(expected_expression)
221
-
222
- cucumber_expression = CucumberExpression.new(generated_expression.source, @parameter_type_registry)
223
- match = cucumber_expression.match(text)
224
- if match.nil?
225
- raise "Expected text '#{text}' to match generated expression '#{generated_expression.source}'"
226
- end
227
- expect(match.length).to eq(expected_argument_names.length)
228
- end
229
- end
230
- end
231
- end
@@ -1,57 +0,0 @@
1
- require 'cucumber/cucumber_expressions/cucumber_expression'
2
- require 'cucumber/cucumber_expressions/parameter_type_registry'
3
-
4
- module Cucumber
5
- module CucumberExpressions
6
- describe CucumberExpression do
7
- context "Regexp translation" do
8
- def assert_regexp(expression, regexp)
9
- cucumber_expression = CucumberExpression.new(expression, ParameterTypeRegistry.new)
10
- expect(regexp).to eq(cucumber_expression.regexp)
11
- end
12
-
13
- it "translates no arguments" do
14
- assert_regexp(
15
- "I have 10 cukes in my belly now",
16
- /^I have 10 cukes in my belly now$/
17
- )
18
- end
19
-
20
- it "translates alternation" do
21
- assert_regexp(
22
- "I had/have a great/nice/charming friend",
23
- /^I (?:had|have) a (?:great|nice|charming) friend$/
24
- )
25
- end
26
-
27
- it "translates alternation with non-alpha" do
28
- assert_regexp(
29
- "I said Alpha1/Beta1",
30
- /^I said (?:Alpha1|Beta1)$/
31
- )
32
- end
33
-
34
- it "translates parameters" do
35
- assert_regexp(
36
- "I have {float} cukes at {int} o'clock",
37
- /^I have ((?=.*\d.*)[-+]?\d*(?:\.(?=\d.*))?\d*(?:\d+[E][-+]?\d+)?) cukes at ((?:-?\d+)|(?:\d+)) o'clock$/
38
- )
39
- end
40
-
41
- it "translates parenthesis to non-capturing optional capture group" do
42
- assert_regexp(
43
- "I have many big(ish) cukes",
44
- /^I have many big(?:ish)? cukes$/
45
- )
46
- end
47
-
48
- it "translates parenthesis with alpha unicode" do
49
- assert_regexp(
50
- "Привет, Мир(ы)!",
51
- /^Привет, Мир(?:ы)?!$/
52
- )
53
- end
54
- end
55
- end
56
- end
57
- end