diff --git a/CHANGELOG.md b/CHANGELOG.md index b71c5488c..0e00597cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Changed -- [Ruby] Minimum supported ruby is now 2.5+ - - [JavaScript] Added TypeScript source to the package ([#211](https://github.com/cucumber/cucumber-expressions/pull/211)) +- [Ruby] Minimum supported ruby is now 2.5+ ([#232](https://github.com/cucumber/cucumber-expressions/pull/232)) +- [Ruby] Large suite wide refactor for basic rubocop compliance ([#233](https://github.com/cucumber/cucumber-expressions/pull/233)) ## [16.1.2] - 2023-01-17 ### Fixed diff --git a/ruby/.rubocop_todo.yml b/ruby/.rubocop_todo.yml index c41ac704f..42e6d2101 100644 --- a/ruby/.rubocop_todo.yml +++ b/ruby/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2023-10-03 16:26:01 UTC using RuboCop version 1.27.0. +# on 2023-10-03 17:06:00 UTC using RuboCop version 1.27.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -16,22 +16,7 @@ Layout/AccessModifierIndentation: Exclude: - 'lib/cucumber/cucumber_expressions/cucumber_expression_generator.rb' -# Offense count: 45 -# This cop supports safe auto-correction (--auto-correct). -Layout/ClosingParenthesisIndentation: - Exclude: - - 'lib/cucumber/cucumber_expressions/argument.rb' - - 'lib/cucumber/cucumber_expressions/combinatorial_generated_expression_factory.rb' - - 'lib/cucumber/cucumber_expressions/cucumber_expression_parser.rb' - - 'lib/cucumber/cucumber_expressions/cucumber_expression_tokenizer.rb' - - 'lib/cucumber/cucumber_expressions/errors.rb' - - 'spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb' - - 'spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb' - - 'spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb' - - 'spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb' - - 'spec/cucumber/cucumber_expressions/regular_expression_spec.rb' - -# Offense count: 25 +# Offense count: 23 # This cop supports safe auto-correction (--auto-correct). Layout/EmptyLineAfterGuardClause: Exclude: @@ -40,12 +25,10 @@ Layout/EmptyLineAfterGuardClause: - 'lib/cucumber/cucumber_expressions/combinatorial_generated_expression_factory.rb' - 'lib/cucumber/cucumber_expressions/cucumber_expression.rb' - 'lib/cucumber/cucumber_expressions/cucumber_expression_parser.rb' - - 'lib/cucumber/cucumber_expressions/cucumber_expression_tokenizer.rb' - 'lib/cucumber/cucumber_expressions/parameter_type.rb' - 'lib/cucumber/cucumber_expressions/parameter_type_matcher.rb' - 'lib/cucumber/cucumber_expressions/parameter_type_registry.rb' - 'lib/cucumber/cucumber_expressions/tree_regexp.rb' - - 'spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb' - 'spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb' - 'spec/cucumber/cucumber_expressions/regular_expression_spec.rb' @@ -56,20 +39,18 @@ Layout/EmptyLineAfterMagicComment: - 'Gemfile' - 'Rakefile' -# Offense count: 2 +# Offense count: 1 # This cop supports safe auto-correction (--auto-correct). # Configuration parameters: EmptyLineBetweenMethodDefs, EmptyLineBetweenClassDefs, EmptyLineBetweenModuleDefs, AllowAdjacentOneLineDefs, NumberOfEmptyLines. Layout/EmptyLineBetweenDefs: Exclude: - 'lib/cucumber/cucumber_expressions/ast.rb' - - 'lib/cucumber/cucumber_expressions/errors.rb' -# Offense count: 3 +# Offense count: 2 # This cop supports safe auto-correction (--auto-correct). Layout/EmptyLines: Exclude: - 'lib/cucumber/cucumber_expressions/ast.rb' - - 'lib/cucumber/cucumber_expressions/errors.rb' - 'lib/cucumber/cucumber_expressions/parameter_type.rb' # Offense count: 2 @@ -92,15 +73,13 @@ Layout/EmptyLinesAroundClassBody: - 'lib/cucumber/cucumber_expressions/parameter_type_registry.rb' - 'lib/cucumber/cucumber_expressions/regular_expression.rb' -# Offense count: 4 +# Offense count: 1 # This cop supports safe auto-correction (--auto-correct). # Configuration parameters: EnforcedStyle. # SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines Layout/EmptyLinesAroundModuleBody: Exclude: - - 'lib/cucumber/cucumber_expressions/combinatorial_generated_expression_factory.rb' - 'spec/cucumber/cucumber_expressions/combinatorial_generated_expression_factory_test.rb' - - 'spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb' # Offense count: 1 # This cop supports safe auto-correction (--auto-correct). @@ -109,23 +88,6 @@ Layout/ExtraSpacing: Exclude: - 'cucumber-cucumber-expressions.gemspec' -# Offense count: 47 -# This cop supports safe auto-correction (--auto-correct). -# Configuration parameters: EnforcedStyle, IndentationWidth. -# SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses -Layout/FirstArgumentIndentation: - Exclude: - - 'lib/cucumber/cucumber_expressions/argument.rb' - - 'lib/cucumber/cucumber_expressions/combinatorial_generated_expression_factory.rb' - - 'lib/cucumber/cucumber_expressions/cucumber_expression_parser.rb' - - 'lib/cucumber/cucumber_expressions/cucumber_expression_tokenizer.rb' - - 'lib/cucumber/cucumber_expressions/errors.rb' - - 'spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb' - - 'spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb' - - 'spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb' - - 'spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb' - - 'spec/cucumber/cucumber_expressions/regular_expression_spec.rb' - # Offense count: 4 # This cop supports safe auto-correction (--auto-correct). # Configuration parameters: EnforcedStyle, IndentationWidth. @@ -145,14 +107,6 @@ Layout/FirstHashElementIndentation: - 'cucumber-cucumber-expressions.gemspec' - 'lib/cucumber/cucumber_expressions/ast.rb' -# Offense count: 1 -# This cop supports safe auto-correction (--auto-correct). -# Configuration parameters: EnforcedStyle, IndentationWidth. -# SupportedStyles: consistent, align_parentheses -Layout/FirstParameterIndentation: - Exclude: - - 'lib/cucumber/cucumber_expressions/errors.rb' - # Offense count: 4 # This cop supports safe auto-correction (--auto-correct). # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. @@ -176,15 +130,13 @@ Layout/HeredocIndentation: Layout/LineLength: Max: 252 -# Offense count: 12 +# Offense count: 1 # This cop supports safe auto-correction (--auto-correct). # Configuration parameters: EnforcedStyle. # SupportedStyles: symmetrical, new_line, same_line Layout/MultilineMethodCallBraceLayout: Exclude: - - 'spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb' - 'spec/cucumber/cucumber_expressions/parameter_type_spec.rb' - - 'spec/cucumber/cucumber_expressions/regular_expression_spec.rb' # Offense count: 3 # This cop supports safe auto-correction (--auto-correct). @@ -194,15 +146,6 @@ Layout/MultilineMethodCallIndentation: Exclude: - 'lib/cucumber/cucumber_expressions/cucumber_expression_generator.rb' -# Offense count: 2 -# This cop supports safe auto-correction (--auto-correct). -# Configuration parameters: EnforcedStyle, IndentationWidth. -# SupportedStyles: aligned, indented -Layout/MultilineOperationIndentation: - Exclude: - - 'lib/cucumber/cucumber_expressions/cucumber_expression_tokenizer.rb' - - 'lib/cucumber/cucumber_expressions/errors.rb' - # Offense count: 2 # This cop supports safe auto-correction (--auto-correct). # Configuration parameters: EnforcedStyle. @@ -239,7 +182,7 @@ Layout/SpaceInLambdaLiteral: Exclude: - 'spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb' -# Offense count: 101 +# Offense count: 58 # This cop supports safe auto-correction (--auto-correct). # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. # SupportedStyles: space, no_space @@ -259,7 +202,7 @@ Layout/SpaceInsideBlockBraces: - 'spec/cucumber/cucumber_expressions/parameter_type_spec.rb' - 'spec/cucumber/cucumber_expressions/tree_regexp_spec.rb' -# Offense count: 25 +# Offense count: 24 # This cop supports safe auto-correction (--auto-correct). # Configuration parameters: EnforcedStyle. # SupportedStyles: space, compact, no_space @@ -342,11 +285,11 @@ Lint/UnusedBlockArgument: Metrics/AbcSize: Max: 59 -# Offense count: 12 +# Offense count: 11 # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. # IgnoredMethods: refine Metrics/BlockLength: - Max: 187 + Max: 183 # Offense count: 1 # Configuration parameters: CountBlocks. @@ -356,22 +299,22 @@ Metrics/BlockNesting: # Offense count: 1 # Configuration parameters: CountComments, CountAsOne. Metrics/ClassLength: - Max: 165 + Max: 151 # Offense count: 7 # Configuration parameters: IgnoredMethods. Metrics/CyclomaticComplexity: Max: 15 -# Offense count: 22 +# Offense count: 20 # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. Metrics/MethodLength: - Max: 77 + Max: 71 # Offense count: 4 # Configuration parameters: CountComments, CountAsOne. Metrics/ModuleLength: - Max: 188 + Max: 184 # Offense count: 1 # Configuration parameters: CountKeywordArgs, MaxOptionalParameters. @@ -501,36 +444,13 @@ Style/FormatString: Exclude: - 'lib/cucumber/cucumber_expressions/generated_expression.rb' -# Offense count: 32 -# This cop supports safe auto-correction (--auto-correct). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: always, always_true, never -Style/FrozenStringLiteralComment: - Enabled: false - -# Offense count: 3 +# Offense count: 2 # Configuration parameters: MinBodyLength. Style/GuardClause: Exclude: - 'lib/cucumber/cucumber_expressions/cucumber_expression_generator.rb' - - 'lib/cucumber/cucumber_expressions/parameter_type.rb' - 'lib/cucumber/cucumber_expressions/parameter_type_registry.rb' -# Offense count: 27 -# This cop supports safe auto-correction (--auto-correct). -Style/IfUnlessModifier: - Exclude: - - 'lib/cucumber/cucumber_expressions/ast.rb' - - 'lib/cucumber/cucumber_expressions/combinatorial_generated_expression_factory.rb' - - 'lib/cucumber/cucumber_expressions/cucumber_expression.rb' - - 'lib/cucumber/cucumber_expressions/cucumber_expression_generator.rb' - - 'lib/cucumber/cucumber_expressions/cucumber_expression_parser.rb' - - 'lib/cucumber/cucumber_expressions/cucumber_expression_tokenizer.rb' - - 'lib/cucumber/cucumber_expressions/parameter_type.rb' - - 'lib/cucumber/cucumber_expressions/parameter_type_matcher.rb' - - 'lib/cucumber/cucumber_expressions/tree_regexp.rb' - - 'spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb' - # Offense count: 1 # This cop supports unsafe auto-correction (--auto-correct-all). # Configuration parameters: InverseMethods, InverseBlocks. @@ -538,46 +458,12 @@ Style/InverseMethods: Exclude: - 'lib/cucumber/cucumber_expressions/parameter_type.rb' -# Offense count: 46 -# This cop supports safe auto-correction (--auto-correct). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: line_count_dependent, lambda, literal -Style/Lambda: - Exclude: - - 'lib/cucumber/cucumber_expressions/parameter_type_registry.rb' - - 'lib/cucumber/cucumber_expressions/regular_expression.rb' - - 'spec/cucumber/cucumber_expressions/combinatorial_generated_expression_factory_test.rb' - - 'spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb' - - 'spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb' - - 'spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb' - - 'spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb' - - 'spec/cucumber/cucumber_expressions/parameter_type_spec.rb' - -# Offense count: 21 -# This cop supports safe auto-correction (--auto-correct). -Style/LineEndConcatenation: - Exclude: - - 'lib/cucumber/cucumber_expressions/errors.rb' - - 'spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb' - # Offense count: 1 # This cop supports safe auto-correction (--auto-correct). Style/MultilineTernaryOperator: Exclude: - 'spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb' -# Offense count: 30 -# This cop supports safe auto-correction (--auto-correct). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: literals, strict -Style/MutableConstant: - Exclude: - - 'lib/cucumber/cucumber_expressions/ast.rb' - - 'lib/cucumber/cucumber_expressions/cucumber_expression.rb' - - 'lib/cucumber/cucumber_expressions/parameter_type.rb' - - 'lib/cucumber/cucumber_expressions/parameter_type_registry.rb' - - 'spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb' - # Offense count: 1 # This cop supports safe auto-correction (--auto-correct). Style/NegatedIfElseCondition: @@ -698,21 +584,13 @@ Style/Semicolon: Style/SpecialGlobalVars: EnforcedStyle: use_perl_names -# Offense count: 5 +# Offense count: 3 # This cop supports unsafe auto-correction (--auto-correct-all). # Configuration parameters: Mode. Style/StringConcatenation: Exclude: - 'lib/cucumber/cucumber_expressions/cucumber_expression_parser.rb' - 'lib/cucumber/cucumber_expressions/errors.rb' - - 'spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb' - -# Offense count: 264 -# This cop supports safe auto-correction (--auto-correct). -# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline. -# SupportedStyles: single_quotes, double_quotes -Style/StringLiterals: - Enabled: false # Offense count: 7 # This cop supports unsafe auto-correction (--auto-correct-all). diff --git a/ruby/Gemfile b/ruby/Gemfile index 0770e99e8..9aa539989 100644 --- a/ruby/Gemfile +++ b/ruby/Gemfile @@ -1,3 +1,3 @@ # frozen_string_literal: true -source "https://rubygems.org" +source 'https://rubygems.org' gemspec diff --git a/ruby/Rakefile b/ruby/Rakefile index 4c21117ba..456beb048 100644 --- a/ruby/Rakefile +++ b/ruby/Rakefile @@ -1,15 +1,16 @@ # encoding: utf-8 +# frozen_string_literal: true require 'rubygems' require 'bundler' Bundler::GemHelper.install_tasks -$:.unshift File.expand_path("../lib", __FILE__) +$:.unshift File.expand_path('../lib', __FILE__) Dir['./rake/*.rb'].each do |f| require f end -require "rspec/core/rake_task" +require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) task default: :spec diff --git a/ruby/cucumber-cucumber-expressions.gemspec b/ruby/cucumber-cucumber-expressions.gemspec index ea67419d2..bb66fa2ad 100644 --- a/ruby/cucumber-cucumber-expressions.gemspec +++ b/ruby/cucumber-cucumber-expressions.gemspec @@ -1,18 +1,19 @@ # -*- encoding: utf-8 -*- +# frozen_string_literal: true -version = File.read(File.expand_path("VERSION", __dir__)).strip +version = File.read(File.expand_path('VERSION', __dir__)).strip Gem::Specification.new do |s| s.name = 'cucumber-cucumber-expressions' s.version = version - s.authors = ["Aslak Hellesøy"] + s.authors = ['Aslak Hellesøy'] s.description = 'Cucumber Expressions - a simpler alternative to Regular Expressions' s.summary = "cucumber-expressions-#{s.version}" s.email = 'cukes@googlegroups.com' - s.homepage = "https://github.com/cucumber/cucumber-expressions-ruby#readme" + s.homepage = 'https://github.com/cucumber/cucumber-expressions-ruby#readme' s.platform = Gem::Platform::RUBY - s.license = "MIT" - s.required_ruby_version = ">= 2.5" + s.license = 'MIT' + s.required_ruby_version = '>= 2.5' s.metadata = { 'bug_tracker_uri' => 'https://github.com/cucumber/cucumber/issues', @@ -26,9 +27,9 @@ Gem::Specification.new do |s| s.add_development_dependency 'rspec', '~> 3.11', '>= 3.11.0' s.add_development_dependency 'rubocop', '~> 1.27.0' - s.rubygems_version = ">= 3.0.8" + s.rubygems_version = '>= 3.0.8' s.files = `git ls-files`.split("\n").reject {|path| path =~ /\.gitignore$/ } s.test_files = `git ls-files -- spec/*`.split("\n") - s.rdoc_options = ["--charset=UTF-8"] - s.require_path = "lib" + s.rdoc_options = ['--charset=UTF-8'] + s.require_path = 'lib' end diff --git a/ruby/lib/cucumber/cucumber_expressions/argument.rb b/ruby/lib/cucumber/cucumber_expressions/argument.rb index 4239ca138..2216cf971 100644 --- a/ruby/lib/cucumber/cucumber_expressions/argument.rb +++ b/ruby/lib/cucumber/cucumber_expressions/argument.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/group' require 'cucumber/cucumber_expressions/errors' @@ -14,7 +16,7 @@ def self.build(tree_regexp, text, parameter_types) if arg_groups.length != parameter_types.length raise CucumberExpressionError.new( - "Expression #{tree_regexp.regexp.inspect} has #{arg_groups.length} capture groups (#{arg_groups.map(&:value)}), but there were #{parameter_types.length} parameter types (#{parameter_types.map(&:name)})" + "Expression #{tree_regexp.regexp.inspect} has #{arg_groups.length} capture groups (#{arg_groups.map(&:value)}), but there were #{parameter_types.length} parameter types (#{parameter_types.map(&:name)})" ) end @@ -28,7 +30,7 @@ def initialize(group, parameter_type) end def value(self_obj=:nil) - raise "No self_obj" if self_obj == :nil + raise 'No self_obj' if self_obj == :nil group_values = @group ? @group.values : nil @parameter_type.transform(self_obj, group_values) end diff --git a/ruby/lib/cucumber/cucumber_expressions/ast.rb b/ruby/lib/cucumber/cucumber_expressions/ast.rb index c096cc871..e3433fb65 100644 --- a/ruby/lib/cucumber/cucumber_expressions/ast.rb +++ b/ruby/lib/cucumber/cucumber_expressions/ast.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Cucumber module CucumberExpressions ESCAPE_CHARACTER = '\\' @@ -9,9 +11,7 @@ module CucumberExpressions class Node def initialize(type, nodes, token, start, _end) - if nodes.nil? && token.nil? - raise 'Either nodes or token must be defined' - end + raise 'Either nodes or token must be defined' if nodes.nil? && token.nil? @type = type @nodes = nodes @token = token @@ -40,23 +40,17 @@ def end end def text - if @token.nil? - return @nodes.map { |value| value.text }.join('') - end + return @nodes.map { |value| value.text }.join('') if @token.nil? @token end def to_hash hash = Hash.new - hash["type"] = @type - unless @nodes.nil? - hash["nodes"] = @nodes.map { |node| node.to_hash } - end - unless @token.nil? - hash["token"] = @token - end - hash["start"] = @start - hash["end"] = @end + hash['type'] = @type + hash['nodes'] = @nodes.map { |node| node.to_hash } unless @nodes.nil? + hash['token'] = @token unless @token.nil? + hash['start'] = @start + hash['end'] = @end hash end end @@ -178,10 +172,10 @@ def self.purpose_of(token) def to_hash { - "type" => @type, - "text" => @text, - "start" => @start, - "end" => @end + 'type' => @type, + 'text' => @text, + 'start' => @start, + 'end' => @end } end end diff --git a/ruby/lib/cucumber/cucumber_expressions/combinatorial_generated_expression_factory.rb b/ruby/lib/cucumber/cucumber_expressions/combinatorial_generated_expression_factory.rb index 70a9e6266..341f70620 100644 --- a/ruby/lib/cucumber/cucumber_expressions/combinatorial_generated_expression_factory.rb +++ b/ruby/lib/cucumber/cucumber_expressions/combinatorial_generated_expression_factory.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + require('cucumber/cucumber_expressions/generated_expression') module Cucumber module CucumberExpressions - class CombinatorialGeneratedExpressionFactory def initialize(expression_template, parameter_type_combinations) @expression_template = expression_template @@ -19,9 +20,7 @@ def generate_expressions MAX_EXPRESSIONS = 256 def generate_permutations(generated_expressions, depth, current_parameter_types) - if generated_expressions.length >= MAX_EXPRESSIONS - return - end + return if generated_expressions.length >= MAX_EXPRESSIONS if depth == @parameter_type_combinations.length generated_expression = GeneratedExpression.new(@expression_template, current_parameter_types) @@ -31,19 +30,12 @@ def generate_permutations(generated_expressions, depth, current_parameter_types) (0...@parameter_type_combinations[depth].length).each do |i| # Avoid recursion if no elements can be added. - if generated_expressions.length >= MAX_EXPRESSIONS - return - end + return if generated_expressions.length >= MAX_EXPRESSIONS new_current_parameter_types = current_parameter_types.dup # clone new_current_parameter_types.push(@parameter_type_combinations[depth][i]) - generate_permutations( - generated_expressions, - depth + 1, - new_current_parameter_types - ) + generate_permutations(generated_expressions, depth + 1, new_current_parameter_types) end end end - end end diff --git a/ruby/lib/cucumber/cucumber_expressions/cucumber_expression.rb b/ruby/lib/cucumber/cucumber_expressions/cucumber_expression.rb index 7e58d4219..800bd23e2 100644 --- a/ruby/lib/cucumber/cucumber_expressions/cucumber_expression.rb +++ b/ruby/lib/cucumber/cucumber_expressions/cucumber_expression.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/argument' require 'cucumber/cucumber_expressions/tree_regexp' require 'cucumber/cucumber_expressions/errors' @@ -7,7 +9,7 @@ module Cucumber module CucumberExpressions class CucumberExpression - ESCAPE_PATTERN = /([\\^\[({$.|?*+})\]])/ + ESCAPE_PATTERN = /([\\^\[({$.|?*+})\]])/.freeze def initialize(expression, parameter_type_registry) @expression = expression @@ -72,9 +74,7 @@ def rewrite_optional(node) def rewrite_alternation(node) # Make sure the alternative parts aren't empty and don't contain parameter types node.nodes.each { |alternative| - if alternative.nodes.length == 0 - raise AlternativeMayNotBeEmpty.new(alternative, @expression) - end + raise AlternativeMayNotBeEmpty.new(alternative, @expression) if alternative.nodes.length == 0 assert_not_empty(alternative) { |astNode| raise AlternativeMayNotExclusivelyContainOptionals.new(astNode, @expression) } } regex = node.nodes.map { |n| rewrite_to_regex(n) }.join('|') @@ -88,14 +88,10 @@ def rewrite_alternative(node) def rewrite_parameter(node) name = node.text parameter_type = @parameter_type_registry.lookup_by_type_name(name) - if parameter_type.nil? - raise UndefinedParameterTypeError.new(node, @expression, name) - end + raise UndefinedParameterTypeError.new(node, @expression, name) if parameter_type.nil? @parameter_types.push(parameter_type) regexps = parameter_type.regexps - if regexps.length == 1 - return "(#{regexps[0]})" - end + return "(#{regexps[0]})" if regexps.length == 1 "((?:#{regexps.join(')|(?:')}))" end diff --git a/ruby/lib/cucumber/cucumber_expressions/cucumber_expression_generator.rb b/ruby/lib/cucumber/cucumber_expressions/cucumber_expression_generator.rb index 74285dc1e..9e8e39743 100644 --- a/ruby/lib/cucumber/cucumber_expressions/cucumber_expression_generator.rb +++ b/ruby/lib/cucumber/cucumber_expressions/cucumber_expression_generator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/parameter_type_matcher' require 'cucumber/cucumber_expressions/generated_expression' require 'cucumber/cucumber_expressions/combinatorial_generated_expression_factory' @@ -12,16 +14,14 @@ def initialize(parameter_type_registry) def generate_expressions(text) parameter_type_combinations = [] parameter_type_matchers = create_parameter_type_matchers(text) - expression_template = "" + expression_template = +'' pos = 0 loop do matching_parameter_type_matchers = [] parameter_type_matchers.each do |parameter_type_matcher| advanced_parameter_type_matcher = parameter_type_matcher.advance_to(pos) - if advanced_parameter_type_matcher.find - matching_parameter_type_matchers.push(advanced_parameter_type_matcher) - end + matching_parameter_type_matchers.push(advanced_parameter_type_matcher) if advanced_parameter_type_matcher.find end if matching_parameter_type_matchers.any? @@ -39,16 +39,14 @@ def generate_expressions(text) # Users are most likely to want these, so they should be listed at the top. parameter_types = [] best_parameter_type_matchers.each do |parameter_type_matcher| - unless parameter_types.include?(parameter_type_matcher.parameter_type) - parameter_types.push(parameter_type_matcher.parameter_type) - end + parameter_types.push(parameter_type_matcher.parameter_type) unless parameter_types.include?(parameter_type_matcher.parameter_type) end parameter_types.sort! parameter_type_combinations.push(parameter_types) expression_template += escape(text.slice(pos...best_parameter_type_matcher.start)) - expression_template += "{%s}" + expression_template += '{%s}' pos = best_parameter_type_matcher.start + best_parameter_type_matcher.group.length else @@ -71,9 +69,7 @@ def generate_expressions(text) def create_parameter_type_matchers(text) parameter_matchers = [] @parameter_type_registry.parameter_types.each do |parameter_type| - if parameter_type.use_for_snippets? - parameter_matchers += create_parameter_type_matchers2(parameter_type, text) - end + parameter_matchers += create_parameter_type_matchers2(parameter_type, text) if parameter_type.use_for_snippets? end parameter_matchers end diff --git a/ruby/lib/cucumber/cucumber_expressions/cucumber_expression_parser.rb b/ruby/lib/cucumber/cucumber_expressions/cucumber_expression_parser.rb index e98678947..6a909f8c6 100644 --- a/ruby/lib/cucumber/cucumber_expressions/cucumber_expression_parser.rb +++ b/ruby/lib/cucumber/cucumber_expressions/cucumber_expression_parser.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/ast' require 'cucumber/cucumber_expressions/errors' require 'cucumber/cucumber_expressions/cucumber_expression_tokenizer' @@ -11,16 +13,16 @@ def parse(expression) token = tokens[current] case token.type when TokenType::WHITE_SPACE, TokenType::TEXT, TokenType::END_PARAMETER, TokenType::END_OPTIONAL - return 1, [Node.new(NodeType::TEXT, nil, token.text, token.start, token.end)] + return [1, [Node.new(NodeType::TEXT, nil, token.text, token.start, token.end)]] when TokenType::ALTERNATION raise AlternationNotAllowedInOptional.new(expression, token) when TokenType::BEGIN_PARAMETER, TokenType::START_OF_LINE, TokenType::END_OF_LINE, TokenType::BEGIN_OPTIONAL else # If configured correctly this will never happen - return 0, nil + return [0, nil] end # If configured correctly this will never happen - return 0, nil + return [0, nil] end # name := whitespace | . @@ -28,51 +30,39 @@ def parse(expression) token = tokens[current] case token.type when TokenType::WHITE_SPACE, TokenType::TEXT - return 1, [Node.new(NodeType::TEXT, nil, token.text, token.start, token.end)] + return [1, [Node.new(NodeType::TEXT, nil, token.text, token.start, token.end)]] when TokenType::BEGIN_PARAMETER, TokenType::END_PARAMETER, TokenType::BEGIN_OPTIONAL, TokenType::END_OPTIONAL, TokenType::ALTERNATION raise InvalidParameterTypeNameInNode.new(expression, token) when TokenType::START_OF_LINE, TokenType::END_OF_LINE # If configured correctly this will never happen - return 0, nil + return [0, nil] else # If configured correctly this will never happen - return 0, nil + return [0, nil] end end # parameter := '{' + name* + '}' - parse_parameter = parse_between( - NodeType::PARAMETER, - TokenType::BEGIN_PARAMETER, - TokenType::END_PARAMETER, - [parse_name] - ) + parse_parameter = parse_between(NodeType::PARAMETER, TokenType::BEGIN_PARAMETER, TokenType::END_PARAMETER, [parse_name]) # optional := '(' + option* + ')' # option := optional | parameter | text optional_sub_parsers = [] - parse_optional = parse_between( - NodeType::OPTIONAL, - TokenType::BEGIN_OPTIONAL, - TokenType::END_OPTIONAL, - optional_sub_parsers - ) + parse_optional = parse_between(NodeType::OPTIONAL, TokenType::BEGIN_OPTIONAL, TokenType::END_OPTIONAL, optional_sub_parsers) optional_sub_parsers << parse_optional << parse_parameter << parse_text # alternation := alternative* + ( '/' + alternative* )+ parse_alternative_separator = lambda do |_, tokens, current| - unless looking_at(tokens, current, TokenType::ALTERNATION) - return 0, nil - end + return [0, nil] unless looking_at(tokens, current, TokenType::ALTERNATION) token = tokens[current] - return 1, [Node.new(NodeType::ALTERNATIVE, nil, token.text, token.start, token.end)] + return [1, [Node.new(NodeType::ALTERNATIVE, nil, token.text, token.start, token.end)]] end alternative_parsers = [ - parse_alternative_separator, - parse_optional, - parse_parameter, - parse_text, + parse_alternative_separator, + parse_optional, + parse_parameter, + parse_text, ] # alternation := (?<=left-boundary) + alternative* + ( '/' + alternative* )+ + (?=right-boundary) @@ -81,30 +71,26 @@ def parse(expression) # alternative: = optional | parameter | text parse_alternation = lambda do |expr, tokens, current| previous = current - 1 - unless looking_at_any(tokens, previous, [TokenType::START_OF_LINE, TokenType::WHITE_SPACE, TokenType::END_PARAMETER]) - return 0, nil - end + return [0, nil] unless looking_at_any(tokens, previous, [TokenType::START_OF_LINE, TokenType::WHITE_SPACE, TokenType::END_PARAMETER]) consumed, ast = parse_tokens_until(expr, alternative_parsers, tokens, current, [TokenType::WHITE_SPACE, TokenType::END_OF_LINE, TokenType::BEGIN_PARAMETER]) sub_current = current + consumed - unless ast.map { |astNode| astNode.type }.include? NodeType::ALTERNATIVE - return 0, nil - end + return [0, nil] unless ast.map { |astNode| astNode.type }.include? NodeType::ALTERNATIVE start = tokens[current].start _end = tokens[sub_current].start # Does not consume right hand boundary token - return consumed, [Node.new(NodeType::ALTERNATION, split_alternatives(start, _end, ast), nil, start, _end)] + return [consumed, [Node.new(NodeType::ALTERNATION, split_alternatives(start, _end, ast), nil, start, _end)]] end # # cucumber-expression := ( alternation | optional | parameter | text )* # parse_cucumber_expression = parse_between( - NodeType::EXPRESSION, - TokenType::START_OF_LINE, - TokenType::END_OF_LINE, - [parse_alternation, parse_optional, parse_parameter, parse_text] + NodeType::EXPRESSION, + TokenType::START_OF_LINE, + TokenType::END_OF_LINE, + [parse_alternation, parse_optional, parse_parameter, parse_text] ) tokenizer = CucumberExpressionTokenizer.new @@ -117,30 +103,26 @@ def parse(expression) def parse_between(type, begin_token, end_token, parsers) lambda do |expression, tokens, current| - unless looking_at(tokens, current, begin_token) - return 0, nil - end + return [0, nil] unless looking_at(tokens, current, begin_token) sub_current = current + 1 consumed, ast = parse_tokens_until(expression, parsers, tokens, sub_current, [end_token, TokenType::END_OF_LINE]) sub_current += consumed # endToken not found - unless looking_at(tokens, sub_current, end_token) - raise MissingEndToken.new(expression, begin_token, end_token, tokens[current]) - end + raise MissingEndToken.new(expression, begin_token, end_token, tokens[current]) unless looking_at(tokens, sub_current, end_token) # consumes endToken start = tokens[current].start _end = tokens[sub_current].end consumed = sub_current + 1 - current ast = [Node.new(type, ast, nil, start, _end)] - return consumed, ast + return [consumed, ast] end end def parse_token(expression, parsers, tokens, start_at) parsers.each do |parser| consumed, ast = parser.call(expression, tokens, start_at) - return consumed, ast unless consumed == 0 + return [consumed, ast] unless consumed == 0 end # If configured correctly this will never happen raise 'No eligible parsers for ' + tokens @@ -151,9 +133,7 @@ def parse_tokens_until(expression, parsers, tokens, start_at, end_tokens) size = tokens.length ast = [] while current < size do - if looking_at_any(tokens, current, end_tokens) - break - end + break if looking_at_any(tokens, current, end_tokens) consumed, sub_ast = parse_token(expression, parsers, tokens, current) if consumed == 0 # If configured correctly this will never happen @@ -176,9 +156,7 @@ def looking_at(tokens, at, token) # Keep for completeness return token == TokenType::START_OF_LINE end - if at >= tokens.length - return token == TokenType::END_OF_LINE - end + return token == TokenType::END_OF_LINE if at >= tokens.length tokens[at].type == token end @@ -186,7 +164,7 @@ def split_alternatives(start, _end, alternation) separators = [] alternatives = [] alternative = [] - alternation.each { |n| + alternation.each do |n| if NodeType::ALTERNATIVE == n.type separators.push(n) alternatives.push(alternative) @@ -194,7 +172,7 @@ def split_alternatives(start, _end, alternation) else alternative.push(n) end - } + end alternatives.push(alternative) create_alternative_nodes(start, _end, separators, alternatives) end diff --git a/ruby/lib/cucumber/cucumber_expressions/cucumber_expression_tokenizer.rb b/ruby/lib/cucumber/cucumber_expressions/cucumber_expression_tokenizer.rb index fb65f03ad..8f1b89d72 100644 --- a/ruby/lib/cucumber/cucumber_expressions/cucumber_expression_tokenizer.rb +++ b/ruby/lib/cucumber/cucumber_expressions/cucumber_expression_tokenizer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/ast' require 'cucumber/cucumber_expressions/errors' @@ -15,9 +17,7 @@ def tokenize(expression) codepoints = expression.codepoints - if codepoints.empty? - tokens.push(Token.new(TokenType::START_OF_LINE, '', 0, 0)) - end + tokens.push(Token.new(TokenType::START_OF_LINE, '', 0, 0)) if codepoints.empty? codepoints.each do |codepoint| if !treat_as_text && Token.is_escape_character(codepoint) @@ -63,10 +63,10 @@ def convert_buffer_to_token(token_type) consumed_index = @buffer_start_index + @buffer.length + escape_tokens t = Token.new( - token_type, - @buffer.map { |codepoint| codepoint.chr(Encoding::UTF_8) }.join(''), - @buffer_start_index, - consumed_index + token_type, + @buffer.map { |codepoint| codepoint.chr(Encoding::UTF_8) }.join(''), + @buffer_start_index, + consumed_index ) @buffer = [] @buffer_start_index = consumed_index @@ -74,21 +74,16 @@ def convert_buffer_to_token(token_type) end def token_type_of(codepoint, treat_as_text) - unless treat_as_text - return Token.type_of(codepoint) - end - if Token.can_escape(codepoint) - return TokenType::TEXT - end - raise CantEscape.new( - @expression, - @buffer_start_index + @buffer.length + @escaped - ) + return Token.type_of(codepoint) unless treat_as_text + + return TokenType::TEXT if Token.can_escape(codepoint) + + raise CantEscape.new(@expression, @buffer_start_index + @buffer.length + @escaped) end def should_create_new_token?(previous_token_type, current_token_type) current_token_type != previous_token_type || - (current_token_type != TokenType::WHITE_SPACE && current_token_type != TokenType::TEXT) + (current_token_type != TokenType::WHITE_SPACE && current_token_type != TokenType::TEXT) end end end diff --git a/ruby/lib/cucumber/cucumber_expressions/errors.rb b/ruby/lib/cucumber/cucumber_expressions/errors.rb index c8b82d967..6c16ee241 100644 --- a/ruby/lib/cucumber/cucumber_expressions/errors.rb +++ b/ruby/lib/cucumber/cucumber_expressions/errors.rb @@ -1,16 +1,12 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/ast' module Cucumber module CucumberExpressions class CucumberExpressionError < StandardError - def build_message( - index, - expression, - pointer, - problem, - solution - ) + def build_message(index, expression, pointer, problem, solution) m = <<-EOF This Cucumber Expression has a problem at column #{index + 1}: @@ -40,86 +36,100 @@ def point_at_located(node) class AlternativeMayNotExclusivelyContainOptionals < CucumberExpressionError def initialize(node, expression) - super(build_message( - node.start, - expression, - point_at_located(node), - 'An alternative may not exclusively contain optionals', - "If you did not mean to use an optional you can use '\\(' to escape the the '('" - )) + super( + build_message( + node.start, + expression, + point_at_located(node), + 'An alternative may not exclusively contain optionals', + "If you did not mean to use an optional you can use '\\(' to escape the the '('" + ) + ) end end class AlternativeMayNotBeEmpty < CucumberExpressionError def initialize(node, expression) - super(build_message( - node.start, - expression, - point_at_located(node), - 'Alternative may not be empty', - "If you did not mean to use an alternative you can use '\\/' to escape the the '/'" - )) + super( + build_message( + node.start, + expression, + point_at_located(node), + 'Alternative may not be empty', + "If you did not mean to use an alternative you can use '\\/' to escape the the '/'" + ) + ) end end class CantEscape < CucumberExpressionError def initialize(expression, index) - super(build_message( - index, - expression, - point_at(index), - "Only the characters '{', '}', '(', ')', '\\', '/' and whitespace can be escaped", - "If you did mean to use an '\\' you can use '\\\\' to escape it" - )) + super( + build_message( + index, + expression, + point_at(index), + "Only the characters '{', '}', '(', ')', '\\', '/' and whitespace can be escaped", + "If you did mean to use an '\\' you can use '\\\\' to escape it" + ) + ) end end class OptionalMayNotBeEmpty < CucumberExpressionError def initialize(node, expression) - super(build_message( - node.start, - expression, - point_at_located(node), - 'An optional must contain some text', - "If you did not mean to use an optional you can use '\\(' to escape the the '('" - )) + super( + build_message( + node.start, + expression, + point_at_located(node), + 'An optional must contain some text', + "If you did not mean to use an optional you can use '\\(' to escape the the '('" + ) + ) end end class ParameterIsNotAllowedInOptional < CucumberExpressionError def initialize(node, expression) - super(build_message( - node.start, - expression, - point_at_located(node), - 'An optional may not contain a parameter type', - "If you did not mean to use an parameter type you can use '\\{' to escape the the '{'" - )) + super( + build_message( + node.start, + expression, + point_at_located(node), + 'An optional may not contain a parameter type', + "If you did not mean to use an parameter type you can use '\\{' to escape the the '{'" + ) + ) end end class OptionalIsNotAllowedInOptional < CucumberExpressionError def initialize(node, expression) - super(build_message( - node.start, - expression, - point_at_located(node), - 'An optional may not contain an other optional', - "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." - )) + super( + build_message( + node.start, + expression, + point_at_located(node), + 'An optional may not contain an other optional', + "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." + ) + ) end end class TheEndOfLineCannotBeEscaped < CucumberExpressionError def initialize(expression) index = expression.codepoints.length - 1 - super(build_message( - index, - expression, - point_at(index), - 'The end of line can not be escaped', - "You can use '\\\\' to escape the the '\\'" - )) + super( + build_message( + index, + expression, + point_at(index), + 'The end of line can not be escaped', + "You can use '\\\\' to escape the the '\\'" + ) + ) end end @@ -128,45 +138,50 @@ def initialize(expression, begin_token, end_token, current) begin_symbol = Token::symbol_of(begin_token) end_symbol = Token::symbol_of(end_token) purpose = Token::purpose_of(begin_token) - super(build_message( - current.start, - expression, - point_at_located(current), - "The '#{begin_symbol}' does not have a matching '#{end_symbol}'", - "If you did not intend to use #{purpose} you can use '\\#{begin_symbol}' to escape the #{purpose}" - )) + + super( + build_message( + current.start, + expression, + point_at_located(current), + "The '#{begin_symbol}' does not have a matching '#{end_symbol}'", + "If you did not intend to use #{purpose} you can use '\\#{begin_symbol}' to escape the #{purpose}" + ) + ) end end class AlternationNotAllowedInOptional < CucumberExpressionError def initialize(expression, current) - super(build_message( - current.start, - expression, - point_at_located(current), - "An alternation can not be used inside an optional", - "You can use '\\/' to escape the the '/'" - )) + super( + build_message( + current.start, + expression, + point_at_located(current), + 'An alternation can not be used inside an optional', + "You can use '\\/' to escape the the '/'" + ) + ) end end class InvalidParameterTypeName < CucumberExpressionError def initialize(type_name) - super("Illegal character in parameter name {#{type_name}}. " + - "Parameter names may not contain '{', '}', '(', ')', '\\' or '/'") + super("Illegal character in parameter name {#{type_name}}. Parameter names may not contain '{', '}', '(', ')', '\\' or '/'") end end - class InvalidParameterTypeNameInNode < CucumberExpressionError def initialize(expression, token) - super(build_message( - token.start, - expression, - point_at_located(token), - "Parameter names may not contain '{', '}', '(', ')', '\\' or '/'", - "Did you mean to use a regular expression?" - )) + super( + build_message( + token.start, + expression, + point_at_located(token), + "Parameter names may not contain '{', '}', '(', ')', '\\' or '/'", + 'Did you mean to use a regular expression?' + ) + ) end end @@ -174,11 +189,15 @@ class UndefinedParameterTypeError < CucumberExpressionError attr_reader :undefined_parameter_type_name def initialize(node, expression, undefined_parameter_type_name) - super(build_message(node.start, - expression, - point_at_located(node), - "Undefined parameter type '#{undefined_parameter_type_name}'", - "Please register a ParameterType for '#{undefined_parameter_type_name}'")) + super( + build_message( + node.start, + expression, + point_at_located(node), + "Undefined parameter type '#{undefined_parameter_type_name}'", + "Please register a ParameterType for '#{undefined_parameter_type_name}'" + ) + ) @undefined_parameter_type_name = undefined_parameter_type_name end end diff --git a/ruby/lib/cucumber/cucumber_expressions/expression_factory.rb b/ruby/lib/cucumber/cucumber_expressions/expression_factory.rb index c4973e829..f30cc6277 100644 --- a/ruby/lib/cucumber/cucumber_expressions/expression_factory.rb +++ b/ruby/lib/cucumber/cucumber_expressions/expression_factory.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/errors' require 'cucumber/cucumber_expressions/cucumber_expression' require 'cucumber/cucumber_expressions/regular_expression' diff --git a/ruby/lib/cucumber/cucumber_expressions/generated_expression.rb b/ruby/lib/cucumber/cucumber_expressions/generated_expression.rb index a9c46a1ae..e94458432 100644 --- a/ruby/lib/cucumber/cucumber_expressions/generated_expression.rb +++ b/ruby/lib/cucumber/cucumber_expressions/generated_expression.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Cucumber module CucumberExpressions class GeneratedExpression diff --git a/ruby/lib/cucumber/cucumber_expressions/group.rb b/ruby/lib/cucumber/cucumber_expressions/group.rb index b7c125b61..5f2dd79ce 100644 --- a/ruby/lib/cucumber/cucumber_expressions/group.rb +++ b/ruby/lib/cucumber/cucumber_expressions/group.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Cucumber module CucumberExpressions class Group diff --git a/ruby/lib/cucumber/cucumber_expressions/group_builder.rb b/ruby/lib/cucumber/cucumber_expressions/group_builder.rb index cdf6f5d26..511113162 100644 --- a/ruby/lib/cucumber/cucumber_expressions/group_builder.rb +++ b/ruby/lib/cucumber/cucumber_expressions/group_builder.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/group' module Cucumber diff --git a/ruby/lib/cucumber/cucumber_expressions/parameter_type.rb b/ruby/lib/cucumber/cucumber_expressions/parameter_type.rb index 420b81fae..e5fb0c03f 100644 --- a/ruby/lib/cucumber/cucumber_expressions/parameter_type.rb +++ b/ruby/lib/cucumber/cucumber_expressions/parameter_type.rb @@ -1,17 +1,17 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/errors' module Cucumber module CucumberExpressions class ParameterType - ILLEGAL_PARAMETER_NAME_PATTERN = /([\[\]()$.|?*+])/ - UNESCAPE_PATTERN = /(\\([\[$.|?*+\]]))/ + ILLEGAL_PARAMETER_NAME_PATTERN = /([\[\]()$.|?*+])/.freeze + UNESCAPE_PATTERN = /(\\([\[$.|?*+\]]))/.freeze attr_reader :name, :type, :regexps def self.check_parameter_type_name(type_name) - unless is_valid_parameter_type_name(type_name) - raise CucumberExpressionError.new("Illegal character in parameter name {#{type_name}}. Parameter names may not contain '[]()$.|?*+'") - end + raise CucumberExpressionError.new("Illegal character in parameter name {#{type_name}}. Parameter names may not contain '[]()$.|?*+'") unless is_valid_parameter_type_name(type_name) end def self.is_valid_parameter_type_name(type_name) @@ -75,9 +75,7 @@ def regexp_source(regexp) 'MULTILINE' ].each do |option_name| option = Regexp.const_get(option_name) - if regexp.options & option != 0 - raise CucumberExpressionError.new("ParameterType Regexps can't use option Regexp::#{option_name}") - end + raise CucumberExpressionError.new("ParameterType Regexps can't use option Regexp::#{option_name}") if regexp.options & option != 0 end regexp.source end diff --git a/ruby/lib/cucumber/cucumber_expressions/parameter_type_matcher.rb b/ruby/lib/cucumber/cucumber_expressions/parameter_type_matcher.rb index d50d0e2fd..0bb039a35 100644 --- a/ruby/lib/cucumber/cucumber_expressions/parameter_type_matcher.rb +++ b/ruby/lib/cucumber/cucumber_expressions/parameter_type_matcher.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Cucumber module CucumberExpressions class ParameterTypeMatcher @@ -9,12 +11,10 @@ def initialize(parameter_type, regexp, text, match_position=0) end def advance_to(new_match_position) - (new_match_position...@text.length).each {|advancedPos| + (new_match_position...@text.length).each do |advancedPos| matcher = self.class.new(parameter_type, @regexp, @text, advancedPos) - if matcher.find && matcher.full_word? - return matcher - end - } + return matcher if matcher.find && matcher.full_word? + end self.class.new(parameter_type, @regexp, @text, @text.length) end diff --git a/ruby/lib/cucumber/cucumber_expressions/parameter_type_registry.rb b/ruby/lib/cucumber/cucumber_expressions/parameter_type_registry.rb index de78ad981..3369293a4 100644 --- a/ruby/lib/cucumber/cucumber_expressions/parameter_type_registry.rb +++ b/ruby/lib/cucumber/cucumber_expressions/parameter_type_registry.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/parameter_type' require 'cucumber/cucumber_expressions/errors' require 'cucumber/cucumber_expressions/cucumber_expression_generator' @@ -6,27 +8,27 @@ module Cucumber module CucumberExpressions class ParameterTypeRegistry - INTEGER_REGEXPS = [/-?\d+/, /\d+/] - FLOAT_REGEXP = /(?=.*\d.*)[-+]?\d*(?:\.(?=\d.*))?\d*(?:\d+[E][-+]?\d+)?/ - WORD_REGEXP = /[^\s]+/ - STRING_REGEXP = /"([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'/ - ANONYMOUS_REGEXP = /.*/ + INTEGER_REGEXPS = [/-?\d+/, /\d+/].freeze + FLOAT_REGEXP = /(?=.*\d.*)[-+]?\d*(?:\.(?=\d.*))?\d*(?:\d+[E][-+]?\d+)?/.freeze + WORD_REGEXP = /[^\s]+/.freeze + STRING_REGEXP = /"([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'/.freeze + ANONYMOUS_REGEXP = /.*/.freeze def initialize @parameter_type_by_name = {} @parameter_types_by_regexp = Hash.new {|hash, regexp| hash[regexp] = []} - define_parameter_type(ParameterType.new('int', INTEGER_REGEXPS, Integer, lambda {|s = nil| s && s.to_i}, true, true)) - define_parameter_type(ParameterType.new('float', FLOAT_REGEXP, Float, lambda {|s = nil| s && s.to_f}, true, false)) - define_parameter_type(ParameterType.new('word', WORD_REGEXP, String, lambda {|s = nil| s}, false, false)) - define_parameter_type(ParameterType.new('string', STRING_REGEXP, String, lambda { |s1, s2| arg = s1 != nil ? s1 : s2; arg.gsub(/\\"/, '"').gsub(/\\'/, "'")}, true, false)) - define_parameter_type(ParameterType.new('', ANONYMOUS_REGEXP, String, lambda {|s = nil| s}, false, true)) - define_parameter_type(ParameterType.new('bigdecimal', FLOAT_REGEXP, BigDecimal, lambda {|s = nil| BigDecimal(s)}, false, false)) - define_parameter_type(ParameterType.new('biginteger', INTEGER_REGEXPS, Integer, lambda {|s = nil| s && s.to_i}, false, false)) - define_parameter_type(ParameterType.new('byte', INTEGER_REGEXPS, Integer, lambda {|s = nil| s && s.to_i}, false, false)) - define_parameter_type(ParameterType.new('short', INTEGER_REGEXPS, Integer, lambda {|s = nil| s && s.to_i}, false, false)) - define_parameter_type(ParameterType.new('long', INTEGER_REGEXPS, Integer, lambda {|s = nil| s && s.to_i}, false, false)) - define_parameter_type(ParameterType.new('double', FLOAT_REGEXP, Float, lambda {|s = nil| s && s.to_f}, false, false)) + define_parameter_type(ParameterType.new('int', INTEGER_REGEXPS, Integer, ->(s = nil) { s && s.to_i}, true, true)) + define_parameter_type(ParameterType.new('float', FLOAT_REGEXP, Float, ->(s = nil) { s && s.to_f}, true, false)) + define_parameter_type(ParameterType.new('word', WORD_REGEXP, String, ->(s = nil) { s}, false, false)) + define_parameter_type(ParameterType.new('string', STRING_REGEXP, String, ->(s1, s2) { arg = s1 != nil ? s1 : s2; arg.gsub(/\\"/, '"').gsub(/\\'/, "'")}, true, false)) + define_parameter_type(ParameterType.new('', ANONYMOUS_REGEXP, String, ->(s = nil) { s}, false, true)) + define_parameter_type(ParameterType.new('bigdecimal', FLOAT_REGEXP, BigDecimal, ->(s = nil) { BigDecimal(s)}, false, false)) + define_parameter_type(ParameterType.new('biginteger', INTEGER_REGEXPS, Integer, ->(s = nil) { s && s.to_i}, false, false)) + define_parameter_type(ParameterType.new('byte', INTEGER_REGEXPS, Integer, ->(s = nil) { s && s.to_i}, false, false)) + define_parameter_type(ParameterType.new('short', INTEGER_REGEXPS, Integer, ->(s = nil) { s && s.to_i}, false, false)) + define_parameter_type(ParameterType.new('long', INTEGER_REGEXPS, Integer, ->(s = nil) { s && s.to_i}, false, false)) + define_parameter_type(ParameterType.new('double', FLOAT_REGEXP, Float, ->(s = nil) { s && s.to_f}, false, false)) end def lookup_by_type_name(name) @@ -54,7 +56,7 @@ def define_parameter_type(parameter_type) if parameter_type.name != nil if @parameter_type_by_name.has_key?(parameter_type.name) if parameter_type.name.length == 0 - raise CucumberExpressionError.new("The anonymous parameter type has already been defined") + raise CucumberExpressionError.new('The anonymous parameter type has already been defined') else raise CucumberExpressionError.new("There is already a parameter with name #{parameter_type.name}") end diff --git a/ruby/lib/cucumber/cucumber_expressions/regular_expression.rb b/ruby/lib/cucumber/cucumber_expressions/regular_expression.rb index b608221e5..b831dd52a 100644 --- a/ruby/lib/cucumber/cucumber_expressions/regular_expression.rb +++ b/ruby/lib/cucumber/cucumber_expressions/regular_expression.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/argument' require 'cucumber/cucumber_expressions/parameter_type' require 'cucumber/cucumber_expressions/tree_regexp' @@ -23,7 +25,7 @@ def match(text) nil, parameter_type_regexp, String, - lambda {|*s| s[0]}, + ->(*s) { s[0]}, false, false ) diff --git a/ruby/lib/cucumber/cucumber_expressions/tree_regexp.rb b/ruby/lib/cucumber/cucumber_expressions/tree_regexp.rb index 6c7712b90..9c17e25d8 100644 --- a/ruby/lib/cucumber/cucumber_expressions/tree_regexp.rb +++ b/ruby/lib/cucumber/cucumber_expressions/tree_regexp.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/group_builder' require 'cucumber/cucumber_expressions/errors' @@ -42,7 +44,7 @@ def match(s) end # (?X) - raise CucumberExpressionError.new("Named capture groups are not supported. See https://github.com/cucumber/cucumber/issues/329") + raise CucumberExpressionError.new('Named capture groups are not supported. See https://github.com/cucumber/cucumber/issues/329') end private def create_group_builder(regexp) @@ -60,9 +62,7 @@ def match(s) group_start_stack.push(i) group_builder = GroupBuilder.new non_capturing = is_non_capturing(source, i) - if non_capturing - group_builder.set_non_capturing! - end + group_builder.set_non_capturing! if non_capturing stack.push(group_builder) elsif c == ')' && !escaping && !char_class gb = stack.pop diff --git a/ruby/spec/cucumber/cucumber_expressions/argument_spec.rb b/ruby/spec/cucumber/cucumber_expressions/argument_spec.rb index 136c7413d..917df2dbd 100644 --- a/ruby/spec/cucumber/cucumber_expressions/argument_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/argument_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/argument' require 'cucumber/cucumber_expressions/tree_regexp' require 'cucumber/cucumber_expressions/parameter_type_registry' @@ -8,9 +10,9 @@ module CucumberExpressions it 'exposes parameter_type' do tree_regexp = TreeRegexp.new(/three (.*) mice/) parameter_type_registry = ParameterTypeRegistry.new - arguments = Argument.build(tree_regexp, "three blind mice", [parameter_type_registry.lookup_by_type_name("string")]) + arguments = Argument.build(tree_regexp, 'three blind mice', [parameter_type_registry.lookup_by_type_name('string')]) argument = arguments[0] - expect(argument.parameter_type.name).to eq("string") + expect(argument.parameter_type.name).to eq('string') end end end diff --git a/ruby/spec/cucumber/cucumber_expressions/combinatorial_generated_expression_factory_test.rb b/ruby/spec/cucumber/cucumber_expressions/combinatorial_generated_expression_factory_test.rb index 87286cc3b..0a69e4e98 100644 --- a/ruby/spec/cucumber/cucumber_expressions/combinatorial_generated_expression_factory_test.rb +++ b/ruby/spec/cucumber/cucumber_expressions/combinatorial_generated_expression_factory_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/parameter_type' require 'cucumber/cucumber_expressions/combinatorial_generated_expression_factory' @@ -14,13 +16,13 @@ class Timestamp; end it 'generates multiple expressions' do parameter_type_combinations = [ [ - ParameterType.new('color', /red|blue|yellow/, Color, lambda {|s| Color.new}, true, false), - ParameterType.new('csscolor', /red|blue|yellow/, CssColor, lambda {|s| CssColor.new}, true, false) + ParameterType.new('color', /red|blue|yellow/, Color, ->(s) { Color.new}, true, false), + ParameterType.new('csscolor', /red|blue|yellow/, CssColor, ->(s) { CssColor.new}, true, false) ], [ - ParameterType.new('date', /\d{4}-\d{2}-\d{2}/, Date, lambda {|s| Date.new}, true, false), - ParameterType.new('datetime', /\d{4}-\d{2}-\d{2}/, DateTime, lambda {|s| DateTime.new}, true, false), - ParameterType.new('timestamp', /\d{4}-\d{2}-\d{2}/, Timestamp, lambda {|s| Timestamp.new}, true, false) + ParameterType.new('date', /\d{4}-\d{2}-\d{2}/, Date, ->(s) { Date.new}, true, false), + ParameterType.new('datetime', /\d{4}-\d{2}-\d{2}/, DateTime, ->(s) { DateTime.new}, true, false), + ParameterType.new('timestamp', /\d{4}-\d{2}-\d{2}/, Timestamp, ->(s) { Timestamp.new}, true, false) ] ] diff --git a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb index 9ffa3cd68..68e473c88 100644 --- a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_generator_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/cucumber_expression_generator' require 'cucumber/cucumber_expressions/cucumber_expression' require 'cucumber/cucumber_expressions/parameter_type' @@ -14,203 +16,204 @@ class Currency @generator = CucumberExpressionGenerator.new(@parameter_type_registry) end - it "documents expression generation" do + it 'documents expression generation' do parameter_registry = ParameterTypeRegistry.new ### [generate-expression] generator = CucumberExpressionGenerator.new(parameter_registry) - undefined_step_text = "I have 2 cucumbers and 1.5 tomato" + undefined_step_text = 'I have 2 cucumbers and 1.5 tomato' generated_expression = generator.generate_expressions(undefined_step_text)[0] - expect(generated_expression.source).to eq("I have {int} cucumbers and {float} tomato") + expect(generated_expression.source).to eq('I have {int} cucumbers and {float} tomato') expect(generated_expression.parameter_types[1].type).to eq(Float) ### [generate-expression] end - it "generates expression for no args" do - assert_expression("hello", [], "hello") + it 'generates expression for no args' do + assert_expression('hello', [], 'hello') end - it "generates expression with escaped left parenthesis" do - assert_expression( - "\\(iii)", [], - "(iii)") + it 'generates expression with escaped left parenthesis' do + assert_expression('\\(iii)', [], '(iii)') end - it "generates expression with escaped left curly brace" do - assert_expression( - "\\{iii}", [], - "{iii}") + it 'generates expression with escaped left curly brace' do + assert_expression('\\{iii}', [], '{iii}') end - it "generates expression with escaped slashes" do - assert_expression( - "The {int}\\/{int}\\/{int} hey", ["int", "int2", "int3"], - "The 1814/05/17 hey") + it 'generates expression with escaped slashes' do + assert_expression('The {int}\\/{int}\\/{int} hey', ['int', 'int2', 'int3'], 'The 1814/05/17 hey') end - it "generates expression for int float arg" do - assert_expression( - "I have {int} cukes and {float} euro", ["int", "float"], - "I have 2 cukes and 1.5 euro") + it 'generates expression for int float arg' do + assert_expression('I have {int} cukes and {float} euro', ['int', 'float'], 'I have 2 cukes and 1.5 euro') end - it "generates expression for strings" do - assert_expression( - "I like {string} and {string}", ["string", "string2"], - 'I like "bangers" and \'mash\'') + it 'generates expression for strings' do + assert_expression('I like {string} and {string}', ['string', 'string2'], 'I like "bangers" and \'mash\'') end - it "generates expression with % sign" do - assert_expression( - "I am {int}% foobar", ["int"], - 'I am 20% foobar') + it 'generates expression with % sign' do + assert_expression('I am {int}% foobar', ['int'], 'I am 20% foobar') end - it "generates expression for just int" do - assert_expression( - "{int}", ["int"], - "99999") + it 'generates expression for just int' do + assert_expression('{int}', ['int'], '99999') end - it "numbers only second argument when builtin type is not reserved keyword" do - assert_expression( - "I have {int} cukes and {int} euro", ["int", "int2"], - "I have 2 cukes and 5 euro") + it 'numbers only second argument when builtin type is not reserved keyword' do + assert_expression('I have {int} cukes and {int} euro', ['int', 'int2'], 'I have 2 cukes and 5 euro') end - it "numbers only second argument when type is not reserved keyword" do - @parameter_type_registry.define_parameter_type(ParameterType.new( - 'currency', - '[A-Z]{3}', - Currency, - lambda {|s| Currency.new(s)}, - true, - true - )) + it 'numbers only second argument when type is not reserved keyword' do + @parameter_type_registry.define_parameter_type( + ParameterType.new( + 'currency', + '[A-Z]{3}', + Currency, + ->(s) { Currency.new(s)}, + true, + true + ) + ) - assert_expression( - "I have a {currency} account and a {currency} account", ["currency", "currency2"], - "I have a EUR account and a GBP account") + assert_expression('I have a {currency} account and a {currency} account', ['currency', 'currency2'], 'I have a EUR account and a GBP account') end - it "exposes parameters in generated expression" do - expression = @generator.generate_expressions("I have 2 cukes and 1.5 euro")[0] + it 'exposes parameters in a generated expression' do + expression = @generator.generate_expressions('I have 2 cukes and 1.5 euro')[0] types = expression.parameter_types.map(&:type) + expect(types).to eq([Integer, Float]) end - it "matches parameter types with optional capture groups" do - @parameter_type_registry.define_parameter_type(ParameterType.new( + it 'matches parameter types with optional capture groups' do + @parameter_type_registry.define_parameter_type( + ParameterType.new( 'optional-flight', /(1st flight)?/, String, - lambda {|s| s}, + ->(s) { s}, true, false - )) - @parameter_type_registry.define_parameter_type(ParameterType.new( + ) + ) + @parameter_type_registry.define_parameter_type( + ParameterType.new( 'optional-hotel', /(1 hotel)?/, String, - lambda {|s| s}, + ->(s) { s}, true, false - )) + ) + ) - expression = @generator.generate_expressions("I reach Stage 4: 1st flight -1 hotel")[0] + expression = @generator.generate_expressions('I reach Stage 4: 1st flight -1 hotel')[0] # While you would expect this to be `I reach Stage {int}: {optional-flight} -{optional-hotel}` # the `-1` causes {int} to match just before {optional-hotel}. - expect(expression.source).to eq("I reach Stage {int}: {optional-flight} {int} hotel") + + expect(expression.source).to eq('I reach Stage {int}: {optional-flight} {int} hotel') end - it "generates at most 256 expressions" do + it 'generates at most 256 expressions' do for i in 0..3 - @parameter_type_registry.define_parameter_type(ParameterType.new( + @parameter_type_registry.define_parameter_type( + ParameterType.new( "my-type-#{i}", /([a-z] )*?[a-z]/, String, - lambda {|s| s}, + ->(s) { s}, true, false - )) + ) + ) end # This would otherwise generate 4^11=4194300 expressions and consume just shy of 1.5GB. - expressions = @generator.generate_expressions("a s i m p l e s t e p") + expressions = @generator.generate_expressions('a s i m p l e s t e p') + expect(expressions.length).to eq(256) end - it "prefers expression with longest non empty match" do - @parameter_type_registry.define_parameter_type(ParameterType.new( + it 'prefers expression with longest non empty match' do + @parameter_type_registry.define_parameter_type( + ParameterType.new( 'zero-or-more', /[a-z]*/, String, - lambda {|s| s}, + ->(s) { s}, true, false - )) - @parameter_type_registry.define_parameter_type(ParameterType.new( + ) + ) + @parameter_type_registry.define_parameter_type( + ParameterType.new( 'exactly-one', /[a-z]/, String, - lambda {|s| s}, + ->(s) { s}, true, false - )) + ) + ) + expressions = @generator.generate_expressions('a simple step') - expressions = @generator.generate_expressions("a simple step") expect(expressions.length).to eq(2) - expect(expressions[0].source).to eq("{exactly-one} {zero-or-more} {zero-or-more}") - expect(expressions[1].source).to eq("{zero-or-more} {zero-or-more} {zero-or-more}") + expect(expressions[0].source).to eq('{exactly-one} {zero-or-more} {zero-or-more}') + expect(expressions[1].source).to eq('{zero-or-more} {zero-or-more} {zero-or-more}') end - context "does not suggest parameter when match is" do + context 'does not suggest parameter when match is' do before do - @parameter_type_registry.define_parameter_type(ParameterType.new( + @parameter_type_registry.define_parameter_type( + ParameterType.new( 'direction', /(up|down)/, String, - lambda {|s| s}, + ->(s) { s}, true, false - )) + ) + ) end - it "at the beginning of a word" do - expect(@generator.generate_expressions("When I download a picture")[0].source).not_to eq("When I {direction}load a picture") - expect(@generator.generate_expressions("When I download a picture")[0].source).to eq("When I download a picture") + it 'at the beginning of a word' do + expect(@generator.generate_expressions('When I download a picture')[0].source).not_to eq('When I {direction}load a picture') + expect(@generator.generate_expressions('When I download a picture')[0].source).to eq('When I download a picture') end - it "inside a word" do - expect(@generator.generate_expressions("When I watch the muppet show")[0].source).not_to eq("When I watch the m{direction}pet show") - expect(@generator.generate_expressions("When I watch the muppet show")[0].source).to eq("When I watch the muppet show") + it 'inside a word' do + expect(@generator.generate_expressions('When I watch the muppet show')[0].source).not_to eq('When I watch the m{direction}pet show') + expect(@generator.generate_expressions('When I watch the muppet show')[0].source).to eq('When I watch the muppet show') end - it "at the end of a word" do - expect(@generator.generate_expressions("When I create a group")[0].source).not_to eq("When I create a gro{direction}") - expect(@generator.generate_expressions("When I create a group")[0].source).to eq("When I create a group") + it 'at the end of a word' do + expect(@generator.generate_expressions('When I create a group')[0].source).not_to eq('When I create a gro{direction}') + expect(@generator.generate_expressions('When I create a group')[0].source).to eq('When I create a group') end end - context "does suggest parameter when match is" do + context 'does suggest parameter when match is' do before do - @parameter_type_registry.define_parameter_type(ParameterType.new( + @parameter_type_registry.define_parameter_type( + ParameterType.new( 'direction', /(up|down)/, String, - lambda {|s| s}, + ->(s) { s}, true, false - )) + ) + ) end - it "a full word" do - expect(@generator.generate_expressions("When I go down the road")[0].source).to eq("When I go {direction} the road") - expect(@generator.generate_expressions("When I walk up the hill")[0].source).to eq("When I walk {direction} the hill") - expect(@generator.generate_expressions("up the hill, the road goes down")[0].source).to eq("{direction} the hill, the road goes {direction}") + it 'a full word' do + expect(@generator.generate_expressions('When I go down the road')[0].source).to eq('When I go {direction} the road') + expect(@generator.generate_expressions('When I walk up the hill')[0].source).to eq('When I walk {direction} the hill') + expect(@generator.generate_expressions('up the hill, the road goes down')[0].source).to eq('{direction} the hill, the road goes {direction}') end it 'wrapped around punctuation characters' do - expect(@generator.generate_expressions("When direction is:down")[0].source).to eq("When direction is:{direction}") - expect(@generator.generate_expressions("Then direction is down.")[0].source).to eq("Then direction is {direction}.") + expect(@generator.generate_expressions('When direction is:down')[0].source).to eq('When direction is:{direction}') + expect(@generator.generate_expressions('Then direction is down.')[0].source).to eq('Then direction is {direction}.') end end @@ -221,9 +224,9 @@ def assert_expression(expected_expression, expected_argument_names, text) cucumber_expression = CucumberExpression.new(generated_expression.source, @parameter_type_registry) match = cucumber_expression.match(text) - if match.nil? - raise "Expected text '#{text}' to match generated expression '#{generated_expression.source}'" - end + + raise "Expected text '#{text}' to match generated expression '#{generated_expression.source}'" if match.nil? + expect(match.length).to eq(expected_argument_names.length) end end diff --git a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_parser_spec.rb b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_parser_spec.rb index e2b78b703..764c5ed2a 100644 --- a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_parser_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'yaml' require 'cucumber/cucumber_expressions/cucumber_expression_parser' require 'cucumber/cucumber_expressions/errors' diff --git a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb index 8968e2351..b5dc0ce4e 100644 --- a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'yaml' require 'cucumber/cucumber_expressions/cucumber_expression' require 'cucumber/cucumber_expressions/parameter_type_registry' @@ -8,6 +10,7 @@ module CucumberExpressions Dir['../testdata/cucumber-expression/matching/*.yaml'].each do |path| expectation = YAML.load_file(path) + it "matches #{path}" do parameter_registry = ParameterTypeRegistry.new if expectation['exception'] @@ -36,115 +39,110 @@ module CucumberExpressions end end - it "documents match arguments" do + it 'documents match arguments' do parameter_registry = ParameterTypeRegistry.new ### [capture-match-arguments] - expr = "I have {int} cuke(s)" + expr = 'I have {int} cuke(s)' expression = CucumberExpression.new(expr, parameter_registry) - args = expression.match("I have 7 cukes") + args = expression.match('I have 7 cukes') + expect(args[0].value(nil)).to eq(7) ### [capture-match-arguments] end - it "matches float" do - expect(match("{float}", "")).to eq(nil) - expect(match("{float}", ".")).to eq(nil) - expect(match("{float}", ",")).to eq(nil) - expect(match("{float}", "-")).to eq(nil) - expect(match("{float}", "E")).to eq(nil) - expect(match("{float}", "1,")).to eq(nil) - expect(match("{float}", ",1")).to eq(nil) - expect(match("{float}", "1.")).to eq(nil) - - expect(match("{float}", "1")).to eq([1]) - expect(match("{float}", "-1")).to eq([-1]) - expect(match("{float}", "1.1")).to eq([1.1]) - expect(match("{float}", "1,000")).to eq(nil) - expect(match("{float}", "1,000,0")).to eq(nil) - expect(match("{float}", "1,000.1")).to eq(nil) - expect(match("{float}", "1,000,10")).to eq(nil) - expect(match("{float}", "1,0.1")).to eq(nil) - expect(match("{float}", "1,000,000.1")).to eq(nil) - expect(match("{float}", "-1.1")).to eq([-1.1]) - - expect(match("{float}", ".1")).to eq([0.1]) - expect(match("{float}", "-.1")).to eq([-0.1]) - expect(match("{float}", "-.1000001")).to eq([-0.1000001]) - expect(match("{float}", "1E1")).to eq([10.0]) - expect(match("{float}", ".1E1")).to eq([1]) - expect(match("{float}", "E1")).to eq(nil) - expect(match("{float}", "-.1E-1")).to eq([-0.01]) - expect(match("{float}", "-.1E-2")).to eq([-0.001]) - expect(match("{float}", "-.1E+1")).to eq([-1]) - expect(match("{float}", "-.1E+2")).to eq([-10]) - expect(match("{float}", "-.1E1")).to eq([-1]) - expect(match("{float}", "-.1E2")).to eq([-10]) + it 'matches float' do + expect(match('{float}', '')).to eq(nil) + expect(match('{float}', '.')).to eq(nil) + expect(match('{float}', ',')).to eq(nil) + expect(match('{float}', '-')).to eq(nil) + expect(match('{float}', 'E')).to eq(nil) + expect(match('{float}', '1,')).to eq(nil) + expect(match('{float}', ',1')).to eq(nil) + expect(match('{float}', '1.')).to eq(nil) + + expect(match('{float}', '1')).to eq([1]) + expect(match('{float}', '-1')).to eq([-1]) + expect(match('{float}', '1.1')).to eq([1.1]) + expect(match('{float}', '1,000')).to eq(nil) + expect(match('{float}', '1,000,0')).to eq(nil) + expect(match('{float}', '1,000.1')).to eq(nil) + expect(match('{float}', '1,000,10')).to eq(nil) + expect(match('{float}', '1,0.1')).to eq(nil) + expect(match('{float}', '1,000,000.1')).to eq(nil) + expect(match('{float}', '-1.1')).to eq([-1.1]) + + expect(match('{float}', '.1')).to eq([0.1]) + expect(match('{float}', '-.1')).to eq([-0.1]) + expect(match('{float}', '-.1000001')).to eq([-0.1000001]) + expect(match('{float}', '1E1')).to eq([10.0]) + expect(match('{float}', '.1E1')).to eq([1]) + expect(match('{float}', 'E1')).to eq(nil) + expect(match('{float}', '-.1E-1')).to eq([-0.01]) + expect(match('{float}', '-.1E-2')).to eq([-0.001]) + expect(match('{float}', '-.1E+1')).to eq([-1]) + expect(match('{float}', '-.1E+2')).to eq([-10]) + expect(match('{float}', '-.1E1')).to eq([-1]) + expect(match('{float}', '-.1E2')).to eq([-10]) end - it "float with zero" do - expect(match("{float}", "0")).to eq([0.0]) + it 'float with zero' do + expect(match('{float}', '0')).to eq([0.0]) end - it "matches anonymous" do - expect(match("{}", "0.22")).to eq(["0.22"]) + it 'matches anonymous' do + expect(match('{}', '0.22')).to eq(['0.22']) end - it "exposes source" do - expr = "I have {int} cuke(s)" + it 'exposes source' do + expr = 'I have {int} cuke(s)' + expect(CucumberExpression.new(expr, ParameterTypeRegistry.new).source).to eq(expr) end - it "exposes source via #to_s" do - expr = "I have {int} cuke(s)" + it 'exposes source via #to_s' do + expr = 'I have {int} cuke(s)' + expect(CucumberExpression.new(expr, ParameterTypeRegistry.new).to_s).to eq(expr.inspect) end - it "unmatched optional groups have undefined values" do + it 'unmatched optional groups have undefined values' do parameter_type_registry = ParameterTypeRegistry.new parameter_type_registry.define_parameter_type( - ParameterType.new( - 'textAndOrNumber', - /([A-Z]+)?(?: )?([0-9]+)?/, - Object, - -> (s1, s2) { - [s1, s2] - }, - false, - true - ) - ) - expression = CucumberExpression.new( - '{textAndOrNumber}', - parameter_type_registry + ParameterType.new( + 'textAndOrNumber', + /([A-Z]+)?(?: )?([0-9]+)?/, + Object, + -> (s1, s2) { [s1, s2] }, + false, + true + ) ) + expression = CucumberExpression.new('{textAndOrNumber}', parameter_type_registry) - class World - end + class World; end - expect(expression.match("TLA")[0].value(World.new)).to eq(["TLA", nil]) - expect(expression.match("123")[0].value(World.new)).to eq([nil, "123"]) + expect(expression.match('TLA')[0].value(World.new)).to eq(['TLA', nil]) + expect(expression.match('123')[0].value(World.new)).to eq([nil, '123']) end # Ruby specific - it "delegates transform to custom object" do + it 'delegates transform to custom object' do parameter_type_registry = ParameterTypeRegistry.new parameter_type_registry.define_parameter_type( - ParameterType.new( - 'widget', - /\w+/, - Object, - -> (s) { - self.create_widget(s) - }, - false, - true - ) + ParameterType.new( + 'widget', + /\w+/, + Object, + -> (s) { self.create_widget(s) }, + false, + true + ) ) expression = CucumberExpression.new( - 'I have a {widget}', - parameter_type_registry + 'I have a {widget}', + parameter_type_registry ) class World @@ -153,21 +151,20 @@ def create_widget(s) end end - args = expression.match("I have a bolt") + args = expression.match('I have a bolt') + expect(args[0].value(World.new)).to eq('widget:bolt') end - it "reports undefined parameter type name" do + it 'reports undefined parameter type name' do parameter_type_registry = ParameterTypeRegistry.new - begin - CucumberExpression.new( - 'I have {int} {widget}(s) in {word}', - parameter_type_registry - ) - rescue UndefinedParameterTypeError => e - expect(e.undefined_parameter_type_name).to eq('widget') - end + CucumberExpression.new( + 'I have {int} {widget}(s) in {word}', + parameter_type_registry + ) + rescue UndefinedParameterTypeError => e + expect(e.undefined_parameter_type_name).to eq('widget') end def match(expression, text) diff --git a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_tokenizer_spec.rb b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_tokenizer_spec.rb index 78895f91f..19f11d7f3 100644 --- a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_tokenizer_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_tokenizer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'yaml' require 'cucumber/cucumber_expressions/cucumber_expression_tokenizer' require 'cucumber/cucumber_expressions/errors' diff --git a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_transformation_spec.rb b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_transformation_spec.rb index c83cea69c..178d0ed3d 100644 --- a/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_transformation_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/cucumber_expression_transformation_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'yaml' require 'cucumber/cucumber_expressions/cucumber_expression' require 'cucumber/cucumber_expressions/parameter_type_registry' diff --git a/ruby/spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb b/ruby/spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb index f4c7e1517..9d36c62d0 100644 --- a/ruby/spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/custom_parameter_type_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/cucumber_expression' require 'cucumber/cucumber_expressions/regular_expression' require 'cucumber/cucumber_expressions/parameter_type_registry' @@ -40,54 +42,56 @@ def ==(other) end end - describe "Custom parameter type" do + describe 'Custom parameter type' do before do parameter_type_registry = ParameterTypeRegistry.new - parameter_type_registry.define_parameter_type(ParameterType.new( + parameter_type_registry.define_parameter_type( + ParameterType.new( 'color', # name /red|blue|yellow/, # regexp Color, # type - lambda {|s| Color.new(s)}, # transform + ->(s) { Color.new(s)}, # transform true, # use_for_snippets false # prefer_for_regexp_match - )) + ) + ) @parameter_type_registry = parameter_type_registry end - it "throws exception for illegal character in parameter name" do + it 'throws exception for illegal character in parameter name' do expect do ParameterType.new( - '[string]', - /.*/, - String, - lambda {|s| s}, - true, - false + '[string]', + /.*/, + String, + ->(s) { s}, + true, + false ) end.to raise_error("Illegal character in parameter name {[string]}. Parameter names may not contain '[]()$.|?*+'") end describe CucumberExpression do - it "matches parameters with custom parameter type" do - expression = CucumberExpression.new("I have a {color} ball", @parameter_type_registry) - transformed_argument_value = expression.match("I have a red ball")[0].value(nil) + it 'matches parameters with custom parameter type' do + expression = CucumberExpression.new('I have a {color} ball', @parameter_type_registry) + transformed_argument_value = expression.match('I have a red ball')[0].value(nil) + expect(transformed_argument_value).to eq(Color.new('red')) end - it "matches parameters with multiple capture groups" do - @parameter_type_registry.define_parameter_type(ParameterType.new( + it 'matches parameters with multiple capture groups' do + @parameter_type_registry.define_parameter_type( + ParameterType.new( 'coordinate', /(\d+),\s*(\d+),\s*(\d+)/, Coordinate, - lambda {|x, y, z| Coordinate.new(x.to_i, y.to_i, z.to_i)}, + ->(x, y, z) { Coordinate.new(x.to_i, y.to_i, z.to_i)}, true, false - )) - - expression = CucumberExpression.new( - 'A {int} thick line from {coordinate} to {coordinate}', - @parameter_type_registry + ) ) + + expression = CucumberExpression.new('A {int} thick line from {coordinate} to {coordinate}', @parameter_type_registry) args = expression.match('A 5 thick line from 10,20,30 to 40,50,60') thick = args[0].value(nil) @@ -100,95 +104,110 @@ def ==(other) expect(to).to eq(Coordinate.new(40, 50, 60)) end - it "matches parameters with custom parameter type using optional capture group" do + it 'matches parameters with custom parameter type using optional capture group' do parameter_type_registry = ParameterTypeRegistry.new - parameter_type_registry.define_parameter_type(ParameterType.new( + parameter_type_registry.define_parameter_type( + ParameterType.new( 'color', [/red|blue|yellow/, /(?:dark|light) (?:red|blue|yellow)/], Color, - lambda {|s| Color.new(s)}, + ->(s) { Color.new(s)}, true, false - )) - expression = CucumberExpression.new("I have a {color} ball", parameter_type_registry) - transformed_argument_value = expression.match("I have a dark red ball")[0].value(nil) + ) + ) + expression = CucumberExpression.new('I have a {color} ball', parameter_type_registry) + transformed_argument_value = expression.match('I have a dark red ball')[0].value(nil) + expect(transformed_argument_value).to eq(Color.new('dark red')) end - it "defers transformation until queried from argument" do - @parameter_type_registry.define_parameter_type(ParameterType.new( + it 'defers transformation until queried from argument' do + @parameter_type_registry.define_parameter_type( + ParameterType.new( 'throwing', /bad/, CssColor, - lambda {|s| raise "Can't transform [#{s}]"}, + ->(s) { raise "Can't transform [#{s}]"}, true, false - )) - expression = CucumberExpression.new("I have a {throwing} parameter", @parameter_type_registry) - args = expression.match("I have a bad parameter") + ) + ) + expression = CucumberExpression.new('I have a {throwing} parameter', @parameter_type_registry) + args = expression.match('I have a bad parameter') + expect {args[0].value(nil)}.to raise_error("Can't transform [bad]") end - describe "conflicting parameter type" do - it "is detected for type name" do + describe 'conflicting parameter type' do + it 'is detected for type name' do expect { - @parameter_type_registry.define_parameter_type(ParameterType.new( + @parameter_type_registry.define_parameter_type( + ParameterType.new( 'color', /.*/, CssColor, - lambda {|s| CssColor.new(s)}, + ->(s) { CssColor.new(s)}, true, false - )) - }.to raise_error("There is already a parameter with name color") + ) + ) + }.to raise_error('There is already a parameter with name color') end - it "is not detected for type" do - @parameter_type_registry.define_parameter_type(ParameterType.new( + it 'is not detected for type' do + @parameter_type_registry.define_parameter_type( + ParameterType.new( 'whatever', /.*/, Color, - lambda {|s| Color.new(s)}, + ->(s) { Color.new(s)}, false, false - )) + ) + ) end - it "is not detected for regexp" do - @parameter_type_registry.define_parameter_type(ParameterType.new( + it 'is not detected for regexp' do + @parameter_type_registry.define_parameter_type( + ParameterType.new( 'css-color', /red|blue|yellow/, CssColor, - lambda {|s| CssColor.new(s)}, + ->(s) { CssColor.new(s)}, true, false - )) + ) + ) + css_color = CucumberExpression.new('I have a {css-color} ball', @parameter_type_registry) + css_color_value = css_color.match('I have a blue ball')[0].value(nil) - css_color = CucumberExpression.new("I have a {css-color} ball", @parameter_type_registry) - css_color_value = css_color.match("I have a blue ball")[0].value(nil) - expect(css_color_value).to eq(CssColor.new("blue")) + expect(css_color_value).to eq(CssColor.new('blue')) - color = CucumberExpression.new("I have a {color} ball", @parameter_type_registry) - color_value = color.match("I have a blue ball")[0].value(nil) - expect(color_value).to eq(Color.new("blue")) + color = CucumberExpression.new('I have a {color} ball', @parameter_type_registry) + color_value = color.match('I have a blue ball')[0].value(nil) + + expect(color_value).to eq(Color.new('blue')) end end end describe RegularExpression do - it "matches arguments with custom parameter type without name" do + it 'matches arguments with custom parameter types without a name' do parameter_type_registry = ParameterTypeRegistry.new - parameter_type_registry.define_parameter_type(ParameterType.new( + parameter_type_registry.define_parameter_type( + ParameterType.new( nil, /red|blue|yellow/, Color, - lambda {|s| Color.new(s)}, + ->(s) { Color.new(s)}, true, false - )) - + ) + ) expression = RegularExpression.new(/I have a (red|blue|yellow) ball/, parameter_type_registry) - value = expression.match("I have a red ball")[0].value(nil) + value = expression.match('I have a red ball')[0].value(nil) + expect(value).to eq(Color.new('red')) end end diff --git a/ruby/spec/cucumber/cucumber_expressions/expression_factory_spec.rb b/ruby/spec/cucumber/cucumber_expressions/expression_factory_spec.rb index 167040cb4..0d9e35348 100644 --- a/ruby/spec/cucumber/cucumber_expressions/expression_factory_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/expression_factory_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/expression_factory' module Cucumber diff --git a/ruby/spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb b/ruby/spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb index f6f75761a..e88cf0a65 100644 --- a/ruby/spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/parameter_type_registry_spec.rb @@ -1,20 +1,16 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/parameter_type_registry' require 'cucumber/cucumber_expressions/parameter_type' require 'cucumber/cucumber_expressions/errors' module Cucumber module CucumberExpressions + CAPITALISED_WORD = /[A-Z]+\w+/.freeze - CAPITALISED_WORD = /[A-Z]+\w+/ - - class Name - end - - class Person - end - - class Place - end + class Name; end + class Person; end + class Place; end describe ParameterTypeRegistry do before do @@ -22,63 +18,63 @@ class Place end it 'does not allow more than one prefer_for_regexp_match parameter type for each regexp' do - @registry.define_parameter_type(ParameterType.new("name", CAPITALISED_WORD, Name, lambda {|s| Name.new}, true, true)) - @registry.define_parameter_type(ParameterType.new("person", CAPITALISED_WORD, Person, lambda {|s| Person.new}, true, false)) + @registry.define_parameter_type(ParameterType.new('name', CAPITALISED_WORD, Name, ->(s) { Name.new}, true, true)) + @registry.define_parameter_type(ParameterType.new('person', CAPITALISED_WORD, Person, ->(s) { Person.new}, true, false)) expect do - @registry.define_parameter_type(ParameterType.new("place", CAPITALISED_WORD, Place, lambda {|s| Place.new}, true, true)) + @registry.define_parameter_type(ParameterType.new('place', CAPITALISED_WORD, Place, ->(s) { Place.new}, true, true)) end.to raise_error( - CucumberExpressionError, - "There can only be one preferential parameter type per regexp. The regexp /[A-Z]+\\w+/ is used for two preferential parameter types, {name} and {place}" - ) + CucumberExpressionError, + 'There can only be one preferential parameter type per regexp. The regexp /[A-Z]+\\w+/ is used for two preferential parameter types, {name} and {place}' + ) end it 'looks up prefer_for_regexp_match parameter type by regexp' do - name = ParameterType.new("name", CAPITALISED_WORD, Name, lambda {|s| Name.new}, true, false) - person = ParameterType.new("person", CAPITALISED_WORD, Person, lambda {|s| Person.new}, true, true) - place = ParameterType.new("place", CAPITALISED_WORD, Place, lambda {|s| Place.new}, true, false) + name = ParameterType.new('name', CAPITALISED_WORD, Name, ->(s) { Name.new}, true, false) + person = ParameterType.new('person', CAPITALISED_WORD, Person, ->(s) { Person.new}, true, true) + place = ParameterType.new('place', CAPITALISED_WORD, Place, ->(s) { Place.new}, true, false) @registry.define_parameter_type(name) @registry.define_parameter_type(person) @registry.define_parameter_type(place) - expect(@registry.lookup_by_regexp(CAPITALISED_WORD.source, /([A-Z]+\w+) and ([A-Z]+\w+)/, "Lisa and Bob")).to eq(person) + expect(@registry.lookup_by_regexp(CAPITALISED_WORD.source, /([A-Z]+\w+) and ([A-Z]+\w+)/, 'Lisa and Bob')).to eq(person) end it 'throws ambiguous exception when no parameter types are prefer_for_regexp_match' do - name = ParameterType.new("name", CAPITALISED_WORD, Name, lambda {|s| Name.new}, true, false) - person = ParameterType.new("person", CAPITALISED_WORD, Person, lambda {|s| Person.new}, true, false) - place = ParameterType.new("place", CAPITALISED_WORD, Place, lambda {|s| Place.new}, true, false) + name = ParameterType.new('name', CAPITALISED_WORD, Name, ->(s) { Name.new}, true, false) + person = ParameterType.new('person', CAPITALISED_WORD, Person, ->(s) { Person.new}, true, false) + place = ParameterType.new('place', CAPITALISED_WORD, Place, ->(s) { Place.new}, true, false) @registry.define_parameter_type(name) @registry.define_parameter_type(person) @registry.define_parameter_type(place) expect do - expect(@registry.lookup_by_regexp(CAPITALISED_WORD.source, /([A-Z]+\w+) and ([A-Z]+\w+)/, "Lisa and Bob")).to eq(person) + expect(@registry.lookup_by_regexp(CAPITALISED_WORD.source, /([A-Z]+\w+) and ([A-Z]+\w+)/, 'Lisa and Bob')).to eq(person) end.to raise_error( - CucumberExpressionError, - "Your Regular Expression /([A-Z]+\\w+) and ([A-Z]+\\w+)/\n" + - "matches multiple parameter types with regexp /[A-Z]+\\w+/:\n" + - " {name}\n" + - " {person}\n" + - " {place}\n" + - "\n" + - "I couldn't decide which one to use. You have two options:\n" + - "\n" + - "1) Use a Cucumber Expression instead of a Regular Expression. Try one of these:\n" + - " {name} and {name}\n" + - " {name} and {person}\n" + - " {name} and {place}\n" + - " {person} and {name}\n" + - " {person} and {person}\n" + - " {person} and {place}\n" + - " {place} and {name}\n" + - " {place} and {person}\n" + - " {place} and {place}\n" + - "\n" + - "2) Make one of the parameter types preferential and continue to use a Regular Expression.\n" + - "\n" - ) + CucumberExpressionError, + "Your Regular Expression /([A-Z]+\\w+) and ([A-Z]+\\w+)/\n" \ + "matches multiple parameter types with regexp /[A-Z]+\\w+/:\n" \ + " {name}\n" \ + " {person}\n" \ + " {place}\n" \ + "\n" \ + "I couldn't decide which one to use. You have two options:\n" \ + "\n" \ + "1) Use a Cucumber Expression instead of a Regular Expression. Try one of these:\n" \ + " {name} and {name}\n" \ + " {name} and {person}\n" \ + " {name} and {place}\n" \ + " {person} and {name}\n" \ + " {person} and {person}\n" \ + " {person} and {place}\n" \ + " {place} and {name}\n" \ + " {place} and {person}\n" \ + " {place} and {place}\n" \ + "\n" \ + "2) Make one of the parameter types preferential and continue to use a Regular Expression.\n" \ + "\n" + ) end end end diff --git a/ruby/spec/cucumber/cucumber_expressions/parameter_type_spec.rb b/ruby/spec/cucumber/cucumber_expressions/parameter_type_spec.rb index 58fce60e3..486e55f6a 100644 --- a/ruby/spec/cucumber/cucumber_expressions/parameter_type_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/parameter_type_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/parameter_type' module Cucumber @@ -5,7 +7,7 @@ module CucumberExpressions describe ParameterType do it 'does not allow ignore flag on regexp' do expect do - ParameterType.new("case-insensitive", /[a-z]+/i, String, lambda {|s| s}, true, true) + ParameterType.new('case-insensitive', /[a-z]+/i, String, ->(s) { s}, true, true) end.to raise_error( CucumberExpressionError, "ParameterType Regexps can't use option Regexp::IGNORECASE") diff --git a/ruby/spec/cucumber/cucumber_expressions/regular_expression_spec.rb b/ruby/spec/cucumber/cucumber_expressions/regular_expression_spec.rb index f21ae72ed..ebfec8b43 100644 --- a/ruby/spec/cucumber/cucumber_expressions/regular_expression_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/regular_expression_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'yaml' require 'cucumber/cucumber_expressions/regular_expression' require 'cucumber/cucumber_expressions/parameter_type_registry' @@ -7,68 +9,74 @@ module CucumberExpressions describe RegularExpression do Dir['../testdata/regular-expression/matching/*.yaml'].each do |path| expectation = YAML.load_file(path) + it "matches #{path}" do parameter_registry = ParameterTypeRegistry.new expression = RegularExpression.new(Regexp.new(expectation['expression']), parameter_registry) matches = expression.match(expectation['text']) values = matches.map { |arg| arg.value(nil) } + expect(values).to eq(expectation['expected_args']) end end - it "does no transform by default" do - expect( match(/(\d\d)/, "22") ).to eq(["22"]) + it 'does not transform by default' do + expect( match(/(\d\d)/, '22') ).to eq(['22']) end - it "does not transform anonymous" do - expect( match(/(.*)/, "22") ).to eq(["22"]) + it 'does not transform anonymous' do + expect( match(/(.*)/, '22') ).to eq(['22']) end - it "transforms negative int" do - expect( match(/(-?\d+)/, "-22") ).to eq([-22]) + it 'transforms negative int' do + expect( match(/(-?\d+)/, '-22') ).to eq([-22]) end - it "transforms positive int" do - expect( match(/(\d+)/, "22") ).to eq([22]) + it 'transforms positive int' do + expect( match(/(\d+)/, '22') ).to eq([22]) end - it "returns nil when there is no match" do - expect( match(/hello/, "world") ).to be_nil + it 'returns nil when there is no match' do + expect( match(/hello/, 'world') ).to be_nil end - it "matches empty string when there is an empty string match" do + it 'matches empty string when there is an empty string match' do expect( match(/^The value equals "([^"]*)"$/, 'The value equals ""') ).to eq(['']) end - it "matches nested capture group without match" do + it 'matches nested capture group without match' do expect( match(/^a user( named "([^"]*)")?$/, 'a user') ).to eq([nil]) end - it "matches nested capture group with match" do + it 'matches nested capture group with match' do expect( match(/^a user( named "([^"]*)")?$/, 'a user named "Charlie"') ).to eq(['Charlie']) end - it "ignores non capturing groups" do - expect( match( - /(\S+) ?(can|cannot) (?:delete|cancel) the (\d+)(?:st|nd|rd|th) (attachment|slide) ?(?:upload)?/, - "I can cancel the 1st slide upload") - ).to eq(["I", "can", 1, "slide"]) + it 'ignores non capturing groups' do + expect( + match( + /(\S+) ?(can|cannot) (?:delete|cancel) the (\d+)(?:st|nd|rd|th) (attachment|slide) ?(?:upload)?/, + 'I can cancel the 1st slide upload' + ) + ).to eq(['I', 'can', 1, 'slide']) end - it "matches capture group nested in optional one" do + it 'matches capture group nested in optional one' do regexp = /^a (pre-commercial transaction |pre buyer fee model )?purchase(?: for \$(\d+))?$/ + expect( match(regexp, 'a purchase') ).to eq([nil, nil]) expect( match(regexp, 'a purchase for $33') ).to eq([nil, 33]) expect( match(regexp, 'a pre buyer fee model purchase') ).to eq(['pre buyer fee model ', nil]) end - it "works with escaped parenthesis" do + it 'works with escaped parentheses' do expect( match(/Across the line\(s\)/, 'Across the line(s)') ).to eq([]) end - it "exposes source and regexp" do + it 'exposes source and regexp' do regexp = /I have (\d+) cukes? in my (\+) now/ expression = RegularExpression.new(regexp, ParameterTypeRegistry.new) + expect(expression.regexp).to eq(regexp) expect(expression.source).to eq(regexp.source) end diff --git a/ruby/spec/cucumber/cucumber_expressions/tree_regexp_spec.rb b/ruby/spec/cucumber/cucumber_expressions/tree_regexp_spec.rb index 86994360e..d2ef0fdd4 100644 --- a/ruby/spec/cucumber/cucumber_expressions/tree_regexp_spec.rb +++ b/ruby/spec/cucumber/cucumber_expressions/tree_regexp_spec.rb @@ -1,14 +1,16 @@ +# frozen_string_literal: true + require 'cucumber/cucumber_expressions/tree_regexp' module Cucumber module CucumberExpressions describe TreeRegexp do - it 'exposes group source' do + it 'exposes the group source' do tr = TreeRegexp.new(/(a(?:b)?)(c)/) expect(tr.group_builder.children.map{|gb| gb.source}).to eq(['a(?:b)?', 'c']) end - it 'builds tree' do + it 'builds a tree' do tr = TreeRegexp.new(/(a(?:b)?)(c)/) group = tr.match('ac') expect(group.value).to eq('ac') @@ -78,7 +80,7 @@ module CucumberExpressions }.to raise_error(/Named capture groups are not supported/) end - it 'matches optional group' do + it 'matches an optional group' do tr = TreeRegexp.new(/^Something( with an optional argument)?/) group = tr.match('Something') expect(group.children[0].value).to eq(nil) @@ -99,45 +101,45 @@ module CucumberExpressions expect(group.children[2].children[2].value).to eq('60') end - it 'detects multiple non capturing groups' do + it 'detects multiple non-capturing groups' do tr = TreeRegexp.new(/(?:a)(:b)(\?c)(d)/) - group = tr.match("a:b?cd") + group = tr.match('a:b?cd') expect(group.children.length).to eq(3) end - it 'works with escaped backslash' do + it 'works with escaped backslashes' do tr = TreeRegexp.new(/foo\\(bar|baz)/) - group = tr.match("foo\\bar") + group = tr.match('foo\\bar') expect(group.children.length).to eq(1) end - it 'works with escaped slash' do + it 'works with escaped slashes' do tr = TreeRegexp.new(/^I go to '\/(.+)'$/) group = tr.match("I go to '/hello'") expect(group.children.length).to eq(1) end - it 'works with digit and word' do + it 'works with digit and word regexp metacharacters' do tr = TreeRegexp.new(/^(\d) (\w+)$/) - group = tr.match("2 you") + group = tr.match('2 you') expect(group.children.length).to eq(2) end - it 'captures non capturing groups with capturing groups inside' do + it 'captures non-capturing groups with capturing groups inside' do tr = TreeRegexp.new(/the stdout(?: from "(.*?)")?/) - group = tr.match("the stdout") - expect(group.value).to eq("the stdout") + group = tr.match('the stdout') + expect(group.value).to eq('the stdout') expect(group.children[0].value).to eq(nil) expect(group.children.length).to eq(1) end it 'works with flags' do tr = TreeRegexp.new(/HELLO/i) - group = tr.match("hello") - expect(group.value).to eq("hello") + group = tr.match('hello') + expect(group.value).to eq('hello') end - it('does not consider parenthesis in character class as group') do + it('does not consider parentheses in regexp character classes as a group') do tr = TreeRegexp.new(/^drawings: ([A-Z_, ()]+)$/) group = tr.match('drawings: ONE, TWO(ABC)') expect(group.value).to eq('drawings: ONE, TWO(ABC)') @@ -152,14 +154,14 @@ module CucumberExpressions expect(group.children.length).to eq 0 end - it 'works with non capturing inline flags' do + it 'works with non-capturing inline flags' do tr = TreeRegexp.new(/(?i:HELLO)/) group = tr.match('hello') expect(group.value).to eq('hello') expect(group.children.length).to eq 0 end - it 'works with empty capturing group' do + it 'works with empty capturing groups' do tr = TreeRegexp.new(/()/) group = tr.match('') expect(group.value).to eq('') @@ -167,20 +169,19 @@ module CucumberExpressions expect(group.children.length).to eq 1 end - it 'works with empty non-capturing group' do + it 'works with empty non-capturing groups' do tr = TreeRegexp.new(/(?:)/) group = tr.match('') expect(group.value).to eq('') expect(group.children.length).to eq 0 end - it 'works with empty non-look ahead' do + it 'works with empty non-look ahead groups' do tr = TreeRegexp.new(/(?<=)/) group = tr.match('') expect(group.value).to eq('') expect(group.children.length).to eq 0 end - end end end