cucumber 3.1.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 (112) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +173 -14
  3. data/CONTRIBUTING.md +2 -18
  4. data/README.md +4 -5
  5. data/bin/cucumber +1 -1
  6. data/lib/autotest/cucumber_mixin.rb +34 -39
  7. data/lib/cucumber.rb +1 -1
  8. data/lib/cucumber/cli/configuration.rb +5 -5
  9. data/lib/cucumber/cli/main.rb +12 -12
  10. data/lib/cucumber/cli/options.rb +69 -74
  11. data/lib/cucumber/cli/profile_loader.rb +49 -26
  12. data/lib/cucumber/configuration.rb +31 -23
  13. data/lib/cucumber/constantize.rb +2 -5
  14. data/lib/cucumber/deprecate.rb +31 -7
  15. data/lib/cucumber/errors.rb +5 -7
  16. data/lib/cucumber/events.rb +13 -6
  17. data/lib/cucumber/events/envelope.rb +9 -0
  18. data/lib/cucumber/events/gherkin_source_parsed.rb +11 -0
  19. data/lib/cucumber/events/hook_test_step_created.rb +13 -0
  20. data/lib/cucumber/events/step_activated.rb +2 -1
  21. data/lib/cucumber/events/test_case_created.rb +13 -0
  22. data/lib/cucumber/events/test_case_ready.rb +12 -0
  23. data/lib/cucumber/events/test_step_created.rb +13 -0
  24. data/lib/cucumber/events/undefined_parameter_type.rb +10 -0
  25. data/lib/cucumber/file_specs.rb +6 -6
  26. data/lib/cucumber/filters.rb +1 -0
  27. data/lib/cucumber/filters/activate_steps.rb +5 -3
  28. data/lib/cucumber/filters/broadcast_test_case_ready_event.rb +12 -0
  29. data/lib/cucumber/filters/prepare_world.rb +5 -9
  30. data/lib/cucumber/filters/quit.rb +1 -3
  31. data/lib/cucumber/filters/tag_limits/verifier.rb +2 -4
  32. data/lib/cucumber/formatter/ansicolor.rb +40 -45
  33. data/lib/cucumber/formatter/ast_lookup.rb +165 -0
  34. data/lib/cucumber/formatter/backtrace_filter.rb +9 -8
  35. data/lib/cucumber/formatter/console.rb +58 -66
  36. data/lib/cucumber/formatter/console_counts.rb +4 -9
  37. data/lib/cucumber/formatter/console_issues.rb +6 -3
  38. data/lib/cucumber/formatter/duration.rb +1 -1
  39. data/lib/cucumber/formatter/duration_extractor.rb +3 -1
  40. data/lib/cucumber/formatter/errors.rb +6 -0
  41. data/lib/cucumber/formatter/fanout.rb +2 -0
  42. data/lib/cucumber/formatter/html.rb +11 -598
  43. data/lib/cucumber/formatter/http_io.rb +146 -0
  44. data/lib/cucumber/formatter/ignore_missing_messages.rb +1 -1
  45. data/lib/cucumber/formatter/interceptor.rb +8 -28
  46. data/lib/cucumber/formatter/io.rb +17 -11
  47. data/lib/cucumber/formatter/json.rb +101 -109
  48. data/lib/cucumber/formatter/junit.rb +56 -56
  49. data/lib/cucumber/formatter/message.rb +22 -0
  50. data/lib/cucumber/formatter/message_builder.rb +255 -0
  51. data/lib/cucumber/formatter/pretty.rb +359 -153
  52. data/lib/cucumber/formatter/progress.rb +30 -32
  53. data/lib/cucumber/formatter/query/hook_by_test_step.rb +31 -0
  54. data/lib/cucumber/formatter/query/pickle_by_test.rb +26 -0
  55. data/lib/cucumber/formatter/query/pickle_step_by_test_step.rb +26 -0
  56. data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +40 -0
  57. data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +40 -0
  58. data/lib/cucumber/formatter/rerun.rb +22 -4
  59. data/lib/cucumber/formatter/stepdefs.rb +1 -2
  60. data/lib/cucumber/formatter/steps.rb +2 -3
  61. data/lib/cucumber/formatter/summary.rb +16 -8
  62. data/lib/cucumber/formatter/unicode.rb +15 -17
  63. data/lib/cucumber/formatter/usage.rb +11 -10
  64. data/lib/cucumber/gherkin/data_table_parser.rb +17 -6
  65. data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +13 -17
  66. data/lib/cucumber/gherkin/formatter/escaping.rb +2 -2
  67. data/lib/cucumber/gherkin/steps_parser.rb +17 -8
  68. data/lib/cucumber/glue/dsl.rb +1 -1
  69. data/lib/cucumber/glue/hook.rb +34 -11
  70. data/lib/cucumber/glue/invoke_in_world.rb +13 -18
  71. data/lib/cucumber/glue/proto_world.rb +42 -33
  72. data/lib/cucumber/glue/registry_and_more.rb +42 -12
  73. data/lib/cucumber/glue/snippet.rb +23 -22
  74. data/lib/cucumber/glue/step_definition.rb +42 -19
  75. data/lib/cucumber/glue/world_factory.rb +1 -1
  76. data/lib/cucumber/hooks.rb +11 -11
  77. data/lib/cucumber/multiline_argument.rb +4 -6
  78. data/lib/cucumber/multiline_argument/data_table.rb +97 -64
  79. data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +1 -1
  80. data/lib/cucumber/multiline_argument/doc_string.rb +1 -1
  81. data/lib/cucumber/platform.rb +3 -3
  82. data/lib/cucumber/rake/task.rb +16 -16
  83. data/lib/cucumber/rspec/disable_option_parser.rb +9 -8
  84. data/lib/cucumber/running_test_case.rb +2 -53
  85. data/lib/cucumber/runtime.rb +54 -58
  86. data/lib/cucumber/runtime/after_hooks.rb +8 -4
  87. data/lib/cucumber/runtime/before_hooks.rb +8 -4
  88. data/lib/cucumber/runtime/for_programming_languages.rb +4 -2
  89. data/lib/cucumber/runtime/step_hooks.rb +3 -2
  90. data/lib/cucumber/runtime/support_code.rb +13 -15
  91. data/lib/cucumber/runtime/user_interface.rb +6 -16
  92. data/lib/cucumber/step_definition_light.rb +4 -3
  93. data/lib/cucumber/step_definitions.rb +2 -2
  94. data/lib/cucumber/step_match.rb +12 -11
  95. data/lib/cucumber/step_match_search.rb +2 -1
  96. data/lib/cucumber/term/ansicolor.rb +9 -9
  97. data/lib/cucumber/version +1 -1
  98. metadata +224 -82
  99. data/lib/cucumber/events/gherkin_source_parsed.rb~ +0 -14
  100. data/lib/cucumber/formatter/ast_lookup.rb~ +0 -9
  101. data/lib/cucumber/formatter/cucumber.css +0 -286
  102. data/lib/cucumber/formatter/cucumber.sass +0 -247
  103. data/lib/cucumber/formatter/hook_query_visitor.rb +0 -42
  104. data/lib/cucumber/formatter/html_builder.rb +0 -121
  105. data/lib/cucumber/formatter/inline-js.js +0 -30
  106. data/lib/cucumber/formatter/jquery-min.js +0 -154
  107. data/lib/cucumber/formatter/json_pretty.rb +0 -11
  108. data/lib/cucumber/formatter/legacy_api/adapter.rb +0 -1028
  109. data/lib/cucumber/formatter/legacy_api/ast.rb +0 -394
  110. data/lib/cucumber/formatter/legacy_api/results.rb +0 -50
  111. data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +0 -32
  112. data/lib/cucumber/step_argument.rb +0 -25
