gherkin 2.12.2 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (333) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -15
  3. data/CONTRIBUTING.md +23 -0
  4. data/Gemfile +0 -3
  5. data/LICENSE +18 -17
  6. data/Makefile +65 -0
  7. data/README.md +9 -268
  8. data/Rakefile +17 -19
  9. data/bin/gherkin-generate-ast +21 -0
  10. data/bin/gherkin-generate-pickles +25 -0
  11. data/bin/gherkin-generate-tokens +12 -0
  12. data/gherkin-ruby.razor +218 -0
  13. data/gherkin.gemspec +22 -76
  14. data/lib/gherkin/ast_builder.rb +243 -0
  15. data/lib/gherkin/ast_node.rb +30 -0
  16. data/lib/gherkin/dialect.rb +58 -0
  17. data/lib/gherkin/errors.rb +45 -0
  18. data/lib/gherkin/gherkin-languages.json +2968 -0
  19. data/lib/gherkin/gherkin_line.rb +95 -0
  20. data/lib/gherkin/parser.rb +1910 -0
  21. data/lib/gherkin/pickles/compiler.rb +164 -0
  22. data/lib/gherkin/token.rb +18 -0
  23. data/lib/gherkin/token_formatter_builder.rb +39 -0
  24. data/lib/gherkin/token_matcher.rb +169 -0
  25. data/lib/gherkin/token_scanner.rb +40 -0
  26. data/spec/capture_warnings.rb +68 -0
  27. data/spec/coverage.rb +10 -0
  28. data/spec/gherkin/parser_spec.rb +146 -0
  29. metadata +60 -567
  30. data/.gitattributes +0 -2
  31. data/.mailmap +0 -2
  32. data/.rbenv-gemsets +0 -1
  33. data/.rspec +0 -1
  34. data/.ruby-gemset +0 -1
  35. data/.ruby-version +0 -1
  36. data/.yardopts +0 -5
  37. data/History.md +0 -881
  38. data/build_native_gems.sh +0 -7
  39. data/cucumber.yml +0 -5
  40. data/examples/parse_and_output_json.rb +0 -19
  41. data/ext/gherkin_lexer_ar/extconf.rb +0 -6
  42. data/ext/gherkin_lexer_ar/gherkin_lexer_ar.c +0 -1432
  43. data/ext/gherkin_lexer_bg/extconf.rb +0 -6
  44. data/ext/gherkin_lexer_bg/gherkin_lexer_bg.c +0 -1655
  45. data/ext/gherkin_lexer_bm/extconf.rb +0 -6
  46. data/ext/gherkin_lexer_bm/gherkin_lexer_bm.c +0 -1516
  47. data/ext/gherkin_lexer_ca/extconf.rb +0 -6
  48. data/ext/gherkin_lexer_ca/gherkin_lexer_ca.c +0 -1581
  49. data/ext/gherkin_lexer_cs/extconf.rb +0 -6
  50. data/ext/gherkin_lexer_cs/gherkin_lexer_cs.c +0 -1515
  51. data/ext/gherkin_lexer_cy_gb/extconf.rb +0 -6
  52. data/ext/gherkin_lexer_cy_gb/gherkin_lexer_cy_gb.c +0 -1282
  53. data/ext/gherkin_lexer_da/extconf.rb +0 -6
  54. data/ext/gherkin_lexer_da/gherkin_lexer_da.c +0 -1298
  55. data/ext/gherkin_lexer_de/extconf.rb +0 -6
  56. data/ext/gherkin_lexer_de/gherkin_lexer_de.c +0 -1425
  57. data/ext/gherkin_lexer_el/extconf.rb +0 -6
  58. data/ext/gherkin_lexer_el/gherkin_lexer_el.c +0 -1919
  59. data/ext/gherkin_lexer_en/extconf.rb +0 -6
  60. data/ext/gherkin_lexer_en/gherkin_lexer_en.c +0 -1418
  61. data/ext/gherkin_lexer_en_au/extconf.rb +0 -6
  62. data/ext/gherkin_lexer_en_au/gherkin_lexer_en_au.c +0 -1765
  63. data/ext/gherkin_lexer_en_lol/extconf.rb +0 -6
  64. data/ext/gherkin_lexer_en_lol/gherkin_lexer_en_lol.c +0 -1177
  65. data/ext/gherkin_lexer_en_old/extconf.rb +0 -6
  66. data/ext/gherkin_lexer_en_old/gherkin_lexer_en_old.c +0 -1309
  67. data/ext/gherkin_lexer_en_pirate/extconf.rb +0 -6
  68. data/ext/gherkin_lexer_en_pirate/gherkin_lexer_en_pirate.c +0 -1471
  69. data/ext/gherkin_lexer_en_scouse/extconf.rb +0 -6
  70. data/ext/gherkin_lexer_en_scouse/gherkin_lexer_en_scouse.c +0 -1634
  71. data/ext/gherkin_lexer_en_tx/extconf.rb +0 -6
  72. data/ext/gherkin_lexer_en_tx/gherkin_lexer_en_tx.c +0 -1265
  73. data/ext/gherkin_lexer_eo/extconf.rb +0 -6
  74. data/ext/gherkin_lexer_eo/gherkin_lexer_eo.c +0 -1241
  75. data/ext/gherkin_lexer_es/extconf.rb +0 -6
  76. data/ext/gherkin_lexer_es/gherkin_lexer_es.c +0 -1399
  77. data/ext/gherkin_lexer_et/extconf.rb +0 -6
  78. data/ext/gherkin_lexer_et/gherkin_lexer_et.c +0 -1236
  79. data/ext/gherkin_lexer_fa/extconf.rb +0 -6
  80. data/ext/gherkin_lexer_fa/gherkin_lexer_fa.c +0 -1475
  81. data/ext/gherkin_lexer_fi/extconf.rb +0 -6
  82. data/ext/gherkin_lexer_fi/gherkin_lexer_fi.c +0 -1215
  83. data/ext/gherkin_lexer_fr/extconf.rb +0 -6
  84. data/ext/gherkin_lexer_fr/gherkin_lexer_fr.c +0 -1493
  85. data/ext/gherkin_lexer_gl/extconf.rb +0 -6
  86. data/ext/gherkin_lexer_gl/gherkin_lexer_gl.c +0 -1374
  87. data/ext/gherkin_lexer_he/extconf.rb +0 -6
  88. data/ext/gherkin_lexer_he/gherkin_lexer_he.c +0 -1374
  89. data/ext/gherkin_lexer_hi/extconf.rb +0 -6
  90. data/ext/gherkin_lexer_hi/gherkin_lexer_hi.c +0 -1848
  91. data/ext/gherkin_lexer_hr/extconf.rb +0 -6
  92. data/ext/gherkin_lexer_hr/gherkin_lexer_hr.c +0 -1323
  93. data/ext/gherkin_lexer_hu/extconf.rb +0 -6
  94. data/ext/gherkin_lexer_hu/gherkin_lexer_hu.c +0 -1376
  95. data/ext/gherkin_lexer_id/extconf.rb +0 -6
  96. data/ext/gherkin_lexer_id/gherkin_lexer_id.c +0 -1208
  97. data/ext/gherkin_lexer_is/extconf.rb +0 -6
  98. data/ext/gherkin_lexer_is/gherkin_lexer_is.c +0 -1376
  99. data/ext/gherkin_lexer_it/extconf.rb +0 -6
  100. data/ext/gherkin_lexer_it/gherkin_lexer_it.c +0 -1340
  101. data/ext/gherkin_lexer_ja/extconf.rb +0 -6
  102. data/ext/gherkin_lexer_ja/gherkin_lexer_ja.c +0 -1699
  103. data/ext/gherkin_lexer_kn/extconf.rb +0 -6
  104. data/ext/gherkin_lexer_kn/gherkin_lexer_kn.c +0 -1965
  105. data/ext/gherkin_lexer_ko/extconf.rb +0 -6
  106. data/ext/gherkin_lexer_ko/gherkin_lexer_ko.c +0 -1360
  107. data/ext/gherkin_lexer_lt/extconf.rb +0 -6
  108. data/ext/gherkin_lexer_lt/gherkin_lexer_lt.c +0 -1296
  109. data/ext/gherkin_lexer_lu/extconf.rb +0 -6
  110. data/ext/gherkin_lexer_lu/gherkin_lexer_lu.c +0 -1389
  111. data/ext/gherkin_lexer_lv/extconf.rb +0 -6
  112. data/ext/gherkin_lexer_lv/gherkin_lexer_lv.c +0 -1425
  113. data/ext/gherkin_lexer_nl/extconf.rb +0 -6
  114. data/ext/gherkin_lexer_nl/gherkin_lexer_nl.c +0 -1368
  115. data/ext/gherkin_lexer_no/extconf.rb +0 -6
  116. data/ext/gherkin_lexer_no/gherkin_lexer_no.c +0 -1311
  117. data/ext/gherkin_lexer_pa/extconf.rb +0 -6
  118. data/ext/gherkin_lexer_pa/gherkin_lexer_pa.c +0 -2160
  119. data/ext/gherkin_lexer_pl/extconf.rb +0 -6
  120. data/ext/gherkin_lexer_pl/gherkin_lexer_pl.c +0 -1738
  121. data/ext/gherkin_lexer_pt/extconf.rb +0 -6
  122. data/ext/gherkin_lexer_pt/gherkin_lexer_pt.c +0 -1711
  123. data/ext/gherkin_lexer_ro/extconf.rb +0 -6
  124. data/ext/gherkin_lexer_ro/gherkin_lexer_ro.c +0 -1427
  125. data/ext/gherkin_lexer_ru/extconf.rb +0 -6
  126. data/ext/gherkin_lexer_ru/gherkin_lexer_ru.c +0 -2071
  127. data/ext/gherkin_lexer_sk/extconf.rb +0 -6
  128. data/ext/gherkin_lexer_sk/gherkin_lexer_sk.c +0 -1739
  129. data/ext/gherkin_lexer_sr_cyrl/extconf.rb +0 -6
  130. data/ext/gherkin_lexer_sr_cyrl/gherkin_lexer_sr_cyrl.c +0 -2112
  131. data/ext/gherkin_lexer_sr_latn/extconf.rb +0 -6
  132. data/ext/gherkin_lexer_sr_latn/gherkin_lexer_sr_latn.c +0 -1567
  133. data/ext/gherkin_lexer_sv/extconf.rb +0 -6
  134. data/ext/gherkin_lexer_sv/gherkin_lexer_sv.c +0 -1324
  135. data/ext/gherkin_lexer_th/extconf.rb +0 -6
  136. data/ext/gherkin_lexer_th/gherkin_lexer_th.c +0 -2840
  137. data/ext/gherkin_lexer_tl/extconf.rb +0 -6
  138. data/ext/gherkin_lexer_tl/gherkin_lexer_tl.c +0 -2021
  139. data/ext/gherkin_lexer_tr/extconf.rb +0 -6
  140. data/ext/gherkin_lexer_tr/gherkin_lexer_tr.c +0 -1347
  141. data/ext/gherkin_lexer_tt/extconf.rb +0 -6
  142. data/ext/gherkin_lexer_tt/gherkin_lexer_tt.c +0 -1936
  143. data/ext/gherkin_lexer_uk/extconf.rb +0 -6
  144. data/ext/gherkin_lexer_uk/gherkin_lexer_uk.c +0 -1941
  145. data/ext/gherkin_lexer_uz/extconf.rb +0 -6
  146. data/ext/gherkin_lexer_uz/gherkin_lexer_uz.c +0 -1651
  147. data/ext/gherkin_lexer_vi/extconf.rb +0 -6
  148. data/ext/gherkin_lexer_vi/gherkin_lexer_vi.c +0 -1458
  149. data/ext/gherkin_lexer_zh_cn/extconf.rb +0 -6
  150. data/ext/gherkin_lexer_zh_cn/gherkin_lexer_zh_cn.c +0 -1314
  151. data/ext/gherkin_lexer_zh_tw/extconf.rb +0 -6
  152. data/ext/gherkin_lexer_zh_tw/gherkin_lexer_zh_tw.c +0 -1307
  153. data/features/.cucumber/stepdefs.json +0 -244
  154. data/features/escaped_pipes.feature +0 -8
  155. data/features/feature_parser.feature +0 -237
  156. data/features/json_formatter.feature +0 -498
  157. data/features/json_parser.feature +0 -331
  158. data/features/native_lexer.feature +0 -19
  159. data/features/parser_with_native_lexer.feature +0 -205
  160. data/features/pretty_formatter.feature +0 -17
  161. data/features/step_definitions/eyeball_steps.rb +0 -3
  162. data/features/step_definitions/gherkin_steps.rb +0 -29
  163. data/features/step_definitions/json_formatter_steps.rb +0 -30
  164. data/features/step_definitions/json_parser_steps.rb +0 -21
  165. data/features/step_definitions/pretty_formatter_steps.rb +0 -85
  166. data/features/steps_parser.feature +0 -46
  167. data/features/support/env.rb +0 -41
  168. data/install_mingw_os_x.sh +0 -5
  169. data/js/.npmignore +0 -1
  170. data/js/lib/gherkin/lexer/.npmignore +0 -0
  171. data/lib/gherkin.rb +0 -2
  172. data/lib/gherkin/README.md +0 -7
  173. data/lib/gherkin/c_lexer.rb +0 -17
  174. data/lib/gherkin/formatter/ansi_escapes.rb +0 -97
  175. data/lib/gherkin/formatter/argument.rb +0 -16
  176. data/lib/gherkin/formatter/escaping.rb +0 -15
  177. data/lib/gherkin/formatter/filter_formatter.rb +0 -150
  178. data/lib/gherkin/formatter/hashable.rb +0 -25
  179. data/lib/gherkin/formatter/json_formatter.rb +0 -133
  180. data/lib/gherkin/formatter/line_filter.rb +0 -26
  181. data/lib/gherkin/formatter/model.rb +0 -281
  182. data/lib/gherkin/formatter/pretty_formatter.rb +0 -245
  183. data/lib/gherkin/formatter/regexp_filter.rb +0 -21
  184. data/lib/gherkin/formatter/step_printer.rb +0 -21
  185. data/lib/gherkin/formatter/tag_count_formatter.rb +0 -47
  186. data/lib/gherkin/formatter/tag_filter.rb +0 -19
  187. data/lib/gherkin/i18n.json +0 -786
  188. data/lib/gherkin/i18n.rb +0 -176
  189. data/lib/gherkin/json_parser.rb +0 -177
  190. data/lib/gherkin/lexer/ar.rb +0 -1170
  191. data/lib/gherkin/lexer/bg.rb +0 -1382
  192. data/lib/gherkin/lexer/bm.rb +0 -1250
  193. data/lib/gherkin/lexer/ca.rb +0 -1310
  194. data/lib/gherkin/lexer/cs.rb +0 -1246
  195. data/lib/gherkin/lexer/cy_gb.rb +0 -1032
  196. data/lib/gherkin/lexer/da.rb +0 -1048
  197. data/lib/gherkin/lexer/de.rb +0 -1166
  198. data/lib/gherkin/lexer/el.rb +0 -1628
  199. data/lib/gherkin/lexer/en.rb +0 -1156
  200. data/lib/gherkin/lexer/en_au.rb +0 -1486
  201. data/lib/gherkin/lexer/en_lol.rb +0 -934
  202. data/lib/gherkin/lexer/en_old.rb +0 -1037
  203. data/lib/gherkin/lexer/en_pirate.rb +0 -1210
  204. data/lib/gherkin/lexer/en_scouse.rb +0 -1362
  205. data/lib/gherkin/lexer/en_tx.rb +0 -1016
  206. data/lib/gherkin/lexer/encoding.rb +0 -41
  207. data/lib/gherkin/lexer/eo.rb +0 -995
  208. data/lib/gherkin/lexer/es.rb +0 -1140
  209. data/lib/gherkin/lexer/et.rb +0 -990
  210. data/lib/gherkin/lexer/fa.rb +0 -1214
  211. data/lib/gherkin/lexer/fi.rb +0 -969
  212. data/lib/gherkin/lexer/fr.rb +0 -1228
  213. data/lib/gherkin/lexer/gl.rb +0 -1117
  214. data/lib/gherkin/lexer/he.rb +0 -1118
  215. data/lib/gherkin/lexer/hi.rb +0 -1559
  216. data/lib/gherkin/lexer/hr.rb +0 -1066
  217. data/lib/gherkin/lexer/hu.rb +0 -1118
  218. data/lib/gherkin/lexer/i18n_lexer.rb +0 -48
  219. data/lib/gherkin/lexer/id.rb +0 -963
  220. data/lib/gherkin/lexer/is.rb +0 -1120
  221. data/lib/gherkin/lexer/it.rb +0 -1086
  222. data/lib/gherkin/lexer/ja.rb +0 -1418
  223. data/lib/gherkin/lexer/kn.rb +0 -1672
  224. data/lib/gherkin/lexer/ko.rb +0 -1102
  225. data/lib/gherkin/lexer/lt.rb +0 -1045
  226. data/lib/gherkin/lexer/lu.rb +0 -1132
  227. data/lib/gherkin/lexer/lv.rb +0 -1166
  228. data/lib/gherkin/lexer/nl.rb +0 -1115
  229. data/lib/gherkin/lexer/no.rb +0 -1060
  230. data/lib/gherkin/lexer/pa.rb +0 -1852
  231. data/lib/gherkin/lexer/pl.rb +0 -1457
  232. data/lib/gherkin/lexer/pt.rb +0 -1430
  233. data/lib/gherkin/lexer/ro.rb +0 -1164
  234. data/lib/gherkin/lexer/ru.rb +0 -1766
  235. data/lib/gherkin/lexer/sk.rb +0 -1452
  236. data/lib/gherkin/lexer/sr_cyrl.rb +0 -1803
  237. data/lib/gherkin/lexer/sr_latn.rb +0 -1294
  238. data/lib/gherkin/lexer/sv.rb +0 -1070
  239. data/lib/gherkin/lexer/th.rb +0 -2492
  240. data/lib/gherkin/lexer/tl.rb +0 -1726
  241. data/lib/gherkin/lexer/tr.rb +0 -1092
  242. data/lib/gherkin/lexer/tt.rb +0 -1643
  243. data/lib/gherkin/lexer/uk.rb +0 -1646
  244. data/lib/gherkin/lexer/uz.rb +0 -1376
  245. data/lib/gherkin/lexer/vi.rb +0 -1198
  246. data/lib/gherkin/lexer/zh_cn.rb +0 -1058
  247. data/lib/gherkin/lexer/zh_tw.rb +0 -1052
  248. data/lib/gherkin/listener/event.rb +0 -45
  249. data/lib/gherkin/listener/formatter_listener.rb +0 -150
  250. data/lib/gherkin/native.rb +0 -7
  251. data/lib/gherkin/native/java.rb +0 -72
  252. data/lib/gherkin/native/null.rb +0 -5
  253. data/lib/gherkin/native/therubyracer.rb +0 -41
  254. data/lib/gherkin/parser/meta.txt +0 -5
  255. data/lib/gherkin/parser/parser.rb +0 -166
  256. data/lib/gherkin/parser/root.txt +0 -11
  257. data/lib/gherkin/parser/steps.txt +0 -4
  258. data/lib/gherkin/platform.rb +0 -13
  259. data/lib/gherkin/rubify.rb +0 -31
  260. data/lib/gherkin/tag_expression.rb +0 -63
  261. data/ragel/lexer.c.rl.erb +0 -454
  262. data/ragel/lexer.java.rl.erb +0 -219
  263. data/ragel/lexer.js.rl.erb +0 -322
  264. data/ragel/lexer.rb.rl.erb +0 -179
  265. data/ragel/lexer_common.rl.erb +0 -50
  266. data/spec/gherkin/c_lexer_spec.rb +0 -22
  267. data/spec/gherkin/fixtures/1.feature +0 -8
  268. data/spec/gherkin/fixtures/comments_in_table.feature +0 -9
  269. data/spec/gherkin/fixtures/complex.feature +0 -45
  270. data/spec/gherkin/fixtures/complex.json +0 -139
  271. data/spec/gherkin/fixtures/complex_for_filtering.feature +0 -60
  272. data/spec/gherkin/fixtures/complex_with_tags.feature +0 -61
  273. data/spec/gherkin/fixtures/dos_line_endings.feature +0 -45
  274. data/spec/gherkin/fixtures/examples_with_only_header.feature +0 -14
  275. data/spec/gherkin/fixtures/hantu_pisang.feature +0 -35
  276. data/spec/gherkin/fixtures/i18n_fr.feature +0 -14
  277. data/spec/gherkin/fixtures/i18n_fr2.feature +0 -8
  278. data/spec/gherkin/fixtures/i18n_no.feature +0 -7
  279. data/spec/gherkin/fixtures/i18n_pt1.feature +0 -44
  280. data/spec/gherkin/fixtures/i18n_pt2.feature +0 -4
  281. data/spec/gherkin/fixtures/i18n_pt3.feature +0 -4
  282. data/spec/gherkin/fixtures/i18n_pt4.feature +0 -4
  283. data/spec/gherkin/fixtures/i18n_zh-CN.feature +0 -9
  284. data/spec/gherkin/fixtures/iso-8859-1.feature +0 -6
  285. data/spec/gherkin/fixtures/issue_145.feature +0 -22
  286. data/spec/gherkin/fixtures/scenario_outline_with_tags.feature +0 -13
  287. data/spec/gherkin/fixtures/scenario_without_steps.feature +0 -5
  288. data/spec/gherkin/fixtures/simple_with_comments.feature +0 -7
  289. data/spec/gherkin/fixtures/simple_with_tags.feature +0 -11
  290. data/spec/gherkin/fixtures/with_bom.feature +0 -3
  291. data/spec/gherkin/fixtures/with_bom_and_language_spec.feature +0 -4
  292. data/spec/gherkin/formatter/ansi_escapes_spec.rb +0 -32
  293. data/spec/gherkin/formatter/filter_formatter_spec.rb +0 -204
  294. data/spec/gherkin/formatter/json_formatter_spec.rb +0 -179
  295. data/spec/gherkin/formatter/model_spec.rb +0 -28
  296. data/spec/gherkin/formatter/pretty_formatter_spec.rb +0 -184
  297. data/spec/gherkin/formatter/spaces.feature +0 -9
  298. data/spec/gherkin/formatter/step_printer_spec.rb +0 -55
  299. data/spec/gherkin/formatter/tabs.feature +0 -9
  300. data/spec/gherkin/formatter/tag_count_formatter_spec.rb +0 -30
  301. data/spec/gherkin/i18n_spec.rb +0 -256
  302. data/spec/gherkin/java_lexer_spec.rb +0 -20
  303. data/spec/gherkin/json_parser_spec.rb +0 -165
  304. data/spec/gherkin/lexer/i18n_lexer_spec.rb +0 -65
  305. data/spec/gherkin/native_lexer_spec.rb +0 -29
  306. data/spec/gherkin/parser/parser_spec.rb +0 -16
  307. data/spec/gherkin/rubify_spec.rb +0 -23
  308. data/spec/gherkin/sexp_recorder.rb +0 -59
  309. data/spec/gherkin/shared/doc_string_group.rb +0 -161
  310. data/spec/gherkin/shared/encoding_group.rb +0 -48
  311. data/spec/gherkin/shared/lexer_group.rb +0 -589
  312. data/spec/gherkin/shared/row_group.rb +0 -123
  313. data/spec/gherkin/shared/tags_group.rb +0 -52
  314. data/spec/gherkin/tag_expression_spec.rb +0 -146
  315. data/spec/spec_helper.rb +0 -94
  316. data/tasks/apidoc.rake +0 -32
  317. data/tasks/bench.rake +0 -184
  318. data/tasks/bench/feature_builder.rb +0 -49
  319. data/tasks/bench/null_listener.rb +0 -4
  320. data/tasks/compile.rake +0 -83
  321. data/tasks/cucumber.rake +0 -23
  322. data/tasks/gems.rake +0 -46
  323. data/tasks/ikvm.rake +0 -126
  324. data/tasks/ragel_task.rb +0 -124
  325. data/tasks/release.rake +0 -34
  326. data/tasks/rspec.rake +0 -6
  327. data/tasks/yard/default/layout/html/bubble_32x32.png +0 -0
  328. data/tasks/yard/default/layout/html/bubble_48x48.png +0 -0
  329. data/tasks/yard/default/layout/html/footer.erb +0 -5
  330. data/tasks/yard/default/layout/html/index.erb +0 -1
  331. data/tasks/yard/default/layout/html/layout.erb +0 -25
  332. data/tasks/yard/default/layout/html/logo.erb +0 -1
  333. data/tasks/yard/default/layout/html/setup.rb +0 -4
