bryanl-gherkin 2.11.1.1

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 (187) hide show
  1. data/.gitattributes +2 -0
  2. data/.mailmap +2 -0
  3. data/.rbenv-gemsets +1 -0
  4. data/.rspec +1 -0
  5. data/.rvmrc +1 -0
  6. data/.travis.yml +16 -0
  7. data/.yardopts +5 -0
  8. data/Gemfile +5 -0
  9. data/History.md +788 -0
  10. data/LICENSE +20 -0
  11. data/README.md +272 -0
  12. data/Rakefile +26 -0
  13. data/build_native_gems.sh +7 -0
  14. data/cucumber.yml +4 -0
  15. data/examples/parse_and_output_json.rb +19 -0
  16. data/features/.cucumber/stepdefs.json +244 -0
  17. data/features/escaped_pipes.feature +8 -0
  18. data/features/feature_parser.feature +237 -0
  19. data/features/json_formatter.feature +498 -0
  20. data/features/json_parser.feature +331 -0
  21. data/features/native_lexer.feature +19 -0
  22. data/features/parser_with_native_lexer.feature +205 -0
  23. data/features/pretty_formatter.feature +16 -0
  24. data/features/step_definitions/eyeball_steps.rb +3 -0
  25. data/features/step_definitions/gherkin_steps.rb +29 -0
  26. data/features/step_definitions/json_formatter_steps.rb +30 -0
  27. data/features/step_definitions/json_parser_steps.rb +20 -0
  28. data/features/step_definitions/pretty_formatter_steps.rb +85 -0
  29. data/features/steps_parser.feature +46 -0
  30. data/features/support/env.rb +42 -0
  31. data/gherkin.gemspec +77 -0
  32. data/install_mingw_os_x.sh +7 -0
  33. data/js/.npmignore +1 -0
  34. data/js/lib/gherkin/lexer/.npmignore +0 -0
  35. data/lib/gherkin.rb +2 -0
  36. data/lib/gherkin/c_lexer.rb +17 -0
  37. data/lib/gherkin/formatter/ansi_escapes.rb +97 -0
  38. data/lib/gherkin/formatter/argument.rb +16 -0
  39. data/lib/gherkin/formatter/escaping.rb +15 -0
  40. data/lib/gherkin/formatter/filter_formatter.rb +146 -0
  41. data/lib/gherkin/formatter/hashable.rb +19 -0
  42. data/lib/gherkin/formatter/json_formatter.rb +122 -0
  43. data/lib/gherkin/formatter/line_filter.rb +26 -0
  44. data/lib/gherkin/formatter/model.rb +281 -0
  45. data/lib/gherkin/formatter/pretty_formatter.rb +244 -0
  46. data/lib/gherkin/formatter/regexp_filter.rb +21 -0
  47. data/lib/gherkin/formatter/step_printer.rb +21 -0
  48. data/lib/gherkin/formatter/tag_count_formatter.rb +47 -0
  49. data/lib/gherkin/formatter/tag_filter.rb +19 -0
  50. data/lib/gherkin/i18n.rb +180 -0
  51. data/lib/gherkin/i18n.yml +613 -0
  52. data/lib/gherkin/js_lexer.rb +20 -0
  53. data/lib/gherkin/json_parser.rb +177 -0
  54. data/lib/gherkin/lexer/i18n_lexer.rb +46 -0
  55. data/lib/gherkin/listener/event.rb +45 -0
  56. data/lib/gherkin/listener/formatter_listener.rb +143 -0
  57. data/lib/gherkin/native.rb +7 -0
  58. data/lib/gherkin/native/java.rb +72 -0
  59. data/lib/gherkin/native/null.rb +5 -0
  60. data/lib/gherkin/native/therubyracer.rb +39 -0
  61. data/lib/gherkin/parser/meta.txt +5 -0
  62. data/lib/gherkin/parser/parser.rb +164 -0
  63. data/lib/gherkin/parser/root.txt +11 -0
  64. data/lib/gherkin/parser/steps.txt +4 -0
  65. data/lib/gherkin/rb_lexer.rb +8 -0
  66. data/lib/gherkin/rb_lexer/README.rdoc +8 -0
  67. data/lib/gherkin/rb_lexer/ar.rb +1165 -0
  68. data/lib/gherkin/rb_lexer/bg.rb +1377 -0
  69. data/lib/gherkin/rb_lexer/bm.rb +1081 -0
  70. data/lib/gherkin/rb_lexer/ca.rb +1305 -0
  71. data/lib/gherkin/rb_lexer/cs.rb +1157 -0
  72. data/lib/gherkin/rb_lexer/cy_gb.rb +1027 -0
  73. data/lib/gherkin/rb_lexer/da.rb +1043 -0
  74. data/lib/gherkin/rb_lexer/de.rb +1151 -0
  75. data/lib/gherkin/rb_lexer/en.rb +1151 -0
  76. data/lib/gherkin/rb_lexer/en_au.rb +971 -0
  77. data/lib/gherkin/rb_lexer/en_lol.rb +929 -0
  78. data/lib/gherkin/rb_lexer/en_pirate.rb +1205 -0
  79. data/lib/gherkin/rb_lexer/en_scouse.rb +1357 -0
  80. data/lib/gherkin/rb_lexer/en_tx.rb +1011 -0
  81. data/lib/gherkin/rb_lexer/eo.rb +990 -0
  82. data/lib/gherkin/rb_lexer/es.rb +1135 -0
  83. data/lib/gherkin/rb_lexer/et.rb +985 -0
  84. data/lib/gherkin/rb_lexer/fi.rb +964 -0
  85. data/lib/gherkin/rb_lexer/fr.rb +1223 -0
  86. data/lib/gherkin/rb_lexer/he.rb +1113 -0
  87. data/lib/gherkin/rb_lexer/hr.rb +1061 -0
  88. data/lib/gherkin/rb_lexer/hu.rb +1113 -0
  89. data/lib/gherkin/rb_lexer/id.rb +958 -0
  90. data/lib/gherkin/rb_lexer/is.rb +1115 -0
  91. data/lib/gherkin/rb_lexer/it.rb +1081 -0
  92. data/lib/gherkin/rb_lexer/ja.rb +1413 -0
  93. data/lib/gherkin/rb_lexer/ko.rb +1097 -0
  94. data/lib/gherkin/rb_lexer/lt.rb +1040 -0
  95. data/lib/gherkin/rb_lexer/lu.rb +1127 -0
  96. data/lib/gherkin/rb_lexer/lv.rb +1161 -0
  97. data/lib/gherkin/rb_lexer/nl.rb +1110 -0
  98. data/lib/gherkin/rb_lexer/no.rb +1055 -0
  99. data/lib/gherkin/rb_lexer/pl.rb +1452 -0
  100. data/lib/gherkin/rb_lexer/pt.rb +1425 -0
  101. data/lib/gherkin/rb_lexer/ro.rb +1159 -0
  102. data/lib/gherkin/rb_lexer/ru.rb +1749 -0
  103. data/lib/gherkin/rb_lexer/sk.rb +1041 -0
  104. data/lib/gherkin/rb_lexer/sr_cyrl.rb +1798 -0
  105. data/lib/gherkin/rb_lexer/sr_latn.rb +1289 -0
  106. data/lib/gherkin/rb_lexer/sv.rb +1065 -0
  107. data/lib/gherkin/rb_lexer/tr.rb +1087 -0
  108. data/lib/gherkin/rb_lexer/uk.rb +1641 -0
  109. data/lib/gherkin/rb_lexer/uz.rb +1371 -0
  110. data/lib/gherkin/rb_lexer/vi.rb +1193 -0
  111. data/lib/gherkin/rb_lexer/zh_cn.rb +1053 -0
  112. data/lib/gherkin/rb_lexer/zh_tw.rb +1047 -0
  113. data/lib/gherkin/rubify.rb +24 -0
  114. data/lib/gherkin/tag_expression.rb +62 -0
  115. data/ragel/lexer.c.rl.erb +454 -0
  116. data/ragel/lexer.java.rl.erb +219 -0
  117. data/ragel/lexer.js.rl.erb +227 -0
  118. data/ragel/lexer.rb.rl.erb +174 -0
  119. data/ragel/lexer_common.rl.erb +50 -0
  120. data/spec/gherkin/c_lexer_spec.rb +22 -0
  121. data/spec/gherkin/fixtures/1.feature +8 -0
  122. data/spec/gherkin/fixtures/comments_in_table.feature +9 -0
  123. data/spec/gherkin/fixtures/complex.feature +45 -0
  124. data/spec/gherkin/fixtures/complex.json +139 -0
  125. data/spec/gherkin/fixtures/complex_for_filtering.feature +60 -0
  126. data/spec/gherkin/fixtures/complex_with_tags.feature +61 -0
  127. data/spec/gherkin/fixtures/dos_line_endings.feature +45 -0
  128. data/spec/gherkin/fixtures/examples_with_only_header.feature +14 -0
  129. data/spec/gherkin/fixtures/hantu_pisang.feature +35 -0
  130. data/spec/gherkin/fixtures/i18n_fr.feature +14 -0
  131. data/spec/gherkin/fixtures/i18n_fr2.feature +8 -0
  132. data/spec/gherkin/fixtures/i18n_no.feature +7 -0
  133. data/spec/gherkin/fixtures/i18n_pt1.feature +44 -0
  134. data/spec/gherkin/fixtures/i18n_pt2.feature +4 -0
  135. data/spec/gherkin/fixtures/i18n_pt3.feature +4 -0
  136. data/spec/gherkin/fixtures/i18n_pt4.feature +4 -0
  137. data/spec/gherkin/fixtures/i18n_zh-CN.feature +9 -0
  138. data/spec/gherkin/fixtures/issue_145.feature +22 -0
  139. data/spec/gherkin/fixtures/scenario_outline_with_tags.feature +13 -0
  140. data/spec/gherkin/fixtures/scenario_without_steps.feature +5 -0
  141. data/spec/gherkin/fixtures/simple_with_comments.feature +7 -0
  142. data/spec/gherkin/fixtures/simple_with_tags.feature +11 -0
  143. data/spec/gherkin/fixtures/with_bom.feature +3 -0
  144. data/spec/gherkin/formatter/ansi_escapes_spec.rb +32 -0
  145. data/spec/gherkin/formatter/filter_formatter_spec.rb +204 -0
  146. data/spec/gherkin/formatter/json_formatter_spec.rb +92 -0
  147. data/spec/gherkin/formatter/model_spec.rb +28 -0
  148. data/spec/gherkin/formatter/pretty_formatter_spec.rb +177 -0
  149. data/spec/gherkin/formatter/spaces.feature +9 -0
  150. data/spec/gherkin/formatter/step_printer_spec.rb +55 -0
  151. data/spec/gherkin/formatter/tabs.feature +9 -0
  152. data/spec/gherkin/formatter/tag_count_formatter_spec.rb +30 -0
  153. data/spec/gherkin/i18n_spec.rb +241 -0
  154. data/spec/gherkin/java_lexer_spec.rb +20 -0
  155. data/spec/gherkin/js_lexer_spec.rb +23 -0
  156. data/spec/gherkin/json_parser_spec.rb +176 -0
  157. data/spec/gherkin/lexer/i18n_lexer_spec.rb +43 -0
  158. data/spec/gherkin/output_stream_string_io.rb +20 -0
  159. data/spec/gherkin/parser/parser_spec.rb +16 -0
  160. data/spec/gherkin/rb_lexer_spec.rb +20 -0
  161. data/spec/gherkin/sexp_recorder.rb +59 -0
  162. data/spec/gherkin/shared/bom_group.rb +20 -0
  163. data/spec/gherkin/shared/doc_string_group.rb +163 -0
  164. data/spec/gherkin/shared/lexer_group.rb +591 -0
  165. data/spec/gherkin/shared/row_group.rb +125 -0
  166. data/spec/gherkin/shared/tags_group.rb +54 -0
  167. data/spec/gherkin/tag_expression_spec.rb +142 -0
  168. data/spec/spec_helper.rb +75 -0
  169. data/tasks/bench.rake +184 -0
  170. data/tasks/bench/feature_builder.rb +49 -0
  171. data/tasks/bench/null_listener.rb +4 -0
  172. data/tasks/compile.rake +120 -0
  173. data/tasks/cucumber.rake +22 -0
  174. data/tasks/gems.rake +31 -0
  175. data/tasks/ikvm.rake +124 -0
  176. data/tasks/ragel_task.rb +100 -0
  177. data/tasks/release.rake +49 -0
  178. data/tasks/rspec.rake +8 -0
  179. data/tasks/yard.rake +7 -0
  180. data/tasks/yard/default/layout/html/bubble_32x32.png +0 -0
  181. data/tasks/yard/default/layout/html/bubble_48x48.png +0 -0
  182. data/tasks/yard/default/layout/html/footer.erb +5 -0
  183. data/tasks/yard/default/layout/html/index.erb +1 -0
  184. data/tasks/yard/default/layout/html/layout.erb +25 -0
  185. data/tasks/yard/default/layout/html/logo.erb +1 -0
  186. data/tasks/yard/default/layout/html/setup.rb +4 -0
  187. metadata +473 -0
