cucumber 3.0.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +216 -17
  3. data/CONTRIBUTING.md +4 -21
  4. data/README.md +8 -10
  5. data/bin/cucumber +1 -1
  6. data/lib/autotest/cucumber.rb +1 -0
  7. data/lib/autotest/cucumber_mixin.rb +35 -39
  8. data/lib/autotest/cucumber_rails.rb +1 -0
  9. data/lib/autotest/cucumber_rails_rspec.rb +1 -0
  10. data/lib/autotest/cucumber_rails_rspec2.rb +1 -0
  11. data/lib/autotest/cucumber_rspec.rb +1 -0
  12. data/lib/autotest/cucumber_rspec2.rb +1 -0
  13. data/lib/autotest/discover.rb +1 -0
  14. data/lib/cucumber.rb +2 -1
  15. data/lib/cucumber/cli/configuration.rb +6 -5
  16. data/lib/cucumber/cli/main.rb +14 -14
  17. data/lib/cucumber/cli/options.rb +113 -116
  18. data/lib/cucumber/cli/profile_loader.rb +50 -29
  19. data/lib/cucumber/cli/rerun_file.rb +1 -0
  20. data/lib/cucumber/configuration.rb +38 -29
  21. data/lib/cucumber/constantize.rb +8 -10
  22. data/lib/cucumber/core_ext/string.rb +1 -0
  23. data/lib/cucumber/deprecate.rb +32 -8
  24. data/lib/cucumber/encoding.rb +2 -1
  25. data/lib/cucumber/errors.rb +6 -7
  26. data/lib/cucumber/events.rb +14 -7
  27. data/lib/cucumber/events/envelope.rb +9 -0
  28. data/lib/cucumber/events/gherkin_source_parsed.rb +11 -0
  29. data/lib/cucumber/events/gherkin_source_read.rb +1 -4
  30. data/lib/cucumber/events/hook_test_step_created.rb +13 -0
  31. data/lib/cucumber/events/step_activated.rb +6 -6
  32. data/lib/cucumber/events/step_definition_registered.rb +4 -8
  33. data/lib/cucumber/events/test_case_created.rb +13 -0
  34. data/lib/cucumber/events/test_case_finished.rb +0 -4
  35. data/lib/cucumber/events/test_case_ready.rb +12 -0
  36. data/lib/cucumber/events/test_case_started.rb +0 -4
  37. data/lib/cucumber/events/test_run_finished.rb +2 -3
  38. data/lib/cucumber/events/test_run_started.rb +2 -4
  39. data/lib/cucumber/events/test_step_created.rb +13 -0
  40. data/lib/cucumber/events/test_step_finished.rb +0 -4
  41. data/lib/cucumber/events/test_step_started.rb +1 -5
  42. data/lib/cucumber/events/undefined_parameter_type.rb +10 -0
  43. data/lib/cucumber/file_specs.rb +7 -6
  44. data/lib/cucumber/filters.rb +2 -0
  45. data/lib/cucumber/filters/activate_steps.rb +6 -4
  46. data/lib/cucumber/filters/apply_after_hooks.rb +1 -0
  47. data/lib/cucumber/filters/apply_after_step_hooks.rb +1 -0
  48. data/lib/cucumber/filters/apply_around_hooks.rb +1 -0
  49. data/lib/cucumber/filters/apply_before_hooks.rb +1 -0
  50. data/lib/cucumber/filters/broadcast_test_case_ready_event.rb +12 -0
  51. data/lib/cucumber/filters/broadcast_test_run_started_event.rb +2 -1
  52. data/lib/cucumber/filters/gated_receiver.rb +1 -2
  53. data/lib/cucumber/filters/prepare_world.rb +6 -13
  54. data/lib/cucumber/filters/quit.rb +3 -6
  55. data/lib/cucumber/filters/randomizer.rb +6 -7
  56. data/lib/cucumber/filters/retry.rb +2 -2
  57. data/lib/cucumber/filters/tag_limits.rb +2 -2
  58. data/lib/cucumber/filters/tag_limits/test_case_index.rb +1 -2
  59. data/lib/cucumber/filters/tag_limits/verifier.rb +3 -6
  60. data/lib/cucumber/formatter/ansicolor.rb +33 -37
  61. data/lib/cucumber/formatter/ast_lookup.rb +165 -0
  62. data/lib/cucumber/formatter/backtrace_filter.rb +10 -10
  63. data/lib/cucumber/formatter/console.rb +65 -74
  64. data/lib/cucumber/formatter/console_counts.rb +4 -9
  65. data/lib/cucumber/formatter/console_issues.rb +9 -6
  66. data/lib/cucumber/formatter/duration.rb +2 -1
  67. data/lib/cucumber/formatter/duration_extractor.rb +4 -2
  68. data/lib/cucumber/formatter/errors.rb +6 -0
  69. data/lib/cucumber/formatter/fail_fast.rb +9 -6
  70. data/lib/cucumber/formatter/fanout.rb +3 -3
  71. data/lib/cucumber/formatter/html.rb +11 -602
  72. data/lib/cucumber/formatter/http_io.rb +146 -0
  73. data/lib/cucumber/formatter/ignore_missing_messages.rb +2 -3
  74. data/lib/cucumber/formatter/interceptor.rb +11 -18
  75. data/lib/cucumber/formatter/io.rb +18 -11
  76. data/lib/cucumber/formatter/json.rb +102 -109
  77. data/lib/cucumber/formatter/junit.rb +73 -68
  78. data/lib/cucumber/formatter/message.rb +22 -0
  79. data/lib/cucumber/formatter/message_builder.rb +255 -0
  80. data/lib/cucumber/formatter/pretty.rb +360 -153
  81. data/lib/cucumber/formatter/progress.rb +31 -32
  82. data/lib/cucumber/formatter/query/hook_by_test_step.rb +31 -0
  83. data/lib/cucumber/formatter/query/pickle_by_test.rb +26 -0
  84. data/lib/cucumber/formatter/query/pickle_step_by_test_step.rb +26 -0
  85. data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +40 -0
  86. data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +40 -0
  87. data/lib/cucumber/formatter/rerun.rb +23 -4
  88. data/lib/cucumber/formatter/stepdefs.rb +2 -2
  89. data/lib/cucumber/formatter/steps.rb +4 -5
  90. data/lib/cucumber/formatter/summary.rb +17 -9
  91. data/lib/cucumber/formatter/unicode.rb +16 -18
  92. data/lib/cucumber/formatter/usage.rb +30 -26
  93. data/lib/cucumber/gherkin/data_table_parser.rb +18 -6
  94. data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +83 -86
  95. data/lib/cucumber/gherkin/formatter/escaping.rb +13 -12
  96. data/lib/cucumber/gherkin/i18n.rb +1 -0
  97. data/lib/cucumber/gherkin/steps_parser.rb +18 -8
  98. data/lib/cucumber/glue/dsl.rb +2 -1
  99. data/lib/cucumber/glue/hook.rb +35 -11
  100. data/lib/cucumber/glue/invoke_in_world.rb +15 -20
  101. data/lib/cucumber/glue/proto_world.rb +47 -39
  102. data/lib/cucumber/glue/registry_and_more.rb +54 -23
  103. data/lib/cucumber/glue/snippet.rb +24 -27
  104. data/lib/cucumber/glue/step_definition.rb +51 -28
  105. data/lib/cucumber/glue/world_factory.rb +1 -3
  106. data/lib/cucumber/hooks.rb +24 -14
  107. data/lib/cucumber/load_path.rb +1 -0
  108. data/lib/cucumber/multiline_argument.rb +6 -8
  109. data/lib/cucumber/multiline_argument/data_table.rb +106 -73
  110. data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +8 -11
  111. data/lib/cucumber/multiline_argument/doc_string.rb +2 -1
  112. data/lib/cucumber/platform.rb +4 -3
  113. data/lib/cucumber/project_initializer.rb +1 -1
  114. data/lib/cucumber/rake/task.rb +21 -18
  115. data/lib/cucumber/rspec/disable_option_parser.rb +10 -8
  116. data/lib/cucumber/rspec/doubles.rb +1 -0
  117. data/lib/cucumber/running_test_case.rb +4 -54
  118. data/lib/cucumber/runtime.rb +57 -61
  119. data/lib/cucumber/runtime/after_hooks.rb +9 -4
  120. data/lib/cucumber/runtime/before_hooks.rb +9 -4
  121. data/lib/cucumber/runtime/for_programming_languages.rb +12 -9
  122. data/lib/cucumber/runtime/step_hooks.rb +5 -2
  123. data/lib/cucumber/runtime/support_code.rb +16 -22
  124. data/lib/cucumber/runtime/user_interface.rb +8 -19
  125. data/lib/cucumber/step_definition_light.rb +6 -4
  126. data/lib/cucumber/step_definitions.rb +3 -2
  127. data/lib/cucumber/step_match.rb +20 -18
  128. data/lib/cucumber/step_match_search.rb +9 -9
  129. data/lib/cucumber/term/ansicolor.rb +39 -39
  130. data/lib/cucumber/unit.rb +1 -0
  131. data/lib/cucumber/version +1 -1
  132. data/lib/simplecov_setup.rb +1 -0
  133. metadata +214 -127
  134. data/lib/cucumber/formatter/cucumber.css +0 -286
  135. data/lib/cucumber/formatter/cucumber.sass +0 -247
  136. data/lib/cucumber/formatter/hook_query_visitor.rb +0 -41
  137. data/lib/cucumber/formatter/html_builder.rb +0 -120
  138. data/lib/cucumber/formatter/inline-js.js +0 -30
  139. data/lib/cucumber/formatter/jquery-min.js +0 -154
  140. data/lib/cucumber/formatter/json_pretty.rb +0 -10
  141. data/lib/cucumber/formatter/legacy_api/adapter.rb +0 -1028
  142. data/lib/cucumber/formatter/legacy_api/ast.rb +0 -394
  143. data/lib/cucumber/formatter/legacy_api/results.rb +0 -50
  144. data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +0 -32
  145. data/lib/cucumber/step_argument.rb +0 -24
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'autotest/rails'
3
4
  require 'autotest/cucumber_mixin'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'autotest/cucumber_mixin'
