cucumber 0.1.12 → 0.1.13

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 (101) hide show
  1. data/History.txt +38 -3
  2. data/Manifest.txt +17 -1
  3. data/README.txt +2 -39
  4. data/bin/cucumber +1 -1
  5. data/examples/calculator_ruby_features/features/addition.rb +16 -0
  6. data/examples/i18n/ar/features/step_definitons/calculator_steps.rb +1 -1
  7. data/examples/i18n/da/features/step_definitons/kalkulator_steps.rb +1 -0
  8. data/examples/i18n/de/features/step_definitons/calculator_steps.rb +1 -0
  9. data/examples/i18n/en/features/step_definitons/calculator_steps.rb +1 -0
  10. data/examples/i18n/es/features/step_definitons/calculador_steps.rb +1 -0
  11. data/examples/i18n/et/features/step_definitions/kalkulaator_steps.rb +1 -0
  12. data/examples/i18n/fr/features/addition.feature +13 -11
  13. data/examples/i18n/fr/features/step_definitions/calculatrice_steps.rb +6 -2
  14. data/examples/i18n/id/features/step_definitons/calculator_steps.rb +1 -0
  15. data/examples/i18n/it/features/step_definitons/calcolatrice_steps.rb +1 -0
  16. data/examples/i18n/ja/features/step_definitons/calculator_steps.rb +2 -0
  17. data/examples/i18n/lt/features/step_definitons/calculator_steps.rb +1 -0
  18. data/examples/i18n/no/features/step_definitons/kalkulator_steps.rb +1 -0
  19. data/examples/i18n/pt/features/step_definitions/calculadora_steps.rb +1 -0
  20. data/examples/i18n/ro/features/step_definitons/calculator_steps.rb +1 -0
  21. data/examples/i18n/se/features/step_definitons/kalkulator_steps.rb +1 -0
  22. data/examples/i18n/zh-CN/features/step_definitons/calculator_steps.rb +1 -0
  23. data/examples/selenium/features/search.feature +1 -1
  24. data/examples/selenium/features/step_definitons/stories_steps.rb +2 -3
  25. data/examples/tickets/features/lib/eatting_machine.rb +18 -0
  26. data/examples/tickets/features/lib/pantry.rb +20 -0
  27. data/examples/tickets/features/scenario_outline.feature +64 -0
  28. data/examples/tickets/features/step_definitons/scenario_outline_steps.rb +34 -0
  29. data/examples/tickets/features/step_definitons/tickets_steps.rb +4 -0
  30. data/gem_tasks/fix_cr_lf.rake +1 -1
  31. data/gem_tasks/yard.rake +8 -0
  32. data/lib/autotest/cucumber_mixin.rb +3 -3
  33. data/lib/cucumber.rb +2 -0
  34. data/lib/cucumber/broadcaster.rb +1 -1
  35. data/lib/cucumber/cli.rb +87 -42
  36. data/lib/cucumber/core_ext/exception.rb +20 -0
  37. data/lib/cucumber/core_ext/string.rb +1 -1
  38. data/lib/cucumber/executor.rb +35 -18
  39. data/lib/cucumber/formatters/ansicolor.rb +65 -74
  40. data/lib/cucumber/formatters/html_formatter.rb +33 -10
  41. data/lib/cucumber/formatters/pretty_formatter.rb +58 -16
  42. data/lib/cucumber/formatters/progress_formatter.rb +3 -0
  43. data/lib/cucumber/formatters/unicode.rb +27 -0
  44. data/lib/cucumber/languages.yml +6 -4
  45. data/lib/cucumber/platform.rb +1 -0
  46. data/lib/cucumber/rails/world.rb +6 -6
  47. data/lib/cucumber/step_mother.rb +3 -0
  48. data/lib/cucumber/tree/feature.rb +28 -2
  49. data/lib/cucumber/tree/scenario.rb +62 -1
  50. data/lib/cucumber/tree/step.rb +32 -1
  51. data/lib/cucumber/treetop_parser/feature.treetop.erb +54 -7
  52. data/lib/cucumber/treetop_parser/feature_ar.rb +377 -18
  53. data/lib/cucumber/treetop_parser/feature_cy.rb +377 -18
  54. data/lib/cucumber/treetop_parser/feature_da.rb +377 -18
  55. data/lib/cucumber/treetop_parser/feature_de.rb +377 -18
  56. data/lib/cucumber/treetop_parser/feature_en-lol.rb +377 -18
  57. data/lib/cucumber/treetop_parser/feature_en-tx.rb +377 -18
  58. data/lib/cucumber/treetop_parser/feature_en.rb +377 -18
  59. data/lib/cucumber/treetop_parser/feature_es.rb +377 -18
  60. data/lib/cucumber/treetop_parser/feature_et.rb +377 -18
  61. data/lib/cucumber/treetop_parser/feature_fr.rb +389 -30
  62. data/lib/cucumber/treetop_parser/feature_id.rb +377 -18
  63. data/lib/cucumber/treetop_parser/feature_it.rb +377 -18
  64. data/lib/cucumber/treetop_parser/feature_ja.rb +377 -18
  65. data/lib/cucumber/treetop_parser/feature_lt.rb +377 -18
  66. data/lib/cucumber/treetop_parser/feature_nl.rb +377 -18
  67. data/lib/cucumber/treetop_parser/feature_no.rb +377 -18
  68. data/lib/cucumber/treetop_parser/feature_pl.rb +377 -18
  69. data/lib/cucumber/treetop_parser/feature_pt.rb +377 -18
  70. data/lib/cucumber/treetop_parser/feature_ro.rb +377 -18
  71. data/lib/cucumber/treetop_parser/feature_ro2.rb +377 -18
  72. data/lib/cucumber/treetop_parser/feature_ru.rb +377 -18
  73. data/lib/cucumber/treetop_parser/feature_se.rb +377 -18
  74. data/lib/cucumber/treetop_parser/feature_zh-CN.rb +377 -18
  75. data/lib/cucumber/version.rb +1 -1
  76. data/lib/cucumber/world.rb +1 -0
  77. data/lib/cucumber/world/pending.rb +22 -0
  78. data/rails_generators/cucumber/templates/env.rb +1 -0
  79. data/rails_generators/feature/feature_generator.rb +22 -2
  80. data/rails_generators/feature/templates/feature.erb +15 -12
  81. data/rails_generators/feature/templates/steps.erb +16 -14
  82. data/spec/cucumber/cli_spec.rb +87 -6
  83. data/spec/cucumber/executor_spec.rb +102 -30
  84. data/spec/cucumber/formatters/ansicolor_spec.rb +10 -10
  85. data/spec/cucumber/formatters/html_formatter_spec.rb +30 -0
  86. data/spec/cucumber/formatters/pretty_formatter_spec.rb +139 -4
  87. data/spec/cucumber/formatters/progress_formatter_spec.rb +16 -0
  88. data/spec/cucumber/tree/feature_spec.rb +84 -5
  89. data/spec/cucumber/tree/row_scenario_outline_spec.rb +73 -0
  90. data/spec/cucumber/tree/row_step_outline_spec.rb +38 -0
  91. data/spec/cucumber/tree/scenario_outline_spec.rb +50 -0
  92. data/spec/cucumber/tree/step_outline_spec.rb +17 -0
  93. data/spec/cucumber/tree/step_spec.rb +9 -0
  94. data/spec/cucumber/treetop_parser/empty_scenario_outline.feature +3 -0
  95. data/spec/cucumber/treetop_parser/feature_parser_spec.rb +22 -0
  96. data/spec/cucumber/treetop_parser/invalid_scenario_outlines.feature +7 -0
  97. data/spec/cucumber/treetop_parser/scenario_outline.feature +16 -0
  98. data/spec/cucumber/world/pending_spec.rb +46 -0
  99. data/spec/spec_helper.rb +2 -1
  100. metadata +19 -4
  101. data/TODO.txt +0 -26
