cucumber 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
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