cucumber-expressions 1.0.4 → 2.0.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: 0b8ed8f5d21a95380e884f0c080d076e2e89d17f
4
- data.tar.gz: 7682387d1c85962fb28b6c21683bb48157ef3b49
3
+ metadata.gz: 882d05ea05136cc6af4f3bc4ef6bccfe42531645
4
+ data.tar.gz: 42c7abf6782587c48aa8e264598637a459bbdc86
5
5
  SHA512:
6
- metadata.gz: a66f2c66cc3de2a570ac6cc317f54eb4988bc4d99185b8e9649cff3c26b85670cbea82754cf8ad4483f60351494de83890068e3f970e3c7fa870e83d0e23a709
7
- data.tar.gz: c34c94c1760c2a8a264c338000a0473b0d557fffe253e6bf1793f0e006d106de1ab59f47b9e2ebed1a4565c05b4715c79fddc103e4e2b26156a8b761252e7051
6
+ metadata.gz: 598ce9757f1518d1e9eae317a3f9718efb6339001fa36a5dea1e03fd690f44abd34524652f7b195c271c8b5128082676ffbd2dfef8b2a9aa2ee4bc6cd71ba3c7
7
+ data.tar.gz: 38121b06c1d4ca408a28f407cb0ae3b0f47de3464fe20128de05667ab34fdd93b5f369dbb2d24b26b4f9f742a93744e1dbccbb0d930478c8de3633b305fa8891
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |s|
3
3
  s.name = 'cucumber-expressions'
4
- s.version = '1.0.4'
4
+ s.version = '2.0.0'
5
5
  s.authors = ["Aslak Hellesøy"]
6
6
  s.description = 'Cucumber Expressions - a simpler alternative to Regular Expressions'
7
7
  s.summary = "cucumber-expressions-#{s.version}"
data/examples.txt CHANGED
@@ -2,10 +2,14 @@ I have {n} cuke(s) in my {bodypart} now
2
2
  I have 22 cukes in my belly now
3
3
  ["22","belly"]
4
4
  ---
5
- I have {n:int} cuke(s) in my {bodypart} now
5
+ I have {int} cuke(s) in my {bodypart} now
6
6
  I have 1 cuke in my belly now
7
7
  [1,"belly"]
8
8
  ---
9
+ I have {int} cuke(s) and some \[]^$.|?*+ {something}
10
+ I have 1 cuke and some \[]^$.|?*+ characters
11
+ [1,"characters"]
12
+ ---
9
13
  /I have (\d+) cukes? in my (.+) now/
10
14
  I have 22 cukes in my belly now
11
15
  [22,"belly"]
@@ -2,14 +2,14 @@ require 'cucumber/cucumber_expressions/argument'
2
2
 
3
3
  module Cucumber
4
4
  module CucumberExpressions
5
- class ArgumentMatcher
6
- def self.match_arguments(regexp, text, transforms)
5
+ class ArgumentBuilder
6
+ def self.build_arguments(regexp, text, parameters)
7
7
  m = regexp.match(text)
8
8
  return nil if m.nil?
9
9
  (1...m.length).map do |index|
10
10
  value = m[index]
11
- transform = transforms[index-1]
12
- transformed_value = transform.transform(value)
11
+ parameter = parameters[index-1]
12
+ transformed_value = parameter.transform(value)
13
13
  Argument.new(m.offset(index)[0], value, transformed_value)
14
14
  end
15
15
  end
@@ -1,22 +1,25 @@
1
- require 'cucumber/cucumber_expressions/argument_matcher'
2
- require 'cucumber/cucumber_expressions/transform'
1
+ require 'cucumber/cucumber_expressions/argument_builder'
2
+ require 'cucumber/cucumber_expressions/parameter'
3
3
 
4
4
  module Cucumber
5
5
  module CucumberExpressions
6
6
  class CucumberExpression
7
7
  PARAMETER_PATTERN = /\{([^}:]+)(:([^}]+))?}/
8
- OPTIONAL_PATTERN = /\(([^\)]+)\)/
8
+ OPTIONAL_PATTERN = /\(([^)]+)\)/
9
9
 
10
10
  attr_reader :source
11
11
 
12
- def initialize(expression, types, transform_lookup)
12
+ def initialize(expression, types, parameter_registry)
13
13
  @source = expression
14
- @transforms = []
14
+ @parameters = []
15
15
  regexp = "^"
16
16
  type_index = 0
17
17
  match = nil
18
18
  match_offset = 0
19
19
 
20
+ # Does not include (){} because they have special meaning
21
+ expression = expression.gsub(/([\\\^\[$.|?*+\]])/, '\\\\\1')
22
+
20
23
  # Create non-capturing, optional capture groups from parenthesis
21
24
  expression = expression.gsub(OPTIONAL_PATTERN, '(?:\1)?')
22
25
 
@@ -26,26 +29,30 @@ module Cucumber
26
29
 
27
30
  parameter_name = match[1]
28
31
  type_name = match[3]
32
+ if type_name
33
+ $stderr.puts("Cucumber expression parameter syntax {#{parameter_name}:#{type_name}} is deprecated. Please use {#{type_name}} instead.")
34
+ end
35
+
29
36
  type = types.length <= type_index ? nil : types[type_index]
30
37
  type_index += 1
31
38
 
32
- transform = nil
33
- if (type)
34
- transform = transform_lookup.lookup_by_type(type)
39
+ parameter = nil
40
+ if type
41
+ parameter = parameter_registry.lookup_by_type(type)
35
42
  end
36
- if (transform.nil? && type_name)
37
- transform = transform_lookup.lookup_by_type_name(type_name, false)
43
+ if parameter.nil? && type_name
44
+ parameter = parameter_registry.lookup_by_type_name(type_name)
38
45
  end
39
- if (transform.nil?)
40
- transform = transform_lookup.lookup_by_type_name(parameter_name, true)
46
+ if parameter.nil?
47
+ parameter = parameter_registry.lookup_by_type_name(parameter_name)
41
48
  end