@@ -17,7 +17,7 @@ module Cucumber
17
17
  @matches = {}
18
18
  config.on_event :step_activated do |event|
19
19
  test_step, step_match = *event.attributes
20
- @matches[test_step.source] = step_match
20
+ @matches[test_step.to_s] = step_match
21
21
  end
22
22
  config.on_event :step_definition_registered, &method(:on_step_definition_registered)
23
23
  end
@@ -28,25 +28,26 @@ module Cucumber
28
28
  end
29
29
 
30
30
  def on_step_match(event)
31
- @matches[event.test_step.source] = event.step_match
31
+ @matches[event.test_step.to_s] = event.step_match
32
32
  super
33
33
  end
34
34
 
35
35
  def on_test_step_finished(event)
36
- return if HookQueryVisitor.new(event.test_step).hook?
36
+ return if event.test_step.hook?
37
37
 
38
38
  test_step = event.test_step
39
39
  result = event.result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)
40
- step_match = @matches[test_step.source]
40
+ step_match = @matches[test_step.to_s]
41
41
 
42
42
  unless step_match.nil?
43
43
  step_definition = step_match.step_definition
44
44
  stepdef_key = StepDefKey.new(step_definition.expression.to_s, step_definition.location)
45
45
  unless @stepdef_to_match[stepdef_key].map { |key| key[:location] }.include? test_step.location