3
4
  require 'autotest/rails_rspec'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'autotest/cucumber_mixin'
3
4
  require 'autotest/rails_rspec2'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'autotest/cucumber_mixin'
3
4
  require 'autotest/rspec'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'autotest/cucumber_mixin'
3
4
  require 'autotest/rspec2'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  Autotest.add_discovery do
3
4
  if File.directory?('features')
4
5
  if ENV['AUTOFEATURE'] =~ /true/i
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'yaml'
3
4
  require 'cucumber/encoding'
4
5
  require 'cucumber/platform'
@@ -9,7 +10,7 @@ require 'cucumber/term/ansicolor'
9
10
 
10
11
  module Cucumber
11
12
  class << self
12
- attr_accessor :wants_to_quit
13
+ attr_accessor :wants_to_quit, :use_legacy_autoloader
13
14
 
14
15
  def logger
15
16
  return @log if @log
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'logger'
3
4
  require 'cucumber/cli/options'
4
5
  require 'cucumber/cli/rerun_file'
@@ -19,7 +20,7 @@ module Cucumber
19
20
  def initialize(out_stream = STDOUT, error_stream = STDERR)
20
21
  @out_stream = out_stream
21
22
  @error_stream = error_stream
22
- @options = Options.new(@out_stream, @error_stream, :default_profile => 'default')
23
+ @options = Options.new(@out_stream, @error_stream, default_profile: 'default')
23
24
  end
