cucumber 0.3.102 → 0.3.103

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/History.txt +18 -0
  2. data/Manifest.txt +6 -2
  3. data/examples/java/README.textile +3 -3
  4. data/examples/self_test/features/sample.feature +1 -1
  5. data/examples/self_test/features/search_sample.feature +1 -1
  6. data/features/custom_formatter.feature +4 -4
  7. data/features/steps_formatter.feature +2 -1
  8. data/lib/cucumber/ast.rb +1 -0
  9. data/lib/cucumber/ast/table.rb +4 -4
  10. data/lib/cucumber/ast/tree_walker.rb +185 -0
  11. data/lib/cucumber/ast/visitor.rb +2 -106
  12. data/lib/cucumber/cli/configuration.rb +28 -28
  13. data/lib/cucumber/cli/language_help_formatter.rb +5 -7
  14. data/lib/cucumber/cli/main.rb +3 -3
  15. data/lib/cucumber/core_ext/string.rb +0 -22
  16. data/lib/cucumber/formatter/html.rb +203 -113
  17. data/lib/cucumber/formatter/junit.rb +29 -23
  18. data/lib/cucumber/formatter/pdf.rb +74 -69
  19. data/lib/cucumber/formatter/pretty.rb +93 -78
  20. data/lib/cucumber/formatter/profile.rb +2 -2
  21. data/lib/cucumber/formatter/progress.rb +16 -10
  22. data/lib/cucumber/formatter/rerun.rb +4 -5
  23. data/lib/cucumber/formatter/steps.rb +6 -7
  24. data/lib/cucumber/formatter/tag_cloud.rb +7 -6
  25. data/lib/cucumber/formatter/usage.rb +7 -10
  26. data/lib/cucumber/language_support/step_definition_methods.rb +4 -4
  27. data/lib/cucumber/rails/action_controller.rb +1 -1
  28. data/lib/cucumber/rails/active_record.rb +27 -14
  29. data/lib/cucumber/rb_support/rb_language.rb +5 -0
  30. data/lib/cucumber/rb_support/rb_step_definition.rb +9 -16
  31. data/lib/cucumber/rb_support/regexp_argument_matcher.rb +21 -0
  32. data/lib/cucumber/step_argument.rb +9 -0
  33. data/lib/cucumber/step_match.rb +24 -5
  34. data/lib/cucumber/version.rb +1 -1
  35. data/rails_generators/cucumber/templates/env.rb +14 -0
  36. data/spec/cucumber/ast/background_spec.rb +1 -2
  37. data/spec/cucumber/ast/scenario_outline_spec.rb +3 -2
  38. data/spec/cucumber/ast/scenario_spec.rb +1 -1
  39. data/spec/cucumber/ast/tree_walker_spec.rb +18 -0
  40. data/spec/cucumber/formatter/html_spec.rb +221 -2
  41. data/spec/cucumber/formatter/progress_spec.rb +9 -4
  42. data/spec/cucumber/parser/feature_parser_spec.rb +31 -27
  43. data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +18 -0
  44. data/spec/cucumber/step_match_spec.rb +40 -0
  45. metadata +8 -4
  46. data/lib/cucumber/rb_support/rb_group.rb +0 -11
  47. data/spec/cucumber/core_ext/string_spec.rb +0 -41
@@ -3,21 +3,20 @@ require 'cucumber/formatter/ordered_xml_markup'
3
3
  module Cucumber
4
4
  module Formatter
5
5
  # The formatter used for <tt>--format junit</tt>
6
- class Junit < Cucumber::Ast::Visitor
7
-
6
+ class Junit
8
7
  def initialize(step_mother, io, options)
9
- super(step_mother)
10
8
  raise "You *must* specify --out DIR for the junit formatter" unless String === io && File.directory?(io)
11
9
  @reportdir = io
12
10
  @options = options
13
11
  end
14
12
 
15
- def visit_feature(feature)
13
+ def before_feature(feature)
16
14
  @failures = @errors = @tests = 0
17
15
  @builder = OrderedXmlMarkup.new( :indent => 2 )
18
16
  @time = 0
19
- super
20
-
17
+ end
18
+
19
+ def after_feature(feature)
21
20
  @testsuite = OrderedXmlMarkup.new( :indent => 2 )
22
21
  @testsuite.instruct!
