benhamill-gherkin 2.3.5

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 (170) hide show
  1. data/.gitattributes +2 -0
  2. data/.gitignore +11 -0
  3. data/.mailmap +2 -0
  4. data/.rspec +1 -0
  5. data/.rvmrc +1 -0
  6. data/Gemfile +7 -0
  7. data/History.txt +363 -0
  8. data/LICENSE +20 -0
  9. data/README.rdoc +149 -0
  10. data/Rakefile +19 -0
  11. data/VERSION +1 -0
  12. data/build_native_gems.sh +8 -0
  13. data/cucumber.yml +3 -0
  14. data/features/escaped_pipes.feature +8 -0
  15. data/features/feature_parser.feature +237 -0
  16. data/features/json_formatter.feature +377 -0
  17. data/features/json_parser.feature +318 -0
  18. data/features/native_lexer.feature +19 -0
  19. data/features/parser_with_native_lexer.feature +205 -0
  20. data/features/pretty_formatter.feature +15 -0
  21. data/features/step_definitions/eyeball_steps.rb +3 -0
  22. data/features/step_definitions/gherkin_steps.rb +29 -0
  23. data/features/step_definitions/json_formatter_steps.rb +28 -0
  24. data/features/step_definitions/json_parser_steps.rb +20 -0
  25. data/features/step_definitions/pretty_formatter_steps.rb +84 -0
  26. data/features/steps_parser.feature +46 -0
  27. data/features/support/env.rb +38 -0
  28. data/gherkin.gemspec +61 -0
  29. data/ikvm/.gitignore +3 -0
  30. data/java/.gitignore +5 -0
  31. data/java/src/main/java/gherkin/lexer/i18n/.gitignore +1 -0
  32. data/java/src/main/resources/gherkin/.gitignore +1 -0
  33. data/js/lib/gherkin/lexer/i18n/ar.js +1094 -0
  34. data/js/lib/gherkin/lexer/i18n/bg.js +1308 -0
  35. data/js/lib/gherkin/lexer/i18n/ca.js +1236 -0
  36. data/js/lib/gherkin/lexer/i18n/cs.js +1090 -0
  37. data/js/lib/gherkin/lexer/i18n/cy_gb.js +958 -0
  38. data/js/lib/gherkin/lexer/i18n/da.js +974 -0
  39. data/js/lib/gherkin/lexer/i18n/de.js +1082 -0
  40. data/js/lib/gherkin/lexer/i18n/en.js +965 -0
  41. data/js/lib/gherkin/lexer/i18n/en_au.js +902 -0
  42. data/js/lib/gherkin/lexer/i18n/en_lol.js +859 -0
  43. data/js/lib/gherkin/lexer/i18n/en_pirate.js +1136 -0
  44. data/js/lib/gherkin/lexer/i18n/en_scouse.js +1289 -0
  45. data/js/lib/gherkin/lexer/i18n/en_tx.js +942 -0
  46. data/js/lib/gherkin/lexer/i18n/eo.js +916 -0
  47. data/js/lib/gherkin/lexer/i18n/es.js +1049 -0
  48. data/js/lib/gherkin/lexer/i18n/et.js +915 -0
  49. data/js/lib/gherkin/lexer/i18n/fi.js +894 -0
  50. data/js/lib/gherkin/lexer/i18n/fr.js +1116 -0
  51. data/js/lib/gherkin/lexer/i18n/he.js +1044 -0
  52. data/js/lib/gherkin/lexer/i18n/hr.js +994 -0
  53. data/js/lib/gherkin/lexer/i18n/hu.js +1043 -0
  54. data/js/lib/gherkin/lexer/i18n/id.js +884 -0
  55. data/js/lib/gherkin/lexer/i18n/it.js +1007 -0
  56. data/js/lib/gherkin/lexer/i18n/ja.js +1344 -0
  57. data/js/lib/gherkin/lexer/i18n/ko.js +1028 -0
  58. data/js/lib/gherkin/lexer/i18n/lt.js +972 -0
  59. data/js/lib/gherkin/lexer/i18n/lu.js +1057 -0
  60. data/js/lib/gherkin/lexer/i18n/lv.js +1092 -0
  61. data/js/lib/gherkin/lexer/i18n/nl.js +1036 -0
  62. data/js/lib/gherkin/lexer/i18n/no.js +986 -0
  63. data/js/lib/gherkin/lexer/i18n/pl.js +1140 -0
  64. data/js/lib/gherkin/lexer/i18n/pt.js +1000 -0
  65. data/js/lib/gherkin/lexer/i18n/ro.js +1089 -0
  66. data/js/lib/gherkin/lexer/i18n/ru.js +1560 -0
  67. data/js/lib/gherkin/lexer/i18n/sk.js +972 -0
  68. data/js/lib/gherkin/lexer/i18n/sr_cyrl.js +1728 -0
  69. data/js/lib/gherkin/lexer/i18n/sr_latn.js +1220 -0
  70. data/js/lib/gherkin/lexer/i18n/sv.js +997 -0
  71. data/js/lib/gherkin/lexer/i18n/tr.js +1014 -0
  72. data/js/lib/gherkin/lexer/i18n/uk.js +1572 -0
  73. data/js/lib/gherkin/lexer/i18n/uz.js +1302 -0
  74. data/js/lib/gherkin/lexer/i18n/vi.js +1124 -0
  75. data/js/lib/gherkin/lexer/i18n/zh_cn.js +902 -0
  76. data/js/lib/gherkin/lexer/i18n/zh_tw.js +940 -0
  77. data/lib/.gitignore +4 -0
  78. data/lib/gherkin.rb +2 -0
  79. data/lib/gherkin/c_lexer.rb +17 -0
  80. data/lib/gherkin/formatter/ansi_escapes.rb +95 -0
  81. data/lib/gherkin/formatter/argument.rb +16 -0
  82. data/lib/gherkin/formatter/escaping.rb +15 -0
  83. data/lib/gherkin/formatter/filter_formatter.rb +136 -0
  84. data/lib/gherkin/formatter/hashable.rb +19 -0
  85. data/lib/gherkin/formatter/json_formatter.rb +102 -0
  86. data/lib/gherkin/formatter/line_filter.rb +26 -0
  87. data/lib/gherkin/formatter/model.rb +236 -0
  88. data/lib/gherkin/formatter/pretty_formatter.rb +243 -0
  89. data/lib/gherkin/formatter/regexp_filter.rb +21 -0
  90. data/lib/gherkin/formatter/step_printer.rb +17 -0
  91. data/lib/gherkin/formatter/tag_count_formatter.rb +47 -0
  92. data/lib/gherkin/formatter/tag_filter.rb +19 -0
  93. data/lib/gherkin/i18n.rb +175 -0
  94. data/lib/gherkin/i18n.yml +588 -0
  95. data/lib/gherkin/json_parser.rb +137 -0
  96. data/lib/gherkin/lexer/i18n_lexer.rb +47 -0
  97. data/lib/gherkin/listener/event.rb +45 -0
  98. data/lib/gherkin/listener/formatter_listener.rb +113 -0
  99. data/lib/gherkin/native.rb +7 -0
  100. data/lib/gherkin/native/ikvm.rb +55 -0
  101. data/lib/gherkin/native/java.rb +55 -0
  102. data/lib/gherkin/native/null.rb +9 -0
  103. data/lib/gherkin/parser/meta.txt +5 -0
  104. data/lib/gherkin/parser/parser.rb +164 -0
  105. data/lib/gherkin/parser/root.txt +11 -0
  106. data/lib/gherkin/parser/steps.txt +4 -0
  107. data/lib/gherkin/rb_lexer.rb +8 -0
  108. data/lib/gherkin/rb_lexer/.gitignore +1 -0
  109. data/lib/gherkin/rb_lexer/README.rdoc +8 -0
  110. data/lib/gherkin/rubify.rb +24 -0
  111. data/lib/gherkin/tag_expression.rb +62 -0
  112. data/lib/gherkin/version.rb +3 -0
  113. data/ragel/i18n/.gitignore +1 -0
  114. data/ragel/lexer.c.rl.erb +439 -0
  115. data/ragel/lexer.java.rl.erb +208 -0
  116. data/ragel/lexer.rb.rl.erb +167 -0
  117. data/ragel/lexer_common.rl.erb +50 -0
  118. data/spec/gherkin/c_lexer_spec.rb +21 -0
  119. data/spec/gherkin/fixtures/1.feature +8 -0
  120. data/spec/gherkin/fixtures/comments_in_table.feature +9 -0
  121. data/spec/gherkin/fixtures/complex.feature +45 -0
  122. data/spec/gherkin/fixtures/complex.json +143 -0
  123. data/spec/gherkin/fixtures/complex_for_filtering.feature +60 -0
  124. data/spec/gherkin/fixtures/complex_with_tags.feature +61 -0
  125. data/spec/gherkin/fixtures/dos_line_endings.feature +45 -0
  126. data/spec/gherkin/fixtures/hantu_pisang.feature +35 -0
  127. data/spec/gherkin/fixtures/i18n_fr.feature +14 -0
  128. data/spec/gherkin/fixtures/i18n_no.feature +7 -0
  129. data/spec/gherkin/fixtures/i18n_zh-CN.feature +9 -0
  130. data/spec/gherkin/fixtures/scenario_outline_with_tags.feature +13 -0
  131. data/spec/gherkin/fixtures/scenario_without_steps.feature +5 -0
  132. data/spec/gherkin/fixtures/simple_with_comments.feature +7 -0
  133. data/spec/gherkin/fixtures/simple_with_tags.feature +11 -0
  134. data/spec/gherkin/fixtures/with_bom.feature +3 -0
  135. data/spec/gherkin/formatter/ansi_escapes_spec.rb +19 -0
  136. data/spec/gherkin/formatter/filter_formatter_spec.rb +165 -0
  137. data/spec/gherkin/formatter/model_spec.rb +28 -0
  138. data/spec/gherkin/formatter/pretty_formatter_spec.rb +158 -0
  139. data/spec/gherkin/formatter/spaces.feature +9 -0
  140. data/spec/gherkin/formatter/step_printer_spec.rb +55 -0
  141. data/spec/gherkin/formatter/tabs.feature +9 -0
  142. data/spec/gherkin/formatter/tag_count_formatter_spec.rb +30 -0
  143. data/spec/gherkin/i18n_spec.rb +152 -0
  144. data/spec/gherkin/java_lexer_spec.rb +20 -0
  145. data/spec/gherkin/java_libs.rb +20 -0
  146. data/spec/gherkin/json_parser_spec.rb +113 -0
  147. data/spec/gherkin/lexer/i18n_lexer_spec.rb +43 -0
  148. data/spec/gherkin/output_stream_string_io.rb +20 -0
  149. data/spec/gherkin/parser/parser_spec.rb +16 -0
  150. data/spec/gherkin/rb_lexer_spec.rb +19 -0
  151. data/spec/gherkin/sexp_recorder.rb +56 -0
  152. data/spec/gherkin/shared/lexer_group.rb +593 -0
  153. data/spec/gherkin/shared/py_string_group.rb +153 -0
  154. data/spec/gherkin/shared/row_group.rb +125 -0
  155. data/spec/gherkin/shared/tags_group.rb +54 -0
  156. data/spec/gherkin/tag_expression_spec.rb +137 -0
  157. data/spec/spec_helper.rb +69 -0
  158. data/tasks/bench.rake +184 -0
  159. data/tasks/bench/feature_builder.rb +49 -0
  160. data/tasks/bench/generated/.gitignore +1 -0
  161. data/tasks/bench/null_listener.rb +4 -0
  162. data/tasks/compile.rake +102 -0
  163. data/tasks/cucumber.rake +20 -0
  164. data/tasks/gems.rake +35 -0
  165. data/tasks/ikvm.rake +79 -0
  166. data/tasks/ragel_task.rb +70 -0
  167. data/tasks/rdoc.rake +9 -0
  168. data/tasks/release.rake +30 -0
  169. data/tasks/rspec.rake +8 -0
  170. metadata +609 -0