24
25
 
25
26
  def parse!(args)
@@ -63,7 +64,7 @@ module Cucumber
63
64
  end
64
65
 
65
66
  def fail_fast?
66
- !!@options[:fail_fast]
67
+ @options[:fail_fast]
67
68
  end
68
69
 
69
70
  def retry_attempts
@@ -78,7 +79,7 @@ module Cucumber
78
79
  logger = Logger.new(@out_stream)
79
80
  logger.formatter = LogFormatter.new
80
81
  logger.level = Logger::INFO
81
- logger.level = Logger::DEBUG if self.verbose?
82
+ logger.level = Logger::DEBUG if verbose?
82
83
  logger
83
84
  end
84
85
 
@@ -107,7 +108,7 @@ module Cucumber
107
108
  end
108
109
 
109
110
  def to_hash
110
- Hash(@options).merge(out_stream: @out_stream, error_stream: @error_stream)
111
+ Hash(@options).merge(out_stream: @out_stream, error_stream: @error_stream, seed: seed)
111
112
  end
112
113
 
113
114
  private
@@ -130,7 +131,7 @@ module Cucumber
130
131
  f[2] == @out_stream ? -1 : 1
131
132
  end
132
133
  @options[:formats].uniq!
133
- @options.check_formatter_stream_conflicts()
134
+ @options.check_formatter_stream_conflicts
134
135
  end
135
136
  end
136
137
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'optparse'
3
4
  require 'cucumber'
4
5
  require 'logger'
@@ -13,7 +14,7 @@ module Cucumber
13
14
  end
14
15
  end
15
16
 
16
- def initialize(args, _=nil, out=STDOUT, err=STDERR, kernel=Kernel)
17
+ def initialize(args, _ = nil, out = STDOUT, err = STDERR, kernel = Kernel)
17
18
  @args = args
18
19
  @out = out
19
20
  @err = err
@@ -23,22 +24,15 @@ module Cucumber
23
24
  def execute!(existing_runtime = nil)
24
25
  trap_interrupt
25
26
 
26
- runtime = if existing_runtime
27
- existing_runtime.configure(configuration)
28
- existing_runtime
29
- else
30
- Runtime.new(configuration)
31
- end
27
+ runtime = runtime(existing_runtime)
32
28
 
33
29
  runtime.run!
34
30
  if Cucumber.wants_to_quit
35
31
  exit_unable_to_finish
32
+ elsif runtime.failure?
33
+ exit_tests_failed
36
34
  else
37
- if runtime.failure?
38
- exit_tests_failed
39
- else
40
- exit_ok
41
- end
35
+ exit_ok
42
36
  end
43
37
  rescue SystemExit => e
44
38
  @kernel.exit(e.status)
@@ -55,7 +49,7 @@ module Cucumber
55
49
  rescue Errno::EACCES, Errno::ENOENT => e
56
50
  @err.puts("#{e.message} (#{e.class})")
57
51
  exit_unable_to_finish
58
- rescue Exception => e
52
+ rescue Exception => e # rubocop:disable Lint/RescueException
59
53
  @err.puts("#{e.message} (#{e.class})")
60
54
  @err.puts(e.backtrace.join("\n"))
61
55
  exit_unable_to_finish
@@ -70,7 +64,6 @@ module Cucumber
70
64
 
71
65
  private
72
66
 
73
-
74
67
  def exit_ok
75
68
  @kernel.exit 0
76
69
  end
@@ -93,8 +86,15 @@ module Cucumber
93
86
  exit_unable_to_finish! if Cucumber.wants_to_quit
94
87
  Cucumber.wants_to_quit = true
95
88
  STDERR.puts "\nExiting... Interrupt again to exit immediately."
89
+ exit_unable_to_finish
96
90
  end
97
91
  end
92
+
93
+ def runtime(existing_runtime)
94
+ return Runtime.new(configuration) unless existing_runtime
95
+ existing_runtime.configure(configuration)
96
+ existing_runtime
97
+ end
98
98
  end
99
99
  end
100
100
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'cucumber/cli/profile_loader'
3
4
  require 'cucumber/formatter/ansicolor'
4
5
  require 'cucumber/glue/registry_and_more'