23
22
  @testsuite.testsuite(
@@ -25,7 +24,7 @@ module Cucumber
25
24
  :errors => @errors,
26
25
  :tests => @tests,
27
26
  :time => "%.6f" % @time,
28
- :name => @feature_name ) do
27
+ :name => @feature_name ) do
29
28
  @testsuite << @builder.target!
30
29
  end
31
30
 
@@ -34,18 +33,20 @@ module Cucumber
34
33
  File.open(feature_filename, 'w') { |file| file.write(@testsuite.target!) }
35
34
  end
36
35
 
37
- def visit_background(name)
36
+ def before_background(*args)
38
37
  @in_background = true
39
- super
38
+ end
39
+
40
+ def after_background(*args)
40
41
  @in_background = false
41
42
  end
42
43
 
43
- def visit_feature_name(name)
44
+ def feature_name(name)
44
45
  lines = name.split(/\r?\n/)
45
46
  @feature_name = lines[0].sub(/Feature\:/, '').strip
46
47
  end
47
48
 
48
- def visit_scenario_name(keyword, name, file_colon_line, source_indent)
49
+ def scenario_name(keyword, name, file_colon_line, source_indent)
49
50
  scenario_name = name.strip.delete(".\r\n")
50
51
  scenario_name = "Unnamed scenario" if name.blank?
51
52
  @scenario = scenario_name
@@ -53,11 +54,13 @@ module Cucumber
53
54
  @output = "Scenario#{ " outline" if @outline}: #{@scenario}\n\n"
54
55
  end
55
56
 
56
- def visit_steps(steps)
57
+ def before_steps(steps)
58
+ @steps_start = Time.now
59
+ end
60
+
61
+ def after_steps(steps)
57
62
  return if @in_background
58
- start = Time.now
59
- super
60
- duration = Time.now - start
63
+ duration = Time.now - @steps_start
61
64
  unless @outline
62
65
  if steps.failed?
63
66
  steps.each { |step| @output += "#{step.keyword} #{step.name}\n" }
@@ -67,16 +70,21 @@ module Cucumber
67
70
  end
68
71
  end
69
72
 
70
- def visit_outline_table(outline_table)
73
+ def before_outline_table(outline_table)
71
74
  @header_row = true
72
- super(outline_table)
73
75
  end
74
76
 
75
- def visit_table_row(table_row)
77
+ def before_table_row(table_row)
78
+ if @outline
79
+ @table_start = Time.now
80
+ end
81
+
82
+ @header_row = false
83
+ end
84
+
85
+ def after_table_row(table_row)
76
86
  if @outline
77
- start = Time.now
78
- super(table_row)
79
- duration = Time.now - start
87
+ duration = Time.now - @table_start
80
88
  unless @header_row
81
89
  name_suffix = " (outline example : #{table_row.name})"
82
90
  if table_row.failed?
@@ -85,8 +93,6 @@ module Cucumber
85
93
  end
86
94
  build_testcase(duration, table_row.status, table_row.exception, name_suffix)
87
95
  end
88
- else
89
- super(table_row)
90
96
  end
91
97
  @header_row = false
92
98
  end
@@ -10,13 +10,13 @@ module Cucumber
10
10
  BLACK = '000000'
11
11
  GREY = '999999'
12
12
 
13
- class Pdf < Ast::Visitor
13
+ class Pdf
14
14
  include FileUtils
15
15
  include Console
16
16
  attr_writer :indent
17
17
 
18
18
  def initialize(step_mother, io, options)
19
- super(step_mother)
19
+ @step_mother = step_mother
20
20
  raise "You *must* specify --out FILE for the pdf formatter" unless File === io
21
21
 
22
22
  if(options[:dry_run])
@@ -53,41 +53,12 @@ module Cucumber
53
53
  end
54
54
  end
55
55
 
56
- def keep_with(&block)
57
- @buffer << block
58
- end
59
-
60
- def render(doc)
61
- @doc = doc
62
- @buffer.each do |proc|
63
- proc.call
64
- end
65
- end
66
-
67
- # This method does a 'test' rendering on a blank page, to see the rendered height of the buffer
68
- # if that too high for the space left on the age in the real document, we do a page break.
69
- # This obviously doesn't work if a scenario is longer than a whole page (God forbid)
70
- def flush
71
- @scrap.start_new_page
72
- oldy = @scrap.y
73
- render @scrap
74
- height = (oldy - @scrap.y) + 36 # whops magic number
75
- if ((@pdf.y - height) < @pdf.bounds.bottom)
76
- @pdf.start_new_page
77
- end
78
- render @pdf
79
- @pdf.move_down(20)
80
- @buffer = []
81
- end
82
-
83
- # regular visitor entries
84
- def visit_features(features)
85
- super
56
+ def after_features(features)
86
57
  @pdf.render_file(@io.path)
