cucumber 1.2.1 → 1.2.2

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 (172) hide show
  1. data/.rvmrc +1 -1
  2. data/.travis.yml +3 -2
  3. data/DEVELOPERS.md +48 -0
  4. data/History.md +22 -3
  5. data/README.md +13 -31
  6. data/Rakefile +1 -0
  7. data/cucumber.gemspec +18 -17
  8. data/cucumber.yml +3 -2
  9. data/examples/i18n/cs/Rakefile +6 -0
  10. data/examples/i18n/cs/features/addition.feature +17 -0
  11. data/examples/i18n/cs/features/division.feature +11 -0
  12. data/examples/i18n/cs/features/step_definitons/calculator_steps.rb +24 -0
  13. data/examples/i18n/cs/lib/calculator.rb +14 -0
  14. data/examples/i18n/hi/Rakefile +6 -0
  15. data/examples/i18n/hi/features/addition.feature +16 -0
  16. data/examples/i18n/hi/features/division.feature +10 -0
  17. data/examples/i18n/hi/features/step_definitons/calculator_steps.rb +24 -0
  18. data/examples/i18n/hi/lib/calculator.rb +15 -0
  19. data/examples/python/README.textile +2 -1
  20. data/examples/ruby2python/README.textile +2 -1
  21. data/features/.cucumber/stepdefs.json +1688 -445
  22. data/features/assertions.feature +69 -0
  23. data/features/formatter_callbacks.feature +189 -0
  24. data/features/html_formatter.feature +19 -0
  25. data/features/json_formatter.feature +8 -4
  26. data/features/nested_steps_with_second_arg.feature +73 -0
  27. data/features/step_definitions.feature +65 -0
  28. data/features/step_definitions/cucumber_steps.rb +18 -3
  29. data/fixtures/self_test/features/support/env.rb +1 -1
  30. data/gem_tasks/cucumber.rake +5 -3
  31. data/gem_tasks/downloads.rb +3 -3
  32. data/gem_tasks/stats +4 -2
  33. data/gem_tasks/yard.rake +31 -13
  34. data/legacy_features/default_snippets.feature +3 -3
  35. data/legacy_features/language_help.feature +4 -0
  36. data/legacy_features/report_called_undefined_steps.feature +1 -1
  37. data/legacy_features/snippet.feature +3 -3
  38. data/legacy_features/snippets_when_using_star_keyword.feature +1 -1
  39. data/legacy_features/step_definitions/cucumber_steps.rb +4 -3
  40. data/legacy_features/support/env.rb +1 -1
  41. data/legacy_features/support/fake_wire_server.rb +9 -9
  42. data/lib/autotest/cucumber_mixin.rb +14 -14
  43. data/lib/autotest/discover.rb +2 -0
  44. data/lib/cucumber.rb +2 -2
  45. data/lib/cucumber/ast.rb +1 -1
  46. data/lib/cucumber/ast/background.rb +11 -7
  47. data/lib/cucumber/ast/comment.rb +2 -2
  48. data/lib/cucumber/ast/doc_string.rb +1 -1
  49. data/lib/cucumber/ast/examples.rb +1 -1
  50. data/lib/cucumber/ast/feature.rb +2 -2
  51. data/lib/cucumber/ast/feature_element.rb +1 -1
  52. data/lib/cucumber/ast/multiline_argument.rb +2 -2
  53. data/lib/cucumber/ast/names.rb +2 -2
  54. data/lib/cucumber/ast/outline_table.rb +4 -5
  55. data/lib/cucumber/ast/scenario.rb +14 -14
  56. data/lib/cucumber/ast/scenario_outline.rb +4 -4
  57. data/lib/cucumber/ast/step.rb +3 -3
  58. data/lib/cucumber/ast/step_collection.rb +5 -5
  59. data/lib/cucumber/ast/step_invocation.rb +8 -8
  60. data/lib/cucumber/ast/table.rb +40 -27
  61. data/lib/cucumber/ast/tree_walker.rb +9 -8
  62. data/lib/cucumber/ast/visitor.rb +1 -1
  63. data/lib/cucumber/cli/configuration.rb +10 -10
  64. data/lib/cucumber/cli/drb_client.rb +1 -1
  65. data/lib/cucumber/cli/main.rb +3 -3
  66. data/lib/cucumber/cli/options.rb +3 -2
  67. data/lib/cucumber/cli/profile_loader.rb +1 -1
  68. data/lib/cucumber/configuration.rb +12 -12
  69. data/lib/cucumber/constantize.rb +11 -2
  70. data/lib/cucumber/core_ext/disable_mini_and_test_unit_autorun.rb +1 -1
  71. data/lib/cucumber/core_ext/instance_exec.rb +4 -4
  72. data/lib/cucumber/core_ext/proc.rb +3 -3
  73. data/lib/cucumber/errors.rb +1 -1
  74. data/lib/cucumber/feature_file.rb +1 -1
  75. data/lib/cucumber/formatter/ansicolor.rb +36 -23
  76. data/lib/cucumber/formatter/console.rb +45 -25
  77. data/lib/cucumber/formatter/debug.rb +7 -7
  78. data/lib/cucumber/formatter/duration.rb +1 -1
  79. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +7 -0
  80. data/lib/cucumber/formatter/gpretty.rb +1 -1
  81. data/lib/cucumber/formatter/html.rb +52 -53
  82. data/lib/cucumber/formatter/interceptor.rb +2 -2
  83. data/lib/cucumber/formatter/json.rb +1 -1
  84. data/lib/cucumber/formatter/json_pretty.rb +2 -1
  85. data/lib/cucumber/formatter/junit.rb +1 -1
  86. data/lib/cucumber/formatter/ordered_xml_markup.rb +1 -1
  87. data/lib/cucumber/formatter/pretty.rb +12 -12
  88. data/lib/cucumber/formatter/progress.rb +5 -5
  89. data/lib/cucumber/formatter/rerun.rb +5 -5
  90. data/lib/cucumber/formatter/stepdefs.rb +1 -1
  91. data/lib/cucumber/formatter/steps.rb +6 -6
  92. data/lib/cucumber/formatter/summary.rb +6 -6
  93. data/lib/cucumber/formatter/unicode.rb +18 -18
  94. data/lib/cucumber/formatter/usage.rb +7 -7
  95. data/lib/cucumber/js_support/js_dsl.js +1 -1
  96. data/lib/cucumber/language_support.rb +1 -1
  97. data/lib/cucumber/parser/gherkin_builder.rb +33 -33
  98. data/lib/cucumber/platform.rb +3 -2
  99. data/lib/cucumber/py_support/py_dsl.py +2 -2
  100. data/lib/cucumber/py_support/py_language.py +2 -2
  101. data/lib/cucumber/py_support/py_language.rb +2 -2
  102. data/lib/cucumber/rake/task.rb +4 -3
  103. data/lib/cucumber/rb_support/rb_dsl.rb +10 -10
  104. data/lib/cucumber/rb_support/rb_language.rb +27 -19
  105. data/lib/cucumber/rb_support/rb_step_definition.rb +39 -11
  106. data/lib/cucumber/rb_support/rb_transform.rb +3 -3
  107. data/lib/cucumber/rb_support/rb_world.rb +15 -15
  108. data/lib/cucumber/rb_support/regexp_argument_matcher.rb +1 -1
  109. data/lib/cucumber/rspec/disable_option_parser.rb +1 -1
  110. data/lib/cucumber/rspec/doubles.rb +1 -1
  111. data/lib/cucumber/runtime.rb +11 -10
  112. data/lib/cucumber/runtime/features_loader.rb +6 -6
  113. data/lib/cucumber/runtime/for_programming_languages.rb +8 -15
  114. data/lib/cucumber/runtime/results.rb +6 -6
  115. data/lib/cucumber/runtime/support_code.rb +37 -28
  116. data/lib/cucumber/runtime/user_interface.rb +4 -4
  117. data/lib/cucumber/step_definition_light.rb +4 -4
  118. data/lib/cucumber/step_definitions.rb +2 -3
  119. data/lib/cucumber/step_match.rb +6 -6
  120. data/lib/cucumber/step_mother.rb +1 -1
  121. data/lib/cucumber/term/ansicolor.rb +22 -22
  122. data/lib/cucumber/wire_support/configuration.rb +11 -14
  123. data/lib/cucumber/wire_support/connection.rb +10 -9
  124. data/lib/cucumber/wire_support/request_handler.rb +3 -3
  125. data/lib/cucumber/wire_support/wire_exception.rb +3 -3
  126. data/lib/cucumber/wire_support/wire_language.rb +11 -11
  127. data/lib/cucumber/wire_support/wire_packet.rb +7 -5
  128. data/lib/cucumber/wire_support/wire_protocol.rb +6 -6
  129. data/lib/cucumber/wire_support/wire_protocol/requests.rb +20 -20
  130. data/lib/cucumber/wire_support/wire_step_definition.rb +4 -4
  131. data/spec/cucumber/ast/background_spec.rb +4 -4
  132. data/spec/cucumber/ast/doc_string_spec.rb +8 -8
  133. data/spec/cucumber/ast/feature_factory.rb +4 -4
  134. data/spec/cucumber/ast/feature_spec.rb +18 -18
  135. data/spec/cucumber/ast/outline_table_spec.rb +3 -3
  136. data/spec/cucumber/ast/step_spec.rb +4 -4
  137. data/spec/cucumber/ast/table_spec.rb +50 -29
  138. data/spec/cucumber/ast/tree_walker_spec.rb +12 -4
  139. data/spec/cucumber/broadcaster_spec.rb +1 -1
  140. data/spec/cucumber/cli/configuration_spec.rb +10 -4
  141. data/spec/cucumber/cli/drb_client_spec.rb +1 -1
  142. data/spec/cucumber/cli/main_spec.rb +28 -7
  143. data/spec/cucumber/cli/options_spec.rb +3 -3
  144. data/spec/cucumber/configuration_spec.rb +4 -4
  145. data/spec/cucumber/constantize_spec.rb +2 -0
  146. data/spec/cucumber/core_ext/proc_spec.rb +7 -7
  147. data/spec/cucumber/formatter/ansicolor_spec.rb +2 -2
  148. data/spec/cucumber/formatter/duration_spec.rb +2 -2
  149. data/spec/cucumber/formatter/html_spec.rb +31 -31
  150. data/spec/cucumber/formatter/interceptor_spec.rb +10 -0
  151. data/spec/cucumber/formatter/progress_spec.rb +1 -1
  152. data/spec/cucumber/formatter/spec_helper.rb +7 -7
  153. data/spec/cucumber/rake/forked_spec.rb +15 -2
  154. data/spec/cucumber/rake/rcov_spec.rb +2 -2
  155. data/spec/cucumber/rb_support/rb_language_spec.rb +34 -17
  156. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +45 -35
  157. data/spec/cucumber/rb_support/rb_transform_spec.rb +3 -3
  158. data/spec/cucumber/runtime/for_programming_languages_spec.rb +31 -0
  159. data/spec/cucumber/runtime/results_spec.rb +5 -5
  160. data/spec/cucumber/runtime/support_code_spec.rb +13 -2
  161. data/spec/cucumber/runtime_spec.rb +7 -7
  162. data/spec/cucumber/step_match_spec.rb +2 -2
  163. data/spec/cucumber/wire_support/configuration_spec.rb +16 -6
  164. data/spec/cucumber/wire_support/connection_spec.rb +25 -11
  165. data/spec/cucumber/wire_support/wire_exception_spec.rb +3 -3
  166. data/spec/cucumber/wire_support/wire_language_spec.rb +3 -3
  167. data/spec/cucumber/wire_support/wire_packet_spec.rb +4 -4
  168. data/spec/cucumber/wire_support/wire_step_definition_spec.rb +1 -1
  169. data/spec/spec_helper.rb +2 -2
  170. metadata +98 -128
  171. data/legacy_features/html_formatter.feature +0 -8
  172. data/legacy_features/html_formatter/a.html +0 -561