@@ -7,56 +8,55 @@ require 'cucumber/core/test/result'
7
8
 
8
9
  module Cucumber
9
10
  module Cli
10
-
11
11
  class Options
12
12
  INDENT = ' ' * 53
13
13
  BUILTIN_FORMATS = {
14
- 'html' => ['Cucumber::Formatter::Html', 'Generates a nice looking HTML report.'],
15
14
  'pretty' => ['Cucumber::Formatter::Pretty', 'Prints the feature as is - in colours.'],
16
15
  'progress' => ['Cucumber::Formatter::Progress', 'Prints one character per scenario.'],
17
16
  'rerun' => ['Cucumber::Formatter::Rerun', 'Prints failing files with line numbers.'],
18
- 'usage' => ['Cucumber::Formatter::Usage', "Prints where step definitions are used.\n" +
19
- "#{INDENT}The slowest step definitions (with duration) are\n" +
20
- "#{INDENT}listed first. If --dry-run is used the duration\n" +
21
- "#{INDENT}is not shown, and step definitions are sorted by\n" +
17
+ 'usage' => ['Cucumber::Formatter::Usage', "Prints where step definitions are used.\n" \
18
+ "#{INDENT}The slowest step definitions (with duration) are\n" \
19
+ "#{INDENT}listed first. If --dry-run is used the duration\n" \
20
+ "#{INDENT}is not shown, and step definitions are sorted by\n" \
22
21
  "#{INDENT}filename instead."],
23
- 'stepdefs' => ['Cucumber::Formatter::Stepdefs', "Prints All step definitions with their locations. Same as\n" +
22
+ 'stepdefs' => ['Cucumber::Formatter::Stepdefs', "Prints All step definitions with their locations. Same as\n" \
24
23
  "#{INDENT}the usage formatter, except that steps are not printed."],
25
24
  'junit' => ['Cucumber::Formatter::Junit', 'Generates a report similar to Ant+JUnit.'],
26
- 'json' => ['Cucumber::Formatter::Json', 'Prints the feature as JSON'],
27
- 'json_pretty' => ['Cucumber::Formatter::JsonPretty', 'Prints the feature as prettified JSON'],
25
+ 'json' => ['Cucumber::Formatter::Json', '[DEPRECATED] Prints the feature as JSON'],
26
+ 'message' => ['Cucumber::Formatter::Message', 'Outputs protobuf messages'],
27
+ 'html' => ['Cucumber::Formatter::HTML', 'Outputs HTML report'],
28
28
  'summary' => ['Cucumber::Formatter::Summary', 'Summary output of feature and scenarios']
29
- }
29
+ }.freeze
30
30
  max = BUILTIN_FORMATS.keys.map(&:length).max
31
31
  FORMAT_HELP_MSG = [
32
- 'Use --format rerun --out rerun.txt to write out failing',
33
- 'features. You can rerun them with cucumber @rerun.txt.',
34
- 'FORMAT can also be the fully qualified class name of',
35
- "your own custom formatter. If the class isn't loaded,",
36
- 'Cucumber will attempt to require a file with a relative',
37
- 'file name that is the underscore name of the class name.',
38
- 'Example: --format Foo::BarZap -> Cucumber will look for',
39
- 'foo/bar_zap.rb. You can place the file with this relative',
40
- 'path underneath your features/support directory or anywhere',
41
- "on Ruby's LOAD_PATH, for example in a Ruby gem."
42
- ]
32
+ 'Use --format rerun --out rerun.txt to write out failing',
33
+ 'features. You can rerun them with cucumber @rerun.txt.',
34
+ 'FORMAT can also be the fully qualified class name of',
35
+ "your own custom formatter. If the class isn't loaded,",
36
+ 'Cucumber will attempt to require a file with a relative',
37
+ 'file name that is the underscore name of the class name.',
38
+ 'Example: --format Foo::BarZap -> Cucumber will look for',
39
+ 'foo/bar_zap.rb. You can place the file with this relative',
40
+ 'path underneath your features/support directory or anywhere',
41
+ "on Ruby's LOAD_PATH, for example in a Ruby gem."
42
+ ].freeze
43
43
 
44
44
  FORMAT_HELP = (BUILTIN_FORMATS.keys.sort.map do |key|
45
45
  " #{key}#{' ' * (max - key.length)} : #{BUILTIN_FORMATS[key][1]}"
46
46
  end) + FORMAT_HELP_MSG