42
- if (transform.nil?)
43
- transform = transform_lookup.create_anonymous_lookup(lambda {|s| s})
49
+ if parameter.nil?
50
+ parameter = parameter_registry.create_anonymous_lookup(lambda {|s| s})
44
51
  end
45
- @transforms.push(transform)
52
+ @parameters.push(parameter)
46
53
 
47
54
  text = expression.slice(match_offset...match.offset(0)[0])
48
- capture_regexp = capture_group_regexp(transform.capture_group_regexps)
55
+ capture_regexp = capture_group_regexp(parameter.capture_group_regexps)
49
56
  match_offset = match.offset(0)[1]
50
57
  regexp += text
51
58
  regexp += capture_regexp
@@ -56,7 +63,7 @@ module Cucumber
56
63
  end
57
64
 
58
65
  def match(text)
59
- ArgumentMatcher.match_arguments(@regexp, text, @transforms)
66
+ ArgumentBuilder.build_arguments(@regexp, text, @parameters)
60
67
  end
61
68
 
62
69
  private
@@ -1,46 +1,44 @@
1
- require 'cucumber/cucumber_expressions/transform_matcher'
1
+ require 'cucumber/cucumber_expressions/parameter_matcher'
2
2
  require 'cucumber/cucumber_expressions/generated_expression'
3
3
 
4
4
  module Cucumber
5
5
  module CucumberExpressions
6
6
  class CucumberExpressionGenerator
7
- def initialize(transform_lookup)
8
- @transform_lookup = transform_lookup
7
+ def initialize(parameter_registry)
8
+ @parameter_registry = parameter_registry
9
9
  end
10
10
 
11
- def generate_expression(text, typed)
12
- argumentNames = []
13
- transform_matchers = create_transform_matchers(text)
14
- transforms = []
11
+ def generate_expression(text)
12
+ parameter_names = []
13
+ parameter_matchers = create_parameter_matchers(text)
14
+ parameters = []
15
+ usage_by_type_name = Hash.new(0)
15
16
 
16
17
  expression = ""
17
- arg_counter = 0
18
18
  pos = 0
19
19
 
20
20
  loop do
21
- matching_transform_matchers = []
22
- transform_matchers.each do |transform_matcher|
23
- advanced_transform_matcher = transform_matcher.advance_to(pos)
24
- if advanced_transform_matcher.find
25
- matching_transform_matchers.push(advanced_transform_matcher)
21
+ matching_parameter_matchers = []
22
+ parameter_matchers.each do |parameter_matcher|
23
+ advanced_parameter_matcher = parameter_matcher.advance_to(pos)
24
+ if advanced_parameter_matcher.find
25
+ matching_parameter_matchers.push(advanced_parameter_matcher)
26
26
  end
27
27
  end
28
28
 
29
- if matching_transform_matchers.any?
30
- argumentName = "arg#{arg_counter += 1}"
31
- argumentNames.push(argumentName)
32
- matching_transform_matchers = matching_transform_matchers.sort
33
- best_transform_matcher = matching_transform_matchers[0]
34
- transforms.push(best_transform_matcher.transform)
29
+ if matching_parameter_matchers.any?
30
+ matching_parameter_matchers = matching_parameter_matchers.sort
31
+ best_parameter_matcher = matching_parameter_matchers[0]
32
+ parameter = best_parameter_matcher.parameter
33
+ parameters.push(parameter)
35
34
 
36
- expression += text.slice(pos...best_transform_matcher.start)
37
- expression += "{#{argumentName}"
35
+ parameter_name = get_parameter_name(parameter.type_name, usage_by_type_name)
36
+ parameter_names.push(parameter_name)
38
37
 
39
- if typed
40
- expression += ":#{best_transform_matcher.transform.type_name}"
41
- end
42
- expression += "}"
43
- pos = best_transform_matcher.start + best_transform_matcher.group.length
38
+ expression += text.slice(pos...best_parameter_matcher.start)
39
+ expression += "{#{parameter.type_name}}"
40
+
41
+ pos = best_parameter_matcher.start + best_parameter_matcher.group.length
44
42
  else
45
43
  break
46
44
  end
@@ -51,25 +49,30 @@ module Cucumber
51
49
  end
52
50
 
53
51
  expression += text.slice(pos..-1)
54
- GeneratedExpression.new(expression, argumentNames, transforms)
52
+ GeneratedExpression.new(expression, parameter_names, parameters)
55
53
  end
56
54
 
57
55
  private
58
56
 
59
- def create_transform_matchers(text)
60
- transform_matchers = []
61
- @transform_lookup.transforms.each do |transform|
62
- transform_matchers += create_transform_matchers2(transform, text)
57
+ def get_parameter_name(type_name, usage_by_type_name)
58
+ count = (usage_by_type_name[type_name] += 1)
59
+ count == 1 ? type_name : "#{type_name}#{count}"
60
+ end
61
+
62
+ def create_parameter_matchers(text)
63
+ parameter_matchers = []
64
+ @parameter_registry.parameters.each do |parameter|
65
+ parameter_matchers += create_parameter_matchers2(parameter, text)
63
66
  end
64
- transform_matchers
67
+ parameter_matchers
65
68
  end
66
69
 
67
- def create_transform_matchers2(transform, text)
70
+ def create_parameter_matchers2(parameter, text)
68
71
  result = []
69
- capture_group_regexps = transform.capture_group_regexps
72
+ capture_group_regexps = parameter.capture_group_regexps
70
73
  capture_group_regexps.each do |capture_group_regexp|
71
74
  regexp = Regexp.new("(#{capture_group_regexp})")
72
- result.push(TransformMatcher.new(transform, regexp, text))
75
+ result.push(ParameterMatcher.new(parameter, regexp, text))
73
76
  end
74
77
  result
75
78
  end
@@ -1,10 +1,10 @@
1
1
  module Cucumber
2
2
  module CucumberExpressions
3
3
  class GeneratedExpression
4
- attr_reader :source, :argumentNames, :transforms
4
+ attr_reader :source, :parameter_names, :parameters
5
5
 