46
46
  duration = DurationExtractor.new(result).result_duration
47
+ keyword = @ast_lookup.step_source(test_step).step.keyword
47
48
 
48
49
  @stepdef_to_match[stepdef_key] << {
49
- keyword: test_step.source.last.keyword,
50
+ keyword: keyword,
50
51
  step_match: step_match,
51
52
  status: result.to_sym,
52
53
  location: test_step.location,
@@ -64,9 +65,9 @@ module Cucumber
64
65
  aggregate_info
65
66
 
66
67
  keys = if config.dry_run?
67
- @stepdef_to_match.keys.sort { |a, b| a.regexp_source <=> b.regexp_source }
68
+ @stepdef_to_match.keys.sort_by(&:regexp_source)
68
69
  else
69
- @stepdef_to_match.keys.sort { |a, b| a.mean_duration <=> b.mean_duration }.reverse
70
+ @stepdef_to_match.keys.sort_by(&:mean_duration).reverse
70
71
  end
71
72
 
72
73
  keys.each do |stepdef_key|
@@ -83,7 +84,7 @@ module Cucumber
83
84
  end
84
85
 
85
86
  def print_step_definition(stepdef_key)
86
- @io.print format_string(format('%.7f', stepdef_key.mean_duration), :skipped) + ' ' unless config.dry_run?
87
+ @io.print format_string(format('%<duration>.7f', duration: stepdef_key.mean_duration), :skipped) + ' ' unless config.dry_run?
87
88
  @io.print format_string(stepdef_key.regexp_source, stepdef_key.status)
88
89
  if config.source?
89
90
  indent = max_length - stepdef_key.regexp_source.unpack('U*').length
@@ -96,7 +97,7 @@ module Cucumber
96
97
  def print_steps(stepdef_key)
97
98
  @stepdef_to_match[stepdef_key].each do |step|
98
99
  @io.print ' '
99
- @io.print format_string(format('%.7f', step[:duration]), :skipped) + ' ' unless config.dry_run?
100
+ @io.print format_string(format('%<duration>.7f', duration: step[:duration]), :skipped) + ' ' unless config.dry_run?
100
101
  @io.print format_step(step[:keyword], step[:step_match], step[:status], nil)
101
102
  if config.source?
102
103
  indent = max_length - (step[:keyword].unpack('U*').length + step[:step_match].format_args.unpack('U*').length)
@@ -135,7 +136,7 @@ module Cucumber
135
136
  end
136
137
 
137
138
  def worst_status(statuses)
138
- [:passed, :undefined, :pending, :skipped, :failed].find do |status|
139
+ %i[passed undefined pending skipped failed].find do |status|
139
140
  statuses.include?(status)
140
141
  end
141
142
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'gherkin/token_scanner'
4
- require 'gherkin/parser'
3
+ require 'gherkin'
5
4
  require 'gherkin/dialect'
6
5
 
7
6
  module Cucumber
@@ -12,15 +11,27 @@ module Cucumber
12
11
  end
13
12
 
14
13
  def parse(text)
15
- token_scanner = ::Gherkin::TokenScanner.new(feature_header + text)
16
- parser = ::Gherkin::Parser.new
17
- gherkin_document = parser.parse(token_scanner)
14
+ gherkin_document = nil
15
+ messages = ::Gherkin.from_source('dummy', feature_header + text, gherkin_options)
18
16
 
19
- gherkin_document[:feature][:children][0][:steps][0][:argument][:rows].each do |row|
17
+ messages.each do |message|
18
+ gherkin_document = message.gherkin_document.to_hash unless message.gherkin_document.nil?
19
+ end
20
+
21
+ return if gherkin_document.nil?
22
+ gherkin_document[:feature][:children][0][:scenario][:steps][0][:data_table][:rows].each do |row|
20
23
  @builder.row(row[:cells].map { |cell| cell[:value] })
21
24
  end
22
25
  end
23
26
 
27
+ def gherkin_options
28
+ {
29
+ include_source: false,
30
+ include_gherkin_document: true,
31
+ include_pickles: false
32
+ }
33
+ end
34
+
24
35
  def feature_header
25
36
  dialect = ::Gherkin::Dialect.for('en')
26
37
  %(#{dialect.feature_keywords[0]}:
@@ -51,23 +51,21 @@ module Cucumber
51
51
  'white' => "\e[37m",
52
52
  'grey' => "\e[90m",
53
53
  'bold' => "\e[1m"
54
- }
54
+ }.freeze
55
55
 