47
- PROFILE_SHORT_FLAG = '-p'
48
- NO_PROFILE_SHORT_FLAG = '-P'
49
- PROFILE_LONG_FLAG = '--profile'
50
- NO_PROFILE_LONG_FLAG = '--no-profile'
51
- FAIL_FAST_FLAG = '--fail-fast'
52
- RETRY_FLAG = '--retry'
47
+ PROFILE_SHORT_FLAG = '-p'.freeze
48
+ NO_PROFILE_SHORT_FLAG = '-P'.freeze
49
+ PROFILE_LONG_FLAG = '--profile'.freeze
50
+ NO_PROFILE_LONG_FLAG = '--no-profile'.freeze
51
+ FAIL_FAST_FLAG = '--fail-fast'.freeze
52
+ RETRY_FLAG = '--retry'.freeze
53
53
  OPTIONS_WITH_ARGS = [
54
- '-r', '--require', '--i18n-keywords', '-f', '--format', '-o',
55
- '--out', '-t', '--tags', '-n', '--name', '-e', '--exclude',
56
- PROFILE_SHORT_FLAG, PROFILE_LONG_FLAG, RETRY_FLAG, '-l',
57
- '--lines', '--port', '-I', '--snippet-type'
58
- ]
59
- ORDER_TYPES = %w{defined random}
54
+ '-r', '--require', '--i18n-keywords', '-f', '--format', '-o',
55
+ '--out', '-t', '--tags', '-n', '--name', '-e', '--exclude',
56
+ PROFILE_SHORT_FLAG, PROFILE_LONG_FLAG, RETRY_FLAG, '-l',
57
+ '--lines', '--port', '-I', '--snippet-type'
58
+ ].freeze
59
+ ORDER_TYPES = %w[defined random].freeze
60
60
  TAG_LIMIT_MATCHER = /(?<tag_name>\@\w+):(?<limit>\d+)/x
61
61
 
62
62
  def self.parse(args, out_stream, error_stream, options = {})
@@ -85,40 +85,38 @@ module Cucumber
85
85
  @options[key] = value
86
86
  end
87
87
 
88
- def parse!(args) # rubocop:disable Metrics/AbcSize
88
+ def parse!(args) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
89
89
  @args = args
90
90
  @expanded_args = @args.dup
91
91
 
92
92
  @args.extend(::OptionParser::Arguable)
93
93
 
94
- @args.options do |opts|
94
+ @args.options do |opts| # rubocop:disable Metrics/BlockLength
95
95
  opts.banner = banner
96
- opts.on('-r LIBRARY|DIR', '--require LIBRARY|DIR', *require_files_msg) {|lib| require_files(lib) }
96
+ opts.on('-r LIBRARY|DIR', '--require LIBRARY|DIR', *require_files_msg) { |lib| require_files(lib) }
97
97
 
98
- if(Cucumber::JRUBY)
99
- opts.on('-j DIR', '--jars DIR', 'Load all the jars under DIR') {|jars| load_jars(jars) }
100
- end
98
+ opts.on('-j DIR', '--jars DIR', 'Load all the jars under DIR') { |jars| load_jars(jars) } if Cucumber::JRUBY
101
99
 
102
- opts.on("#{RETRY_FLAG} ATTEMPTS", *retry_msg) {|v| set_option :retry, v.to_i }
100
+ opts.on("#{RETRY_FLAG} ATTEMPTS", *retry_msg) { |v| set_option :retry, v.to_i }
103
101
  opts.on('--i18n-languages', *i18n_languages_msg) { list_languages_and_exit }
104
- opts.on('--i18n-keywords LANG', *i18n_keywords_msg) {|lang| set_language lang }
102
+ opts.on('--i18n-keywords LANG', *i18n_keywords_msg) { |lang| language lang }
105
103
  opts.on(FAIL_FAST_FLAG, 'Exit immediately following the first failing scenario') { set_option :fail_fast }
106
104
  opts.on('-f FORMAT', '--format FORMAT', *format_msg, *FORMAT_HELP) do |v|
107
105
  add_option :formats, [*parse_formats(v), @out_stream]
108
106
  end