6
- def initialize(source, argumentNames, transforms)
7
- @source, @argumentNames, @transforms = source, argumentNames, transforms
6
+ def initialize(source, parameter_names, parameters)
7
+ @source, @parameter_names, @parameters = source, parameter_names, parameters
8
8
  end
9
9
  end
10
10
  end
@@ -1,22 +1,29 @@
1
1
  module Cucumber
2
2
  module CucumberExpressions
3
- class Transform
3
+ class Parameter
4
4
  attr_reader :type_name, :type, :capture_group_regexps
5
5
 
6
- # Create a new Transform
6
+ # Create a new Parameter
7
7
  #
8
8
  # @param type_name [Array] array of class or type name to use in {arg:type_name}
9
9
  # @param capture_group_regexps [Array] list of regexps for capture groups.
10
- # @param transformer lambda that transforms a String to another type
10
+ # @param transformer lambda that transforms a String to (possibly) another type
11
11
  #
12
12
  def initialize(type_name, type, capture_group_regexps, transformer)
13
13
  @type_name, @type, @transformer = type_name, type, transformer
14
- @capture_group_regexps = capture_group_regexps.is_a?(String) ? [capture_group_regexps] : capture_group_regexps
14
+ @capture_group_regexps = string_array(capture_group_regexps)
15
15
  end
16
16
 
17
17
  def transform(value)
18
18
  @transformer.call(value)
19
19
  end
20
+
21
+ private
22
+
23
+ def string_array(capture_group_regexps)
24
+ array = capture_group_regexps.is_a?(Array) ? capture_group_regexps : [capture_group_regexps]
25
+ array.map { |r| r.is_a?(String) ? r : r.source }
26
+ end
20
27
  end
21
28
  end
22
29
  end
@@ -1,15 +1,15 @@
1
1
  module Cucumber
2
2
  module CucumberExpressions
3
- class TransformMatcher
4
- attr_reader :transform
3
+ class ParameterMatcher
4
+ attr_reader :parameter
5
5
 
6
- def initialize(transform, regexp, text, match_position=0)
7
- @transform, @regexp, @text = transform, regexp, text
6
+ def initialize(parameter, regexp, text, match_position=0)
7
+ @parameter, @regexp, @text = parameter, regexp, text
8
8
  @match = @regexp.match(@text, match_position)
9
9
  end
10
10
 
11
11
  def advance_to(new_match_position)
12
- self.class.new(@transform, @regexp, @text, new_match_position)
12
+ self.class.new(parameter, @regexp, @text, new_match_position)
13
13
  end
14
14
 
15
15
  def find
@@ -0,0 +1,64 @@
1
+ require 'cucumber/cucumber_expressions/parameter'
2
+
3
+ module Cucumber
4
+ module CucumberExpressions
5
+ class ParameterRegistry
6
+ INTEGER_REGEXPS = ['-?\d+', '\d+']
7
+ FLOATING_POINT_REGEXPS = ['-?\d*\.?\d+']
8
+
9
+ def initialize
10
+ @parameters_by_type_name = {}
11
+ @parameters_by_capture_group_regexp = {}
12
+ @parameters_by_class = {}
13
+
14
+ add_parameter(Parameter.new('int', Integer, INTEGER_REGEXPS, lambda {|s| s.to_i}))
15
+ add_parameter(Parameter.new('float', Float, FLOATING_POINT_REGEXPS, lambda {|s| s.to_f}))
16
+ end
17
+
18
+ def lookup_by_type(type)
19
+ if type.is_a?(Class)
20
+ lookup_by_class(type)
21
+ elsif type.is_a?(String)
22
+ lookup_by_type_name(type)
23
+ else
24
+ raise Exception.new("Type must be string or class, but was #{type} of type #{type.class}")
25
+ end
26
+ end
27
+
28
+ def lookup_by_class(clazz)
29
+ parameter = @parameters_by_class[clazz]
30
+ if parameter.nil?
31
+ create_anonymous_lookup(lambda {|s| clazz.new(s)})
32
+ else
33
+ parameter
34
+ end
35
+ end
36
+
37
+ def lookup_by_type_name(type_name)
38
+ @parameters_by_type_name[type_name]
39
+ end
40
+
41
+ def lookup_by_capture_group_regexp(capture_group_regexp)
42
+ @parameters_by_capture_group_regexp[capture_group_regexp]
43
+ end
44
+
45
+ def create_anonymous_lookup(proc)
46
+ Parameter.new(nil, nil, ['.+'], proc)
47
+ end
48
+
49
+ def add_parameter(parameter)
50
+ @parameters_by_type_name[parameter.type_name] = parameter
51
+ @parameters_by_class[parameter.type] = parameter
52
+
53
+ parameter.capture_group_regexps.each do |capture_group_regexp|
54
+ @parameters_by_capture_group_regexp[capture_group_regexp] = parameter
55
+ end
56
+ end
57
+
58
+ def parameters
59
+ @parameters_by_type_name.values
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -1,13 +1,13 @@
1
- require 'cucumber/cucumber_expressions/argument_matcher'
1
+ require 'cucumber/cucumber_expressions/argument_builder'
2
2
 
3
3
  module Cucumber
4
4
  module CucumberExpressions
5
5
  class RegularExpression