56
56
  ALIASES = Hash.new do |h, k|
57
- if k.to_s =~ /(.*)_arg/
58
- h[$1] + ',bold'
59
- end
60
- end.merge({
61
- 'undefined' => 'yellow',
62
- 'pending' => 'yellow',
63
- 'executing' => 'grey',
64
- 'failed' => 'red',
65
- 'passed' => 'green',
66
- 'outline' => 'cyan',
67
- 'skipped' => 'cyan',
68
- 'comments' => 'grey',
69
- 'tag' => 'cyan'
70
- })
57
+ h[Regexp.last_match(1)] + ',bold' if k.to_s =~ /(.*)_arg/
58
+ end.merge(
59
+ 'undefined' => 'yellow',
60
+ 'pending' => 'yellow',
61
+ 'executing' => 'grey',
62
+ 'failed' => 'red',
63
+ 'passed' => 'green',
64
+ 'outline' => 'cyan',
65
+ 'skipped' => 'cyan',
66
+ 'comments' => 'grey',
67
+ 'tag' => 'cyan'
68
+ )
71
69
 
72
70
  if ENV['GHERKIN_COLORS'] # Example: export GHERKIN_COLORS="passed=red:failed=yellow"
73
71
  ENV['GHERKIN_COLORS'].split(':').each do |pair|
@@ -93,8 +91,6 @@ module Cucumber
93
91
  def up(n)
94
92
  "\e[#{n}A"
95
93
  end
96
-
97
- extend self
98
94
  end
99
95
  end
100
96
  end
@@ -10,8 +10,8 @@ module Cucumber
10
10
  # * \ becomes \\
11
11
  #
12
12
  # This is used in the pretty formatter.
13
- def escape_cell(s)
14
- s.gsub(/\\(?!\|)/, '\\\\\\\\').gsub(/\n/, '\\n').gsub(/\|/, '\\|')
13
+ def escape_cell(sym)
14
+ sym.gsub(/\\(?!\|)/, '\\\\\\\\').gsub(/\n/, '\\n').gsub(/\|/, '\\|')
15
15
  end
16
16
  end
17
17
  end
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'gherkin/token_scanner'
4
- require 'gherkin/token_matcher'
5
- require 'gherkin/parser'
3
+ require 'gherkin'
6
4
  require 'gherkin/dialect'
7
5
 
8
6
  module Cucumber
@@ -15,12 +13,23 @@ module Cucumber
15
13
 
16
14
  def parse(text)
17
15
  dialect = ::Gherkin::Dialect.for(@language)
18
- token_matcher = ::Gherkin::TokenMatcher.new(@language)
19
- token_scanner = ::Gherkin::TokenScanner.new(feature_header(dialect) + text)
20
- parser = ::Gherkin::Parser.new
21
- gherkin_document = parser.parse(token_scanner, token_matcher)
16
+ gherkin_document = nil
17
+ messages = ::Gherkin.from_source('dummy', feature_header(dialect) + text, gherkin_options)
22
18
 
23
- @builder.steps(gherkin_document[:feature][:children][0][:steps])
19
+ messages.each do |message|
20
+ gherkin_document = message.gherkin_document.to_hash unless message.gherkin_document.nil?
21
+ end
22
+
23
+ @builder.steps(gherkin_document[:feature][:children][0][:scenario][:steps])
24
+ end
25
+
26
+ def gherkin_options
27
+ {
28
+ default_dialect: @language,
29
+ include_source: false,
30
+ include_gherkin_document: true,
31
+ include_pickles: false
32
+ }
24
33
  end