@@ -0,0 +1,244 @@
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
+
114
+ doc_string(step.doc_string) if step.doc_string
115
+ table(step.rows) if step.rows
116
+ end
117
+
118
+ class MonochromeFormat
119
+ def text(text)
120
+ text
121
+ end
122
+ end
123
+
124
+ class ColorFormat
125
+ include AnsiEscapes
126
+
127
+ def initialize(status)
128
+ @status = status
129
+ end
130
+
131
+ def text(text)
132
+ self.__send__(@status) + text + reset
133
+ end
134
+ end
135
+
136
+ def arg_format(key)
137
+ format("#{key}_arg")
138
+ end
139
+
140
+ def format(key)
141
+ if @formats.nil?
142
+ if @monochrome
143
+ @formats = Hash.new(MonochromeFormat.new)
144
+ else
145
+ @formats = Hash.new do |formats, status|
146
+ formats[status] = ColorFormat.new(status)
147
+ end
148
+ end
149
+ end
150
+ @formats[key]
151
+ end
152
+
153
+ def eof
154
+ replay
155
+ # NO-OP
156
+ end
157
+
158
+ def done
159
+ # NO-OP
160
+ end
161
+
162
+ def table(rows)
163
+ cell_lengths = rows.map do |row|
164
+ row.cells.map do |cell|
165
+ escape_cell(cell).unpack("U*").length
166
+ end
167
+ end
168
+ max_lengths = cell_lengths.transpose.map { |col_lengths| col_lengths.max }.flatten
169
+
170
+ rows.each_with_index do |row, i|
171
+ row.comments.each do |comment|
172
+ @io.puts " #{comment.value}"
173
+ end
174
+ j = -1
175
+ @io.puts ' | ' + row.cells.zip(max_lengths).map { |cell, max_length|
176
+ j += 1
177
+ color(cell, nil, j) + ' ' * (max_length - cell_lengths[i][j])
178
+ }.join(' | ') + ' |'
179
+ end
180
+ end
181
+
182
+ private
183
+
184
+ def doc_string(doc_string)
185
+ @io.puts " \"\"\"" + doc_string.content_type + "\n" + escape_triple_quotes(indent(doc_string.value, ' ')) + "\n \"\"\""
186
+ end
187
+
188
+ def exception(exception)
189
+ exception_text = "#{exception.message} (#{exception.class})\n#{(exception.backtrace || []).join("\n")}".gsub(/^/, ' ')
190
+ @io.puts(failed(exception_text))
191
+ end
192
+
193
+ def color(cell, statuses, col)
194
+ if statuses
195
+ self.__send__(statuses[col], escape_cell(cell)) + reset
196
+ else
197
+ escape_cell(cell)
198
+ end
199
+ end
200
+
201
+ if(RUBY_VERSION =~ /^1\.9/)
202
+ START = /#{'^'.encode('UTF-8')}/
203
+ TRIPLE_QUOTES = /#{'"""'.encode('UTF-8')}/
204
+ else
205
+ START = /^/
206
+ TRIPLE_QUOTES = /"""/
207
+ end
208
+
209
+ def indent(string, indentation)
210
+ string.gsub(START, indentation)
211
+ end
212
+
213
+ def escape_triple_quotes(s)
214
+ s.gsub(TRIPLE_QUOTES, '\"\"\"')
215
+ end
216
+
217
+ def print_tags(tags, indent)
218
+ @io.write(tags.empty? ? '' : indent + tags.map{|tag| tag.name}.join(' ') + "\n")
219
+ end
220
+
221
+ def print_comments(comments, indent)
222
+ @io.write(comments.empty? ? '' : indent + comments.map{|comment| comment.value}.join("\n#{indent}") + "\n")
223
+ end
224
+
225
+ def print_description(description, indent, newline=true)
226
+ if description != ""
227
+ @io.puts indent(description, indent)
228
+ @io.puts if newline
229
+ end
230
+ end
231
+
232
+ def indented_location(location, proceed)
233
+ indentation = proceed ? @indentations.shift : @indentations[0]
234
+ location ? (' ' * indentation + ' ' + comments + "# #{location}" + reset) : ''
235
+ end
236
+
237
+ def calculate_location_indentations
238
+ line_widths = ([@statement] + @steps).map {|step| (step.keyword+step.name).unpack("U*").length}
239
+ max_line_width = line_widths.max
240
+ @indentations = line_widths.map{|w| max_line_width - w}
241
+ end
242
+ end
243
+ end
244
+ end
@@ -0,0 +1,21 @@
1
+ module Gherkin
2
+ module Formatter
3
+ class RegexpFilter
4
+ def initialize(regexen)
5
+ @regexen = regexen
6
+ end
7
+
8
+ def eval(tags, names, ranges)
9
+ @regexen.detect do |regexp|
10
+ names.detect do |name|
11
+ name =~ regexp
12
+ end
13
+ end
14
+ end
15
+
16
+ def filter_table_body_rows(rows)
17
+ rows
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module Gherkin
2
+ module Formatter
3
+ class StepPrinter
4
+ def write_step(io, text_format, arg_format, step_name, arguments)
5
+ unpacked_step_name = step_name.unpack("U*")
6
+
7
+ text_start = 0
8
+ arguments.each do |arg|
9
+ if(arg.offset != 0 && !arg.offset.nil?)
10
+ io.write(text_format.text(unpacked_step_name[text_start..arg.offset-1].pack("U*")))
11
+ end
12
+ if(!arg.val.nil?)
13
+ io.write(arg_format.text(arg.val))
14
+ text_start = arg.offset + arg.val.unpack("U*").length
15
+ end
16
+ end
17
+ io.write(text_format.text(unpacked_step_name[text_start..-1].pack("U*"))) unless text_start == unpacked_step_name.length
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ module Gherkin
2
+ module Formatter
3
+ class TagCountFormatter
4
+ def initialize(formatter, tag_counts)
5
+ @formatter = formatter
6
+ @tag_counts = tag_counts
7
+ end
8
+
9
+ def uri(uri)
10
+ @uri = uri
11
+ end
12
+
13
+ def feature(feature)
14
+ @feature_tags = feature.tags
15
+ @formatter.feature(feature)
16
+ end
17
+
18
+ def scenario(scenario)
19
+ record_tags((@feature_tags.to_a + scenario.tags.to_a).uniq, scenario.line)
20
+ @formatter.scenario(scenario)
21
+ end
22
+
23
+ def scenario_outline(scenario_outline)
24
+ @scenario_outline_tags = scenario_outline.tags
25
+ @formatter.scenario_outline(scenario_outline)
26
+ end
27
+
28
+ def examples(examples)
29
+ record_tags((@feature_tags.to_a + @scenario_outline_tags.to_a + examples.tags.to_a).uniq, examples.line)
30
+ @formatter.examples(examples)
31
+ end
32
+
33
+ private
34
+
35
+ def record_tags(tags, line)
36
+ tags.each do |tag|
37
+ @tag_counts[tag.name] ||= []
38
+ @tag_counts[tag.name] << "#{@uri}:#{line}"
39
+ end
40
+ end
41
+
42
+ def method_missing(*args)
43
+ @formatter.__send__(*args)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,19 @@
1
+ require 'gherkin/tag_expression'
2
+
3
+ module Gherkin
4
+ module Formatter
5
+ class TagFilter
6
+ def initialize(tags)
7
+ @tag_expression = TagExpression.new(tags)
8
+ end
9
+
10
+ def eval(tags, names, ranges)
11
+ @tag_expression.eval(tags.uniq)
12
+ end
13
+
14
+ def filter_table_body_rows(rows)
15
+ rows
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,180 @@
1
+ require 'yaml'
2
+ require 'gherkin/rubify'
3
+ require 'gherkin/native'
4
+
5
+ module Gherkin
6
+ class I18n
7
+ LexerNotFound = Class.new(LoadError)
8
+
9
+ native_impl('gherkin') unless defined?(BYPASS_NATIVE_IMPL)
10
+
11
+ FEATURE_ELEMENT_KEYS = %w{feature background scenario scenario_outline examples}
12
+ STEP_KEYWORD_KEYS = %w{given when then and but}
13
+ KEYWORD_KEYS = FEATURE_ELEMENT_KEYS + STEP_KEYWORD_KEYS
14
+ LANGUAGES = YAML.load_file(File.dirname(__FILE__) + '/i18n.yml')
15
+
16
+ class << self
17
+ include Rubify
18
+
19
+ # Used by code generators for other lexer tools like pygments lexer and textmate bundle
20
+ def all
21
+ LANGUAGES.keys.sort.map{|iso_code| get(iso_code)}
22
+ end
23
+
24
+ def get(iso_code)
25
+ languages[iso_code] ||= new(iso_code)
26
+ end
27
+
28
+ # Returns all keyword translations and aliases of +keywords+, escaped and joined with <tt>|</tt>.
29
+ # This method is convenient for editor support and syntax highlighting engines for Gherkin, where
30
+ # there is typically a code generation tool to generate regular expressions for recognising the
31
+ # various I18n translations of Gherkin's keywords.
32
+ #
33
+ # The +keywords+ arguments can be one of <tt>:feature</tt>, <tt>:background</tt>, <tt>:scenario</tt>,
34
+ # <tt>:scenario_outline</tt>, <tt>:examples</tt>, <tt>:step</tt>.
35
+ def keyword_regexp(*keywords)
36
+ unique_keywords = all.map do |i18n|
37
+ keywords.map do |keyword|
38
+ if keyword.to_s == 'step'
39
+ i18n.step_keywords.to_a
40
+ else
41
+ i18n.keywords(keyword).to_a
42
+ end
43
+ end
44
+ end
45
+
46
+ unique_keywords.flatten.compact.map{|kw| kw.to_s}.sort.reverse.uniq.join('|').gsub(/\*/, '\*')
47
+ end
48
+
49
+ def code_keywords
50
+ rubify(all.map{|i18n| i18n.code_keywords}).flatten.uniq.sort
51
+ end
52
+
53
+ def code_keyword_for(gherkin_keyword)
54
+ gherkin_keyword.gsub(/[\s',!]/, '').strip
55
+ end
56
+
57
+ def language_table
58
+ require 'stringio'
59
+ require 'gherkin/formatter/pretty_formatter'
60
+ require 'gherkin/formatter/model'
61
+ io = StringIO.new
62
+ pf = Gherkin::Formatter::PrettyFormatter.new(io, true, false)
63
+ table = all.map do |i18n|
64
+ Formatter::Model::DataTableRow.new([], [i18n.iso_code, i18n.keywords('name')[0], i18n.keywords('native')[0]], nil)
65
+ end
66
+ pf.table(table)
67
+ io.string
68
+ end
69
+
70
+ def unicode_escape(word, prefix="\\u")
71
+ word = word.unpack("U*").map do |c|
72
+ if c > 127 || c == 32
73
+ "#{prefix}%04x" % c
74
+ else
75
+ c.chr
76
+ end
77
+ end.join
78
+ end
79
+
80
+ private
81
+
82
+ def languages
83
+ @languages ||= {}
84
+ end
85
+ end
86
+
87
+ attr_reader :iso_code
88
+
89
+ def initialize(iso_code)
90
+ @iso_code = iso_code
91
+ @keywords = LANGUAGES[iso_code]
92
+ raise "Language not supported: #{iso_code.inspect}" if @iso_code.nil?
93
+ @keywords['grammar_name'] = @keywords['name'].gsub(/\s/, '')
94
+ end
95
+
96
+ def lexer(listener, force_ruby=false)
97
+ if force_ruby
98
+ rb(listener)
99
+ else
100
+ begin
101
+ c(listener)
102
+ rescue NameError, LoadError => e
103
+ warn("WARNING: #{e.message}. Reverting to Ruby lexer.")
104
+ rb(listener)
105
+ end
106
+ end
107
+ rescue LoadError => e
108
+ raise LexerNotFound, "No lexer was found for #{iso_code} (#{e.message}). Supported languages are listed in gherkin/i18n.yml."
109
+ end
110
+
111
+ def c(listener)
112
+ require 'gherkin/c_lexer'
113
+ CLexer[underscored_iso_code].new(listener)
114
+ end
115
+
116
+ def rb(listener)
117
+ require 'gherkin/rb_lexer'
118
+ RbLexer[underscored_iso_code].new(listener)
119
+ end
120
+
121
+ def js(listener)
122
+ require 'gherkin/js_lexer'
123
+ JsLexer[underscored_iso_code].new(listener)
124
+ end
125
+
126
+ def underscored_iso_code
127
+ @iso_code.gsub(/[\s-]/, '_').downcase
128
+ end
129
+
130
+ # Keywords that can be used in Gherkin source
131
+ def step_keywords
132
+ STEP_KEYWORD_KEYS.map{|iso_code| keywords(iso_code)}.flatten.uniq
133
+ end
134
+
135
+ # Keywords that can be used in code
136
+ def code_keywords
137
+ result = step_keywords.map{|keyword| self.class.code_keyword_for(keyword)}
138
+ result.delete('*')
139
+ result
140
+ end
141
+
142
+ def keywords(key)
143
+ key = key.to_s
144
+ raise "No #{key.inspect} in #{@keywords.inspect}" if @keywords[key].nil?
145
+ @keywords[key].split('|').map{|keyword| real_keyword(key, keyword)}
146
+ end
147
+
148
+ def keyword_table
149
+ require 'stringio'
150
+ require 'gherkin/formatter/pretty_formatter'
151
+ require 'gherkin/formatter/model'
152
+ io = StringIO.new
153
+ pf = Gherkin::Formatter::PrettyFormatter.new(io, false, false)
154
+
155
+ gherkin_keyword_table = KEYWORD_KEYS.map do |key|
156
+ Formatter::Model::Row.new([], [key, keywords(key).map{|keyword| %{"#{keyword}"}}.join(', ')], nil)
157
+ end
158
+
159
+ code_keyword_table = STEP_KEYWORD_KEYS.map do |key|
160
+ code_keywords = keywords(key).reject{|keyword| keyword == '* '}.map do |keyword|
161
+ %{"#{self.class.code_keyword_for(keyword)}"}
162
+ end.join(', ')
163
+ Formatter::Model::Row.new([], ["#{key} (code)", code_keywords], nil)
164
+ end
165
+
166
+ pf.table(gherkin_keyword_table + code_keyword_table)
167
+ io.string
168
+ end
169
+
170
+ private
171
+
172
+ def real_keyword(key, keyword)
173
+ if(STEP_KEYWORD_KEYS.index(key))
174
+ (keyword + ' ').sub(/< $/, '')
175
+ else
176
+ keyword
177
+ end
178
+ end
179
+ end
180
+ end