@@ -0,0 +1,236 @@
1
+ require 'gherkin/native'
2
+ require 'gherkin/formatter/hashable'
3
+
4
+ module Gherkin
5
+ module Formatter
6
+ module Model
7
+ class BasicStatement < Hashable
8
+ attr_reader :comments, :keyword, :name, :line
9
+
10
+ def initialize(comments, keyword, name, line)
11
+ @comments, @keyword, @name, @line = comments, keyword, name, line
12
+ end
13
+
14
+ def line_range
15
+ first = @comments.any? ? @comments[0].line : first_non_comment_line
16
+ first..line
17
+ end
18
+
19
+ def first_non_comment_line
20
+ @line
21
+ end
22
+ end
23
+
24
+ class DescribedStatement < BasicStatement
25
+ attr_reader :description
26
+
27
+ def initialize(comments, keyword, name, description, line)
28
+ super(comments, keyword, name, line)
29
+ @description = description
30
+ end
31
+ end
32
+
33
+ class TagStatement < DescribedStatement
34
+ attr_reader :tags
35
+
36
+ def initialize(comments, tags, keyword, name, description, line)
37
+ super(comments, keyword, name, description, line)
38
+ @tags = tags
39
+ end
40
+
41
+ def first_non_comment_line
42
+ @tags.any? ? @tags[0].line : @line
43
+ end
44
+ end
45
+
46
+ class Feature < TagStatement
47
+ native_impl('gherkin')
48
+
49
+ def initialize(comments, tags, keyword, name, description, line)
50
+ super(comments, tags, keyword, name, description, line)
51
+ end
52
+
53
+ def replay(formatter)
54
+ formatter.feature(self)
55
+ end
56
+ end
57
+
58
+ class Background < DescribedStatement
59
+ native_impl('gherkin')
60
+
61
+ def initialize(comments, keyword, name, description, line)
62
+ super(comments, keyword, name, description, line)
63
+ @type = "background"
64
+ end
65
+
66
+ def replay(formatter)
67
+ formatter.background(self)
68
+ end
69
+ end
70
+
71
+ class Scenario < TagStatement
72
+ native_impl('gherkin')
73
+
74
+ def initialize(comments, tags, keyword, name, description, line)
75
+ super(comments, tags, keyword, name, description, line)
76
+ @type = "scenario"
77
+ end
78
+
79
+ def replay(formatter)
80
+ formatter.scenario(self)
81
+ end
82
+ end
83
+
84
+ class ScenarioOutline < TagStatement
85
+ native_impl('gherkin')
86
+
87
+ def initialize(comments, tags, keyword, name, description, line)
88
+ super(comments, tags, keyword, name, description, line)
89
+ @type = "scenario_outline"
90
+ end
91
+
92
+ def replay(formatter)
93
+ formatter.scenario_outline(self)
94
+ end
95
+ end
96
+
97
+ class Examples < TagStatement
98
+ native_impl('gherkin')
99
+
100
+ attr_accessor :rows
101
+
102
+ def initialize(comments, tags, keyword, name, description, line, rows=nil)
103
+ super(comments, tags, keyword, name, description, line)
104
+ @rows = rows
105
+ end
106
+
107
+ def replay(formatter)
108
+ formatter.examples(self)
109
+ end
110
+ end
111
+
112
+ class Step < BasicStatement
113
+ native_impl('gherkin')
114
+
115
+ attr_accessor :multiline_arg
116
+
117
+ def line_range
118
+ range = super
119
+ case multiline_arg
120
+ when Array
121
+ range = range.first..multiline_arg[-1].line
122
+ when Model::PyString
123
+ range = range.first..multiline_arg.line_range.last
124
+ end
125
+ range
126
+ end
127
+
128
+ def replay(formatter)
129
+ formatter.step(self)
130
+ end
131
+
132
+ def outline_args
133
+ offset = 0
134
+ name.scan(/<[^<]*>/).map do |val|
135
+ offset = name.index(val, offset)
136
+ Argument.new(offset, val)
137
+ end
138
+ end
139
+
140
+ def to_hash
141
+ hash = super
142
+ if Array === @multiline_arg
143
+ hash['multiline_arg'] = {
144
+ 'type' => 'table',
145
+ 'value' => hash['multiline_arg']
146
+ }
147
+ elsif PyString === @multiline_arg
148
+ hash['multiline_arg']['type'] = 'py_string'
149
+ end
150
+ hash
151
+ end
152
+ end
153
+
154
+ class Comment < Hashable
155
+ native_impl('gherkin')
156
+
157
+ attr_reader :value, :line
158
+
159
+ def initialize(value, line)
160
+ @value, @line = value, line
161
+ end
162
+ end
163
+
164
+ class Tag < Hashable
165
+ native_impl('gherkin')
166
+
167
+ attr_reader :name, :line
168
+
169
+ def initialize(name, line)
170
+ @name, @line = name, line
171
+ end
172
+
173
+ def eql?(tag)
174
+ @name.eql?(tag.name)
175
+ end
176
+
177
+ def hash
178
+ @name.hash
179
+ end
180
+ end
181
+
182
+ class PyString < Hashable
183
+ native_impl('gherkin')
184
+
185
+ attr_reader :value, :line
186
+
187
+ def initialize(value, line)
188
+ @value, @line = value, line
189
+ end
190
+
191
+ def line_range
192
+ line_count = value.split(/\r?\n/).length
193
+ line..(line+line_count+1)
194
+ end
195
+ end
196
+
197
+ class Row < Hashable
198
+ native_impl('gherkin')
199
+
200
+ attr_reader :comments, :cells, :line
201
+
202
+ def initialize(comments, cells, line)
203
+ @comments, @cells, @line = comments, cells, line
204
+ end
205
+ end
206
+
207
+ class Match < Hashable
208
+ native_impl('gherkin')
209
+
210
+ attr_reader :arguments, :location
211
+
212
+ def initialize(arguments, location)
213
+ @arguments, @location = arguments, location
214
+ end
215
+
216
+ def replay(formatter)
217
+ formatter.match(self)
218
+ end
219
+ end
220
+
221
+ class Result < Hashable
222
+ native_impl('gherkin')
223
+
224
+ attr_reader :status, :duration, :error_message
225
+
226
+ def initialize(status, duration, error_message)
227
+ @status, @duration, @error_message = status, duration, error_message
228
+ end
229
+
230
+ def replay(formatter)
231
+ formatter.result(self)
232
+ end
233
+ end
234
+ end
235
+ end
236
+ end
@@ -0,0 +1,243 @@
1
+ # encoding: utf-8
2
+ require 'gherkin/formatter/ansi_escapes'
3
+ require 'gherkin/formatter/step_printer'
4
+ require 'gherkin/formatter/argument'
5
+ require 'gherkin/formatter/escaping'
6
+ require 'gherkin/formatter/model'
7
+ require 'gherkin/native'
8
+
9
+ module Gherkin
10
+ module Formatter
11
+ class PrettyFormatter
12
+ native_impl('gherkin')
13
+
14
+ include AnsiEscapes
15
+ include Escaping
16
+
17
+ def initialize(io, monochrome, executing)
18
+ @io = io
19
+ @step_printer = StepPrinter.new
20
+ @monochrome = monochrome
21
+ @executing = executing
22
+ @background = nil
23
+ @tag_statement = nil
24
+ @steps = []
25
+ end
26
+
27
+ def uri(uri)
28
+ @uri = uri
29
+ end
30
+
31
+ def feature(feature)
32
+ print_comments(feature.comments, '')
33
+ print_tags(feature.tags, '')
34
+ @io.puts "#{feature.keyword}: #{feature.name}"
35
+ print_description(feature.description, ' ', false)
36
+ end
37
+
38
+ def background(background)
39
+ replay
40
+ @statement = background
41
+ end
42
+
43
+ def scenario(scenario)
44
+ replay
45
+ @statement = scenario
46
+ end
47
+
48
+ def scenario_outline(scenario_outline)
49
+ replay
50
+ @statement = scenario_outline
51
+ end
52
+
53
+ def replay
54
+ print_statement
55
+ print_steps
56
+ end
57
+
58
+ def print_statement
59
+ return if @statement.nil?
60
+ calculate_location_indentations
61
+ @io.puts
62
+ print_comments(@statement.comments, ' ')
63
+ print_tags(@statement.tags, ' ') if @statement.respond_to?(:tags) # Background doesn't
64
+ @io.write " #{@statement.keyword}: #{@statement.name}"
65
+ location = @executing ? "#{@uri}:#{@statement.line}" : nil
66
+ @io.puts indented_location(location, true)
67
+ print_description(@statement.description, ' ')
68
+ @statement = nil
69
+ end
70
+
71
+ def print_steps
72
+ while(@steps.any?)
73
+ print_step('skipped', [], nil, true)
74
+ end
75
+ end
76
+
77
+ def examples(examples)
78
+ replay
79
+ @io.puts
80
+ print_comments(examples.comments, ' ')
81
+ print_tags(examples.tags, ' ')
82
+ @io.puts " #{examples.keyword}: #{examples.name}"
83
+ print_description(examples.description, ' ')
84
+ table(examples.rows)
85
+ end
86
+
87
+ def step(step)
88
+ @steps << step
89
+ end
90
+
91
+ def match(match)
92
+ @match = match
93
+ print_statement
94
+ print_step('executing', @match.arguments, @match.location, false)
95
+ end
96
+
97
+ def result(result)
98
+ @io.write(up(1))
99
+ print_step(result.status, @match.arguments, @match.location, true)
100
+ end
101
+
102
+ def print_step(status, arguments, location, proceed)
103
+ step = proceed ? @steps.shift : @steps[0]
104
+
105
+ text_format = format(status)
106
+ arg_format = arg_format(status)
107
+
108
+ print_comments(step.comments, ' ')
109
+ @io.write(' ')
110
+ @io.write(text_format.text(step.keyword))
111
+ @step_printer.write_step(@io, text_format, arg_format, step.name, arguments)
112
+ @io.puts(indented_location(location, proceed))
113
+ case step.multiline_arg
114
+ when Model::PyString
115
+ py_string(step.multiline_arg)
116
+ when Array
117
+ table(step.multiline_arg)
118
+ end
119
+ end
120
+
121
+ class MonochromeFormat
122
+ def text(text)
123
+ text
124
+ end
125
+ end
126
+
127
+ class ColorFormat
128
+ include AnsiEscapes
129
+
130
+ def initialize(status)
131
+ @status = status
132
+ end
133
+
134
+ def text(text)
135
+ self.__send__(@status) + text + reset
136
+ end
137
+ end
138
+
139
+ def arg_format(key)
140
+ format("#{key}_arg")
141
+ end
142
+
143
+ def format(key)
144
+ if @formats.nil?
145
+ if @monochrome
146
+ @formats = Hash.new(MonochromeFormat.new)
147
+ else
148
+ @formats = Hash.new do |formats, status|
149
+ formats[status] = ColorFormat.new(status)
150
+ end
151
+ end
152
+ end
153
+ @formats[key]
154
+ end
155
+
156
+ def eof
157
+ replay
158
+ # NO-OP
159
+ end
160
+
161
+ def table(rows)
162
+ cell_lengths = rows.map do |row|
163
+ row.cells.map do |cell|
164
+ escape_cell(cell).unpack("U*").length
165
+ end
166
+ end
167
+ max_lengths = cell_lengths.transpose.map { |col_lengths| col_lengths.max }.flatten
168
+
169
+ rows.each_with_index do |row, i|
170
+ row.comments.each do |comment|
171
+ @io.puts " #{comment.value}"
172
+ end
173
+ j = -1
174
+ @io.puts ' | ' + row.cells.zip(max_lengths).map { |cell, max_length|
175
+ j += 1
176
+ color(cell, nil, j) + ' ' * (max_length - cell_lengths[i][j])
177
+ }.join(' | ') + ' |'
178
+ end
179
+ end
180
+
181
+ private
182
+
183
+ def py_string(py_string)
184
+ @io.puts " \"\"\"\n" + escape_triple_quotes(indent(py_string.value, ' ')) + "\n \"\"\""
185
+ end
186
+
187
+ def exception(exception)
188
+ exception_text = "#{exception.message} (#{exception.class})\n#{(exception.backtrace || []).join("\n")}".gsub(/^/, ' ')
189
+ @io.puts(failed(exception_text))
190
+ end
191
+
192
+ def color(cell, statuses, col)
193
+ if statuses
194
+ self.__send__(statuses[col], escape_cell(cell)) + reset
195
+ else
196
+ escape_cell(cell)
197
+ end
198
+ end
199
+
200
+ if(RUBY_VERSION =~ /^1\.9/)
201
+ START = /#{'^'.encode('UTF-8')}/
202
+ TRIPLE_QUOTES = /#{'"""'.encode('UTF-8')}/
203
+ else
204
+ START = /^/
205
+ TRIPLE_QUOTES = /"""/
206
+ end
207
+
208
+ def indent(string, indentation)
209
+ string.gsub(START, indentation)
210
+ end
211
+
212
+ def escape_triple_quotes(s)
213
+ s.gsub(TRIPLE_QUOTES, '\"\"\"')
214
+ end
215
+
216
+ def print_tags(tags, indent)
217
+ @io.write(tags.empty? ? '' : indent + tags.map{|tag| tag.name}.join(' ') + "\n")
218
+ end
219
+
220
+ def print_comments(comments, indent)
221
+ @io.write(comments.empty? ? '' : indent + comments.map{|comment| comment.value}.join("\n#{indent}") + "\n")
222
+ end
223
+
224
+ def print_description(description, indent, newline=true)
225
+ if description != ""
226
+ @io.puts indent(description, indent)
227
+ @io.puts if newline
228
+ end
229
+ end
230
+
231
+ def indented_location(location, proceed)
232
+ indentation = proceed ? @indentations.shift : @indentations[0]
233
+ location ? (' ' * indentation + ' ' + comments + "# #{location}" + reset) : ''
234
+ end
235
+
236
+ def calculate_location_indentations
237
+ line_widths = ([@statement] + @steps).map {|step| (step.keyword+step.name).unpack("U*").length}
238
+ max_line_width = line_widths.max
239
+ @indentations = line_widths.map{|w| max_line_width - w}
240
+ end
241
+ end
242
+ end
243
+ end