25
34
 
26
35
  def feature_header(dialect)
@@ -137,4 +137,4 @@ module Cucumber
137
137
  end
138
138
 
139
139
  # TODO: can we avoid adding methods to the global namespace (Kernel)
140
- extend(Cucumber::Glue::Dsl)
140
+ extend(Cucumber::Glue::Dsl) # rubocop:disable Style/MixinUsage
@@ -6,14 +6,15 @@ module Cucumber
6
6
  module Glue
7
7
  # TODO: Kill pointless wrapper for Before, After and AfterStep hooks with fire
8
8
  class Hook
9
- attr_reader :tag_expressions, :location
9
+ attr_reader :id, :tag_expressions, :location
10
10
 
11
- def initialize(registry, tag_expressions, proc)
11
+ def initialize(id, registry, tag_expressions, proc)
12
+ @id = id
12
13
  @registry = registry
13
- @tag_expressions = tag_expressions
14
+ @tag_expressions = sanitize_tag_expressions(tag_expressions)
14
15
  @proc = proc
15
- @location = Cucumber::Core::Ast::Location.from_source_location(*@proc.source_location)
16
- warn_for_old_style_tag_expressions(tag_expressions)
16
+ @location = Cucumber::Core::Test::Location.from_source_location(*@proc.source_location)
17
+ fail_for_old_style_tag_expressions(@tag_expressions)
17
18
  end
18
19
 
19
20
  def invoke(pseudo_method, arguments, &block)
@@ -27,16 +28,38 @@ module Cucumber
27
28
  )
28
29
  end
29
30
 
31
+ def to_envelope
32
+ Cucumber::Messages::Envelope.new(
33
+ hook: Cucumber::Messages::Hook.new(
34
+ id: id,
35
+ tag_expression: tag_expressions.join(' '),
36
+ source_reference: Cucumber::Messages::SourceReference.new(
37
+ uri: location.file,
38
+ location: Cucumber::Messages::Location.new(
39
+ line: location.lines.first
40
+ )
41
+ )
42
+ )
43
+ )
44
+ end
45
+
30
46
  private
31
47
 
32
- def warn_for_old_style_tag_expressions(tag_expressions)
48
+ def sanitize_tag_expressions(tag_expressions)
49
+ # TODO: remove when '~@no-clobber' has been changed to 'not @no-clobber' in aruba
50
+ tag_expressions.map { |tag_expression| tag_expression == '~@no-clobber' ? 'not @no-clobber' : tag_expression }
51
+ end
52
+
53
+ def fail_for_old_style_tag_expressions(tag_expressions)
33
54
  tag_expressions.each do |tag_expression|
34
- if tag_expression.include?('~') && tag_expression != '~@no-clobber' # ~@no-clobber is used in aruba
35
- warn("Deprecated: Found tagged hook with '#{tag_expression}'. Support for '~@tag' will be removed from the next release of Cucumber. Please use 'not @tag' instead.")
36
- end
37
- if tag_expression.include?(',')
38
- warn("Deprecated: Found tagged hook with '#{tag_expression}'. Support for '@tag1,@tag2' will be removed from the next release of Cucumber. Please use '@tag or @tag2' instead.")
55
+ if tag_expression.include?('~')
56
+ raise("Found tagged hook with '#{tag_expression}'." \
57
+ "'~@tag' is no longer supported, use 'not @tag' instead.")
39
58
  end
59
+
60
+ next unless tag_expression.include?(',')
61
+ warn("Found tagged hook with '#{tag_expression}'." \
62
+ "'@tag1,@tag2' is no longer supported, use '@tag or @tag2' instead.")
40
63
  end
41
64
  end
42
65
  end
@@ -11,16 +11,15 @@ module Cucumber
11
11
  return if Cucumber.use_full_backtrace
12
12
 
13
13
  instance_exec_pos = backtrace.index(instance_exec_invocation_line)