109
- opts.on('--init', *init_msg) {|v| initialize_project }
110
- opts.on('-o', '--out [FILE|DIR]', *out_msg) {|v| set_out_stream v }
111
- opts.on('-t TAG_EXPRESSION', '--tags TAG_EXPRESSION', *tags_msg) {|v| add_tag v }
112
- opts.on('-n NAME', '--name NAME', *name_msg) {|v| add_option :name_regexps, /#{v}/ }
113
- opts.on('-e', '--exclude PATTERN', *exclude_msg) {|v| add_option :excludes, Regexp.new(v) }
114
- opts.on(PROFILE_SHORT_FLAG, "#{PROFILE_LONG_FLAG} PROFILE", *profile_short_flag_msg) {|v| add_profile v }
115
- opts.on(NO_PROFILE_SHORT_FLAG, NO_PROFILE_LONG_FLAG, *no_profile_short_flag_msg) {|v| disable_profile_loading }
116
- opts.on('-c', '--[no-]color', *color_msg) {|v| set_color v }
107
+ opts.on('--init', *init_msg) { |_v| initialize_project }
108
+ opts.on('-o', '--out [FILE|DIR|URL]', *out_msg) { |v| out_stream v }
109
+ opts.on('-t TAG_EXPRESSION', '--tags TAG_EXPRESSION', *tags_msg) { |v| add_tag v }
110
+ opts.on('-n NAME', '--name NAME', *name_msg) { |v| add_option :name_regexps, /#{v}/ }
111
+ opts.on('-e', '--exclude PATTERN', *exclude_msg) { |v| add_option :excludes, Regexp.new(v) }
112
+ opts.on(PROFILE_SHORT_FLAG, "#{PROFILE_LONG_FLAG} PROFILE", *profile_short_flag_msg) { |v| add_profile v }
113
+ opts.on(NO_PROFILE_SHORT_FLAG, NO_PROFILE_LONG_FLAG, *no_profile_short_flag_msg) { |_v| disable_profile_loading }
114
+ opts.on('-c', '--[no-]color', *color_msg) { |v| color v }
117
115
  opts.on('-d', '--dry-run', *dry_run_msg) { set_dry_run_and_duration }
118
116
  opts.on('-m', '--no-multiline', "Don't print multiline strings and tables under steps.") { set_option :no_multiline }
119
117
  opts.on('-s', '--no-source', "Don't print the file and line of the step definition with the steps.") { set_option :source, false }
120
118
  opts.on('-i', '--no-snippets', "Don't print snippets for pending steps.") { set_option :snippets, false }
121
- opts.on('-I', '--snippet-type TYPE', *snippet_type_msg) {|v| set_option :snippet_type, v.to_sym }
119
+ opts.on('-I', '--snippet-type TYPE', *snippet_type_msg) { |v| set_option :snippet_type, v.to_sym }
122
120
  opts.on('-q', '--quiet', 'Alias for --no-snippets --no-source.') { shut_up }
123
121
  opts.on('--no-duration', "Don't print the duration at the end of the summary") { set_option :duration, false }
124
122
  opts.on('-b', '--backtrace', 'Show full backtrace for all errors.') { Cucumber.use_full_backtrace = true }
@@ -129,20 +127,18 @@ module Cucumber
129
127
  opts.on('-w', '--wip', 'Fail if there are any passing scenarios.') { set_option :wip }
130
128
  opts.on('-v', '--verbose', 'Show the files and features loaded.') { set_option :verbose }
131
129
  opts.on('-g', '--guess', 'Guess best match for Ambiguous steps.') { set_option :guess }
132
- opts.on('-l', '--lines LINES', *lines_msg) {|lines| set_option :lines, lines }
130
+ opts.on('-l', '--lines LINES', *lines_msg) { |lines| set_option :lines, lines }
133
131
  opts.on('-x', '--expand', 'Expand Scenario Outline Tables in output.') { set_option :expand }
134
132
 
135
133
  opts.on('--order TYPE[:SEED]', 'Run examples in the specified order. Available types:',
136
- *<<-TEXT.split("\n")) do |order|
134
+ *<<-TEXT.split("\n")) do |order|
137
135
  [defined] Run scenarios in the order they were defined (default).
138
136
  [random] Shuffle scenarios before running.
139
137
  Specify SEED to reproduce the shuffling from a previous run.
140
138
  e.g. --order random:5738
141
- TEXT
139
+ TEXT
142
140
  @options[:order], @options[:seed] = *order.split(':')
143
- unless ORDER_TYPES.include?(@options[:order])
144
- fail "'#{@options[:order]}' is not a recognised order type. Please use one of #{ORDER_TYPES.join(", ")}."
145
- end
141
+ raise "'#{@options[:order]}' is not a recognised order type. Please use one of #{ORDER_TYPES.join(', ')}." unless ORDER_TYPES.include?(@options[:order])
146
142
  end
147
143
 
148
144
  opts.on_tail('--version', 'Show version.') { exit_ok(Cucumber::VERSION) }
@@ -152,9 +148,9 @@ TEXT
152
148
  @args.map! { |a| "#{a}:#{@options[:lines]}" } if @options[:lines]
153
149
 
154
150
  extract_environment_variables
155
- @options[:paths] = @args.dup #whatver is left over
151
+ @options[:paths] = @args.dup # whatver is left over
156
152
 
157
- check_formatter_stream_conflicts()
153
+ check_formatter_stream_conflicts
158
154
 
159
155
  merge_profiles
160
156
 
@@ -169,7 +165,7 @@ TEXT
169
165
  @options[:filters] ||= []
170
166
  end
171
167
 
172
- def check_formatter_stream_conflicts()
168
+ def check_formatter_stream_conflicts
173
169
  streams = @options[:formats].uniq.map { |(_, _, stream)| stream }
174
170
  return if streams == streams.uniq
175
171
  raise 'All but one formatter must use --out, only one can print to each stream (or STDOUT)'
@@ -194,18 +190,15 @@ TEXT
194
190
  end
195
191
 
196
192
  def dry_run_msg
197
- [
198
- 'Invokes formatters without executing the steps.',
199
- 'This also omits the loading of your support/env.rb file if it exists.'
200
- ]
193
+ ['Invokes formatters without executing the steps.']
201
194
  end
202
195
 
203
196
  def exclude_msg
204
- [ "Don't run feature files or require ruby files matching PATTERN" ]
197
+ ["Don't run feature files or require ruby files matching PATTERN"]
205
198
  end
206
199
 
207
200
  def format_msg
208
- [ 'How to format features (Default: pretty). Available formats:' ]
201
+ ['How to format features (Default: pretty). Available formats:']
209
202
  end
210
203
 
211
204
  def i18n_languages_msg
@@ -217,7 +210,7 @@ TEXT
217
210
  def i18n_keywords_msg
218
211
  [
219
212
  'List keywords for in a particular language',
220
- %{Run with "--i18n help" to see all languages}
213
+ %(Run with "--i18n help" to see all languages)
221
214
  ]
222
215
  end
223
216
 
@@ -229,7 +222,7 @@ TEXT
229
222
  end
230
223
 
231
224
  def lines_msg
232
- [ 'Run given line numbers. Equivalent to FILE:LINE syntax' ]
225
+ ['Run given line numbers. Equivalent to FILE:LINE syntax']
233
226
  end
234
227
 
235
228
  def no_profile_short_flag_msg
@@ -249,7 +242,7 @@ TEXT
249
242
  end
250
243
 
251
244
  def retry_msg
252
- [ 'Specify the number of times to retry failing tests (default: 0)' ]
245
+ ['Specify the number of times to retry failing tests (default: 0)']
253
246
  end
254
247
 
255
248
  def name_msg
@@ -273,7 +266,7 @@ TEXT
273
266
  [formatter, options_hash]
274
267
  end
275
268
 
276
- def set_out_stream(v)
269
+ def out_stream(v)
277
270
  @options[:formats] << ['pretty', {}, nil] if @options[:formats].empty?
278
271
  @options[:formats][-1][2] = v
279
272
  end
@@ -303,10 +296,14 @@ TEXT
303
296
 
304
297
  def out_msg
305
298
  [
306
- 'Write output to a file/directory instead of STDOUT. This option',
299
+ 'Write output to a file/directory/URL instead of STDOUT. This option',
307
300
  'applies to the previously specified --format, or the',
308
301
  'default format if no format is specified. Check the specific',
309
- "formatter's docs to see whether to pass a file or a dir."
302
+ "formatter's docs to see whether to pass a file, dir or URL.",
303
+ "\n",
304
+ 'When using a URL, the output of the formatter will be sent as the HTTP request body.',
305
+ 'HTTP headers and request method can be set with cURL like options.',
306
+ 'Example: --out "http://example.com -X POST -H Content-Type:text/json"'
310
307
  ]
311
308
  end
312
309
 
@@ -314,11 +311,13 @@ TEXT
314
311
  [
315
312
  'Require files before executing the features. If this',
316
313
  'option is not specified, all *.rb files that are',
317
- 'siblings or below the features will be loaded auto-',
314
+ 'siblings of or below the features will be loaded auto-',
318
315
  'matically. Automatic loading is disabled when this',
319
- 'option is specified, and all loading becomes explicit.',
320
- 'Files under directories named "support" are always',
321
- 'loaded first.',
316
+ 'option is specified; all loading becomes explicit.',
317
+ 'Files in directories named "support" are still always',
318
+ 'loaded first when their parent directories are',
319
+ 'required or if the "support" directoires themselves are',
320
+ 'explicitly required.',
322
321
  'This option can be specified multiple times.'
323
322
  ]
324
323
  end
@@ -332,12 +331,12 @@ TEXT
332
331
 
333
332
  def banner
334
333
  [
335
- 'Usage: cucumber [options] [ [FILE|DIR|URL][:LINE[:LINE]*] ]+', '',
336
- 'Examples:',
337
- 'cucumber examples/i18n/en/features',
338
- 'cucumber @rerun.txt (See --format rerun)',
339
- 'cucumber examples/i18n/it/features/somma.feature:6:98:113',
340
- 'cucumber -s -i http://rubyurl.com/eeCl', '', ''
334
+ 'Usage: cucumber [options] [ [FILE|DIR|URL][:LINE[:LINE]*] ]+', '',
335
+ 'Examples:',
336
+ 'cucumber examples/i18n/en/features',
337
+ 'cucumber @rerun.txt (See --format rerun)',
338
+ 'cucumber examples/i18n/it/features/somma.feature:6:98:113',
339
+ 'cucumber -s -i http://rubyurl.com/eeCl', '', ''
341
340
  ].join("\n")
342
341
  end
343
342
 
@@ -349,13 +348,13 @@ TEXT
349
348
  end
350
349
 
351
350
  def require_jars(jars)
352
- Dir["#{jars}/**/*.jar"].each {|jar| require jar}
351
+ Dir["#{jars}/**/*.jar"].each { |jar| require jar }
353
352
  end
354
353
 
355
- def set_language(lang)
354
+ def language(lang)
356
355
  require 'gherkin/dialect'
357
356
 
358
- return indicate_invalid_language_and_exit(lang) unless ::Gherkin::DIALECTS.keys.include? lang
357
+ return indicate_invalid_language_and_exit(lang) unless ::Gherkin::DIALECTS.key?(lang)
359
358
  list_keywords_and_exit(lang)
360
359
  end
361
360
 
@@ -364,7 +363,7 @@ TEXT
364
363
  end
365
364
 
366
365
  def non_stdout_formats
367
- @options[:formats].select { |_, _, output| output != @out_stream }
366
+ @options[:formats].reject { |_, _, output| output == @out_stream }
368
367
  end
369
368
 
370
369
  def add_option(option, value)
@@ -372,8 +371,8 @@ TEXT
372
371
  end
373
372
 
374
373
  def add_tag(value)
375
- warn("Deprecated: Found tags option '#{value}'. Support for '~@tag' will be removed from the next release of Cucumber. Please use 'not @tag' instead.") if value.include?('~')
376
- warn("Deprecated: Found tags option '#{value}'. Support for '@tag1,@tag2' will be removed from the next release of Cucumber. Please use '@tag or @tag2' instead.") if value.include?(',')
374
+ raise("Found tags option '#{value}'. '~@tag' is no longer supported, use 'not @tag' instead.") if value.include?('~')
375
+ raise("Found tags option '#{value}'. '@tag1,@tag2' is no longer supported, use '@tag or @tag2' instead.") if value.include?(',')
377
376
  @options[:tag_expressions] << value.gsub(/(@\w+)(:\d+)?/, '\1')
378
377
  add_tag_limits(value)
379
378
  end
@@ -385,13 +384,11 @@ TEXT
385
384
  end
386
385
 
387
386
  def add_tag_limit(tag_limits, tag_name, limit)
388
- if tag_limits[tag_name] && tag_limits[tag_name] != limit
389
- raise "Inconsistent tag limits for #{tag_name}: #{tag_limits[tag_name]} and #{limit}"
390
- end
387
+ raise "Inconsistent tag limits for #{tag_name}: #{tag_limits[tag_name]} and #{limit}" if tag_limits[tag_name] && tag_limits[tag_name] != limit
391
388
  tag_limits[tag_name] = limit
392
389
  end
393
390
 
394
- def set_color(color)
391
+ def color(color)
395
392
  Cucumber::Term::ANSIColor.coloring = color
396
393
  end
397
394
 
@@ -403,7 +400,7 @@ TEXT
403
400
  @profiles << p
404
401
  end
405
402
 
406
- def set_option(option, value=nil)
403
+ def set_option(option, value = nil)
407
404
  @options[option] = value.nil? ? true : value
408
405
  end
409
406
 
@@ -434,7 +431,7 @@ TEXT
434
431
  def extract_environment_variables
435
432
  @args.delete_if do |arg|
436
433
  if arg =~ /^(\w+)=(.*)$/
437
- @options[:env_vars][$1] = $2
434
+ @options[:env_vars][Regexp.last_match(1)] = Regexp.last_match(2)
438
435
  true
439
436
  end
440
437
  end
@@ -463,8 +460,8 @@ TEXT
463
460
  profile_args = profile_loader.args_from(profile)
464
461
  profile_options = Options.parse(
465
462
  profile_args, @out_stream, @error_stream,
466
- :skip_profile_information => true,
467
- :profile_loader => profile_loader
463
+ skip_profile_information: true,
464
+ profile_loader: profile_loader
468
465
  )
469
466
  reverse_merge(profile_options)
470
467
  end
@@ -472,14 +469,14 @@ TEXT
472
469
  def default_profile_should_be_used?
473
470
  @profiles.empty? &&
474
471
  profile_loader.cucumber_yml_defined? &&
475
- profile_loader.has_profile?(@default_profile)
472
+ profile_loader.profile?(@default_profile)
476
473
  end
477
474
 
478
475
  def profile_loader
479
476
  @profile_loader ||= ProfileLoader.new
480
477
  end
481
478
 
482
- def reverse_merge(other_options)
479
+ def reverse_merge(other_options) # rubocop:disable Metrics/AbcSize
483
480
  @options = other_options.options.merge(@options)
484
481
  @options[:require] += other_options[:require]
485
482
  @options[:excludes] += other_options[:excludes]
@@ -508,7 +505,7 @@ TEXT
508
505
  @options[:formats] = stdout_formats[0..0] + non_stdout_formats
509
506
  end
510
507
 
511
- @options[:retry] = other_options[:retry] if @options[:retry] == 0
508
+ @options[:retry] = other_options[:retry] if @options[:retry].zero?
512
509
 
513
510
  self
514
511
  end
@@ -544,7 +541,7 @@ TEXT
544
541
  ['but (code)', to_code_keywords_string(language.but_keywords)]
545
542
  ]
