cucumber 3.1.2 → 8.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 (125) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1880 -1146
  3. data/CONTRIBUTING.md +220 -61
  4. data/README.md +143 -22
  5. data/bin/cucumber +1 -1
  6. data/lib/autotest/cucumber_mixin.rb +49 -53
  7. data/lib/autotest/discover.rb +3 -2
  8. data/lib/cucumber/cli/configuration.rb +32 -7
  9. data/lib/cucumber/cli/main.rb +16 -15
  10. data/lib/cucumber/cli/options.rb +111 -79
  11. data/lib/cucumber/cli/profile_loader.rb +45 -26
  12. data/lib/cucumber/cli/rerun_file.rb +1 -1
  13. data/lib/cucumber/configuration.rb +47 -31
  14. data/lib/cucumber/constantize.rb +3 -6
  15. data/lib/cucumber/deprecate.rb +32 -7
  16. data/lib/cucumber/errors.rb +5 -7
  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 +12 -0
  20. data/lib/cucumber/events/step_activated.rb +0 -5
  21. data/lib/cucumber/events/step_definition_registered.rb +0 -5
  22. data/lib/cucumber/events/test_case_created.rb +12 -0
  23. data/lib/cucumber/events/test_case_ready.rb +12 -0
  24. data/lib/cucumber/events/test_run_finished.rb +2 -1
  25. data/lib/cucumber/events/test_step_created.rb +12 -0
  26. data/lib/cucumber/events/undefined_parameter_type.rb +9 -0
  27. data/lib/cucumber/events.rb +15 -8
  28. data/lib/cucumber/file_specs.rb +8 -7
  29. data/lib/cucumber/filters/activate_steps.rb +6 -3
  30. data/lib/cucumber/filters/broadcast_test_case_ready_event.rb +12 -0
  31. data/lib/cucumber/filters/prepare_world.rb +5 -9
  32. data/lib/cucumber/filters/quit.rb +1 -3
  33. data/lib/cucumber/filters/tag_limits/verifier.rb +3 -7
  34. data/lib/cucumber/filters/tag_limits.rb +1 -3
  35. data/lib/cucumber/filters.rb +1 -0
  36. data/lib/cucumber/formatter/ansicolor.rb +74 -86
  37. data/lib/cucumber/formatter/ast_lookup.rb +163 -0
  38. data/lib/cucumber/formatter/backtrace_filter.rb +10 -7
  39. data/lib/cucumber/formatter/console.rb +76 -68
  40. data/lib/cucumber/formatter/console_counts.rb +4 -9
  41. data/lib/cucumber/formatter/console_issues.rb +12 -4
  42. data/lib/cucumber/formatter/duration.rb +1 -1
  43. data/lib/cucumber/formatter/duration_extractor.rb +4 -1
  44. data/lib/cucumber/formatter/errors.rb +7 -0
  45. data/lib/cucumber/formatter/fanout.rb +3 -1
  46. data/lib/cucumber/formatter/html.rb +11 -598
  47. data/lib/cucumber/formatter/http_io.rb +152 -0
  48. data/lib/cucumber/formatter/ignore_missing_messages.rb +2 -2
  49. data/lib/cucumber/formatter/interceptor.rb +11 -30
  50. data/lib/cucumber/formatter/io.rb +57 -13
  51. data/lib/cucumber/formatter/json.rb +119 -124
  52. data/lib/cucumber/formatter/junit.rb +75 -55
  53. data/lib/cucumber/formatter/message.rb +23 -0
  54. data/lib/cucumber/formatter/message_builder.rb +256 -0
  55. data/lib/cucumber/formatter/pretty.rb +370 -153
  56. data/lib/cucumber/formatter/progress.rb +31 -32
  57. data/lib/cucumber/formatter/publish_banner_printer.rb +77 -0
  58. data/lib/cucumber/formatter/query/hook_by_test_step.rb +32 -0
  59. data/lib/cucumber/formatter/query/pickle_by_test.rb +26 -0
  60. data/lib/cucumber/formatter/query/pickle_step_by_test_step.rb +26 -0
  61. data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +40 -0
  62. data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +42 -0
  63. data/lib/cucumber/formatter/rerun.rb +24 -4
  64. data/lib/cucumber/formatter/stepdefs.rb +1 -2
  65. data/lib/cucumber/formatter/steps.rb +8 -6
  66. data/lib/cucumber/formatter/summary.rb +17 -8
  67. data/lib/cucumber/formatter/unicode.rb +18 -20
  68. data/lib/cucumber/formatter/url_reporter.rb +17 -0
  69. data/lib/cucumber/formatter/usage.rb +18 -15
  70. data/lib/cucumber/gherkin/data_table_parser.rb +18 -6
  71. data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +14 -18
  72. data/lib/cucumber/gherkin/formatter/escaping.rb +2 -2
  73. data/lib/cucumber/gherkin/steps_parser.rb +17 -8
  74. data/lib/cucumber/glue/dsl.rb +29 -15
  75. data/lib/cucumber/glue/hook.rb +37 -11
  76. data/lib/cucumber/glue/invoke_in_world.rb +17 -22
  77. data/lib/cucumber/glue/proto_world.rb +47 -53
  78. data/lib/cucumber/glue/registry_and_more.rb +62 -17
  79. data/lib/cucumber/glue/registry_wrapper.rb +31 -0
  80. data/lib/cucumber/glue/snippet.rb +23 -22
  81. data/lib/cucumber/glue/step_definition.rb +48 -23
  82. data/lib/cucumber/glue/world_factory.rb +1 -1
  83. data/lib/cucumber/hooks.rb +12 -11
  84. data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +4 -3
  85. data/lib/cucumber/multiline_argument/data_table.rb +143 -123
  86. data/lib/cucumber/multiline_argument/doc_string.rb +1 -1
  87. data/lib/cucumber/multiline_argument.rb +4 -6
  88. data/lib/cucumber/platform.rb +5 -5
  89. data/lib/cucumber/rake/task.rb +34 -25
  90. data/lib/cucumber/rspec/disable_option_parser.rb +15 -11
  91. data/lib/cucumber/rspec/doubles.rb +3 -5
  92. data/lib/cucumber/running_test_case.rb +3 -53
  93. data/lib/cucumber/runtime/after_hooks.rb +8 -4
  94. data/lib/cucumber/runtime/before_hooks.rb +8 -4
  95. data/lib/cucumber/runtime/for_programming_languages.rb +4 -2
  96. data/lib/cucumber/runtime/meta_message_builder.rb +106 -0
  97. data/lib/cucumber/runtime/step_hooks.rb +6 -2
  98. data/lib/cucumber/runtime/support_code.rb +16 -15
  99. data/lib/cucumber/runtime/user_interface.rb +10 -19
  100. data/lib/cucumber/runtime.rb +78 -76
  101. data/lib/cucumber/step_definition_light.rb +4 -3
  102. data/lib/cucumber/step_definitions.rb +2 -2
  103. data/lib/cucumber/step_match.rb +17 -20
  104. data/lib/cucumber/step_match_search.rb +5 -3
  105. data/lib/cucumber/term/ansicolor.rb +72 -48
  106. data/lib/cucumber/term/banner.rb +57 -0
  107. data/lib/cucumber/version +1 -1
  108. data/lib/cucumber.rb +3 -2
  109. data/lib/simplecov_setup.rb +1 -1
  110. metadata +279 -81
  111. data/lib/cucumber/core_ext/string.rb +0 -11
  112. data/lib/cucumber/events/gherkin_source_parsed.rb~ +0 -14
  113. data/lib/cucumber/formatter/ast_lookup.rb~ +0 -9
  114. data/lib/cucumber/formatter/cucumber.css +0 -286
  115. data/lib/cucumber/formatter/cucumber.sass +0 -247
  116. data/lib/cucumber/formatter/hook_query_visitor.rb +0 -42
  117. data/lib/cucumber/formatter/html_builder.rb +0 -121
  118. data/lib/cucumber/formatter/inline-js.js +0 -30
  119. data/lib/cucumber/formatter/jquery-min.js +0 -154
  120. data/lib/cucumber/formatter/json_pretty.rb +0 -11
  121. data/lib/cucumber/formatter/legacy_api/adapter.rb +0 -1028
  122. data/lib/cucumber/formatter/legacy_api/ast.rb +0 -394
  123. data/lib/cucumber/formatter/legacy_api/results.rb +0 -50
  124. data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +0 -32
  125. data/lib/cucumber/step_argument.rb +0 -25