87
58
  puts "\ndone"
88
59
  end
89
60
 
90
- def visit_feature_name(name)
61
+ def feature_name(name)
91
62
  @pdf.start_new_page
92
63
  name["Feature:"] = "" if name["Feature:"]
93
64
  names = name.split("\n")
@@ -106,18 +77,19 @@ module Cucumber
106
77
  @pdf.move_down(30)
107
78
  end
108
79
 
109
- def visit_feature_element(feature_element)
80
+ def before_feature_element(feature_element)
110
81
  record_tag_occurrences(feature_element, @options)
111
- super
82
+ end
83
+
84
+ def after_feature_element(feature_element)
112
85
  flush
113
86
  end
114
87
 
115
- def visit_feature(feature)
116
- super
88
+ def after_feature(feature)
117
89
  flush
118
90
  end
119
91
 
120
- def visit_feature_element_name(keyword, name)
92
+ def feature_element_name(keyword, name)
121
93
  names = name.empty? ? [name] : name.split("\n")
122
94
  print "."
123
95
  STDOUT.flush
@@ -133,53 +105,55 @@ module Cucumber
133
105
  end
134
106
  end
135
107
 
136
- def visit_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
108
+ def step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
109
+ @hide_this_step = false
137
110
  if exception
138
- return if @exceptions.index(exception)
111
+ if @exceptions.include?(exception)
112
+ @hide_this_step = true
113
+ return
114
+ end
139
115
  @exceptions << exception
140
116
  end
141
- return if status != :failed && @in_background ^ background
142
- @status = status
143
- super
144
- end
145
-
146
- def colorize(text, status)
147
- keep_with do
148
- @doc.fill_color(@status_colors[status] || BLACK)
149
- @doc.text(text)
150
- @doc.fill_color(BLACK)
117
+ if status != :failed && @in_background ^ background
118
+ @hide_this_step = true
119
+ return
151
120
  end
152
121
  end
153
122
 
154
- def visit_step_name(keyword, step_match, status, source_indent, background)
123
+ def step_name(keyword, step_match, status, source_indent, background)
124
+ return if @hide_this_step
155
125
  line = "<b>#{keyword}</b> #{step_match.format_args("%s").gsub('<', '&lt;').gsub('>', '&gt;')}"
156
126
  colorize(line, status)
157
127
  end
158
128
 
159
- def visit_background(background)
129
+ def before_background(background)
160
130
  @in_background = true
161
- super
131
+ end
132
+
133
+ def after_background(background)
162
134
  @in_background = nil
163
135
  end
164
136
 
165
- def visit_multiline_arg(table)
137
+ def before_multiline_arg(table)
138
+ return if @hide_this_step
166
139
  if(table.kind_of? Cucumber::Ast::Table)
167
140
  keep_with do
168
141
  @doc.table(table.rows << table.headers , :position => :center, :row_colors => ['ffffff', 'f0f0f0'])
169
142
  end
170
143
  end
171
- super
172
144
  end
173
145
 
174
146
  #using row_color hack to highlight each row correctly
175
- def visit_outline_table(table)
147
+ def before_outline_table(table)
148
+ return if @hide_this_step
176
149
  row_colors = table.example_rows.map { |r| @status_colors[r.status] unless r.status == :skipped}
177
150
  keep_with do
178
151
  @doc.table(table.rows, :headers => table.headers, :position => :center, :row_colors => row_colors)
179
152
  end
180
153
  end
181
154
 
182
- def visit_py_string(string)
155
+ def before_py_string(string)
156
+ return if @hide_this_step
183
157
  s = %{"""\n#{string}\n"""}.indent(10)
184
158
  s = s.split("\n").map{|l| l =~ /^\s+$/ ? '' : l}
185
159
  s.each do |line|
@@ -189,28 +163,59 @@ module Cucumber
189
163
  end