@@ -1,3 +1,5 @@
1
+ require 'cgi'
2
+
1
3
  module Cucumber
2
4
  module Formatters
3
5
  class HtmlFormatter
@@ -53,15 +55,11 @@ HTML
53
55
  end
54
56
 
55
57
  def visit_regular_scenario(scenario)
56
- @scenario_table_header = scenario.table_header
57
- @io.puts %{ <dl class="new">}
58
- @io.puts %{ <dt>#{Cucumber.language['scenario']}: #{scenario.name}</dt>}
59
- @io.puts %{ <dd>}
60
- @io.puts %{ <ul>}
61
- scenario.accept(self)
62
- @io.puts %{ </ul>}
63
- @io.puts %{ </dd>}
64
- @io.puts %{ </dl>}
58
+ visit_scenario(scenario, Cucumber.language['scenario'])
59
+ end
60
+
61
+ def visit_scenario_outline(scenario)
62
+ visit_scenario(scenario, Cucumber.language['scenario_outline'])
65
63
  end
66
64
 
67
65
  def visit_row_scenario(scenario)
@@ -86,6 +84,7 @@ HTML
86
84
 
87
85
  def visit_row_step(step)
88
86
  _, args, _ = step.regexp_args_proc(@step_mother)
87
+ args = step.visible_args if step.outline?
89
88
  args.each do |arg|
90
89
  @io.puts %{ <td id="#{step.id}"><span>#{arg}</span></td>}
91
90
  end
@@ -95,6 +94,11 @@ HTML
95
94
  regexp, _, _ = step.regexp_args_proc(@step_mother)
96
95
  @io.puts %{ <li class="new" id="#{step.id}">#{step.keyword} #{step.format(regexp, '<span>%s</span>')}</li>}
97
96
  end
97
+
98
+ def visit_step_outline(step)
99
+ regexp, _, _ = step.regexp_args_proc(@step_mother)
100
+ @io.puts %{ <li class="new" id="#{step.id}">#{step.keyword} #{CGI.escapeHTML(step.format(nil))}</li>}
101
+ end
98
102
 
99
103
  def step_passed(step, regexp, args)
100
104
  print_javascript_tag("stepPassed(#{step.id})")
@@ -112,7 +116,11 @@ HTML
112
116
  def step_skipped(step, regexp, args)
113
117
  # noop
114
118
  end
115
-
119
+
120
+ def step_traced(step, regexp, args)
121
+ # noop
122
+ end
123
+
116
124
  def print_javascript_tag(js)
117
125
  @io.puts %{ <script type="text/javascript">#{js}</script>}
118
126
  end
@@ -123,6 +131,21 @@ HTML
123
131
  </html>
124
132
  HTML
125
133
  end
134
+
135
+ private
136
+
137
+ def visit_scenario(scenario, scenario_or_scenario_outline_keyword)
138
+ @scenario_table_header = scenario.table_header
139
+ @io.puts %{ <dl class="new">}
140
+ @io.puts %{ <dt>#{scenario_or_scenario_outline_keyword}: #{scenario.name}</dt>}
141
+ @io.puts %{ <dd>}
142
+ @io.puts %{ <ul>}
143
+ scenario.accept(self)
144
+ @io.puts %{ </ul>}
145
+ @io.puts %{ </dd>}
146
+ @io.puts %{ </dl>}
147
+ end
148
+
126
149
  end
127
150
  end
128
151
  end
@@ -6,7 +6,6 @@ module Cucumber
6
6
  include ANSIColor
7
7
 
8
8
  INDENT = "\n "
9
- BACKTRACE_FILTER_PATTERNS = [/vendor\/rails/, /vendor\/plugins\/cucumber/, /spec\/expectations/, /spec\/matchers/]
10
9
 
11
10
  def initialize(io, step_mother, options={})
12
11
  @io = (io == STDOUT) ? Kernel : io
@@ -18,6 +17,8 @@ module Cucumber
18
17
  @pending_steps = []
19
18
  @skipped = []
20
19
  @last_executed_was_row = false
20
+ @pending_messages = {}
21
+ @forced_pending_step_count = 0
21
22
  end
22
23
 
23
24
  def feature_executing(feature)
@@ -40,17 +41,23 @@ module Cucumber
40
41
  end
41
42
 
42
43
  def scenario_executing(scenario)
44
+ scenario_or_scenario_outline_keyword = scenario.outline? ? Cucumber.language['scenario_outline'] : Cucumber.language['scenario']
45
+
43
46
  @scenario_failed = false
44
47
  @io.puts if @last_executed_was_row && !scenario.row?
45
48
  if scenario.row?
46
49
  @last_executed_was_row = true
47
50
  @io.print " |"
48
51
  else
52
+ scenario_text = "#{scenario_or_scenario_outline_keyword}: #{scenario.name}"
53
+
49
54
  if scenario.pending?
50
55
  @pending_scenarios << scenario
51
- @io.print pending(" #{Cucumber.language['scenario']}: #{scenario.name}")
56
+ @io.print pending(" #{scenario_text}")
57
+ elsif scenario.outline?
58
+ @io.print skipped(" #{scenario_text}")
52
59
  else
53
- @io.print passed(" #{Cucumber.language['scenario']}: #{scenario.name}")
60
+ @io.print passed(" #{scenario_text}")
54
61
  end
55
62
  @last_executed_was_row = false
56
63
 
@@ -78,6 +85,7 @@ module Cucumber
78
85
 
79
86
  def step_passed(step, regexp, args)
80
87
  if step.row?
88
+ args = step.visible_args if step.outline?
81
89
  @passed << step
82
90
  print_passed_args(args)
83
91
  else
@@ -93,6 +101,7 @@ module Cucumber
93
101
 
94
102
  def step_failed(step, regexp, args)
95
103
  if step.row?
104
+ args = step.visible_args if step.outline?
96
105
  @failed << step
97
106
  @scenario_failed = true
98
107
  print_failed_args(args)
@@ -112,12 +121,17 @@ module Cucumber
112
121
  def step_skipped(step, regexp, args)
113
122
  @skipped << step
114
123
  if step.row?
124
+ args = step.visible_args if step.outline?
115
125
  print_skipped_args(args)
116
126
  else
117
127
  @io.print skipped(" #{step.keyword} #{step.format(regexp){|param| skipped_param(param) << skipped}}")
118
128
  if @options[:source]
119
129
  @io.print padding_spaces(step)
120
- @io.print source_comment(step)
130
+ if step.outline?
131
+ @io.print comment("# #{step.file}:#{step.line}")
132
+ else
133
+ @io.print source_comment(step)
134
+ end
121
135
  end
122
136
  @io.puts
123
137
  end
@@ -125,6 +139,7 @@ module Cucumber
125
139
 
126
140
  def step_pending(step, regexp, args)
127
141
  if step.row?
142
+ args = step.visible_args if step.outline?
128
143
  @pending_steps << step
129
144
  print_pending_args(args)
130
145
  else
@@ -136,38 +151,61 @@ module Cucumber
136
151
  end
137
152
  @io.puts
138
153
  end
154
+ if step.forced_to_pending?
155
+ @pending_messages[regexp.inspect] ||= "#{step.keyword} #{regexp.inspect} (#{step.error.message}) #{source_comment(step)}"
156
+ @forced_pending_step_count += 1
157
+ end
158
+ end
159
+
160
+ def step_traced(step, regexp, args)
161
+ @io.print skipped(" #{step.keyword} #{step.format(regexp){|param| skipped_param(param) << skipped}}")
162
+ if @options[:source]
163
+ @io.print padding_spaces(step)
164
+ @io.print comment("# #{step.file}:#{step.line}")
165
+ end
166
+ @io.puts
139
167
  end
140
168
 
141
169
  def output_failing_step(step)
142
- backtrace = step.error.backtrace || []
143
- clean_backtrace = backtrace.map {|b| b.split("\n") }.flatten.reject do |line|
144
- BACKTRACE_FILTER_PATTERNS.detect{|p| line =~ p}
145
- end.map { |line| line.strip }
146
170
  @io.puts failed(" #{step.error.message.split("\n").join(INDENT)} (#{step.error.class})")
147
- @io.puts failed(" #{clean_backtrace.join(INDENT)}")
171
+ @io.puts failed(" #{step.error.cucumber_backtrace.join(INDENT)}")
148
172
  end
149
173
 
150
174
  def dump
151
175
  @io.puts
152
176
 
177
+ print_pending_messages if @pending_messages.any?
178
+
153
179
  @io.puts pending("#{@pending_scenarios.length} scenarios pending") if @pending_scenarios.any?
154
180
 
155
181
  @io.puts passed("#{@passed.length} steps passed") if @passed.any?
156
182
  @io.puts failed("#{@failed.length} steps failed") if @failed.any?
157
183
  @io.puts skipped("#{@skipped.length} steps skipped") if @skipped.any?
158
- @io.puts pending("#{@pending_steps.length} steps pending") if @pending_steps.any?
184
+ if @pending_steps.any?
185
+ @io.print pending("#{@pending_steps.length} steps pending")
186
+ @io.print pending(" (#{number_of_unimplemented_steps} with no step definition)") if number_of_unimplemented_steps > 0
187
+ @io.puts
188
+ end
159
189
 
160
190
  @io.print reset
161
191
 
162
192
  print_snippets if @options[:snippets]
163
193
  end
164
194
 
195
+ def print_pending_messages
196
+ @io.puts "Pending Notes:"
197
+ @pending_messages.each_value do |message|
198
+ @io.puts message
199
+ end
200
+ @io.puts
201
+ end
202
+
165
203
  def print_snippets
166
204
  snippets = @pending_steps
167
205
  snippets.delete_if {|snippet| snippet.row? || @step_mother.has_step_definition?(snippet.name)}
168
206
 
169
207
  unless snippets.empty?
170
- @io.puts "\nYou can use these snippets to implement pending steps:\n\n"
208
+ @io.puts "\nYou can use these snippets to implement pending steps which have no step definition:\n\n"
171
209
 
172
210
  prev_keyword = nil
173
211
  snippets = snippets.map do |step|
@@ -184,6 +222,10 @@ module Cucumber
184
222
 
185
223
  private
186
224
 
225
+ def number_of_unimplemented_steps
226
+ @pending_steps.length - @forced_pending_step_count
227
+ end
228
+
187
229
  def escape_regexp_characters(string)
188
230
  Regexp.escape(string).gsub('\ ', ' ').gsub('/', '\/') unless string.nil?
189
231
  end
@@ -204,7 +246,7 @@ module Cucumber
204
246
  @current_column
205
247
  end
206
248
 
207
- def print_row row_args, &colorize_proc
249
+ def print_row(row_args, &colorize_proc)
208
250
  colorize_proc = Proc.new{|row_element| row_element} unless colorize_proc
209
251
 
210
252
  row_args.each do |row_arg|
@@ -214,19 +256,19 @@ module Cucumber
214
256
  end
215
257
  end
216
258
 
217
- def print_passed_args args
259
+ def print_passed_args(args)
218
260
  print_row(args) {|arg| passed(arg)}
219
261
  end
220
262
 
221
- def print_skipped_args args
263
+ def print_skipped_args(args)
222
264
  print_row(args) {|arg| skipped(arg)}
223
265
  end
224
266
 
225
- def print_failed_args args
267
+ def print_failed_args(args)
226
268
  print_row(args) {|arg| failed(arg)}
227
269
  end
228
270
 
229
- def print_pending_args args
271
+ def print_pending_args(args)
230
272
  print_row(args) {|arg| pending(arg)}
231
273
  end
232
274
  end
@@ -36,6 +36,9 @@ module Cucumber
36
36
  @io.print skipped('_')
37
37
  end
38
38
 
39
+ def step_traced(step, regexp, args)
40
+ end
41
+
39
42
  def dump
40
43
  @io.puts pending
41
44
  @io.puts "\nPending Scenarios:\n\n" if @pending_scenarios.any?
@@ -0,0 +1,27 @@
1
+ # Require this file if you need Unicode support.
2
+ require 'cucumber/platform'
3
+ require 'cucumber/formatters/ansicolor'
4
+
5
+ $KCODE='u'
6
+
7
+ if $CUCUMBER_WINDOWS_MRI && `chcp` =~ /Active code page: (\d+)/
8
+ codepage = $1.to_i
9
+ codepages = (1251..1252)
10
+
11
+ if codepages.include?(codepage)
12
+ $CUCUMBER_CODEPAGE = "cp#{codepage}"
13
+
14
+ require 'iconv'
15
+ module Kernel
16
+ alias cucumber_print print
17
+ def print(*a)
18
+ cucumber_print *Iconv.iconv($CUCUMBER_CODEPAGE, "UTF-8", *a)
19
+ end
20
+
21
+ alias cucumber_puts puts
22
+ def puts(*a)
23
+ cucumber_puts *Iconv.iconv($CUCUMBER_CODEPAGE, "UTF-8", *a)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -7,6 +7,8 @@
7
7
  "en":
8
8
  feature: Feature
9
9
  scenario: Scenario
10
+ scenario_outline: Scenario Outline
11
+ examples: Examples
10
12
  more_examples: More Examples
11
13
  given_scenario: GivenScenario
12
14
  given: Given
@@ -108,11 +110,11 @@
108
110
  but: Kuid
109
111
  # French
110
112
  "fr":
111
- feature: Fonction
112
- scenario: Scenario
113
+ feature: Fonctionnalité
114
+ scenario: Scénario
113
115
  more_examples: Plus d'exemples
114
- given_scenario: SoitScenario
115
- given: Soit
116
+ given_scenario: Soit le Scénario
117
+ given: Etant donné
116
118
  when: Lorsque
117
119
  then: Alors
118
120
  and: Et
@@ -7,3 +7,4 @@ $CUCUMBER_IRONRUBY = Config::CONFIG['sitedir'] =~ /IronRuby/
7
7
  $CUCUMBER_WINDOWS = Config::CONFIG['host_os'] =~ /mswin|mingw/
8
8
  $CUCUMBER_WINDOWS_MRI = $CUCUMBER_WINDOWS && !$CUCUMBER_JRUBY && !$CUCUMBER_IRONRUBY
9
9
  $CUCUMBER_RAILS = defined?(Rails)
10
+ $CUCUMBER_RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
@@ -11,7 +11,7 @@ require 'test/unit/testresult'
11
11
 
12
12
  # These allow exceptions to come through as opposed to being caught and having non-helpful responses returned.
13
13
  ActionController::Base.class_eval do
14
- def perform_action
14
+ def perform_action_with_rescue
15
15
  perform_action_without_rescue
16
16
  end
17
17
  end
@@ -24,7 +24,7 @@ end
24
24
  # So that Test::Unit doesn't launch at the end - makes it think it has already been run.
25
25
  Test::Unit.run = true if Test::Unit.respond_to?(:run=)
26
26
 
27
- $main = self
27
+ $cucumber_toplevel = self
28
28
 
29
29
  module Cucumber #:nodoc:
30
30
  module Rails
@@ -44,22 +44,22 @@ module Cucumber #:nodoc:
44
44
  def self.use_transactional_fixtures
45
45
  World.use_transactional_fixtures = true
46
46
  if defined?(ActiveRecord::Base)
47
- $main.Before do
47
+ $cucumber_toplevel.Before do
48
48
  if ActiveRecord::Base.connection.respond_to?(:increment_open_transactions)
49
49
  ActiveRecord::Base.connection.increment_open_transactions
50
50
  else
51
- ActiveRecord::Base.send :increment_open_transactions
51
+ ActiveRecord::Base.__send__(:increment_open_transactions)
52
52
  end
53
53
  ActiveRecord::Base.connection.begin_db_transaction
54
54
  ActionMailer::Base.deliveries = [] if defined?(ActionMailer::Base)
55
55
  end
56
56
 
57
- $main.After do
57
+ $cucumber_toplevel.After do
58
58
  ActiveRecord::Base.connection.rollback_db_transaction
59
59
  if ActiveRecord::Base.connection.respond_to?(:decrement_open_transactions)
60
60
  ActiveRecord::Base.connection.decrement_open_transactions
61
61
  else
62
- ActiveRecord::Base.send :decrement_open_transactions
62
+ ActiveRecord::Base.__send__(:decrement_open_transactions)
63
63
  end
64
64
  end
65
65
  end
@@ -4,6 +4,9 @@ module Cucumber
4
4
  class Pending < StandardError
5
5
  end
6
6
 
7
+ class ForcedPending < Pending
8
+ end
9
+
7
10
  class Duplicate < StandardError
8
11
  end
9
12
 
@@ -19,11 +19,23 @@ module Cucumber
19
19
  scenario
20
20
  end
21
21
 
22
+ def add_scenario_outline(name, line, &proc)
23
+ scenario = ScenarioOutline.new(self, name, line, &proc)
24
+ @scenarios << scenario
25
+ scenario
26
+ end
27
+
22
28
  def add_row_scenario(template_scenario, values, line)
23
29
  scenario = RowScenario.new(self, template_scenario, values, line)
24
30
  @scenarios << scenario
25
31
  scenario
26
32
  end
33
+
34
+ def add_row_scenario_outline(template_scenario, values, line)
35
+ scenario = RowScenarioOutline.new(self, template_scenario, values, line)
36
+ @scenarios << scenario
37
+ scenario
38
+ end
27
39
 
28
40
  def scenario_named(name)
29
41
  @scenarios.find {|s| s.name == name}
@@ -38,26 +50,40 @@ module Cucumber
38
50
  add_scenario(name, line, &proc)
39
51
  end
40
52
 
53
+ def ScenarioOutline(name, &proc)
54
+ line = caller[0] =~ /:(\d+)$/ ? $1 : nil
55
+ add_scenario_outline(name, line, &proc)
56
+ end
57
+
41
58
  def Table(matrix = [], &proc)
42
59
  table = Table.new(matrix)
43
60
  proc.call(table)
61
+
44
62
  template_scenario = @scenarios.last
45
63
  template_scenario.table_header = matrix[0]
64
+
46
65
  matrix[1..-1].each do |row|
47
- add_row_scenario(template_scenario, row, row.line)
66
+ if template_scenario.outline?
67
+ add_row_scenario_outline(template_scenario, row, row.line)
68
+ else
69
+ add_row_scenario(template_scenario, row, row.line)
70
+ end
48
71
  end
49
72
  end
50
73
 
51
74
  def accept(visitor)
52
75
  visitor.visit_header(@header)
53
76
  @scenarios.each do |scenario|
54
- if scenario.row?
77
+ if scenario.outline? && !scenario.row?
78
+ visitor.visit_scenario_outline(scenario)
79
+ elsif scenario.row?
55
80
  visitor.visit_row_scenario(scenario)
56
81
  else
57
82
  visitor.visit_regular_scenario(scenario)
58
83
  end
59
84
  end
60
85
  end
86
+
61
87
  end
62
88
  end
63
89
  end