@@ -3,7 +3,6 @@
3
3
  require 'forwardable'
4
4
  require 'cucumber/gherkin/data_table_parser'
5
5
  require 'cucumber/gherkin/formatter/escaping'
6
- require 'cucumber/core/ast/describes_itself'
7
6
  require 'cucumber/multiline_argument/data_table/diff_matrices'
8
7
 
9
8
  module Cucumber
@@ -28,19 +27,21 @@ module Cucumber
28
27
  # This will store <tt>[['a', 'b'], ['c', 'd']]</tt> in the <tt>data</tt> variable.
29
28
  #
30
29
  class DataTable
31
- include Core::Ast::DescribesItself
32
-
33
- def self.default_arg_name #:nodoc:
30
+ def self.default_arg_name # :nodoc:
34
31
  'table'
35
32
  end
36
33
 
34
+ def describe_to(visitor, *args)
35
+ visitor.legacy_table(self, *args)
36
+ end
37
+
37
38
  class << self
38
- def from(data, location = Core::Ast::Location.of_caller)
39
+ def from(data)
39
40
  case data
40
41
  when Array
41
- from_array(data, location)
42
+ from_array(data)
42
43
  when String
43
- parse(data, location)
44
+ parse(data)
44
45
  else
45
46
  raise ArgumentError, 'expected data to be a String or an Array.'