190
164
  end
191
165
 
192
- def visit_comment(comment)
193
- comment.accept(self)
166
+ def tag_name(tag_name)
167
+ return if @hide_this_step
168
+ tag = format_string(tag_name, :tag).indent(@indent)
169
+ # TODO should we render tags at all? skipped for now. difficult to place due to page breaks
194
170
  end
195
171
 
196
- def visit_comment_line(comment_line)
172
+ def background_name(keyword, name, file_colon_line, source_indent)
173
+ feature_element_name(keyword, name)
197
174
  end
198
175
 
199
- def visit_tag_name(tag_name)
200
- tag = format_string(tag_name, :tag).indent(@indent)
201
- # TODO should we render tags at all? skipped for now. difficult to place due to page breaks
176
+ def examples_name(keyword, name)
177
+ feature_element_name(keyword, name)
202
178
  end
203
179
 
204
- def visit_background_name(keyword, name, file_colon_line, source_indent)
205
- visit_feature_element_name(keyword, name)
180
+ def scenario_name(keyword, name, file_colon_line, source_indent)
181
+ feature_element_name(keyword, name)
182
+ end
183
+
184
+ private
185
+
186
+ def colorize(text, status)
187
+ keep_with do
188
+ @doc.fill_color(@status_colors[status] || BLACK)
189
+ @doc.text(text)
190
+ @doc.fill_color(BLACK)
191
+ end
192
+ end
193
+
194
+ def keep_with(&block)
195
+ @buffer << block
206
196
  end
207
197
 
208
- def visit_examples_name(keyword, name)
209
- visit_feature_element_name(keyword, name)
198
+ def render(doc)
199
+ @doc = doc
200
+ @buffer.each do |proc|
201
+ proc.call
202
+ end
210
203
  end
211
204
 
212
- def visit_scenario_name(keyword, name, file_colon_line, source_indent)
213
- visit_feature_element_name(keyword, name)
205
+ # This method does a 'test' rendering on a blank page, to see the rendered height of the buffer
206
+ # if that too high for the space left on the age in the real document, we do a page break.
207
+ # This obviously doesn't work if a scenario is longer than a whole page (God forbid)
208
+ def flush
209
+ @scrap.start_new_page
210
+ oldy = @scrap.y
211
+ render @scrap
212
+ height = (oldy - @scrap.y) + 36 # whops magic number
213
+ if ((@pdf.y - height) < @pdf.bounds.bottom)
214
+ @pdf.start_new_page
215
+ end
216
+ render @pdf
217
+ @pdf.move_down(20)
218
+ @buffer = []
214
219
  end
215
220
  end
216
221
  end
@@ -10,191 +10,192 @@ module Cucumber
10
10
  #
11
11
  # If the output is STDOUT (and not a file), there are bright colours to watch too.
12
12
  #
13
- class Pretty < Ast::Visitor
13
+ class Pretty
14
14
  include FileUtils
15
15
  include Console
16
16
  attr_writer :indent
17
+ attr_reader :step_mother
17
18
 
18
19
  def initialize(step_mother, io, options)
19
- super(step_mother)
20
- @io = io
21
- @options = options
20
+ @step_mother, @io, @options = step_mother, io, options
22
21
  @exceptions = []
23
22
  @indent = 0
24
23
  @prefixes = options[:prefixes] || {}
25
24
  end
26
25
 
27
- def visit_features(features)
28
- super
26
+ def after_features(features)
29
27
  print_summary(features) unless @options[:autoformat]
30
28
  end
31
29
 
32
- def visit_feature(feature)
30
+ def before_feature(feature)
33
31
  @exceptions = []
34
32
  @indent = 0
35
33
  if @options[:autoformat]
36
34
  file = File.join(@options[:autoformat], feature.file)
37
35
  dir = File.dirname(file)
38
36
  mkdir_p(dir) unless File.directory?(dir)
39
- File.open(file, Cucumber.file_mode('w')) do |io|
40
- @io = io
41
- super
42
- end
43
- else
44
- super
37
+ @io = File.open(file, Cucumber.file_mode('w'))
45
38
  end
46
39
  end
47
-
48
- def visit_comment(comment)
49
- comment.accept(self)
40
+
41
+ def after_feature(*args)
42
+ @io.close if @options[:autoformat]
50
43
  end