546
543
  )
547
- @out_stream.write(data.to_s({ color: false, prefixes: Hash.new('') }))
544
+ @out_stream.write(data.to_s(color: false, prefixes: Hash.new('')))
548
545
  Kernel.exit(0)
549
546
  end
550
547
 
@@ -553,8 +550,9 @@ TEXT
553
550
  data = Cucumber::MultilineArgument::DataTable.from(
554
551
  ::Gherkin::DIALECTS.keys.map do |key|
555
552
  [key, ::Gherkin::DIALECTS[key].fetch('name'), ::Gherkin::DIALECTS[key].fetch('native')]
556
- end)
557
- @out_stream.write(data.to_s({ color: false, prefixes: Hash.new('') }))
553
+ end
554
+ )
555
+ @out_stream.write(data.to_s(color: false, prefixes: Hash.new('')))
558
556
  Kernel.exit(0)
559
557
  end
560
558
 
@@ -568,23 +566,22 @@ TEXT
568
566
 
569
567
  def default_options
570
568
  {
571
- :strict => Cucumber::Core::Test::Result::StrictConfiguration.new,
572
- :require => [],
573
- :dry_run => false,
574
- :formats => [],
575
- :excludes => [],
576
- :tag_expressions => [],
577
- :tag_limits => {},
578
- :name_regexps => [],
579
- :env_vars => {},
580
- :diff_enabled => true,
581
- :snippets => true,
582
- :source => true,
583
- :duration => true,
584
- :retry => 0
569
+ strict: Cucumber::Core::Test::Result::StrictConfiguration.new,
570
+ require: [],
571
+ dry_run: false,
572
+ formats: [],
573
+ excludes: [],
574
+ tag_expressions: [],
575
+ tag_limits: {},
576
+ name_regexps: [],
577
+ env_vars: {},
578
+ diff_enabled: true,
579
+ snippets: true,
580
+ source: true,
581
+ duration: true,
582
+ retry: 0
585
583
  }
586
584
  end
587
585
  end
588
-
589
586
  end
590
587
  end