@@ -22,10 +22,10 @@ module Cucumber
22
22
  visitor.visit_comment_line(line.strip)
23
23
  end
24
24
  end
25
-
25
+
26
26
  def to_sexp
27
27
  (@value.nil? || @value == '') ? nil : [:comment, @value]
28
28
  end
29
29
  end
30
30
  end
31
- end
31
+ end
@@ -38,7 +38,7 @@ module Cucumber
38
38
  return if Cucumber.wants_to_quit
39
39
  visitor.visit_doc_string(self)
40
40
  end
41
-
41
+
42
42
  def arguments_replaced(arguments) #:nodoc:
43
43
  string = self
44
44
  arguments.each do |name, value|
@@ -5,7 +5,7 @@ module Cucumber
5
5
  class Examples #:nodoc:
6
6
  include Names
7
7
  attr_writer :outline_table
8
-
8
+
9
9
  def initialize(comment, line, keyword, title, description, outline_table)
10
10
  @comment, @keyword, @title, @description, @outline_table = comment, keyword, title, description, outline_table
11
11
  end
@@ -5,7 +5,7 @@ module Cucumber
5
5
  # Represents the root node of a parsed feature.
6
6
  class Feature #:nodoc:
7
7
  include Names
8
-
8
+
9
9
  attr_accessor :language