46
47
  end
@@ -48,15 +49,15 @@ module Cucumber
48
49
 
49
50
  private
50
51
 
51
- def parse(text, location = Core::Ast::Location.of_caller)
52
+ def parse(text)
52
53
  builder = Builder.new
53
54
  parser = Cucumber::Gherkin::DataTableParser.new(builder)
54
55
  parser.parse(text)
55
- from_array(builder.rows, location)
56
+ from_array(builder.rows)
56
57
  end
57
58
 
58
- def from_array(data, location = Core::Ast::Location.of_caller)
59
- new Core::Ast::DataTable.new(data, location)
59
+ def from_array(data)
60
+ new Core::Test::DataTable.new(data)
60
61
  end
61
62
  end
62
63
 
@@ -71,18 +72,18 @@ module Cucumber
71
72
  @rows << row
72
73
  end
73
74
 
74
- def eof
75
- end
75
+ def eof; end
76
76
  end
77
77
 
78
- NULL_CONVERSIONS = Hash.new({ :strict => false, :proc => lambda { |cell_value| cell_value } }).freeze
78
+ NULL_CONVERSIONS = Hash.new(strict: false, proc: ->(cell_value) { cell_value }).freeze
79
79
 
80
- # @param data [Core::Ast::DataTable] the data for the table
81
- # @param conversion_procs [Hash] see map_columns!
82
- # @param header_mappings [Hash] see map_headers!
83
- # @param header_conversion_proc [Proc] see map_headers!
80
+ # @param data [Core::Test::DataTable] the data for the table
81
+ # @param conversion_procs [Hash] see map_column
82
+ # @param header_mappings [Hash] see map_headers
83
+ # @param header_conversion_proc [Proc] see map_headers
84
84
  def initialize(data, conversion_procs = NULL_CONVERSIONS.dup, header_mappings = {}, header_conversion_proc = nil)
85
- raise ArgumentError, 'data must be a Core::Ast::DataTable' unless data.is_a? Core::Ast::DataTable
85
+ raise ArgumentError, 'data must be a Core::Test::DataTable' unless data.is_a? Core::Test::DataTable
86
+
86
87
  ast_table = data
87
88
  # Verify that it's square
88
89
  ast_table.transpose
@@ -107,13 +108,6 @@ module Cucumber
107
108
  @ast_table.location
108
109
  end
109
110
 
110
- # Creates a copy of this table, inheriting any column and header mappings
111
- # registered with #map_column! and #map_headers!.
112
- #
113
- def dup
114
- self.class.new(Core::Ast::DataTable.new(raw, location), @conversion_procs.dup, @header_mappings.dup, @header_conversion_proc)
115
- end
116
-
117
111
  # Returns a new, transposed table. Example:
118
112
  #
119
113
  # | a | 7 | 4 |
@@ -126,7 +120,7 @@ module Cucumber
126
120
  # | 4 | 2 |
127
121
  #
128
122
  def transpose
129
- self.class.new(Core::Ast::DataTable.new(raw.transpose, location), @conversion_procs.dup, @header_mappings.dup, @header_conversion_proc)
123
+ self.class.new(Core::Test::DataTable.new(raw.transpose), @conversion_procs.dup, @header_mappings.dup, @header_conversion_proc)
130
124
  end