14
- if instance_exec_pos
15
- replacement_line = instance_exec_pos + INSTANCE_EXEC_OFFSET
16
- backtrace[replacement_line].gsub!(/`.*'/, "`#{pseudo_method}'") if pseudo_method
14
+ return unless instance_exec_pos
15
+ replacement_line = instance_exec_pos + INSTANCE_EXEC_OFFSET
16
+ backtrace[replacement_line].gsub!(/`.*'/, "`#{pseudo_method}'") if pseudo_method
17
17
 
18
- depth = backtrace.count { |line| line == instance_exec_invocation_line }
19
- end_pos = depth > 1 ? instance_exec_pos : -1
18
+ depth = backtrace.count { |line| line == instance_exec_invocation_line }
19
+ end_pos = depth > 1 ? instance_exec_pos : -1
20
20
 
21
- backtrace[replacement_line + 1..end_pos] = nil
22
- backtrace.compact!
23
- end
21
+ backtrace[replacement_line + 1..end_pos] = nil
22
+ backtrace.compact!
24
23
  end
25
24
 
26
25
  def self.cucumber_instance_exec_in(world, check_arity, pseudo_method, *args, &block)
@@ -31,9 +30,7 @@ module Cucumber
31
30
  ari = ari < 0 ? (ari.abs - 1).to_s + '+' : ari
32
31
  s1 = ari == 1 ? '' : 's'
33
32
  s2 = args.length == 1 ? '' : 's'
34
- raise ArityMismatchError.new(
35
- "Your block takes #{ari} argument#{s1}, but the Regexp matched #{args.length} argument#{s2}."
36
- )
33
+ raise ArityMismatchError, "Your block takes #{ari} argument#{s1}, but the Regexp matched #{args.length} argument#{s2}."
37
34
  end
38
35
  else
39
36
  world.instance_exec(*args, &block)
@@ -50,13 +47,11 @@ module Cucumber
50
47
  end
51
48
 
52
49
  def self.cucumber_run_with_backtrace_filtering(pseudo_method)
53
- begin
54
- yield
55
- rescue Exception => e
56
- instance_exec_invocation_line = "#{__FILE__}:#{__LINE__ - 2}:in `cucumber_run_with_backtrace_filtering'"
57
- replace_instance_exec_invocation_line!((e.backtrace || []), instance_exec_invocation_line, pseudo_method)
58
- raise e
59
- end
50
+ yield
51
+ rescue Exception => e # rubocop:disable Lint/RescueException
52
+ instance_exec_invocation_line = "#{__FILE__}:#{__LINE__ - 2}:in `cucumber_run_with_backtrace_filtering'"
53
+ replace_instance_exec_invocation_line!((e.backtrace || []), instance_exec_invocation_line, pseudo_method)
54
+ raise e
60
55
  end
61
56
 
62
57
  INSTANCE_EXEC_OFFSET = -3
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'cucumber/gherkin/formatter/ansi_escapes'
4
- require 'cucumber/core/ast/data_table'
4
+ require 'cucumber/core/test/data_table'
5
+ require 'cucumber/deprecate'
5
6
 
6
7
  module Cucumber
7
8
  module Glue
@@ -24,7 +25,7 @@ module Cucumber
24
25
  # @example Passing a multiline string
25
26
  # step "the email should contain:", "Dear sir,\nYou've won a prize!\n"
26
27
  # @param [String] name The name of the step
27
- # @param [String,Cucumber::Ast::DocString,Cucumber::Ast::Table] multiline_argument
28
+ # @param [String,Cucumber::Test::DocString,Cucumber::Ast::Table] multiline_argument
28
29
  def step(name, raw_multiline_arg = nil)
29
30
  super
30
31
  end
@@ -67,9 +68,8 @@ module Cucumber
67
68
  # %w{ CUC-101 Peeler 22 }
68
69
  # ])
69
70
  #
70
- def table(text_or_table, file = nil, line = 0)
71
- location = !file ? Core::Ast::Location.of_caller : Core::Ast::Location.new(file, line)
72
- MultilineArgument::DataTable.from(text_or_table, location)
71
+ def table(text_or_table)
72
+ MultilineArgument::DataTable.from(text_or_table)
73
73
  end
74
74
 
75
75
  # Print a message to the output.
@@ -80,7 +80,16 @@ module Cucumber
80
80
  #
81
81
  # If you'd prefer to see the message immediately, call {Kernel.puts} instead.
82
82
  def puts(*messages)
83
- super
83
+ Cucumber.deprecate(
84
+ 'Messages emitted with "puts" will no longer be caught by Cucumber ' \
85
+ 'and sent to the formatter. If you want message to be in the formatted output, ' \
86
+ "please use log(message) instead.\n" \
87
+ 'If you simply want it in the console, '\
88
+ 'keep using "puts" (or Kernel.puts to avoid this message)',
89
+ 'puts(message)',
90
+ '5.0.0'
91
+ )
92
+ messages.each { |message| log(message.to_s) }
84
93
  end
85
94
 
86
95
  # Pause the tests and ask the operator for input
@@ -89,22 +98,33 @@ module Cucumber
89
98
  end
90
99
 
91
100
  # Embed an image in the output
92
- def embed(file, mime_type, label = 'Screenshot')
101
+ def embed(file, mime_type, _label = 'Screenshot')
102
+ Cucumber.deprecate(
103
+ 'Please use attach(file, media_type) instead',
104
+ 'embed(file, mime_type, label)',
105
+ '5.0.0'
106
+ )
107
+ attach(file, mime_type)
108
+ end
109
+
110
+ def log(*messages)
111
+ messages.each { |message| attach(message.to_s.dup, 'text/x.cucumber.log+plain') }
112
+ end
113
+
114
+ def attach(file, media_type)
93
115
  super
94
116
  end
95
117
 
96
118
  # Mark the matched step as pending.
97
119
  def pending(message = 'TODO')
98
- if block_given?
99
- begin
100
- yield
101
- rescue Exception
102
- raise Pending, message
103
- end
104
- raise Pending, "Expected pending '#{message}' to fail. No Error was raised. No longer pending?"
105
- else
120
+ raise Pending, message unless block_given?
121
+
122
+ begin
123
+ yield
124
+ rescue Exception # rubocop:disable Lint/RescueException
106
125
  raise Pending, message
107
126
  end
127
+ raise Pending, "Expected pending '#{message}' to fail. No Error was raised. No longer pending?"
108
128
  end
109
129
 
110
130
  # Skips this step and the remaining steps in the scenario
@@ -123,8 +143,8 @@ module Cucumber
123
143
  end
124
144
 
125
145
  # Dynamially generate the API module, closuring the dependencies
126
- def self.for(runtime, language)
127
- Module.new do
146
+ def self.for(runtime, language) # rubocop:disable Metrics/MethodLength
147
+ Module.new do # rubocop:disable Metrics/BlockLength
128
148
  def self.extended(object)
129
149
  # wrap the dynamically generated module so that we can document the methods
130
150
  # for yardoc, which doesn't like define_method.
@@ -139,32 +159,21 @@ module Cucumber
139
159
  end
140
160
 
141
161
  define_method(:step) do |name, raw_multiline_arg = nil|
142
- location = Core::Ast::Location.of_caller
162
+ location = Core::Test::Location.of_caller
143
163
  runtime.invoke_dynamic_step(name, MultilineArgument.from(raw_multiline_arg, location))
144
164
  end
145
165
 
146
166
  define_method(:steps) do |steps_text|
147
- location = Core::Ast::Location.of_caller
167
+ location = Core::Test::Location.of_caller
148
168
  runtime.invoke_dynamic_steps(steps_text, language, location)
149
169
  end
150
170
 
151
- # rubocop:disable UnneededInterpolation
152
- define_method(:puts) do |*messages|
153
- # Even though they won't be output until later, converting the messages to
154
- # strings right away will protect them from modifications to their original
155
- # objects in the mean time
156
- messages.collect! { |message| "#{message}" }
157
-
158
- runtime.puts(*messages)
159
- end
160
- # rubocop:enable UnneededInterpolation
161
-
162
171
  define_method(:ask) do |question, timeout_seconds = 60|
163
172
  runtime.ask(question, timeout_seconds)
164
173
  end
165
174
 
166
- define_method(:embed) do |file, mime_type, label = 'Screenshot'|
167
- runtime.embed(file, mime_type, label)
175
+ define_method(:attach) do |file, media_type|
176
+ runtime.attach(file, media_type)
168
177
  end
169
178
 
170
179
  # Prints the list of modules that are included in the World
@@ -174,7 +183,7 @@ module Cucumber
174
183
  modules += included_modules
175
184
  end
176
185
  modules << stringify_namespaced_modules
177
- format('#<%s:0x%x>', modules.join('+'), self.object_id)
186
+ format('#<%<modules>s:0x%<object_id>x>', modules: modules.join('+'), object_id: object_id)
178
187
  end
179
188
 
180
189
  private