51
44
 
52
- def visit_comment_line(comment_line)
45
+ def comment_line(comment_line)
53
46
  @io.puts(comment_line.indent(@indent))
54
47
  @io.flush
55
48
  end
56
49
 
57
- def visit_tags(tags)
58
- tags.accept(self)
50
+ def after_tags(tags)
59
51
  if @indent == 1
60
52
  @io.puts
61
53
  @io.flush
62
54
  end
63
55
  end
64
56
 
65
- def visit_tag_name(tag_name)
57
+ def tag_name(tag_name)
66
58
  tag = format_string(tag_name, :tag).indent(@indent)
67
59
  @io.print(tag)
68
60
  @io.flush
69
61
  @indent = 1
70
62
  end
71
63
 
72
- def visit_feature_name(name)
64
+ def feature_name(name)
73
65
  @io.puts(name)
74
66
  @io.puts
75
67
  @io.flush
76
68
  end
77
69
 
78
- def visit_feature_element(feature_element)
70
+ def before_feature_element(feature_element)
79
71
  record_tag_occurrences(feature_element, @options)
80
72
  @indent = 2
81
73
  @scenario_indent = 2
82
- super
74
+ end
75
+
76
+ def after_feature_element(feature_element)
83
77
  @io.puts
84
78
  @io.flush
85
79
  end
86
80
 
87
- def visit_background(background)
81
+ def before_background(background)
88
82
  @indent = 2
89
83
  @scenario_indent = 2
90
84
  @in_background = true
91
- super
85
+ end
86
+
87
+ def after_background(background)
92
88
  @in_background = nil
93
89
  @io.puts
94
90
  @io.flush
95
91
  end
96
92
 
97
- def visit_background_name(keyword, name, file_colon_line, source_indent)
98
- visit_feature_element_name(keyword, name, file_colon_line, source_indent)
93
+ def background_name(keyword, name, file_colon_line, source_indent)
94
+ print_feature_element_name(keyword, name, file_colon_line, source_indent)
99
95
  end
100
96
 
101
- def visit_examples_array(examples_array)
97
+ def before_examples_array(examples_array)
102
98
  @indent = 4
103
99
  @io.puts
104
- examples_array[0..-2].each { |ea| super(ea) }
105
- @last_example = true
106
- super(examples_array.last)
107
- @last_example = nil
100
+ @visiting_first_example_name = true
108
101
  end
109
102
 
110
- def visit_examples_name(keyword, name)
111
- names = name.strip.empty? ? [name.strip] : name.split("\n")
103
+ def examples_name(keyword, name)
104
+ puts unless @visiting_first_example_name
105
+ @visiting_first_example_name = false
106
+ names = name.strip.empty? ? [name.strip] : name.split("\n")
112
107
  @io.puts(" #{keyword} #{names[0]}")
113
108
  names[1..-1].each {|s| @io.puts " #{s}" } unless names.empty?
114
109
  @io.flush
115
110
  @indent = 6
116
111
  @scenario_indent = 6
117
112
  end
113
+
114
+ def before_outline_table(outline_table)
115
+ @table = outline_table
116
+ end
118
117
 
119
- def visit_outline_table(outline_table)
120
- super
118
+ def after_outline_table(outline_table)
119
+ @table = nil
121
120
  @indent = 4
122
- @io.puts unless @last_example
123
121
  end
124
122
 
125
- def visit_scenario_name(keyword, name, file_colon_line, source_indent)
126
- visit_feature_element_name(keyword, name, file_colon_line, source_indent)
127
- end
128
-
129
- def visit_feature_element_name(keyword, name, file_colon_line, source_indent)
130
- @io.puts if @scenario_indent == 6
131
- names = name.empty? ? [name] : name.split("\n")
132
- line = "#{keyword} #{names[0]}".indent(@scenario_indent)
133
- @io.print(line)
134
- if @options[:source]
135
- line_comment = " # #{file_colon_line}".indent(source_indent)
136
- @io.print(format_string(line_comment, :comment))
137
- end
138
- @io.puts
139
- names[1..-1].each {|s| @io.puts " #{s}"}
140
- @io.flush
123
+ def scenario_name(keyword, name, file_colon_line, source_indent)
124
+ print_feature_element_name keyword, name, file_colon_line, source_indent
141
125
  end
142
126
 