131
125
 
132
126
  # Converts this table into an Array of Hash where the keys of each
@@ -141,7 +135,7 @@ module Cucumber
141
135
  #
142
136
  # [{'a' => '2', 'b' => '3', 'sum' => '5'}, {'a' => '7', 'b' => '9', 'sum' => '16'}]
143
137
  #
144
- # Use #map_column! to specify how values in a column are converted.
138
+ # Use #map_column to specify how values in a column are converted.
145
139
  #
146
140
  def hashes
147
141
  @hashes ||= build_hashes
@@ -160,8 +154,8 @@ module Cucumber
160
154
  #
161
155
  def symbolic_hashes
162
156
  @symbolic_hashes ||=
163
- self.hashes.map do |string_hash|
164
- Hash[string_hash.map { |a, b| [symbolize_key(a), b] }]
157
+ hashes.map do |string_hash|
158
+ string_hash.transform_keys { |a| symbolize_key(a) }
165
159
  end
166
160
  end
167
161
 
@@ -179,8 +173,9 @@ module Cucumber
179
173
  #
180
174
  def rows_hash
181
175
  return @rows_hash if @rows_hash
176
+
182
177
  verify_table_width(2)
183
- @rows_hash = self.transpose.hashes[0]
178
+ @rows_hash = transpose.hashes[0]
184
179
  end
185
180
 
186
181
  # Gets the raw data of this table. For example, a Table built from
@@ -199,8 +194,8 @@ module Cucumber
199
194
  end
200
195
  end
201
196
 
202
- def column_names #:nodoc:
203
- @col_names ||= cell_matrix[0].map(&:value)
197
+ def column_names # :nodoc:
198
+ @column_names ||= cell_matrix[0].map(&:value)
204
199
  end
205
200
 
206
201
  def rows
@@ -209,7 +204,7 @@ module Cucumber
209
204
  end
210
205
  end
211
206
 
212
- def each_cells_row(&proc) #:nodoc:
207
+ def each_cells_row(&proc) # :nodoc:
213
208
  cells_rows.each(&proc)
214
209
  end
215
210
 
@@ -228,7 +223,8 @@ module Cucumber
228
223
  pattern.match(header_to_match)
229
224
  end
230
225
 
231
- # Redefines the table headers. This makes it possible to use
226
+ # Returns a new Table where the headers are redefined.
227
+ # This makes it possible to use
232
228
  # prettier and more flexible header names in the features. The
233
229
  # keys of +mappings+ are Strings or regular expressions
234
230
  # (anything that responds to #=== will work) that may match
@@ -244,57 +240,44 @@ module Cucumber
244
240
  # A StepDefinition receiving this table can then map the columns
245
241
  # with both Regexp and String:
246
242
  #
247
- # table.map_headers!(/phone( number)?/i => :phone, 'Address' => :address)
243
+ # table.map_headers(/phone( number)?/i => :phone, 'Address' => :address)
248
244
  # table.hashes
249
245
  # # => [{:phone => '123456', :address => 'xyz'}, {:phone => '345678', :address => 'abc'}]
250
246
  #
251
247
  # You may also pass in a block if you wish to convert all of the headers:
252
248
  #
253
- # table.map_headers! { |header| header.downcase }
249
+ # table.map_headers { |header| header.downcase }
254
250
  # table.hashes.keys
255
251
  # # => ['phone number', 'address']
256
252
  #
257
253
  # When a block is passed in along with a hash then the mappings in the hash take precendence:
258
254
  #
259
- # table.map_headers!('Address' => 'ADDRESS') { |header| header.downcase }
255
+ # table.map_headers('Address' => 'ADDRESS') { |header| header.downcase }
260
256
  # table.hashes.keys
261
257
  # # => ['phone number', 'ADDRESS']
262
258
  #
263
- def map_headers!(mappings = {}, &block)
264
- # TODO: Remove this method for 2.0
265
- clear_cache!
266
- @header_mappings = mappings
267
- @header_conversion_proc = block
268
- end
269
-
270
- # Returns a new Table where the headers are redefined. See #map_headers!
271
259
  def map_headers(mappings = {}, &block)
272
- self.class.new(Core::Ast::DataTable.new(raw, location), @conversion_procs.dup, mappings, block)
260
+ self.class.new(Core::Test::DataTable.new(raw), @conversion_procs.dup, mappings, block)
273
261
  end
274
262
 