6
6
  CAPTURE_GROUP_PATTERN = /\(([^(]+)\)/
7
7
 
8
- def initialize(regexp, types, transform_lookup)
8
+ def initialize(regexp, types, parameter_registry)
9
9
  @regexp = regexp
10
- @transforms = []
10
+ @parameters = []
11
11
 
12
12
  type_index = 0
13
13
  match = nil
@@ -21,24 +21,24 @@ module Cucumber
21
21
  type = types.length <= type_index ? nil : types[type_index]
22
22
  type_index += 1
23
23
 
24
- transform = nil
24
+ parameter = nil
25
25
  if (type)
26
- transform = transform_lookup.lookup_by_type(type)
26
+ parameter = parameter_registry.lookup_by_type(type)
27
27
  end
28
- if (transform.nil?)
29
- transform = transform_lookup.lookup_by_capture_group_regexp(capture_group_pattern)
28
+ if (parameter.nil?)
29
+ parameter = parameter_registry.lookup_by_capture_group_regexp(capture_group_pattern)
30
30
  end
31
- if (transform.nil?)
32
- transform = transform_lookup.create_anonymous_lookup(lambda {|s| s})
31
+ if (parameter.nil?)
32
+ parameter = parameter_registry.create_anonymous_lookup(lambda {|s| s})
33
33
  end
34
34
 
35
- @transforms.push(transform)
35
+ @parameters.push(parameter)
36
36
  match_offset = match.offset(0)[1]
37
37
  end
38
38
  end
39
39
 
40
40
  def match(text)
41
- ArgumentMatcher.match_arguments(@regexp, text, @transforms)
41
+ ArgumentBuilder.build_arguments(@regexp, text, @parameters)
42
42
  end
43
43
 
44
44
  def source
@@ -1,6 +1,6 @@
1
1
  require 'cucumber/cucumber_expressions/cucumber_expression_generator'
2
- require 'cucumber/cucumber_expressions/transform'
3
- require 'cucumber/cucumber_expressions/transform_lookup'
2
+ require 'cucumber/cucumber_expressions/parameter'
3
+ require 'cucumber/cucumber_expressions/parameter_registry'
4
4
 
5
5
  module Cucumber
6
6
  module CucumberExpressions
@@ -9,69 +9,66 @@ module Cucumber
9
9
  end
10
10
 
11
11
  before do
12
- @transform_lookup = TransformLookup.new
13
- @generator = CucumberExpressionGenerator.new(@transform_lookup)
12
+ @parameter_registry = ParameterRegistry.new
13
+ @generator = CucumberExpressionGenerator.new(@parameter_registry)
14
14
  end
15
15
 
16
16
  it "documents expression generation" do
17
- transform_lookup = TransformLookup.new
17
+ parameter_registry = ParameterRegistry.new
18
18
  ### [generate-expression]
19
- generator = CucumberExpressionGenerator.new(transform_lookup)
19
+ generator = CucumberExpressionGenerator.new(parameter_registry)
20
20
  undefined_step_text = "I have 2 cucumbers and 1.5 tomato"
21
- generated_expression = generator.generate_expression(undefined_step_text, true)
22
- expect(generated_expression.source).to eq("I have {arg1:int} cucumbers and {arg2:float} tomato")
23
- expect(generated_expression.argumentNames[0]).to eq("arg1")
24
- expect(generated_expression.transforms[1].type).to eq(Float)
21
+ generated_expression = generator.generate_expression(undefined_step_text)
22
+ expect(generated_expression.source).to eq("I have {int} cucumbers and {float} tomato")
23
+ expect(generated_expression.parameters[1].type).to eq(Float)
25
24
  ### [generate-expression]
26
25
  end
27
26
 
28
27
  it "generates expression for no args" do
29
- assert_typed_expression("hello", "hello")
28
+ assert_expression("hello", [], "hello")
30
29
  end
31
30
 
32
- it "generates expression for int double arg" do
33
- assert_typed_expression(
34
- "I have {arg1:int} cukes and {arg2:float} euro",
31
+ it "generates expression for int float arg" do
32
+ assert_expression(
33
+ "I have {int} cukes and {float} euro", ["int", "float"],
35
34
  "I have 2 cukes and 1.5 euro")
36
35
  end
37
36
 
38
37
  it "generates expression for just int" do
39
- assert_typed_expression(
40
- "{arg1:int}",
38
+ assert_expression(
39
+ "{int}", ["int"],
41
40
  "99999")
42
41
  end
43
42
 
44
- it "generates expression without expression type" do
45
- assert_untyped_expression(
46
- "I have {arg1} cukes and {arg2} euro",
47
- "I have 2 cukes and 1.5 euro")
43
+ it "numbers only second argument when builtin type is not reserved keyword" do
44
+ assert_expression(
45
+ "I have {int} cukes and {int} euro", ["int", "int2"],
46
+ "I have 2 cukes and 5 euro")
48
47
  end
49
48
 
50
- it "generates expression for custom type" do
51
- @transform_lookup.add_transform(Transform.new(
49
+ it "numbers only second argument when type is not reserved keyword" do
50
+ @parameter_registry.add_parameter(Parameter.new(
52
51
  'currency',
53
52
  Currency,
54
53
  '[A-Z]{3}',
55
54
  nil
56
55
  ))
57
56
 
58
- assert_typed_expression(
59
- "I have a {arg1:currency} account",
60
- "I have a EUR account")
57
+ assert_expression(
58
+ "I have a {currency} account and a {currency} account", ["currency", "currency2"],
59
+ "I have a EUR account and a GBP account")
61
60
  end
62
61
 
63
- it "exposes transforms in generated expression" do
64
- expression = @generator.generate_expression("I have 2 cukes and 1.5 euro", true)
65
- types = expression.transforms.map(&:type)
62
+ it "exposes parameters in generated expression" do
63
+ expression = @generator.generate_expression("I have 2 cukes and 1.5 euro")
64
+ types = expression.parameters.map(&:type)
66
65
  expect(types).to eq([Integer, Float])
67
66
  end
68
67
 
69
- def assert_typed_expression(expected, text)
70
- expect(@generator.generate_expression(text, true).source).to eq(expected)
71
- end
72
-
73
- def assert_untyped_expression(expected, text)
74
- expect(@generator.generate_expression(text, false).source).to eq(expected)
68
+ def assert_expression(expected_expression, expected_argument_names, text)
69
+ generated_expression = @generator.generate_expression(text)
70
+ expect(generated_expression.parameter_names).to eq(expected_argument_names)
71
+ expect(generated_expression.source).to eq(expected_expression)
75
72
  end
76
73
  end
77
74
  end
@@ -1,12 +1,12 @@
1
1
  require 'cucumber/cucumber_expressions/cucumber_expression'
2
- require 'cucumber/cucumber_expressions/transform_lookup'
2
+ require 'cucumber/cucumber_expressions/parameter_registry'
3
3
 
4
4
  module Cucumber
5
5
  module CucumberExpressions
6
6
  describe CucumberExpression do
7
7
  context "Regexp translation" do
8
8
  def assert_regexp(expression, regexp)
9
- cucumber_expression = CucumberExpression.new(expression, [], TransformLookup.new)
9
+ cucumber_expression = CucumberExpression.new(expression, [], ParameterRegistry.new)
10
10
  expect(regexp).to eq(cucumber_expression.instance_variable_get('@regexp'))
11
11
  end
12
12
 
@@ -26,7 +26,7 @@ module Cucumber
26
26
 
27
27
  it "translates three typed arguments" do
28
28
  assert_regexp(
29
- "I have {n:float} cukes in my {bodypart} at {time:int} o'clock",
29
+ "I have {float} cukes in my {bodypart} at {int} o'clock",
30
30
  /^I have (-?\d*\.?\d+) cukes in my (.+) at ((?:-?\d+)|(?:\d+)) o'clock$/
31
31
  )
32
32
  end
@@ -1,28 +1,28 @@
1
1
  require 'cucumber/cucumber_expressions/cucumber_expression'
2
- require 'cucumber/cucumber_expressions/transform_lookup'
2
+ require 'cucumber/cucumber_expressions/parameter_registry'
3
3
 
4
4
  module Cucumber
5
5
  module CucumberExpressions
6
6
  describe CucumberExpression do
7
7
  it "documents match arguments" do
8
- transform_lookup = TransformLookup.new
8
+ parameter_registry = ParameterRegistry.new
9
9
 
10
10
  ### [capture-match-arguments]
11
11
  expr = "I have {n} cuke(s) in my {bodypart} now"
12
12
  types = ['int', nil]
13
- expression = CucumberExpression.new(expr, types, transform_lookup)
13
+ expression = CucumberExpression.new(expr, types, parameter_registry)
14
14
  args = expression.match("I have 7 cukes in my belly now")
15
15
  expect( args[0].transformed_value ).to eq(7)
16
16
  expect( args[1].transformed_value ).to eq("belly")
17
17
  ### [capture-match-arguments]
18
18
  end
19
19
 
20
- it "transforms nothing by default" do
20
+ it "does no transform by default" do
21
21
  expect( match("{what}", "22") ).to eq(["22"])
22
22
  end
23
23
 
24
- it "transforms to int by expression type" do
25
- expect( match("{what:int}", "22") ).to eq([22])
24
+ it "transforms to int by parameter type" do
25
+ expect( match("{int}", "22") ).to eq([22])
26
26
  end
27
27
 
28
28
  it "transforms to int by explicit type" do
@@ -30,17 +30,17 @@ module Cucumber
30
30
  end
31
31
 
32
32
  # Ruby-specific
33
- it "transforms to Integer by explicit type" do
33
+ it "parameters to Integer by explicit type" do
34
34
  expect( match("{what}", "22", [Integer]) ).to eq([22])
35
35
  end
36
36
 
37
- it "doesn't match a float to an int" do
38
- expect( match("{what:int}", "1.22") ).to be_nil
37
+ it "doesn't match a float with an int parameter" do
38
+ expect( match("{int}", "1.22") ).to be_nil
39
39
  end
40
40
 
41
- it "transforms to float by expression type" do
42
- expect( match("{what:float}", "0.22") ).to eq([0.22])
43
- expect( match("{what:float}", ".22") ).to eq([0.22])
41
+ it "transforms to float by parameter type" do
42
+ expect( match("{float}", "0.22") ).to eq([0.22])
43
+ expect( match("{float}", ".22") ).to eq([0.22])
44
44
  end
45
45
 
46
46
  it "transforms to float by explicit type" do
@@ -48,26 +48,41 @@ module Cucumber
48
48
  expect( match("{what}", ".22", ['float']) ).to eq([0.22])
49
49
  end
50
50
 
51
- it "doesn't transform unknown type" do
52
- expect { match("{what:unknown}", "something") }.to raise_error(
53
- 'No transform for type name "unknown"')
51
+ it "leaves unknown type untransformed" do
52
+ expect( match("{unknown}", "something") ).to eq(["something"])
53
+ end
54
+
55
+ it "supports deprecated {name:type} syntax for now" do
56
+ expect( match("{param:unknown}", "something") ).to eq(["something"])
54
57
  end
55
58
 
56
59
  it "exposes source" do
57
- expr = "I have {n:int} cuke(s) in my {bodypart} now"
58
- expect(CucumberExpression.new(expr, [], TransformLookup.new).source).to eq(expr)
60
+ expr = "I have {int} cuke(s) in my {bodypart} now"
61
+ expect(CucumberExpression.new(expr, [], ParameterRegistry.new).source).to eq(expr)
59
62
  end
60
63
 
61
64
  it "exposes offset and value" do
62
- expr = "I have {n:int} cuke(s) in my {bodypart} now"
63
- expression = CucumberExpression.new(expr, [], TransformLookup.new)
65
+ expr = "I have {int} cuke(s) in my {bodypart} now"
66
+ expression = CucumberExpression.new(expr, [], ParameterRegistry.new)
64
67
  arg1 = expression.match("I have 800 cukes in my brain now")[0]
65
68
  expect(arg1.offset).to eq(7)
66
69
  expect(arg1.value).to eq("800")
67
70
  end
68
71
 
72
+ describe "RegExp special characters" do
73
+ %w(\\ [ ] ^ $ . | ? * +).each do |character|
74
+ it "escapes #{character}" do
75
+ expr = "I have {int} cuke(s) and #{character}"
76
+ expression = CucumberExpression.new(expr, [], ParameterRegistry.new)
77
+ arg1 = expression.match("I have 800 cukes and #{character}")[0]
78
+ expect(arg1.offset).to eq(7)
79
+ expect(arg1.value).to eq("800")
80
+ end
81
+ end
82
+ end
83
+
69
84
  def match(expression, text, types = [])
70
- cucumber_expression = CucumberExpression.new(expression, types, TransformLookup.new)
85
+ cucumber_expression = CucumberExpression.new(expression, types, ParameterRegistry.new)
71
86
  args = cucumber_expression.match(text)
72
87
  return nil if args.nil?
73
88
  args.map { |arg| arg.transformed_value }
@@ -0,0 +1,87 @@
1
+ require 'cucumber/cucumber_expressions/cucumber_expression'
2
+ require 'cucumber/cucumber_expressions/regular_expression'
3
+ require 'cucumber/cucumber_expressions/parameter_registry'
4
+
5
+ module Cucumber
6
+ module CucumberExpressions
7
+ class Color
8
+ attr_reader :name
9
+
10
+ ### [color-constructor]
11
+ def initialize(name)
12
+ @name = name
13
+ end
14
+ ### [color-constructor]
15
+
16
+ def ==(other)
17
+ other.is_a?(Color) && other.name == name
18
+ end
19
+ end
20
+
21
+ describe "Custom parameter" do
22
+ before do
23
+ @parameter_registry = ParameterRegistry.new
24
+ ### [add-color-parameter]
25
+ @parameter_registry.add_parameter(Parameter.new(
26
+ 'color',
27
+ Color,
28
+ [/red|blue|yellow/, /(?:dark|light) (?:red|blue|yellow)/],
29
+ lambda { |s| Color.new(s) }
30
+ ))
31
+ ### [add-color-parameter]
32
+ end
33
+
34
+ describe CucumberExpression do
35
+ it "matches typed parameters" do
36
+ expression = CucumberExpression.new("I have a {color} ball", [], @parameter_registry)
37
+ parametered_argument_value = expression.match("I have a red ball")[0].transformed_value
38
+ expect( parametered_argument_value ).to eq(Color.new('red'))
39
+ end
40
+
41
+ it "matches typed parameters with optional group" do
42
+ expression = CucumberExpression.new("I have a {color} ball", [], @parameter_registry)
43
+ parametered_argument_value = expression.match("I have a dark red ball")[0].transformed_value
44
+ expect( parametered_argument_value ).to eq(Color.new('dark red'))
45
+ end
46
+
47
+ it "matches untyped parameters with explicit type" do
48
+ expression = CucumberExpression.new("I have a {color} ball", [Color], @parameter_registry)
49
+ parametered_argument_value = expression.match("I have a red ball")[0].transformed_value
50
+ expect( parametered_argument_value ).to eq(Color.new('red'))
51
+ end
52
+
53
+ it "matches untyped parameters with same name as type" do
54
+ expression = CucumberExpression.new("I have a {color} ball", [], @parameter_registry)
55
+ parametered_argument_value = expression.match("I have a red ball")[0].transformed_value
56
+ expect( parametered_argument_value ).to eq(Color.new('red'))
57
+ end
58
+
59
+ it "matches parameters with explicit type that isn't registered" do
60
+ expression = CucumberExpression.new("I have a {color} ball", [Color], ParameterRegistry.new)
61
+ parametered_argument_value = expression.match("I have a red ball")[0].transformed_value
62
+ expect( parametered_argument_value ).to eq(Color.new('red'))
63
+ end
64
+ end
65
+
66
+ describe RegularExpression do
67
+ it "matches parameters with explicit constructor" do
68
+ expression = RegularExpression.new(/I have a (red|blue|yellow) ball/, [Color], @parameter_registry)
69
+ parametered_argument_value = expression.match("I have a red ball")[0].transformed_value
70
+ expect( parametered_argument_value ).to eq(Color.new('red'))
71
+ end
72
+
73
+ it "matches parameters without explicit constructor" do
74
+ expression = RegularExpression.new(/I have a (red|blue|yellow) ball/, [], @parameter_registry)
75
+ parametered_argument_value = expression.match("I have a red ball")[0].transformed_value
76
+ expect( parametered_argument_value ).to eq(Color.new('red'))
77
+ end
78
+
79
+ it "matches parameters with explicit type that isn't registered" do
80
+ expression = RegularExpression.new(/I have a (red|blue|yellow) ball/, [Color], ParameterRegistry.new)
81
+ parametered_argument_value = expression.match("I have a red ball")[0].transformed_value
82
+ expect( parametered_argument_value ).to eq(Color.new('red'))
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -1,6 +1,6 @@
1
1
  require 'cucumber/cucumber_expressions/cucumber_expression'
2
2
  require 'cucumber/cucumber_expressions/regular_expression'
3
- require 'cucumber/cucumber_expressions/transform_lookup'
3
+ require 'cucumber/cucumber_expressions/parameter_registry'
4
4
  require 'json'
5
5
 
6
6
  module Cucumber
@@ -8,8 +8,8 @@ module Cucumber
8
8
  describe 'examples.txt' do
9
9
  def match(expression_text, text)
10
10
  expression = expression_text =~ /\/(.*)\// ?
11
- RegularExpression.new(Regexp.new($1), [], TransformLookup.new) :
12
- CucumberExpression.new(expression_text, [], TransformLookup.new)
11
+ RegularExpression.new(Regexp.new($1), [], ParameterRegistry.new) :
12
+ CucumberExpression.new(expression_text, [], ParameterRegistry.new)
13
13
 
14
14
  arguments = expression.match(text)
15
15
  return nil if arguments.nil?
@@ -1,47 +1,47 @@
1
1
  require 'cucumber/cucumber_expressions/regular_expression'
2
- require 'cucumber/cucumber_expressions/transform_lookup'
2
+ require 'cucumber/cucumber_expressions/parameter_registry'
3
3
 
4
4
  module Cucumber
5
5
  module CucumberExpressions
6
6
  describe RegularExpression do
7
7
  it "documents match arguments" do
8
- transform_lookup = TransformLookup.new
8
+ parameter_registry = ParameterRegistry.new
9
9
 
10
10
  ### [capture-match-arguments]
11
11
  expr = /I have (\d+) cukes? in my (\w*) now/
12
12
  types = ['int', nil]
13
- expression = RegularExpression.new(expr, types, transform_lookup)
13
+ expression = RegularExpression.new(expr, types, parameter_registry)
14
14
  args = expression.match("I have 7 cukes in my belly now")
15
15
  expect( args[0].transformed_value ).to eq(7)
16
16
  expect( args[1].transformed_value ).to eq("belly")
17
17
  ### [capture-match-arguments]
18
18
  end
19
19
 
20
- it "transforms to string by default" do
20
+ it "does no transform by default" do
21
21
  expect( match(/(\d\d)/, "22") ).to eq(["22"])
22
22
  end
23
23
 
24
- it "transforms integer to double using explicit type name" do
24
+ it "transforms int to float by explicit type name" do
25
25
  expect( match(/(.*)/, "22", ['float']) ).to eq([22.0])
26
26
  end
27
27
 
28
- it "transforms integer to double using explicit type" do
28
+ it "transforms int to float by explicit function" do
29
29
  expect( match(/(.*)/, "22", [Float]) ).to eq([22.0])
30
30
  end
31
31
 
32
- it "transforms to int using capture group pattern" do
32
+ it "transforms int by parameter pattern" do
33
33
  expect( match(/(-?\d+)/, "22") ).to eq([22])
34
34
  end
35
35
 
36
- it "transforms to int by alternate capture group pattern" do
36
+ it "transforms int by alternate parameter pattern" do
37
37
  expect( match(/(\d+)/, "22") ).to eq([22])
38
38
  end
39
39
 
40
- it "transforms double without integer value" do
40
+ it "transforms float without integer part" do
41
41
  expect( match(/(.*)/, ".22", ['float']) ).to eq([0.22])
42
42
  end
43
43
 
44
- it "transforms double with sign" do
44
+ it "transforms float with sign" do
45
45
  expect( match(/(.*)/, "-1.22", ['float']) ).to eq([-1.22])
46
46
  end
47
47
 
@@ -57,11 +57,11 @@ module Cucumber
57
57
 
58
58
  it "exposes source" do
59
59
  expr = /I have (\d+) cukes? in my (\+) now/
60
- expect(RegularExpression.new(expr, [], TransformLookup.new).source).to eq(expr)
60
+ expect(RegularExpression.new(expr, [], ParameterRegistry.new).source).to eq(expr)
61
61
  end
62
62
 
63
63
  def match(expression, text, types = [])
64
- regular_expression = RegularExpression.new(expression, types, TransformLookup.new)
64
+ regular_expression = RegularExpression.new(expression, types, ParameterRegistry.new)
65
65
  arguments = regular_expression.match(text)
66
66
  return nil if arguments.nil?
67
67
  arguments.map { |arg| arg.transformed_value }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cucumber-expressions
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aslak Hellesøy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-20 00:00:00.000000000 Z
11
+ date: 2017-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -82,20 +82,20 @@ files:
82
82
  - cucumber-expressions.gemspec
83
83
  - examples.txt
84
84
  - lib/cucumber/cucumber_expressions/argument.rb
85
- - lib/cucumber/cucumber_expressions/argument_matcher.rb
85
+ - lib/cucumber/cucumber_expressions/argument_builder.rb
86
86
  - lib/cucumber/cucumber_expressions/cucumber_expression.rb
87
87
  - lib/cucumber/cucumber_expressions/cucumber_expression_generator.rb
88
88
  - lib/cucumber/cucumber_expressions/generated_expression.rb
89
+ - lib/cucumber/cucumber_expressions/parameter.rb
90
+ - lib/cucumber/cucumber_expressions/parameter_matcher.rb
91
+ - lib/cucumber/cucumber_expressions/parameter_registry.rb
89
92
  - lib/cucumber/cucumber_expressions/regular_expression.rb
90
- - lib/cucumber/cucumber_expressions/transform.rb
91
- - lib/cucumber/cucumber_expressions/transform_lookup.rb
92
- - lib/cucumber/cucumber_expressions/transform_matcher.rb
93
93
  - spec/capture_warnings.rb
94
94
  - spec/coverage.rb
95
95
  - spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb
96
96
  - spec/cucumber/cucumber_expressions/cucumber_expression_regexp_spec.rb
97
97
  - spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb
98
- - spec/cucumber/cucumber_expressions/custom_transform_spec.rb
98
+ - spec/cucumber/cucumber_expressions/custom_parameter_spec.rb
99
99
  - spec/cucumber/cucumber_expressions/expression_examples_spec.rb
100
100
  - spec/cucumber/cucumber_expressions/regular_expression_spec.rb
101
101
  homepage: https://github.com/cucumber/cucumber-expressions-ruby#readme
@@ -119,16 +119,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
119
  version: '0'
120
120
  requirements: []
121
121
  rubyforge_project:
122
- rubygems_version: 2.4.5.2
122
+ rubygems_version: 2.5.2
123
123
  signing_key:
124
124
  specification_version: 4
125
- summary: cucumber-expressions-1.0.4
125
+ summary: cucumber-expressions-2.0.0
126
126
  test_files:
127
127
  - spec/capture_warnings.rb
128
128
  - spec/coverage.rb
129
129
  - spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb
130
130
  - spec/cucumber/cucumber_expressions/cucumber_expression_regexp_spec.rb
131
131
  - spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb
132
- - spec/cucumber/cucumber_expressions/custom_transform_spec.rb
132
+ - spec/cucumber/cucumber_expressions/custom_parameter_spec.rb
133
133
  - spec/cucumber/cucumber_expressions/expression_examples_spec.rb
134
134
  - spec/cucumber/cucumber_expressions/regular_expression_spec.rb
@@ -1,70 +0,0 @@
1
- require 'cucumber/cucumber_expressions/transform'
2
-
3
- module Cucumber
4
- module CucumberExpressions
5
- class TransformLookup
6
- INTEGER_REGEXPS = ['-?\d+', '\d+']
7
- FLOATING_POINT_REGEXPS = ['-?\d*\.?\d+']
8
-
9
- def initialize
10
- @transforms_by_type_name = {}
11
- @transforms_by_capture_group_regexp = {}
12
- @transforms_by_class = {}
13
-
14
- add_transform(Transform.new('int', Integer, INTEGER_REGEXPS, lambda {|s| s.to_i}))
15
- add_transform(Transform.new('float', Float, FLOATING_POINT_REGEXPS, lambda {|s| s.to_f}))
16
- end
17
-
18
- def lookup_by_type(type)
19
- if type.is_a?(Class)
20
- lookup_by_class(type)
21
- elsif type.is_a?(String)
22
- lookup_by_type_name(type, false)
23
- else
24
- raise Exception.new("Type must be string or class, but was #{type} of type #{type.class}")
25
- end
26
- end
27
-
28
- def lookup_by_class(clazz)
29
- transform = @transforms_by_class[clazz]
30
- if transform.nil?
31
- create_anonymous_lookup(lambda {|s| clazz.new(s)})
32
- else
33
- transform
34
- end
35
- end
36
-
37
- def lookup_by_type_name(type_name, ignore_unknown_type_name)
38
- transform = @transforms_by_type_name[type_name]
39
- if transform.nil?
40
- return nil if ignore_unknown_type_name
41
- raise Exception.new("No transform for type name \"#{type_name}\"")
42
- else
43
- transform
44
- end
45
- end
46
-
47
- def lookup_by_capture_group_regexp(capture_group_regexp)
48
- @transforms_by_capture_group_regexp[capture_group_regexp]
49
- end
50
-
51
- def create_anonymous_lookup(proc)
52
- Transform.new(nil, nil, ['.+'], proc)
53
- end
54
-
55
- def add_transform(transform)
56
- @transforms_by_type_name[transform.type_name] = transform
57
- @transforms_by_class[transform.type] = transform
58
-
59
- transform.capture_group_regexps.each do |capture_group_regexp|
60
- @transforms_by_capture_group_regexp[capture_group_regexp] = transform
61
- end
62
- end
63
-
64
- def transforms
65
- @transforms_by_type_name.values
66
- end
67
-
68
- end
69
- end
70
- end
@@ -1,87 +0,0 @@
1
- require 'cucumber/cucumber_expressions/cucumber_expression'
2
- require 'cucumber/cucumber_expressions/regular_expression'
3
- require 'cucumber/cucumber_expressions/transform_lookup'
4
-
5
- module Cucumber
6
- module CucumberExpressions
7
- class Color
8
- attr_reader :name
9
-
10
- ### [color-constructor]
11
- def initialize(name)
12
- @name = name
13
- end
14
- ### [color-constructor]
15
-
16
- def ==(other)
17
- other.is_a?(Color) && other.name == name
18
- end
19
- end
20
-
21
- describe "Custom transform" do
22
- before do
23
- @transform_lookup = TransformLookup.new
24
- ### [add-color-transform]
25
- @transform_lookup.add_transform(Transform.new(
26
- 'color',
27
- Color,
28
- ['red|blue|yellow', '(?:dark|light) (?:red|blue|yellow)'],
29
- lambda { |s| Color.new(s) }
30
- ))
31
- ### [add-color-transform]
32
- end
33
-
34
- describe CucumberExpression do
35
- it "transforms arguments with expression type I" do
36
- expression = CucumberExpression.new("I have a {color:color} ball", [], @transform_lookup)
37
- transformed_argument_value = expression.match("I have a red ball")[0].transformed_value
38
- expect( transformed_argument_value ).to eq(Color.new('red'))
39
- end
40
-
41
- it "transforms arguments with expression type II" do
42
- expression = CucumberExpression.new("I have a {color:color} ball", [], @transform_lookup)
43
- transformed_argument_value = expression.match("I have a dark red ball")[0].transformed_value
44
- expect( transformed_argument_value ).to eq(Color.new('dark red'))
45
- end
46
-
47
- it "transforms arguments with explicit type" do
48
- expression = CucumberExpression.new("I have a {color} ball", [Color], @transform_lookup)
49
- transformed_argument_value = expression.match("I have a red ball")[0].transformed_value
50
- expect( transformed_argument_value ).to eq(Color.new('red'))
51
- end
52
-
53
- it "transforms arguments using argument name as type" do
54
- expression = CucumberExpression.new("I have a {color} ball", [], @transform_lookup)
55
- transformed_argument_value = expression.match("I have a red ball")[0].transformed_value
56
- expect( transformed_argument_value ).to eq(Color.new('red'))
57
- end
58
-
59
- it "transforms arguments with explicit type using constructor directly" do
60
- expression = CucumberExpression.new("I have a {color} ball", [Color], TransformLookup.new)
61
- transformed_argument_value = expression.match("I have a red ball")[0].transformed_value
62
- expect( transformed_argument_value ).to eq(Color.new('red'))
63
- end
64
- end
65
-
66
- describe RegularExpression do
67
- it "transforms arguments with expression type" do
68
- expression = RegularExpression.new(/I have a (red|blue|yellow) ball/, [], @transform_lookup)
69
- transformed_argument_value = expression.match("I have a red ball")[0].transformed_value
70
- expect( transformed_argument_value ).to eq(Color.new('red'))
71
- end
72
-
73
- it "transforms arguments with explicit type" do
74
- expression = RegularExpression.new(/I have a (red|blue|yellow) ball/, ['color'], @transform_lookup)
75
- transformed_argument_value = expression.match("I have a red ball")[0].transformed_value
76
- expect( transformed_argument_value ).to eq(Color.new('red'))
77
- end
78
-
79
- it "transforms arguments with explicit type using constructor directly" do
80
- expression = RegularExpression.new(/I have a (red|blue|yellow) ball/, [Color], TransformLookup.new)
81
- transformed_argument_value = expression.match("I have a red ball")[0].transformed_value
82
- expect( transformed_argument_value ).to eq(Color.new('red'))
83
- end
84
- end
85
- end
86
- end
87
- end