143
- def visit_step(step)
127
+ def before_step(step)
128
+ @current_step = step
144
129
  @indent = 6
145
- super
146
130
  end
147
131
 
148
- def visit_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
132
+ def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
133
+ @hide_this_step = false
149
134
  if exception
150
- return if @exceptions.index(exception)
135
+ if @exceptions.include?(exception)
136
+ @hide_this_step = true
137
+ return
138
+ end
151
139
  @exceptions << exception
152
140
  end
153
- return if status != :failed && @in_background ^ background
141
+ if status != :failed && @in_background ^ background
142
+ @hide_this_step = true
143
+ return
144
+ end
154
145
  @status = status
155
- super
156
146
  end
157
147
 
158
- def visit_step_name(keyword, step_match, status, source_indent, background)
148
+ def step_name(keyword, step_match, status, source_indent, background)
149
+ return if @hide_this_step
159
150
  source_indent = nil unless @options[:source]
160
151
  formatted_step_name = format_step(keyword, step_match, status, source_indent)
161
152
  @io.puts(formatted_step_name.indent(@scenario_indent + 2))
162
153
  end
163
154
 
164
- def visit_multiline_arg(multiline_arg)
165
- return if @options[:no_multiline]
166
- @table = multiline_arg
167
- super
155
+ def py_string(string)
156
+ return if @hide_this_step
157
+ s = %{"""\n#{string}\n"""}.indent(@indent)
158
+ s = s.split("\n").map{|l| l =~ /^\s+$/ ? '' : l}.join("\n")
159
+ @io.puts(format_string(s, @current_step.status))
160
+ @io.flush
168
161
  end
169
162
 
170
- def visit_exception(exception, status)
163
+ def exception(exception, status)
164
+ return if @hide_this_step
171
165
  print_exception(exception, status, @indent)
172
166
  @io.flush
173
167
  end
174
168
 
175
- def visit_table_row(table_row)
169
+ def before_multiline_arg(multiline_arg)
170
+ return if @options[:no_multiline] || @hide_this_step
171
+ @table = multiline_arg
172
+ end
173
+
174
+ def after_multiline_arg(multiline_arg)
175
+ @table = nil
176
+ end
177
+
178
+ def before_table_row(table_row)
179
+ return unless @table
176
180
  @col_index = 0
177
181
  @io.print ' |'.indent(@indent-2)
178
- super
182
+ end
183
+
184
+ def after_table_row(table_row)
185
+ return unless @table
179
186
  @io.puts
180
- if table_row.exception && !@exceptions.index(table_row.exception)
187
+ if table_row.exception && !@exceptions.include?(table_row.exception)
181
188
  print_exception(table_row.exception, :failed, @indent)
182
189
  end
183
190
  end
184
191
 
185
- def visit_py_string(string)
186
- s = %{"""\n#{string}\n"""}.indent(@indent)
187
- s = s.split("\n").map{|l| l =~ /^\s+$/ ? '' : l}.join("\n")
188
- @io.puts(format_string(s, @status))
189
- @io.flush
190
- end
191
-
192
- def visit_table_cell(cell)
193
- super
192
+ def after_table_cell(cell)
193
+ return unless @table
194
194
  @col_index += 1
195
195
  end
196
196
 
197
- def visit_table_cell_value(value, status)
197
+ def table_cell_value(value, status)
198
+ return unless @table
198
199
  status ||= @status || :passed
199
200
  width = @table.col_width(@col_index)
200
201
  cell_text = value.to_s || ''
@@ -205,6 +206,20 @@ module Cucumber
205
206
  end
206
207
 
207
208
  private
209
+
210
+ def print_feature_element_name(keyword, name, file_colon_line, source_indent)
211
+ @io.puts if @scenario_indent == 6
212
+ names = name.empty? ? [name] : name.split("\n")
213
+ line = "#{keyword} #{names[0]}".indent(@scenario_indent)
214
+ @io.print(line)
215
+ if @options[:source]
216
+ line_comment = " # #{file_colon_line}".indent(source_indent)
217
+ @io.print(format_string(line_comment, :comment))
218
+ end
219
+ @io.puts
220
+ names[1..-1].each {|s| @io.puts " #{s}"}
221
+ @io.flush
222
+ end
208
223
 
209
224
  def cell_prefix(status)
210
225
  @prefixes[status]