263
+ # Returns a new Table with an additional column mapping.
264
+ #
275
265
  # Change how #hashes converts column values. The +column_name+ argument identifies the column
276
266
  # and +conversion_proc+ performs the conversion for each cell in that column. If +strict+ is
277
267
  # true, an error will be raised if the column named +column_name+ is not found. If +strict+
278
268
  # is false, no error will be raised. Example:
279
269
  #
280
270
  # Given /^an expense report for (.*) with the following posts:$/ do |table|
281
- # posts_table.map_column!('amount') { |a| a.to_i }
271
+ # posts_table = posts_table.map_column('amount') { |a| a.to_i }
282
272
  # posts_table.hashes.each do |post|
283
273
  # # post['amount'] is a Fixnum, rather than a String
284
274
  # end
285
275
  # end
286
276
  #
287
- def map_column!(column_name, strict = true, &conversion_proc)
288
- # TODO: Remove this method for 2.0
289
- @conversion_procs[column_name.to_s] = { :strict => strict, :proc => conversion_proc }
290
- self
291
- end
292
-
293
- # Returns a new Table with an additional column mapping. See #map_column!
294
- def map_column(column_name, strict = true, &conversion_proc)
277
+ def map_column(column_name, strict: true, &conversion_proc)
295
278
  conversion_procs = @conversion_procs.dup
296
- conversion_procs[column_name.to_s] = { :strict => strict, :proc => conversion_proc }
297
- self.class.new(Core::Ast::DataTable.new(raw, location), conversion_procs, @header_mappings.dup, @header_conversion_proc)
279
+ conversion_procs[column_name.to_s] = { strict: strict, proc: conversion_proc }
280
+ self.class.new(Core::Test::DataTable.new(raw), conversion_procs, @header_mappings.dup, @header_conversion_proc)
298
281
  end
299
282
 
300
283
  # Compares +other_table+ to self. If +other_table+ contains columns
@@ -312,8 +295,8 @@ module Cucumber
312
295
  # where the difference actually is.
313
296
  #
314
297
  # Since all tables that are passed to StepDefinitions always have String
315
- # objects in their cells, you may want to use #map_column! before calling
316
- # #diff!. You can use #map_column! on either of the tables.
298
+ # objects in their cells, you may want to use #map_column before calling
299
+ # #diff!. You can use #map_column on either of the tables.
317
300
  #
318
301
  # A Different error is raised if there are missing rows or columns, or
319
302
  # surplus rows. An error is <em>not</em> raised for surplus columns. An
@@ -346,15 +329,20 @@ module Cucumber
346
329
 
347
330
  class Different < StandardError
348
331
  attr_reader :table
332
+
349
333
  def initialize(table)
350
334
  @table = table
351
335
  super("Tables were not identical:\n#{table}")
352
336
  end
353
337
  end
354
338
 
355
- def to_hash(cells) #:nodoc:
356
- hash = Hash.new do |hash, key|
357
- hash[key.to_s] if key.is_a?(Symbol)
339
+ def to_hash
340
+ cells_rows.map { |cells| cells.map(&:value) }
341
+ end
342
+
343
+ def cells_to_hash(cells) # :nodoc:
344
+ hash = Hash.new do |hash_inner, key|
345
+ hash_inner[key.to_s] if key.is_a?(Symbol)
358
346
  end
359
347
  column_names.each_with_index do |column_name, column_index|
360
348
  hash[column_name] = cells.value(column_index)
@@ -362,66 +350,90 @@ module Cucumber
362
350
  hash
363
351
  end
364
352
 
365
- def index(cells) #:nodoc:
353
+ def index(cells) # :nodoc:
366
354
  cells_rows.index(cells)
367
355
  end
368
356
 
369
- def verify_column(column_name) #:nodoc:
370
- raise %{The column named "#{column_name}" does not exist} unless raw[0].include?(column_name)
357
+ def verify_column(column_name) # :nodoc:
358
+ raise %(The column named "#{column_name}" does not exist) unless raw[0].include?(column_name)
371
359
  end
372
360
 