10
10
  attr_writer :features, :background
11
11
  attr_reader :file, :feature_elements
@@ -80,7 +80,7 @@ module Cucumber
80
80
  file = file.gsub(/\//, '\\') if Cucumber::WINDOWS && file && !ENV['CUCUMBER_FORWARD_SLASH_PATHS']
81
81
  @file = file
82
82
  end
83
-
83
+
84
84
  def file_colon_line(line)
85
85
  "#{@file}:#{line}"
86
86
  end
@@ -65,7 +65,7 @@ module Cucumber
65
65
  def accept_hook?(hook)
66
66
  Gherkin::TagExpression.new(hook.tag_expressions).eval(source_tags)
67
67
  end
68
-
68
+
69
69
  def source_tag_names
70
70
  source_tags.map { |tag| tag.name }
71
71
  end
@@ -10,7 +10,7 @@ module Cucumber
10
10
  def from(argument)
11
11
  return unless argument
12
12
  return argument if argument.respond_to?(:to_step_definition_arg)
13
-
13
+
14
14
  case(rubify(argument))
15
15
  when String
16
16
  # TODO: this duplicates work that gherkin does. We should really pass the string to gherkin and let it parse it.
@@ -27,4 +27,4 @@ module Cucumber
27
27
  end
28
28
  end
29
29
  end
30
- end
30
+ end
@@ -2,7 +2,7 @@ module Cucumber
2
2
  module Ast
3
3
  module Names
4
4
  attr_reader :title, :description
5
-
5
+
6
6
  def name
7
7
  s = @title
8
8
  s += "\n#{@description}" if @description != ""
@@ -10,4 +10,4 @@ module Cucumber
10
10
  end
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -114,9 +114,9 @@ module Cucumber
114
114
  visitor.visit_table_cell(cell)
115
115
  end
116
116
  else
117
- visitor.step_mother.with_hooks(self) do
117
+ visitor.runtime.with_hooks(self) do
118
118
  @step_invocations.each do |step_invocation|
119
- step_invocation.invoke(visitor.step_mother, visitor.configuration)
119
+ step_invocation.invoke(visitor.runtime, visitor.configuration)
120
120
  @exception ||= step_invocation.reported_exception
121
121
  end
122
122
 
@@ -132,12 +132,11 @@ module Cucumber
132
132
  def accept_expand(visitor)
133
133
  if header?
134
134
  else
135
- visitor.step_mother.with_hooks(self) do
135
+ visitor.runtime.with_hooks(self) do
136
136
  @table.visit_scenario_name(visitor, self)
137
137
  @step_invocations.each do |step_invocation|
138
- step_invocation.invoke(visitor.step_mother, visitor.configuration)
138
+ visitor.visit_step(step_invocation)
139
139
  @exception ||= step_invocation.reported_exception
140
- step_invocation.visit_step_result(visitor)
141
140
  end
142
141
  end
143
142
  end
@@ -6,26 +6,26 @@ module Cucumber
6
6
  class Scenario #:nodoc:
7
7
  include FeatureElement
8
8
  include Names
9
-
9
+
10
10
  attr_reader :line
11
-
12
- class EmptyBackground
11
+
12
+ class EmptyBackground
13
13
  def failed?
14
14
  false
15
15
  end
16
-
16
+
17
17
  def feature_elements
18
18
  []
19
19
  end
20
-
20
+
21
21
  def step_collection(step_invocations)
22
22
  StepCollection.new(step_invocations)
23
23
  end
24
-
24
+
25
25
  def init
26
26
  end
27
27
  end
28
-
28
+
29
29
  def initialize(background, comment, tags, line, keyword, title, description, raw_steps)
30
30
  @background = background || EmptyBackground.new
31
31
  @comment, @tags, @line, @keyword, @title, @description, @raw_steps = comment, tags, line, keyword, title, description, raw_steps
@@ -43,14 +43,14 @@ module Cucumber
43
43
 
44
44
  def accept(visitor)
45
45
  return if Cucumber.wants_to_quit
46
-
46
+
47
47
  with_visitor(visitor) do
48
48
  visitor.visit_comment(@comment) unless @comment.empty?
49
49
  visitor.visit_tags(@tags)
50
50
  visitor.visit_scenario_name(@keyword, name, file_colon_line(@line), source_indent(first_line_length))
51
51
 
52
52
  skip_invoke! if @background.failed?
53
- visitor.step_mother.with_hooks(self, skip_hooks?) do
53
+ visitor.runtime.with_hooks(self, skip_hooks?) do
54
54
  skip_invoke! if failed?
55
55
  visitor.visit_steps(@steps)
56
56
  end
@@ -62,7 +62,7 @@ module Cucumber
62
62
  def failed?
63
63
  @steps.failed? || !!@exception
64
64
  end
65
-
65
+
66
66
  def fail!(exception)
67
67
  @exception = exception
68
68
  @current_visitor.visit_exception(@exception, :failed)
@@ -101,16 +101,16 @@ module Cucumber
101
101
  sexp += steps if steps.any?
102
102
  sexp
103
103
  end
104
-
105
-
104
+
105
+
106
106
  def with_visitor(visitor)
107
107
  @current_visitor = visitor
108
108
  yield
109
109
  @current_visitor = nil
110
110
  end
111
-
111
+
112
112
  private
113
-
113
+
114
114
  def skip_hooks?
115
115
  @background.failed? || @executed
116
116
  end
@@ -6,7 +6,7 @@ module Cucumber
6
6
  class ScenarioOutline #:nodoc:
7
7
  include FeatureElement
8
8
  include Names
9
-
9
+
10
10
  module ExamplesArray #:nodoc:
11
11
  def accept(visitor)
12
12
  return if Cucumber.wants_to_quit
@@ -38,7 +38,7 @@ module Cucumber
38
38
  @examples_array = @example_sections.map do |example_section_and_gherkin_examples|
39
39
  example_section = example_section_and_gherkin_examples[0]
40
40
  gherkin_examples = example_section_and_gherkin_examples[1]
41
-
41
+
42
42
  examples_comment = example_section[0]
43
43
  examples_line = example_section[1]
44
44
  examples_keyword = example_section[2]
@@ -98,8 +98,8 @@ module Cucumber
98
98
  def visit_scenario_name(visitor, row)
99
99
  visitor.visit_scenario_name(
100
100
  @feature.language.keywords('scenario')[0],
101
- row.name,
102
- file_colon_line(row.line),
101
+ row.name,
102
+ file_colon_line(row.line),
103
103
  source_indent(first_line_length)
104
104
  )
105
105
  end
@@ -9,7 +9,7 @@ module Cucumber
9
9
  attr_accessor :feature_element, :exception, :multiline_arg
10
10
 
11
11
  INDENT = 2
12
-
12
+
13
13
  def initialize(line, keyword, name, multiline_arg=nil)
14
14
  @line, @keyword, @name, @multiline_arg = line, keyword, name, multiline_arg
15
15
  end
@@ -48,7 +48,7 @@ module Cucumber
48
48
  # Otherwise it's always StepInvocation that gets visited instead.
49
49
  visit_step_result(visitor, first_match(visitor), @multiline_arg, :skipped, nil, nil)
50
50
  end
51
-
51
+
52
52
  def visit_step_result(visitor, step_match, multiline_arg, status, exception, background)
53
53
  visitor.visit_step_result(@keyword, step_match, @multiline_arg, status, exception, source_indent, background, file_colon_line)
54
54
  end
@@ -59,7 +59,7 @@ module Cucumber
59
59
  argument_hash = cells.to_hash
60
60
  delimited_arguments = delimit_argument_names(argument_hash)
61
61
  name = replace_name_arguments(delimited_arguments)
62
- step_match = visitor.step_mother.step_match(name, @name) rescue nil
62
+ step_match = visitor.runtime.step_match(name, @name) rescue nil
63
63
  return step_match if step_match
64
64
  end
65
65
  NoStepMatch.new(self, @name)
@@ -3,21 +3,21 @@ module Cucumber
3
3
  # Holds an Array of Step or StepDefinition
4
4
  class StepCollection #:nodoc:
5
5
  include Enumerable
6
-
6
+
7
7
  def initialize(steps)
8
8
  @steps = steps
9
9
  @steps.each{|step| step.step_collection = self}
10
10
  end
11
11
 
12
- def accept(visitor, &proc)
12
+ def accept(visitor)
13
13
  return if Cucumber.wants_to_quit
14
14
  @steps.each do |step|
15
- visitor.visit_step(step) if proc.nil? || proc.call(step)
15
+ visitor.visit_step(step)
16
16
  end
17
17
  end
18
18
 
19
19
  def step_invocations(background = false)
20
- StepCollection.new(@steps.map{ |step|
20
+ StepCollection.new(@steps.map{ |step|
21
21
  i = step.step_invocation
22
22
  i.background = background
23
23
  i
@@ -62,7 +62,7 @@ module Cucumber
62
62
  def passed?
63
63
  status == :passed
64
64
  end
65
-
65
+
66
66
  def status
67
67
  @steps.each{|step_invocation| return step_invocation.status if step_invocation.status != :passed}
68
68
  :passed
@@ -35,7 +35,7 @@ module Cucumber
35
35
 
36
36
  def accept(visitor)
37
37
  return if Cucumber.wants_to_quit
38
- invoke(visitor.step_mother, visitor.configuration)
38
+ invoke(visitor.runtime, visitor.configuration)
39
39
  visit_step_result(visitor)
40
40
  end
41
41
 
@@ -52,13 +52,13 @@ module Cucumber
52
52
  )
53
53
  end
54
54
 
55
- def invoke(step_mother, configuration)
56
- find_step_match!(step_mother, configuration)
55
+ def invoke(runtime, configuration)
56
+ find_step_match!(runtime, configuration)
57
57
  unless @skip_invoke || configuration.dry_run? || @exception || @step_collection.exception
58
58
  @skip_invoke = true
59
59
  begin
60
60
  @step_match.invoke(@multiline_arg)
61
- step_mother.after_step
61
+ runtime.after_step
62
62
  status!(:passed)
63
63
  rescue Pending => e
64
64
  failed(configuration, e, false)
@@ -77,10 +77,10 @@ module Cucumber
77
77
  end
78
78
  end
79
79
 
80
- def find_step_match!(step_mother, configuration)
80
+ def find_step_match!(runtime, configuration)
81
81
  return if @step_match
82
82
  begin
83
- @step_match = step_mother.step_match(@name)
83
+ @step_match = runtime.step_match(@name)
84
84
  rescue Undefined => e
85
85
  failed(configuration, e, true)
86
86
  status!(:undefined)
@@ -90,7 +90,7 @@ module Cucumber
90
90
  status!(:failed)
91
91
  @step_match = NoStepMatch.new(@step, @name)
92
92
  end
93
- step_mother.step_visited(self)
93
+ runtime.step_visited(self)
94
94
  end
95
95
 
96
96
  def failed(configuration, e, clear_backtrace)
@@ -113,7 +113,7 @@ module Cucumber
113
113
  def filter_backtrace(e)
114
114
  return e if Cucumber.use_full_backtrace
115
115
  e.backtrace.each{|line| line.gsub!(PWD_PATTERN, "./")}
116
-
116
+
117
117
  filtered = (e.backtrace || []).reject do |line|
118
118
  BACKTRACE_FILTER_PATTERNS.detect { |p| line =~ p }
119
119
  end
@@ -5,7 +5,7 @@ require 'gherkin/formatter/escaping'
5
5
  module Cucumber
6
6
  module Ast
7
7
  # Step Definitions that match a plain text Step with a multiline argument table
8
- # will receive it as an instance of Table. A Table object holds the data of a
8
+ # will receive it as an instance of Table. A Table object holds the data of a
9
9
  # table parsed from a feature file and lets you access and manipulate the data
10
10
  # in different ways.
11
11
  #
@@ -26,13 +26,13 @@ module Cucumber
26
26
  class Table
27
27
  class Different < StandardError
28
28
  attr_reader :table
29
-
29
+
30
30
  def initialize(table)
31
31
  super('Tables were not identical')
32
32
  @table = table
33
33
  end
34
34
  end
35
-
35
+
36
36
  class Builder
37
37
  attr_reader :rows
38
38
 
@@ -50,7 +50,7 @@ module Cucumber
50
50
 
51
51
  include Enumerable
52
52
  include Gherkin::Rubify
53
-
53
+
54
54
  NULL_CONVERSIONS = Hash.new({ :strict => false, :proc => lambda{ |cell_value| cell_value } }).freeze
55
55
 
56
56
  attr_accessor :file
@@ -76,7 +76,7 @@ module Cucumber
76
76
  @cell_class = Cell
77
77
  raw = ensure_array_of_array(rubify(raw))
78
78
  # Verify that it's square
79
- transposed = raw.transpose
79
+ raw.transpose
80
80
  create_cell_matrix(raw)
81
81
  @conversion_procs = conversion_procs
82
82
  @header_mappings = header_mappings
@@ -108,7 +108,7 @@ module Cucumber
108
108
  def transpose
109
109
  self.class.new(raw.transpose, @conversion_procs.dup, @header_mappings.dup, @header_conversion_proc)
110
110
  end
111
-
111
+
112
112
  # Converts this table into an Array of Hash where the keys of each
113
113
  # Hash are the headers in the table. For example, a Table built from
114
114
  # the following plain text:
@@ -126,7 +126,7 @@ module Cucumber
126
126
  def hashes
127
127
  @hashes ||= build_hashes
128
128
  end
129
-
129
+
130
130
  # Converts this table into a Hash where the first column is
131
131
  # used as keys and the second column is used as values
132
132
  #
@@ -137,7 +137,7 @@ module Cucumber
137
137
  #
138
138
  # {'a' => '2', 'b' => '3'}
139
139
  #
140
- # The table must be exactly two columns wide
140
+ # The table must be exactly two columns wide
141
141
  #
142
142
  def rows_hash
143
143
  return @rows_hash if @rows_hash
@@ -163,7 +163,7 @@ module Cucumber
163
163
  end
164
164
  end
165
165
 
166
- def column_names #:nodoc:
166
+ def column_names #:nodoc:
167
167
  @col_names ||= cell_matrix[0].map { |cell| cell.value }
168
168
  end
169
169
 
@@ -193,7 +193,7 @@ module Cucumber
193
193
  # | x | y |
194
194
  #
195
195
  # table.match(/table:column_1_name,column_2_name/) #=> non-nil
196
- #
196
+ #
197
197
  # Note: must use 'table:' prefix on match
198
198
  def match(pattern)
199
199
  header_to_match = "table:#{headers.join(',')}"
@@ -218,7 +218,7 @@ module Cucumber
218
218
  # | 123456 | xyz |
219
219
  # | 345678 | abc |
220
220
  #
221
- # A StepDefinition receiving this table can then map the columns
221
+ # A StepDefinition receiving this table can then map the columns
222
222
  # with both Regexp and String:
223
223
  #
224
224
  # table.map_headers!(/phone( number)?/i => :phone, 'Address' => :address)
@@ -238,6 +238,7 @@ module Cucumber
238
238
  # # => ['phone number', 'ADDRESS']
239
239
  #
240
240
  def map_headers!(mappings={}, &block)
241
+ clear_cache!
241
242
  @header_mappings = mappings
242
243
  @header_conversion_proc = block
243
244
  end
@@ -250,8 +251,8 @@ module Cucumber
250
251
  end
251
252
 
252
253
  # Change how #hashes converts column values. The +column_name+ argument identifies the column
253
- # and +conversion_proc+ performs the conversion for each cell in that column. If +strict+ is
254
- # true, an error will be raised if the column named +column_name+ is not found. If +strict+
254
+ # and +conversion_proc+ performs the conversion for each cell in that column. If +strict+ is
255
+ # true, an error will be raised if the column named +column_name+ is not found. If +strict+
255
256
  # is false, no error will be raised. Example:
256
257
  #
257
258
  # Given /^an expense report for (.*) with the following posts:$/ do |table|
@@ -269,7 +270,7 @@ module Cucumber
269
270
  # Compares +other_table+ to self. If +other_table+ contains columns
270
271
  # and/or rows that are not in self, new columns/rows are added at the
271
272
  # relevant positions, marking the cells in those rows/columns as
272
- # <tt>surplus</tt>. Likewise, if +other_table+ lacks columns and/or
273
+ # <tt>surplus</tt>. Likewise, if +other_table+ lacks columns and/or
273
274
  # rows that are present in self, these are marked as <tt>missing</tt>.
274
275
  #
275
276
  # <tt>surplus</tt> and <tt>missing</tt> cells are recognised by formatters
@@ -300,7 +301,7 @@ module Cucumber
300
301
  # an Array of Hash (similar to the structure returned by #hashes).
301
302
  #
302
303
  # Calling this method is particularly useful in <tt>Then</tt> steps that take
303
- # a Table argument, if you want to compare that table to some actual values.
304
+ # a Table argument, if you want to compare that table to some actual values.
304
305
  #
305
306
  def diff!(other_table, options={})
306
307
  options = {
@@ -315,7 +316,7 @@ module Cucumber
315
316
  other_table.convert_headers!
316
317
  other_table.convert_columns!
317
318
  ensure_green!
318
-
319
+
319
320
  convert_headers!
320
321
  convert_columns!
321
322
 
@@ -339,7 +340,7 @@ module Cucumber
339
340
  last_change = nil
340
341
  missing_row_pos = nil
341
342
  insert_row_pos = nil
342
-
343
+
343
344
  changes.each do |change|
344
345
  if(change.action == '-')
345
346
  missing_row_pos = change.position + inserted
@@ -368,9 +369,9 @@ module Cucumber
368
369
  end
369
370
  end
370
371
  end
371
-
372
+
372
373
  clear_cache!
373
- should_raise =
374
+ should_raise =
374
375
  missing_row_pos && options[:missing_row] ||
375
376
  insert_row_pos && options[:surplus_row] ||
376
377
  missing_col && options[:missing_col] ||
@@ -396,7 +397,7 @@ module Cucumber
396
397
  def verify_column(column_name) #:nodoc:
397
398
  raise %{The column named "#{column_name}" does not exist} unless raw[0].include?(column_name)
398
399
  end
399
-
400
+
400
401
  def verify_table_width(width) #:nodoc:
401
402
  raise %{The table must have exactly #{width} columns} unless raw[0].size == width
402
403
  end
@@ -429,7 +430,7 @@ module Cucumber
429
430
  def headers #:nodoc:
430
431
  raw.first
431
432
  end
432
-
433
+
433
434
  def header_cell(col) #:nodoc:
434
435
  cells_rows[0][col]
435
436
  end
@@ -452,7 +453,7 @@ module Cucumber
452
453
  formatter = Formatter::Pretty.new(nil, io, options)
453
454
  formatter.instance_variable_set('@indent', options[:indent])
454
455
  TreeWalker.new(nil, [formatter]).visit_multiline_arg(self)
455
-
456
+
456
457
  Cucumber::Term::ANSIColor.coloring = c
457
458
  io.rewind
458
459
  s = "\n" + io.read + (" " * (options[:indent] - 2))
@@ -498,7 +499,7 @@ module Cucumber
498
499
  @conversion_procs.each do |column_name, conversion_proc|
499
500
  verify_column(column_name) if conversion_proc[:strict]
500
501
  end
501
-
502
+
502
503
  cell_matrix.transpose.each do |col|
503
504
  column_name = col[0].value
504
505
  conversion_proc = @conversion_procs[column_name][:proc]
@@ -537,7 +538,7 @@ module Cucumber
537
538
  end
538
539
 
539
540
  def clear_cache! #:nodoc:
540
- @hashes = @rows_hash = @rows = @columns = nil
541
+ @hashes = @rows_hash = @col_names = @rows = @columns = nil
541
542
  end
542
543
 
543
544
  def columns #:nodoc:
@@ -580,7 +581,7 @@ module Cucumber
580
581
  end
581
582
 
582
583
  unmapped_cols.each_with_index do |col, col_index|
583
- empty_col = (0...cell_matrix.length).map do |row|
584
+ empty_col = (0...cell_matrix.length).map do |row|
584
585
  SurplusCell.new(nil, self, -1)
585
586
  end
586
587
  cols << empty_col
@@ -600,7 +601,7 @@ module Cucumber
600
601
  end
601
602
 
602
603
  def hashes_to_array(hashes) #:nodoc:
603
- header = hashes[0].keys
604
+ header = hashes[0].keys.sort
604
605
  [header] + hashes.map{|hash| header.map{|key| hash[key]}}
605
606
  end
606
607
 
@@ -698,12 +699,20 @@ module Cucumber
698
699
  SurplusCell === o || value == o.value
699
700
  end
700
701
 
702
+ def eql?(o)
703
+ self == o
704
+ end
705
+
706
+ def hash
707
+ 0
708
+ end
709
+
701
710
  # For testing only
702
711
  def to_sexp #:nodoc:
703
712
  [:cell, @value]
704
713
  end
705
714
  end
706
-
715
+
707
716
  class SurplusCell < Cell #:nodoc:
708
717
  def status
709
718
  :comment
@@ -712,6 +721,10 @@ module Cucumber
712
721
  def ==(o)
713
722
  true
714
723
  end
724
+
725
+ def hash
726
+ 0
727
+ end
715
728
  end
716
729
  end
717
730
  end