@@ -0,0 +1,164 @@
1
+ require_relative '../dialect'
2
+
3
+ module Gherkin
4
+ module Pickles
5
+ class Compiler
6
+ def compile(feature, path)
7
+ pickles = []
8
+ dialect = Dialect.for(feature[:language])
9
+
10
+ feature_tags = feature[:tags]
11
+ background_steps = get_background_steps(feature[:background], path)
12
+
13
+ feature[:scenarioDefinitions].each do |scenario_definition|
14
+ if(scenario_definition[:type] == :Scenario)
15
+ compile_scenario(feature_tags, background_steps, scenario_definition, dialect, path, pickles)
16
+ else
17
+ compile_scenario_outline(feature_tags, background_steps, scenario_definition, dialect, path, pickles)
18
+ end
19
+ end
20
+ return pickles
21
+ end
22
+
23
+ private
24
+
25
+ def compile_scenario(feature_tags, background_steps, scenario, dialect, path, pickles)
26
+ steps = [].concat(background_steps)
27
+
28
+ tags = [].concat(feature_tags).concat(scenario[:tags])
29
+
30
+ scenario[:steps].each do |step|
31
+ steps.push(pickle_step(step, path))
32
+ end
33
+
34
+ pickle = {
35
+ tags: pickle_tags(tags, path),
36
+ name: scenario[:keyword] + ": " + scenario[:name],
37
+ locations: [pickle_location(scenario[:location], path)],
38
+ steps: steps
39
+ }
40
+ pickles.push(pickle)
41
+ end
42
+
43
+ def compile_scenario_outline(feature_tags, background_steps, scenario_outline, dialect, path, pickles)
44
+ keyword = dialect.scenario_keywords[0]
45
+ scenario_outline[:examples].each do |examples|
46
+ variable_cells = examples[:tableHeader][:cells]
47
+ examples[:tableBody].each do |values|
48
+ value_cells = values[:cells]
49
+ steps = [].concat(background_steps)
50
+ tags = [].concat(feature_tags).concat(scenario_outline[:tags]).concat(examples[:tags])
51
+
52
+ scenario_outline[:steps].each do |scenario_outline_step|
53
+ step_text = interpolate(scenario_outline_step[:text], variable_cells, value_cells);
54
+ arguments = create_pickle_arguments(scenario_outline_step[:argument], variable_cells, value_cells, path)
55
+ pickle_step = {
56
+ text: step_text,
57
+ arguments: arguments,
58
+ locations: [
59
+ pickle_location(values[:location], path),
60
+ pickle_step_location(scenario_outline_step, path)
61
+ ]
62
+ }
63
+ steps.push(pickle_step)
64
+ end
65
+
66
+ pickle = {
67
+ name: keyword + ": " + interpolate(scenario_outline[:name], variable_cells, value_cells),
68
+ steps: steps,
69
+ tags: pickle_tags(tags, path),
70
+ locations: [
71
+ pickle_location(values[:location], path),
72
+ pickle_location(scenario_outline[:location], path)
73
+ ]
74
+ }
75
+ pickles.push(pickle);
76
+
77
+ end
78
+ end
79
+ end
80
+
81
+ def create_pickle_arguments(argument, variable_cells, value_cells, path)
82
+ result = []
83
+ return result if argument.nil?
84
+ if (argument[:type] == :DataTable)
85
+ table = {
86
+ rows: argument[:rows].map do |row|
87
+ {
88
+ cells: row[:cells].map do |cell|
89
+ {
90
+ location: pickle_location(cell[:location], path),
91
+ value: interpolate(cell[:value], variable_cells, value_cells)
92
+ }
93
+ end
94
+ }
95
+ end
96
+ }
97
+ result.push(table)
98
+ elsif (argument[:type] == :DocString)
99
+ doc_string = {
100
+ location: pickle_location(argument[:location], path),
101
+ content: interpolate(argument[:content], variable_cells, value_cells)
102
+ }
103
+ result.push(doc_string)
104
+ else
105
+ raise 'Internal error'
106
+ end
107
+ result
108
+ end
109
+
110
+ def interpolate(name, variable_cells, value_cells)
111
+ variable_cells.each_with_index do |variable_cell, n|
112
+ value_cell = value_cells[n]
113
+ name = name.gsub('<' + variable_cell[:value] + '>', value_cell[:value])
114
+ end
115
+ name
116
+ end
117
+
118
+ def get_background_steps(background, path)
119
+ if(background)
120
+ background[:steps].map do |step|
121
+ pickle_step(step, path)
122
+ end
123
+ else
124
+ []
125
+ end
126
+ end
127
+
128
+ def pickle_step(step, path)
129
+ {
130
+ text: step[:text],
131
+ arguments: create_pickle_arguments(step[:argument], [], [], path),
132
+ locations: [pickle_step_location(step, path)]
133
+ }
134
+ end
135
+
136
+ def pickle_step_location(step, path)
137
+ {
138
+ path: path,
139
+ line: step[:location][:line],
140
+ column: step[:location][:column] + (step[:keyword] ? step[:keyword].length : 0)
141
+ }
142
+ end
143
+
144
+ def pickle_location(location, path)
145
+ {
146
+ path: path,
147
+ line: location[:line],
148
+ column: location[:column]
149
+ }
150
+ end
151
+
152
+ def pickle_tags(tags, path)
153
+ tags.map {|tag| pickle_tag(tag, path)}
154
+ end
155
+
156
+ def pickle_tag(tag, path)
157
+ {
158
+ name: tag[:name],
159
+ location: pickle_location(tag[:location], path)
160
+ }
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,18 @@
1
+ module Gherkin
2
+ class Token < Struct.new(:line, :location)
3
+ attr_accessor :matched_type, :matched_text, :matched_keyword, :matched_indent,
4
+ :matched_items, :matched_gherkin_dialect
5
+
6
+ def eof?
7
+ line.nil?
8
+ end
9
+
10
+ def detach
11
+ # TODO: detach line - is this needed?
12
+ end
13
+
14
+ def token_value
15
+ eof? ? "EOF" : line.get_line_text(-1)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,39 @@
1
+ module Gherkin
2
+ class TokenFormatterBuilder
3
+ def initialize
4
+ reset
5
+ end
6
+
7
+ def reset
8
+ @tokens_text = ""
9
+ end
10
+
11
+ def build(token)
12
+ @tokens_text << "#{format_token(token)}\n"
13
+ end
14
+
15
+ def start_rule(rule_type)
16
+ end
17
+
18
+ def end_rule(rule_type)
19
+ end
20
+
21
+ def get_result
22
+ @tokens_text
23
+ end
24
+
25
+ private
26
+ def format_token(token)
27
+ return "EOF" if token.eof?
28
+
29
+ sprintf "(%s:%s)%s:%s/%s/%s",
30
+ token.location[:line],
31
+ token.location[:column],
32
+ token.matched_type,
33
+ token.matched_keyword,
34
+ token.matched_text,
35
+ Array(token.matched_items).map { |i| "#{i.column}:#{i.text}"}.join(',')
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,169 @@
1
+ require_relative 'dialect'
2
+ require_relative 'errors'
3
+
4
+ module Gherkin
5
+ class TokenMatcher
6
+ LANGUAGE_PATTERN = /^\s*#\s*language\s*:\s*([a-zA-Z\-_]+)\s*$/
7
+
8
+ def initialize(dialect_name = 'en')
9
+ @default_dialect_name = dialect_name
10
+ change_dialect(dialect_name, nil)
11
+ reset
12
+ end
13
+
14
+ def reset
15
+ change_dialect(@default_dialect_name, nil) unless @dialect_name == @default_dialect_name
16
+ @active_doc_string_separator = nil
17
+ @indent_to_remove = 0
18
+ end
19
+
20
+ def match_TagLine(token)
21
+ return false unless token.line.start_with?('@')
22
+
23
+ set_token_matched(token, :TagLine, nil, nil, nil, token.line.tags)
24
+ true
25
+ end
26
+
27
+ def match_FeatureLine(token)
28
+ match_title_line(token, :FeatureLine, @dialect.feature_keywords)
29
+ end
30
+
31
+ def match_ScenarioLine(token)
32
+ match_title_line(token, :ScenarioLine, @dialect.scenario_keywords)
33
+ end
34
+
35
+ def match_ScenarioOutlineLine(token)
36
+ match_title_line(token, :ScenarioOutlineLine, @dialect.scenario_outline_keywords)
37
+ end
38
+
39
+ def match_BackgroundLine(token)
40
+ match_title_line(token, :BackgroundLine, @dialect.background_keywords)
41
+ end
42
+
43
+ def match_ExamplesLine(token)
44
+ match_title_line(token, :ExamplesLine, @dialect.examples_keywords)
45
+ end
46
+
47
+ def match_TableRow(token)
48
+ return false unless token.line.start_with?('|')
49
+ # TODO: indent
50
+ set_token_matched(token, :TableRow, nil, nil, nil, token.line.table_cells)
51
+ true
52
+ end
53
+
54
+ def match_Empty(token)
55
+ return false unless token.line.empty?
56
+ set_token_matched(token, :Empty, nil, nil, 0)
57
+ true
58
+ end
59
+
60
+ def match_Comment(token)
61
+ return false unless token.line.start_with?('#')
62
+ text = token.line.get_line_text(0) #take the entire line, including leading space
63
+ set_token_matched(token, :Comment, text, nil, 0)
64
+ true
65
+ end
66
+
67
+ def match_Language(token)
68
+ return false unless token.line.trimmed_line_text =~ LANGUAGE_PATTERN
69
+
70
+ dialect_name = $1
71
+ set_token_matched(token, :Language, dialect_name)
72
+
73
+ change_dialect(dialect_name, token.location)
74
+
75
+ true
76
+ end
77
+
78
+ def match_DocStringSeparator(token)
79
+ if @active_doc_string_separator.nil?
80
+ # open
81
+ _match_DocStringSeparator(token, '"""', true) ||
82
+ _match_DocStringSeparator(token, '```', true)
83
+ else
84
+ # close
85
+ _match_DocStringSeparator(token, @active_doc_string_separator, false)
86
+ end
87
+ end
88
+
89
+ def _match_DocStringSeparator(token, separator, is_open)
90
+ return false unless token.line.start_with?(separator)
91
+
92
+ content_type = nil
93
+ if is_open
94
+ content_type = token.line.get_rest_trimmed(separator.length)
95
+ @active_doc_string_separator = separator
96
+ @indent_to_remove = token.line.indent
97
+ else
98
+ @active_doc_string_separator = nil
99
+ @indent_to_remove = 0
100
+ end
101
+
102
+ # TODO: Use the separator as keyword. That's needed for pretty printing.
103
+ set_token_matched(token, :DocStringSeparator, content_type)
104
+ true
105
+ end
106
+
107
+ def match_EOF(token)
108
+ return false unless token.eof?
109
+ set_token_matched(token, :EOF)
110
+ true
111
+ end
112
+
113
+ def match_Other(token)
114
+ text = token.line.get_line_text(@indent_to_remove) # take the entire line, except removing DocString indents
115
+ set_token_matched(token, :Other, unescape_docstring(text), nil, 0)
116
+ true
117
+ end
118
+
119
+ def match_StepLine(token)
120
+ keywords = @dialect.given_keywords +
121
+ @dialect.when_keywords +
122
+ @dialect.then_keywords +
123
+ @dialect.and_keywords +
124
+ @dialect.but_keywords
125
+
126
+ keyword = keywords.detect { |k| token.line.start_with?(k) }
127
+
128
+ return false unless keyword
129
+
130
+ title = token.line.get_rest_trimmed(keyword.length)
131
+ set_token_matched(token, :StepLine, title, keyword)
132
+ return true
133
+ end
134
+
135
+ private
136
+
137
+ def change_dialect(dialect_name, location)
138
+ dialect = Dialect.for(dialect_name)
139
+ raise NoSuchLanguageException.new(dialect_name, location) if dialect.nil?
140
+
141
+ @dialect_name = dialect_name
142
+ @dialect = dialect
143
+ end
144
+
145
+ def match_title_line(token, token_type, keywords)
146
+ keyword = keywords.detect { |k| token.line.start_with_title_keyword?(k) }
147
+
148
+ return false unless keyword
149
+
150
+ title = token.line.get_rest_trimmed(keyword.length + ':'.length)
151
+ set_token_matched(token, token_type, title, keyword)
152
+ true
153
+ end
154
+
155
+ def set_token_matched(token, matched_type, text=nil, keyword=nil, indent=nil, items=[])
156
+ token.matched_type = matched_type
157
+ token.matched_text = text && text.chomp
158
+ token.matched_keyword = keyword
159
+ token.matched_indent = indent || (token.line && token.line.indent) || 0
160
+ token.matched_items = items
161
+ token.location[:column] = token.matched_indent + 1
162
+ token.matched_gherkin_dialect = @dialect_name
163
+ end
164
+
165
+ def unescape_docstring(text)
166
+ @active_doc_string_separator ? text.gsub("\\\"\\\"\\\"", "\"\"\"") : text
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,40 @@
1
+ require 'stringio'
2
+ require_relative 'token'
3
+ require_relative 'gherkin_line'
4
+
5
+ module Gherkin
6
+ # The scanner reads a gherkin doc (typically read from a .feature file) and
7
+ # creates a token for line. The tokens are passed to the parser, which outputs
8
+ # an AST (Abstract Syntax Tree).
9
+ #
10
+ # If the scanner sees a # language header, it will reconfigure itself dynamically
11
+ # to look for Gherkin keywords for the associated language. The keywords are defined
12
+ # in gherkin-languages.json.
13
+ class TokenScanner
14
+ def initialize(source_or_io)
15
+ @line_number = 0
16
+
17
+ case(source_or_io)
18
+ when String
19
+ @io = StringIO.new(source_or_io)
20
+ when StringIO, IO
21
+ @io = source_or_io
22
+ else
23
+ fail ArgumentError, "Please a pass String, StringIO or IO. I got a #{source_or_io.class}"
24
+ end
25
+ end
26
+
27
+ def read
28
+ location = {line: @line_number += 1}
29
+ if @io.nil? || line = @io.gets
30
+ gherkin_line = line ? GherkinLine.new(line, location[:line]) : nil
31
+ Token.new(gherkin_line, location)
32
+ else
33
+ @io.close unless @io.closed? # ARGF closes the last file after final gets
34
+ @io = nil
35
+ Token.new(nil, location)
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,68 @@
1
+ # With thanks to @myronmarston
2
+ # https://github.com/vcr/vcr/blob/master/spec/capture_warnings.rb
3
+
4
+ module CaptureWarnings
5
+ def report_warnings(&block)
6
+ current_dir = Dir.pwd
7
+ warnings, errors = capture_error(&block).partition { |line| line.include?('warning') }
8
+ project_warnings, other_warnings = warnings.uniq.partition { |line| line.include?(current_dir) }
9
+
10
+ if errors.any?
11
+ puts errors.join("\n")
12
+ end
13
+
14
+ if other_warnings.any?
15
+ puts "#{ other_warnings.count } non-gherkin warnings detected, set VIEW_OTHER_WARNINGS=true to see them."
16
+ print_warnings('other', other_warnings) if ENV['VIEW_OTHER_WARNINGS']
17
+ end
18
+
19
+ if project_warnings.any?
20
+ puts "#{ project_warnings.count } gherkin warnings detected"
21
+ print_warnings('gherkin', project_warnings)
22
+ fail "Please remove all gherkin warnings."
23
+ end
24
+
25
+ ensure_system_exit_if_required
26
+ end
27
+
28
+ def capture_error(&block)
29
+ old_stderr = STDERR.clone
30
+ pipe_r, pipe_w = IO.pipe
31
+ pipe_r.sync = true
32
+ error = ""
33
+ reader = Thread.new do
34
+ begin
35
+ loop do
36
+ error << pipe_r.readpartial(1024)
37
+ end
38
+ rescue EOFError
39
+ end
40
+ end
41
+ STDERR.reopen(pipe_w)
42
+ block.call
43
+ ensure
44
+ capture_system_exit
45
+ STDERR.reopen(old_stderr)
46
+ pipe_w.close
47
+ reader.join
48
+ return error.split("\n")
49
+ end
50
+
51
+ def print_warnings(type, warnings)
52
+ puts
53
+ puts "-" * 30 + " #{type} warnings: " + "-" * 30
54
+ puts
55
+ puts warnings.join("\n")
56
+ puts
57
+ puts "-" * 75
58
+ puts
59
+ end
60
+
61
+ def ensure_system_exit_if_required
62
+ raise @system_exit if @system_exit
63
+ end
64
+
65
+ def capture_system_exit
66
+ @system_exit = $!
67
+ end
68
+ end