373
- def verify_table_width(width) #:nodoc:
374
- raise %{The table must have exactly #{width} columns} unless raw[0].size == width
361
+ def verify_table_width(width) # :nodoc:
362
+ raise %(The table must have exactly #{width} columns) unless raw[0].size == width
375
363
  end
376
364
 
377
- def has_text?(text) #:nodoc:
365
+ # TODO: remove the below function if it's not actually being used.
366
+ # Nothing else in this repo calls it.
367
+ def text?(text) # :nodoc:
378
368
  raw.flatten.compact.detect { |cell_value| cell_value.index(text) }
379
369
  end
380
370
 
381
- def cells_rows #:nodoc:
382
- @rows ||= cell_matrix.map do |cell_row|
371
+ def cells_rows # :nodoc:
372
+ @rows ||= cell_matrix.map do |cell_row| # rubocop:disable Naming/MemoizedInstanceVariableName
383
373
  Cells.new(self, cell_row)
384
374
  end
385
375
  end
386
376
 
387
- def headers #:nodoc:
377
+ def headers # :nodoc:
388
378
  raw.first
389
379
  end
390
380
 
391
- def header_cell(col) #:nodoc:
381
+ def header_cell(col) # :nodoc:
392
382
  cells_rows[0][col]
393
383
  end
394
384
 
395
385
  attr_reader :cell_matrix
396
386
 
397
- def col_width(col) #:nodoc:
387
+ def col_width(col) # :nodoc:
398
388
  columns[col].__send__(:width)
399
389
  end
400
390
 
401
- def to_s(options = {}) #:nodoc:
402
- # TODO: factor out this code so we don't depend on such a big lump of old cruft
403
- require 'cucumber/formatter/pretty'
404
- require 'cucumber/formatter/legacy_api/adapter'
405
- options = {:color => true, :indent => 2, :prefixes => TO_S_PREFIXES}.merge(options)
406
- io = StringIO.new
407
-
408
- c = Cucumber::Term::ANSIColor.coloring?
409
- Cucumber::Term::ANSIColor.coloring = options[:color]
410
- runtime = Struct.new(:configuration).new(Configuration.new)
411
- formatter = Formatter::Pretty.new(runtime, io, options)
412
- formatter.instance_variable_set('@indent', options[:indent])
413
- Formatter::LegacyApi::Ast::MultilineArg.for(self).accept(Formatter::Fanout.new([formatter]))
414
- Cucumber::Term::ANSIColor.coloring = c
415
- io.rewind
416
- s = "\n" + io.read + (' ' * (options[:indent] - 2))
417
- s
391
+ def to_s(options = {}) # :nodoc:
392
+ indentation = options.key?(:indent) ? options[:indent] : 2
393
+ prefixes = options.key?(:prefixes) ? options[:prefixes] : TO_S_PREFIXES
394
+ DataTablePrinter.new(self, indentation, prefixes).to_s
418
395
  end
419
396
 
420
- def description_for_visitors
421
- :legacy_table
397
+ class DataTablePrinter # :nodoc:
398
+ include Cucumber::Gherkin::Formatter::Escaping
399
+ attr_reader :data_table, :indentation, :prefixes
400
+ private :data_table, :indentation, :prefixes
401
+
402
+ def initialize(data_table, indentation, prefixes)
403
+ @data_table = data_table
404
+ @indentation = indentation
405
+ @prefixes = prefixes
406
+ end
407
+
408
+ def to_s
409
+ leading_row = "\n"
410
+ end_indentation = indentation - 2
411
+ trailing_row = "\n#{' ' * end_indentation}"
412
+ table_rows = data_table.cell_matrix.map { |row| format_row(row) }
413
+ leading_row + table_rows.join("\n") + trailing_row
414
+ end
415
+
416
+ private
417
+
418
+ def format_row(row)
419
+ row_start = "#{' ' * indentation}| "
420
+ row_end = '|'
421
+ cells = row.map.with_index do |cell, i|
422
+ format_cell(cell, data_table.col_width(i))
423
+ end
424
+ row_start + cells.join('| ') + row_end
425
+ end
426
+
427
+ def format_cell(cell, col_width)
428
+ cell_text = escape_cell(cell.value.to_s)
429
+ cell_text_width = cell_text.unpack('U*').length
430
+ padded_text = cell_text + (' ' * (col_width - cell_text_width))
431
+ prefix = prefixes[cell.status]
432
+ "#{prefix}#{padded_text} "
433
+ end
422
434
  end
423
435
 
424
- def columns #:nodoc:
436
+ def columns # :nodoc:
425
437
  @columns ||= cell_matrix.transpose.map do |cell_row|
426
438
  Cells.new(self, cell_row)
427
439
  end
@@ -441,19 +453,23 @@ module Cucumber
441
453
  def build_hashes
442
454
  convert_headers!
443
455
  convert_columns!
444
- cells_rows[1..-1].map(&:to_hash)
456
+ cells_rows[1..].map(&:to_hash)
445
457
  end
446
458
 
447
- def create_cell_matrix(ast_table) #:nodoc:
459
+ def create_cell_matrix(ast_table) # :nodoc:
448
460
  ast_table.raw.map do |raw_row|
449
- line = raw_row.line rescue -1
461
+ line = begin
462
+ raw_row.line
463
+ rescue StandardError
464
+ -1
465
+ end
450
466
  raw_row.map do |raw_cell|
451
467
  Cell.new(raw_cell, self, line)
452
468
  end
453
469
  end
454
470
  end
455
471
 
456
- def convert_columns! #:nodoc:
472
+ def convert_columns! # :nodoc:
457
473
  @conversion_procs.each do |column_name, conversion_proc|
458
474
  verify_column(column_name) if conversion_proc[:strict]
459
475
  end
@@ -461,13 +477,13 @@ module Cucumber
461
477
  cell_matrix.transpose.each do |col|
462
478
  column_name = col[0].value
463
479
  conversion_proc = @conversion_procs[column_name][:proc]
464
- col[1..-1].each do |cell|
480
+ col[1..].each do |cell|
465
481
  cell.value = conversion_proc.call(cell.value)
466
482
  end
467
483
  end
468
484
  end
469
485
 
470
- def convert_headers! #:nodoc:
486
+ def convert_headers! # :nodoc:
471
487
  header_cells = cell_matrix[0]
472
488
 
473
489
  if @header_conversion_proc
@@ -476,22 +492,22 @@ module Cucumber
476
492
  end
477
493
 
478
494
  @header_mappings.each_pair do |pre, post|
479
- mapped_cells = header_cells.select { |cell| pre === cell.value }
495
+ mapped_cells = header_cells.select { |cell| pre.is_a?(Regexp) ? cell.value.match?(pre) : cell.value == pre }
480
496
  raise "No headers matched #{pre.inspect}" if mapped_cells.empty?
481
497
  raise "#{mapped_cells.length} headers matched #{pre.inspect}: #{mapped_cells.map(&:value).inspect}" if mapped_cells.length > 1
498
+
482
499
  mapped_cells[0].value = post
483
- if @conversion_procs.key?(pre)
484
- @conversion_procs[post] = @conversion_procs.delete(pre)
485
- end
500
+ @conversion_procs[post] = @conversion_procs.delete(pre) if @conversion_procs.key?(pre)
486
501
  end
487
502
  end
488
503
 
489
- def clear_cache! #:nodoc:
490
- @hashes = @rows_hash = @col_names = @rows = @columns = nil
504
+ def clear_cache! # :nodoc:
505
+ @hashes = @rows_hash = @column_names = @rows = @columns = nil
491
506
  end
492
507
 
493
- def ensure_table(table_or_array) #:nodoc:
494
- return table_or_array if DataTable === table_or_array
508
+ def ensure_table(table_or_array) # :nodoc:
509
+ return table_or_array if DataTable == table_or_array.class
510
+
495
511
  DataTable.from(table_or_array)
496
512
  end
497
513
 
@@ -500,18 +516,20 @@ module Cucumber
500
516
  end
501
517
 
502
518
  # Represents a row of cells or columns of cells
503
- class Cells #:nodoc:
519
+ class Cells # :nodoc:
504
520
  include Enumerable
505
521
  include Cucumber::Gherkin::Formatter::Escaping
506
522
 
507
523
  attr_reader :exception
508
524
 
509
525
  def initialize(table, cells)
510
- @table, @cells = table, cells
526
+ @table = table
527
+ @cells = cells
511
528
  end
512
529
 
513
530
  def accept(visitor)
514
531
  return if Cucumber.wants_to_quit
532
+
515
533
  each do |cell|
516
534
  visitor.visit_table_cell(cell)
517
535
  end
@@ -519,15 +537,15 @@ module Cucumber
519
537
  end
520
538
 
521
539
  # For testing only
522
- def to_sexp #:nodoc:
540
+ def to_sexp # :nodoc:
523
541
  [:row, line, *@cells.map(&:to_sexp)]
524
542
  end
525
543
 
526
- def to_hash #:nodoc:
527
- @to_hash ||= @table.to_hash(self)
544
+ def to_hash # :nodoc:
545
+ @to_hash ||= @table.cells_to_hash(self)
528
546
  end
529
547
 
530
- def value(n) #:nodoc:
548
+ def value(n) # :nodoc:
531
549
  self[n].value
532
550
  end
533
551
 
@@ -558,24 +576,26 @@ module Cucumber
558
576
  end
559
577
  end
560
578
 
561
- class Cell #:nodoc:
579
+ class Cell # :nodoc:
562
580
  attr_reader :line, :table
563
581
  attr_accessor :status, :value
564
582
 
565
583
  def initialize(value, table, line)
566
- @value, @table, @line = value, table, line
584
+ @value = value
585
+ @table = table
586
+ @line = line
567
587
  end
568
588
 
569
589
  def inspect!
570
590
  @value = "(i) #{value.inspect}"
571
591
  end
572
592
 
573
- def ==(o)
574
- SurplusCell === o || value == o.value
593
+ def ==(other)
594
+ SurplusCell == other.class || value == other.value
575
595
  end
576
596
 
577
- def eql?(o)
578
- self == o
597
+ def eql?(other)
598
+ self == other
579
599
  end
580
600
 
581
601
  def hash
@@ -583,17 +603,17 @@ module Cucumber
583
603
  end
584
604
 
585
605
  # For testing only
586
- def to_sexp #:nodoc:
606
+ def to_sexp # :nodoc:
587
607
  [:cell, @value]
588
608
  end
589
609
  end
590
610
 
591
- class SurplusCell < Cell #:nodoc:
611
+ class SurplusCell < Cell # :nodoc:
592
612
  def status
593
613
  :comment
594
614
  end
595
615
 
596
- def ==(_o)
616
+ def ==(_other)
597
617
  true
598
618
  end
599
619
 
@@ -4,7 +4,7 @@ module Cucumber
4
4
  module MultilineArgument
5
5
  class DocString < SimpleDelegator
6
6
  def append_to(array)
7
- array << self.to_s
7
+ array << to_s
8
8
  end
9
9
  end
10
10
  end
@@ -12,10 +12,10 @@ module Cucumber
12
12
  end
13
13
 
14
14
  def from(argument, location = nil, content_type = nil)
15
- location ||= Core::Ast::Location.of_caller
15
+ location ||= Core::Test::Location.of_caller
16
16
  case argument
17
17
  when String
18
- builder.doc_string(Core::Ast::DocString.new(argument, content_type, location))
18
+ builder.doc_string(Core::Test::DocString.new(argument, content_type))
19
19
  when Array
20
20
  location = location.on_line(argument.first.line..argument.last.line)
21
21
  builder.data_table(argument.map(&:cells), location)
@@ -52,11 +52,9 @@ module Cucumber
52
52
  end
53
53
 
54
54
  class None
55
- def append_to(array)
56
- end
55
+ def append_to(array); end
57
56
 
58
- def describe_to(visitor)
59
- end
57
+ def describe_to(visitor); end
60
58
  end
61
59
  end
62
60
  end
@@ -7,9 +7,9 @@ require 'cucumber/core/platform'
7
7
 
8
8
  module Cucumber
9
9
  unless defined?(Cucumber::VERSION)
10
- VERSION = File.read(File.expand_path('../version', __FILE__))
11
- BINARY = File.expand_path(File.dirname(__FILE__) + '/../../bin/cucumber')
12
- LIBDIR = File.expand_path(File.dirname(__FILE__) + '/../../lib')
10
+ VERSION = File.read(File.expand_path('version', __dir__)).strip
11
+ BINARY = File.expand_path("#{File.dirname(__FILE__)}/../../bin/cucumber")
12
+ LIBDIR = File.expand_path("#{File.dirname(__FILE__)}/../../lib")
13
13
  RAILS = defined?(Rails)
14
14
  RUBY_BINARY = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
15
15
  RUBY = defined? RUBY_VERSION
@@ -18,8 +18,8 @@ module Cucumber
18
18
  attr_accessor :use_full_backtrace
19
19
 
20
20
  # @private
21
- def file_mode(m, encoding = 'UTF-8')
22
- "#{m}:#{encoding}"
21
+ def file_mode(mode, encoding = 'UTF-8')
22
+ "#{mode}:#{encoding}"
23
23
  end
24
24
  end
25
25
  self.use_full_backtrace = false