casecumber 1.0.2.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 (563) hide show
  1. data/.gitattributes +1 -0
  2. data/.gitignore +26 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +7 -0
  6. data/.yardopts +0 -0
  7. data/Gemfile +2 -0
  8. data/Gemfile.lock +115 -0
  9. data/History.md +1702 -0
  10. data/LICENSE +22 -0
  11. data/README.md +25 -0
  12. data/Rakefile +12 -0
  13. data/bin/cucumber +22 -0
  14. data/cucumber.gemspec +60 -0
  15. data/cucumber.yml +20 -0
  16. data/examples/i18n/README.textile +18 -0
  17. data/examples/i18n/Rakefile +33 -0
  18. data/examples/i18n/ar/Rakefile +6 -0
  19. data/examples/i18n/ar/features/addition.feature +17 -0
  20. data/examples/i18n/ar/features/step_definitons/calculator_steps.rb +24 -0
  21. data/examples/i18n/ar/lib/calculator.rb +11 -0
  22. data/examples/i18n/bg/Rakefile +6 -0
  23. data/examples/i18n/bg/features/addition.feature +12 -0
  24. data/examples/i18n/bg/features/consecutive_calculations.feature +19 -0
  25. data/examples/i18n/bg/features/division.feature +17 -0
  26. data/examples/i18n/bg/features/step_definitons/calculator_steps.rb +24 -0
  27. data/examples/i18n/bg/features/support/env.rb +5 -0
  28. data/examples/i18n/bg/features/support/world.rb +8 -0
  29. data/examples/i18n/bg/lib/calculator.rb +24 -0
  30. data/examples/i18n/ca/Rakefile +6 -0
  31. data/examples/i18n/ca/features/step_definitons/calculator_steps.rb +21 -0
  32. data/examples/i18n/ca/features/suma.feature +17 -0
  33. data/examples/i18n/ca/lib/calculadora.rb +16 -0
  34. data/examples/i18n/da/Rakefile +6 -0
  35. data/examples/i18n/da/features/sammenlaegning.feature +18 -0
  36. data/examples/i18n/da/features/step_definitons/lommeregner_steps.rb +24 -0
  37. data/examples/i18n/da/lib/lommeregner.rb +11 -0
  38. data/examples/i18n/de/.gitignore +1 -0
  39. data/examples/i18n/de/Rakefile +6 -0
  40. data/examples/i18n/de/features/addition.feature +17 -0
  41. data/examples/i18n/de/features/division.feature +10 -0
  42. data/examples/i18n/de/features/step_definitons/calculator_steps.rb +24 -0
  43. data/examples/i18n/de/lib/calculator.rb +14 -0
  44. data/examples/i18n/en-lol/Rakefile +4 -0
  45. data/examples/i18n/en-lol/features/step_definitions/cucumbrz_steps.rb +16 -0
  46. data/examples/i18n/en-lol/features/stuffing.feature +8 -0
  47. data/examples/i18n/en-lol/features/support/env.rb +7 -0
  48. data/examples/i18n/en-lol/lib/basket.rb +12 -0
  49. data/examples/i18n/en-lol/lib/belly.rb +11 -0
  50. data/examples/i18n/en/.gitignore +1 -0
  51. data/examples/i18n/en/Rakefile +6 -0
  52. data/examples/i18n/en/features/addition.feature +17 -0
  53. data/examples/i18n/en/features/division.feature +10 -0
  54. data/examples/i18n/en/features/step_definitons/calculator_steps.rb +24 -0
  55. data/examples/i18n/en/lib/calculator.rb +14 -0
  56. data/examples/i18n/eo/.gitignore +1 -0
  57. data/examples/i18n/eo/Rakefile +6 -0
  58. data/examples/i18n/eo/features/adicio.feature +17 -0
  59. data/examples/i18n/eo/features/divido.feature +10 -0
  60. data/examples/i18n/eo/features/step_definitons/calculator_steps.rb +24 -0
  61. data/examples/i18n/eo/lib/calculator.rb +14 -0
  62. data/examples/i18n/es/Rakefile +6 -0
  63. data/examples/i18n/es/features/adicion.feature +17 -0
  64. data/examples/i18n/es/features/step_definitons/calculador_steps.rb +21 -0
  65. data/examples/i18n/es/lib/calculador.rb +14 -0
  66. data/examples/i18n/et/Rakefile +6 -0
  67. data/examples/i18n/et/features/jagamine.feature +10 -0
  68. data/examples/i18n/et/features/liitmine.feature +17 -0
  69. data/examples/i18n/et/features/step_definitions/kalkulaator_steps.rb +24 -0
  70. data/examples/i18n/et/lib/kalkulaator.rb +14 -0
  71. data/examples/i18n/fi/.gitignore +1 -0
  72. data/examples/i18n/fi/Rakefile +6 -0
  73. data/examples/i18n/fi/features/jakolasku.feature +10 -0
  74. data/examples/i18n/fi/features/step_definitons/laskin_steps.rb +24 -0
  75. data/examples/i18n/fi/features/yhteenlasku.feature +17 -0
  76. data/examples/i18n/fi/lib/laskin.rb +14 -0
  77. data/examples/i18n/fr/Rakefile +6 -0
  78. data/examples/i18n/fr/features/addition.feature +18 -0
  79. data/examples/i18n/fr/features/addition2.feature +17 -0
  80. data/examples/i18n/fr/features/step_definitions/calculatrice_steps.rb +32 -0
  81. data/examples/i18n/fr/features/support/env.rb +5 -0
  82. data/examples/i18n/fr/lib/calculatrice.rb +10 -0
  83. data/examples/i18n/he/Rakefile +6 -0
  84. data/examples/i18n/he/features/addition.feature +17 -0
  85. data/examples/i18n/he/features/division.feature +10 -0
  86. data/examples/i18n/he/features/step_definitons/calculator_steps.rb +24 -0
  87. data/examples/i18n/he/lib/calculator.rb +15 -0
  88. data/examples/i18n/hu/.gitignore +1 -0
  89. data/examples/i18n/hu/Rakefile +6 -0
  90. data/examples/i18n/hu/features/osszeadas.feature +17 -0
  91. data/examples/i18n/hu/features/osztas.feature +10 -0
  92. data/examples/i18n/hu/features/step_definitons/calculator_steps.rb +25 -0
  93. data/examples/i18n/hu/lib/calculator.rb +14 -0
  94. data/examples/i18n/id/.gitignore +1 -0
  95. data/examples/i18n/id/Rakefile +6 -0
  96. data/examples/i18n/id/features/addition.feature +17 -0
  97. data/examples/i18n/id/features/division.feature +10 -0
  98. data/examples/i18n/id/features/step_definitons/calculator_steps.rb +24 -0
  99. data/examples/i18n/id/lib/calculator.rb +14 -0
  100. data/examples/i18n/it/Rakefile +6 -0
  101. data/examples/i18n/it/features/somma.feature +11 -0
  102. data/examples/i18n/it/features/step_definitons/calcolatrice_steps.rb +24 -0
  103. data/examples/i18n/it/lib/calcolatrice.rb +11 -0
  104. data/examples/i18n/ja/.gitignore +1 -0
  105. data/examples/i18n/ja/Rakefile +6 -0
  106. data/examples/i18n/ja/features/addition.feature +17 -0
  107. data/examples/i18n/ja/features/division.feature +10 -0
  108. data/examples/i18n/ja/features/step_definitons/calculator_steps.rb +19 -0
  109. data/examples/i18n/ja/features/support/env.rb +5 -0
  110. data/examples/i18n/ja/lib/calculator.rb +14 -0
  111. data/examples/i18n/ko/.gitignore +1 -0
  112. data/examples/i18n/ko/Rakefile +6 -0
  113. data/examples/i18n/ko/features/addition.feature +17 -0
  114. data/examples/i18n/ko/features/division.feature +11 -0
  115. data/examples/i18n/ko/features/step_definitons/calculator_steps.rb +24 -0
  116. data/examples/i18n/ko/lib/calculator.rb +14 -0
  117. data/examples/i18n/lt/.gitignore +1 -0
  118. data/examples/i18n/lt/Rakefile +6 -0
  119. data/examples/i18n/lt/features/addition.feature +17 -0
  120. data/examples/i18n/lt/features/division.feature +10 -0
  121. data/examples/i18n/lt/features/step_definitons/calculator_steps.rb +24 -0
  122. data/examples/i18n/lt/lib/calculator.rb +14 -0
  123. data/examples/i18n/lv/Rakefile +6 -0
  124. data/examples/i18n/lv/features/addition.feature +17 -0
  125. data/examples/i18n/lv/features/division.feature +10 -0
  126. data/examples/i18n/lv/features/step_definitons/calculator_steps.rb +24 -0
  127. data/examples/i18n/lv/lib/calculator.rb +14 -0
  128. data/examples/i18n/no/Rakefile +6 -0
  129. data/examples/i18n/no/features/step_definitons/kalkulator_steps.rb +17 -0
  130. data/examples/i18n/no/features/summering.feature +19 -0
  131. data/examples/i18n/no/features/support/env.rb +6 -0
  132. data/examples/i18n/no/lib/kalkulator.rb +11 -0
  133. data/examples/i18n/pl/.gitignore +1 -0
  134. data/examples/i18n/pl/Rakefile +6 -0
  135. data/examples/i18n/pl/features/addition.feature +17 -0
  136. data/examples/i18n/pl/features/division.feature +10 -0
  137. data/examples/i18n/pl/features/step_definitons/calculator_steps.rb +24 -0
  138. data/examples/i18n/pl/features/support/env.rb +5 -0
  139. data/examples/i18n/pl/lib/calculator.rb +14 -0
  140. data/examples/i18n/pt/Rakefile +6 -0
  141. data/examples/i18n/pt/features/adicao.feature +11 -0
  142. data/examples/i18n/pt/features/step_definitions/calculadora_steps.rb +20 -0
  143. data/examples/i18n/pt/features/support/env.rb +5 -0
  144. data/examples/i18n/pt/lib/calculadora.rb +10 -0
  145. data/examples/i18n/ro/Rakefile +6 -0
  146. data/examples/i18n/ro/features/adunare.feature +12 -0
  147. data/examples/i18n/ro/features/step_definitons/calculator_steps.rb +21 -0
  148. data/examples/i18n/ro/lib/calculator.rb +11 -0
  149. data/examples/i18n/ru/Rakefile +6 -0
  150. data/examples/i18n/ru/features/addition.feature +11 -0
  151. data/examples/i18n/ru/features/consecutive_calculations.feature +17 -0
  152. data/examples/i18n/ru/features/division.feature +16 -0
  153. data/examples/i18n/ru/features/step_definitons/calculator_steps.rb +19 -0
  154. data/examples/i18n/ru/features/support/env.rb +5 -0
  155. data/examples/i18n/ru/features/support/world.rb +8 -0
  156. data/examples/i18n/ru/lib/calculator.rb +24 -0
  157. data/examples/i18n/sk/.gitignore +1 -0
  158. data/examples/i18n/sk/Rakefile +6 -0
  159. data/examples/i18n/sk/features/addition.feature +17 -0
  160. data/examples/i18n/sk/features/division.feature +10 -0
  161. data/examples/i18n/sk/features/step_definitons/calculator_steps.rb +24 -0
  162. data/examples/i18n/sk/lib/calculator.rb +14 -0
  163. data/examples/i18n/sr-Cyrl/Rakefile +6 -0
  164. data/examples/i18n/sr-Cyrl/features/sabiranje.feature +18 -0
  165. data/examples/i18n/sr-Cyrl/features/step_definitons/calculator_steps.rb +20 -0
  166. data/examples/i18n/sr-Cyrl/features/support/env.rb +5 -0
  167. data/examples/i18n/sr-Cyrl/lib/calculator.rb +12 -0
  168. data/examples/i18n/sr-Latn/Rakefile +6 -0
  169. data/examples/i18n/sr-Latn/features/sabiranje.feature +18 -0
  170. data/examples/i18n/sr-Latn/features/step_definitons/calculator_steps.rb +24 -0
  171. data/examples/i18n/sr-Latn/lib/calculator.rb +12 -0
  172. data/examples/i18n/sv/Rakefile +6 -0
  173. data/examples/i18n/sv/features/step_definitons/kalkulator_steps.rb +24 -0
  174. data/examples/i18n/sv/features/summering.feature +18 -0
  175. data/examples/i18n/sv/lib/kalkulator.rb +11 -0
  176. data/examples/i18n/tr/.gitignore +1 -0
  177. data/examples/i18n/tr/Rakefile +6 -0
  178. data/examples/i18n/tr/features/bolme.feature +10 -0
  179. data/examples/i18n/tr/features/step_definitons/hesap_makinesi_adimlari.rb +24 -0
  180. data/examples/i18n/tr/features/toplama.feature +18 -0
  181. data/examples/i18n/tr/lib/hesap_makinesi.rb +15 -0
  182. data/examples/i18n/uk/Rakefile +6 -0
  183. data/examples/i18n/uk/features/addition.feature +11 -0
  184. data/examples/i18n/uk/features/consecutive_calculations.feature +17 -0
  185. data/examples/i18n/uk/features/division.feature +16 -0
  186. data/examples/i18n/uk/features/step_definitons/calculator_steps.rb +19 -0
  187. data/examples/i18n/uk/features/support/env.rb +5 -0
  188. data/examples/i18n/uk/features/support/world.rb +8 -0
  189. data/examples/i18n/uk/lib/calculator.rb +24 -0
  190. data/examples/i18n/uz/Rakefile +6 -0
  191. data/examples/i18n/uz/features/addition.feature +10 -0
  192. data/examples/i18n/uz/features/consecutive_calculations.feature +17 -0
  193. data/examples/i18n/uz/features/division.feature +17 -0
  194. data/examples/i18n/uz/features/step_definitons/calculator_steps.rb +19 -0
  195. data/examples/i18n/uz/features/support/env.rb +5 -0
  196. data/examples/i18n/uz/features/support/world.rb +8 -0
  197. data/examples/i18n/uz/lib/calculator.rb +24 -0
  198. data/examples/i18n/zh-CN/Rakefile +4 -0
  199. data/examples/i18n/zh-CN/features/addition.feature +18 -0
  200. data/examples/i18n/zh-CN/features/step_definitons/calculator_steps.rb +26 -0
  201. data/examples/i18n/zh-CN/lib/calculator.rb +10 -0
  202. data/examples/i18n/zh-TW/.gitignore +1 -0
  203. data/examples/i18n/zh-TW/Rakefile +4 -0
  204. data/examples/i18n/zh-TW/features/addition.feature +17 -0
  205. data/examples/i18n/zh-TW/features/division.feature +11 -0
  206. data/examples/i18n/zh-TW/features/step_definitons/calculator_steps.rb +24 -0
  207. data/examples/i18n/zh-TW/lib/calculator.rb +14 -0
  208. data/examples/python/README.textile +7 -0
  209. data/examples/python/Rakefile +4 -0
  210. data/examples/python/features/fibonacci.feature +19 -0
  211. data/examples/python/features/step_definitions/fib_steps.py +11 -0
  212. data/examples/python/lib/.gitignore +1 -0
  213. data/examples/python/lib/fib.py +7 -0
  214. data/examples/ramaze/README.textile +7 -0
  215. data/examples/ramaze/Rakefile +6 -0
  216. data/examples/ramaze/app.rb +21 -0
  217. data/examples/ramaze/features/add.feature +11 -0
  218. data/examples/ramaze/features/step_definitions/add_steps.rb +15 -0
  219. data/examples/ramaze/features/support/env.rb +32 -0
  220. data/examples/ramaze/layout/default.html.erb +8 -0
  221. data/examples/ramaze/view/index.html.erb +5 -0
  222. data/examples/rspec_doubles/Rakefile +4 -0
  223. data/examples/rspec_doubles/features/mocking.feature +9 -0
  224. data/examples/rspec_doubles/features/step_definitions/calvin_steps.rb +19 -0
  225. data/examples/rspec_doubles/features/support/env.rb +12 -0
  226. data/examples/ruby2python/README.textile +7 -0
  227. data/examples/ruby2python/Rakefile +4 -0
  228. data/examples/ruby2python/features/fibonacci.feature +19 -0
  229. data/examples/ruby2python/features/step_definitions/fib_steps.rb +7 -0
  230. data/examples/ruby2python/features/support/env.rb +21 -0
  231. data/examples/ruby2python/lib/.gitignore +1 -0
  232. data/examples/ruby2python/lib/fib.py +7 -0
  233. data/examples/sinatra/README.textile +13 -0
  234. data/examples/sinatra/Rakefile +6 -0
  235. data/examples/sinatra/app.rb +14 -0
  236. data/examples/sinatra/features/add.feature +11 -0
  237. data/examples/sinatra/features/step_definitions/add_steps.rb +15 -0
  238. data/examples/sinatra/features/support/env.rb +10 -0
  239. data/examples/sinatra/views/add.erb +7 -0
  240. data/examples/sinatra/views/layout.erb +8 -0
  241. data/examples/tcl/README.textile +11 -0
  242. data/examples/tcl/Rakefile +6 -0
  243. data/examples/tcl/features/fibonnacci.feature +17 -0
  244. data/examples/tcl/features/step_definitions/fib_steps.rb +7 -0
  245. data/examples/tcl/features/support/env.rb +6 -0
  246. data/examples/tcl/src/fib.tcl +3 -0
  247. data/examples/test_unit/Rakefile +6 -0
  248. data/examples/test_unit/features/step_definitions/test_unit_steps.rb +23 -0
  249. data/examples/test_unit/features/test_unit.feature +9 -0
  250. data/examples/v8/Rakefile +6 -0
  251. data/examples/v8/features/fibonacci.feature +43 -0
  252. data/examples/v8/features/step_definitions/fib_steps.js +49 -0
  253. data/examples/v8/features/support/env.js +14 -0
  254. data/examples/v8/lib/fibonacci.js +19 -0
  255. data/examples/watir/.gitignore +2 -0
  256. data/examples/watir/README.textile +16 -0
  257. data/examples/watir/Rakefile +12 -0
  258. data/examples/watir/cucumber.yml +1 -0
  259. data/examples/watir/features/search.feature +12 -0
  260. data/examples/watir/features/step_definitions/search_steps.rb +26 -0
  261. data/examples/watir/features/support/env.rb +32 -0
  262. data/examples/watir/features/support/screenshots.rb +47 -0
  263. data/features/background.feature +498 -0
  264. data/features/bootstrap.feature +13 -0
  265. data/features/custom_formatter.feature +41 -0
  266. data/features/execute_with_tag_filter.feature +63 -0
  267. data/features/hooks.feature +59 -0
  268. data/features/iso-8859-1.feature +6 -0
  269. data/features/json_formatter.feature +248 -0
  270. data/features/stats_formatters.feature +70 -0
  271. data/features/step_definitions/cucumber-features/cucumber_ruby_mappings.rb +168 -0
  272. data/features/step_definitions/cucumber_steps.rb +23 -0
  273. data/features/step_definitions/iso-8859-1_steps.rb +24 -0
  274. data/features/support/env.rb +26 -0
  275. data/features/tagged_hooks.feature +217 -0
  276. data/features/transforms.feature +63 -0
  277. data/fixtures/json/features/background.feature +7 -0
  278. data/fixtures/json/features/embed.feature +4 -0
  279. data/fixtures/json/features/one_passing_one_failing.feature +11 -0
  280. data/fixtures/json/features/step_definitions/steps.rb +32 -0
  281. data/fixtures/json/features/tables.feature +13 -0
  282. data/fixtures/junit/features/one_passing_one_failing.feature +8 -0
  283. data/fixtures/junit/features/pending.feature +7 -0
  284. data/fixtures/junit/features/scenario_outline.feature +9 -0
  285. data/fixtures/junit/features/some_subdirectory/one_passing_one_failing.feature +8 -0
  286. data/fixtures/junit/features/step_definitions/steps.rb +11 -0
  287. data/fixtures/self_test/.gitignore +1 -0
  288. data/fixtures/self_test/README.textile +6 -0
  289. data/fixtures/self_test/Rakefile +6 -0
  290. data/fixtures/self_test/features/call_undefined_step_from_step_def.feature +7 -0
  291. data/fixtures/self_test/features/failing_expectation.feature +4 -0
  292. data/fixtures/self_test/features/lots_of_undefined.feature +8 -0
  293. data/fixtures/self_test/features/multiline_name.feature +27 -0
  294. data/fixtures/self_test/features/outline_sample.feature +15 -0
  295. data/fixtures/self_test/features/sample.feature +21 -0
  296. data/fixtures/self_test/features/search_sample.feature +32 -0
  297. data/fixtures/self_test/features/step_definitions/sample_steps.rb +84 -0
  298. data/fixtures/self_test/features/support/bubble_256x256.png +0 -0
  299. data/fixtures/self_test/features/support/env.rb +26 -0
  300. data/fixtures/self_test/features/tags_sample.feature +17 -0
  301. data/fixtures/self_test/features/tons_of_cukes.feature +52 -0
  302. data/fixtures/self_test/features/undefined_multiline_args.feature +12 -0
  303. data/fixtures/self_test/list-of-features.txt +1 -0
  304. data/fixtures/steps_library/features/step_definitions/steps_lib1.rb +8 -0
  305. data/fixtures/steps_library/features/step_definitions/steps_lib2.rb +8 -0
  306. data/fixtures/tickets/Rakefile +20 -0
  307. data/fixtures/tickets/features.html +138 -0
  308. data/fixtures/tickets/features/172.feature +28 -0
  309. data/fixtures/tickets/features/177/1.feature +28 -0
  310. data/fixtures/tickets/features/177/2.feature +20 -0
  311. data/fixtures/tickets/features/177/3.feature +18 -0
  312. data/fixtures/tickets/features/180.feature +7 -0
  313. data/fixtures/tickets/features/229/tagged_hooks.feature +8 -0
  314. data/fixtures/tickets/features/229/tagged_hooks.rb +14 -0
  315. data/fixtures/tickets/features/236.feature +13 -0
  316. data/fixtures/tickets/features/241.feature +12 -0
  317. data/fixtures/tickets/features/246.feature +4 -0
  318. data/fixtures/tickets/features/248.feature +11 -0
  319. data/fixtures/tickets/features/270/back.feature +14 -0
  320. data/fixtures/tickets/features/270/back.steps.rb +14 -0
  321. data/fixtures/tickets/features/272/hooks.feature +26 -0
  322. data/fixtures/tickets/features/272/hooks_steps.rb +53 -0
  323. data/fixtures/tickets/features/279/py_string_indent.feature +25 -0
  324. data/fixtures/tickets/features/279/py_string_indent.steps.rb +12 -0
  325. data/fixtures/tickets/features/279/wrong.feature_ +11 -0
  326. data/fixtures/tickets/features/301/filter_background_tagged_hooks.feature +6 -0
  327. data/fixtures/tickets/features/301/filter_background_tagged_hooks_steps.rb +12 -0
  328. data/fixtures/tickets/features/306/only_background.feature +4 -0
  329. data/fixtures/tickets/features/around_timeout.feature +6 -0
  330. data/fixtures/tickets/features/gherkin_67.feature +12 -0
  331. data/fixtures/tickets/features/gherkin_68.feature +4 -0
  332. data/fixtures/tickets/features/half_manual.feature +11 -0
  333. data/fixtures/tickets/features/lib/eatting_machine.rb +18 -0
  334. data/fixtures/tickets/features/lib/pantry.rb +20 -0
  335. data/fixtures/tickets/features/scenario_outline.feature +95 -0
  336. data/fixtures/tickets/features/step_definitons/246_steps.rb +3 -0
  337. data/fixtures/tickets/features/step_definitons/248_steps.rb +15 -0
  338. data/fixtures/tickets/features/step_definitons/around_timeout_steps.rb +9 -0
  339. data/fixtures/tickets/features/step_definitons/half_manual_steps.rb +11 -0
  340. data/fixtures/tickets/features/step_definitons/scenario_outline_steps.rb +42 -0
  341. data/fixtures/tickets/features/step_definitons/tickets_steps.rb +88 -0
  342. data/fixtures/tickets/features/table_diffing.feature +13 -0
  343. data/fixtures/tickets/features/tickets.feature +28 -0
  344. data/gem_tasks/contributors.rake +15 -0
  345. data/gem_tasks/cucumber.rake +21 -0
  346. data/gem_tasks/downloads.rb +7 -0
  347. data/gem_tasks/environment.rake +7 -0
  348. data/gem_tasks/examples.rake +11 -0
  349. data/gem_tasks/fix_cr_lf.rake +10 -0
  350. data/gem_tasks/flog.rake +4 -0
  351. data/gem_tasks/rspec.rake +8 -0
  352. data/gem_tasks/sass.rake +4 -0
  353. data/gem_tasks/stats +14 -0
  354. data/gem_tasks/versions.txt +74 -0
  355. data/gem_tasks/yard.rake +0 -0
  356. data/gem_tasks/yard/default/layout/html/bubble_32x32.png +0 -0
  357. data/gem_tasks/yard/default/layout/html/footer.erb +5 -0
  358. data/gem_tasks/yard/default/layout/html/index.erb +1 -0
  359. data/gem_tasks/yard/default/layout/html/layout.erb +25 -0
  360. data/gem_tasks/yard/default/layout/html/logo.erb +1 -0
  361. data/gem_tasks/yard/default/layout/html/setup.rb +4 -0
  362. data/legacy_features/announce.feature +152 -0
  363. data/legacy_features/api/list_step_defs_as_json.feature +50 -0
  364. data/legacy_features/api/run_cli_main_with_existing_runtime.feature +34 -0
  365. data/legacy_features/around_hooks.feature +232 -0
  366. data/legacy_features/bug_371.feature +32 -0
  367. data/legacy_features/bug_464.feature +16 -0
  368. data/legacy_features/bug_475.feature +42 -0
  369. data/legacy_features/bug_585_tab_indentation.feature +22 -0
  370. data/legacy_features/bug_600.feature +73 -0
  371. data/legacy_features/call_steps_from_stepdefs.feature +154 -0
  372. data/legacy_features/cucumber_cli.feature +591 -0
  373. data/legacy_features/cucumber_cli_outlines.feature +117 -0
  374. data/legacy_features/default_snippets.feature +42 -0
  375. data/legacy_features/diffing.feature +25 -0
  376. data/legacy_features/drb_server_integration.feature +174 -0
  377. data/legacy_features/exception_in_after_block.feature +127 -0
  378. data/legacy_features/exception_in_after_step_block.feature +104 -0
  379. data/legacy_features/exception_in_before_block.feature +98 -0
  380. data/legacy_features/exclude_files.feature +20 -0
  381. data/legacy_features/expand.feature +60 -0
  382. data/legacy_features/html_formatter.feature +8 -0
  383. data/legacy_features/html_formatter/a.html +561 -0
  384. data/legacy_features/junit_formatter.feature +164 -0
  385. data/legacy_features/language_from_header.feature +30 -0
  386. data/legacy_features/language_help.feature +77 -0
  387. data/legacy_features/listener_debugger_formatter.feature +42 -0
  388. data/legacy_features/multiline_names.feature +44 -0
  389. data/legacy_features/post_configuration_hook.feature +50 -0
  390. data/legacy_features/profiles.feature +126 -0
  391. data/legacy_features/rake_task.feature +152 -0
  392. data/legacy_features/report_called_undefined_steps.feature +34 -0
  393. data/legacy_features/rerun_formatter.feature +52 -0
  394. data/legacy_features/simplest.feature +11 -0
  395. data/legacy_features/snippet.feature +23 -0
  396. data/legacy_features/snippets_when_using_star_keyword.feature +36 -0
  397. data/legacy_features/step_definitions/cucumber_steps.rb +172 -0
  398. data/legacy_features/step_definitions/extra_steps.rb +2 -0
  399. data/legacy_features/step_definitions/simplest_steps.rb +3 -0
  400. data/legacy_features/step_definitions/wire_steps.rb +34 -0
  401. data/legacy_features/support/env.rb +157 -0
  402. data/legacy_features/support/env.rb.simplest +7 -0
  403. data/legacy_features/support/fake_wire_server.rb +77 -0
  404. data/legacy_features/table_diffing.feature +45 -0
  405. data/legacy_features/table_mapping.feature +34 -0
  406. data/legacy_features/transform.feature +245 -0
  407. data/legacy_features/unicode_table.feature +35 -0
  408. data/legacy_features/wire_protocol.feature +332 -0
  409. data/legacy_features/wire_protocol_erb.feature +57 -0
  410. data/legacy_features/wire_protocol_table_diffing.feature +119 -0
  411. data/legacy_features/wire_protocol_tags.feature +87 -0
  412. data/legacy_features/wire_protocol_timeouts.feature +63 -0
  413. data/legacy_features/work_in_progress.feature +156 -0
  414. data/lib/README.rdoc +12 -0
  415. data/lib/autotest/cucumber.rb +6 -0
  416. data/lib/autotest/cucumber_mixin.rb +135 -0
  417. data/lib/autotest/cucumber_rails.rb +6 -0
  418. data/lib/autotest/cucumber_rails_rspec.rb +6 -0
  419. data/lib/autotest/cucumber_rails_rspec2.rb +6 -0
  420. data/lib/autotest/cucumber_rspec.rb +6 -0
  421. data/lib/autotest/cucumber_rspec2.rb +6 -0
  422. data/lib/autotest/discover.rb +9 -0
  423. data/lib/cucumber.rb +27 -0
  424. data/lib/cucumber/ast.rb +30 -0
  425. data/lib/cucumber/ast/background.rb +101 -0
  426. data/lib/cucumber/ast/comment.rb +31 -0
  427. data/lib/cucumber/ast/doc_string.rb +80 -0
  428. data/lib/cucumber/ast/examples.rb +46 -0
  429. data/lib/cucumber/ast/feature.rb +106 -0
  430. data/lib/cucumber/ast/feature_element.rb +78 -0
  431. data/lib/cucumber/ast/features.rb +35 -0
  432. data/lib/cucumber/ast/names.rb +13 -0
  433. data/lib/cucumber/ast/outline_table.rb +187 -0
  434. data/lib/cucumber/ast/scenario.rb +119 -0
  435. data/lib/cucumber/ast/scenario_outline.rb +125 -0
  436. data/lib/cucumber/ast/step.rb +126 -0
  437. data/lib/cucumber/ast/step_collection.rb +76 -0
  438. data/lib/cucumber/ast/step_invocation.rb +206 -0
  439. data/lib/cucumber/ast/table.rb +689 -0
  440. data/lib/cucumber/ast/tags.rb +28 -0
  441. data/lib/cucumber/ast/tree_walker.rb +183 -0
  442. data/lib/cucumber/ast/visitor.rb +11 -0
  443. data/lib/cucumber/broadcaster.rb +13 -0
  444. data/lib/cucumber/cli/configuration.rb +209 -0
  445. data/lib/cucumber/cli/drb_client.rb +43 -0
  446. data/lib/cucumber/cli/main.rb +78 -0
  447. data/lib/cucumber/cli/options.rb +410 -0
  448. data/lib/cucumber/cli/profile_loader.rb +91 -0
  449. data/lib/cucumber/configuration.rb +49 -0
  450. data/lib/cucumber/constantize.rb +34 -0
  451. data/lib/cucumber/core_ext/disable_mini_and_test_unit_autorun.rb +25 -0
  452. data/lib/cucumber/core_ext/instance_exec.rb +98 -0
  453. data/lib/cucumber/core_ext/proc.rb +34 -0
  454. data/lib/cucumber/core_ext/string.rb +9 -0
  455. data/lib/cucumber/errors.rb +40 -0
  456. data/lib/cucumber/feature_file.rb +101 -0
  457. data/lib/cucumber/formatter/ansicolor.rb +160 -0
  458. data/lib/cucumber/formatter/console.rb +187 -0
  459. data/lib/cucumber/formatter/cucumber.css +279 -0
  460. data/lib/cucumber/formatter/cucumber.sass +247 -0
  461. data/lib/cucumber/formatter/debug.rb +33 -0
  462. data/lib/cucumber/formatter/duration.rb +13 -0
  463. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +83 -0
  464. data/lib/cucumber/formatter/gpretty.rb +24 -0
  465. data/lib/cucumber/formatter/html.rb +649 -0
  466. data/lib/cucumber/formatter/io.rb +31 -0
  467. data/lib/cucumber/formatter/jquery-min.js +154 -0
  468. data/lib/cucumber/formatter/json.rb +31 -0
  469. data/lib/cucumber/formatter/json_pretty.rb +13 -0
  470. data/lib/cucumber/formatter/junit.rb +155 -0
  471. data/lib/cucumber/formatter/ordered_xml_markup.rb +24 -0
  472. data/lib/cucumber/formatter/pdf.rb +244 -0
  473. data/lib/cucumber/formatter/pretty.rb +237 -0
  474. data/lib/cucumber/formatter/progress.rb +92 -0
  475. data/lib/cucumber/formatter/rerun.rb +68 -0
  476. data/lib/cucumber/formatter/stepdefs.rb +14 -0
  477. data/lib/cucumber/formatter/steps.rb +49 -0
  478. data/lib/cucumber/formatter/summary.rb +35 -0
  479. data/lib/cucumber/formatter/unicode.rb +79 -0
  480. data/lib/cucumber/formatter/usage.rb +127 -0
  481. data/lib/cucumber/js_support/js_dsl.js +57 -0
  482. data/lib/cucumber/js_support/js_language.rb +185 -0
  483. data/lib/cucumber/js_support/js_snippets.rb +27 -0
  484. data/lib/cucumber/language_support.rb +30 -0
  485. data/lib/cucumber/language_support/language_methods.rb +129 -0
  486. data/lib/cucumber/parser.rb +2 -0
  487. data/lib/cucumber/parser/gherkin_builder.rb +129 -0
  488. data/lib/cucumber/platform.rb +29 -0
  489. data/lib/cucumber/py_support/py_dsl.py +10 -0
  490. data/lib/cucumber/py_support/py_language.py +10 -0
  491. data/lib/cucumber/py_support/py_language.rb +84 -0
  492. data/lib/cucumber/rake/task.rb +225 -0
  493. data/lib/cucumber/rb_support/rb_dsl.rb +112 -0
  494. data/lib/cucumber/rb_support/rb_hook.rb +18 -0
  495. data/lib/cucumber/rb_support/rb_language.rb +195 -0
  496. data/lib/cucumber/rb_support/rb_step_definition.rb +82 -0
  497. data/lib/cucumber/rb_support/rb_transform.rb +54 -0
  498. data/lib/cucumber/rb_support/rb_world.rb +103 -0
  499. data/lib/cucumber/rb_support/regexp_argument_matcher.rb +21 -0
  500. data/lib/cucumber/rspec/disable_option_parser.rb +23 -0
  501. data/lib/cucumber/rspec/doubles.rb +16 -0
  502. data/lib/cucumber/runtime.rb +145 -0
  503. data/lib/cucumber/runtime/features_loader.rb +62 -0
  504. data/lib/cucumber/runtime/for_programming_languages.rb +67 -0
  505. data/lib/cucumber/runtime/results.rb +64 -0
  506. data/lib/cucumber/runtime/support_code.rb +203 -0
  507. data/lib/cucumber/runtime/user_interface.rb +81 -0
  508. data/lib/cucumber/step_argument.rb +9 -0
  509. data/lib/cucumber/step_definition_light.rb +20 -0
  510. data/lib/cucumber/step_definitions.rb +14 -0
  511. data/lib/cucumber/step_match.rb +115 -0
  512. data/lib/cucumber/step_mother.rb +10 -0
  513. data/lib/cucumber/wire_support/configuration.rb +31 -0
  514. data/lib/cucumber/wire_support/connection.rb +55 -0
  515. data/lib/cucumber/wire_support/request_handler.rb +32 -0
  516. data/lib/cucumber/wire_support/wire_exception.rb +32 -0
  517. data/lib/cucumber/wire_support/wire_language.rb +54 -0
  518. data/lib/cucumber/wire_support/wire_packet.rb +32 -0
  519. data/lib/cucumber/wire_support/wire_protocol.rb +44 -0
  520. data/lib/cucumber/wire_support/wire_protocol/requests.rb +123 -0
  521. data/lib/cucumber/wire_support/wire_step_definition.rb +26 -0
  522. data/spec/cucumber/ast/background_spec.rb +115 -0
  523. data/spec/cucumber/ast/doc_string_spec.rb +40 -0
  524. data/spec/cucumber/ast/feature_factory.rb +61 -0
  525. data/spec/cucumber/ast/feature_spec.rb +63 -0
  526. data/spec/cucumber/ast/outline_table_spec.rb +21 -0
  527. data/spec/cucumber/ast/scenario_outline_spec.rb +69 -0
  528. data/spec/cucumber/ast/step_spec.rb +66 -0
  529. data/spec/cucumber/ast/table_spec.rb +484 -0
  530. data/spec/cucumber/ast/tree_walker_spec.rb +11 -0
  531. data/spec/cucumber/broadcaster_spec.rb +15 -0
  532. data/spec/cucumber/cli/configuration_spec.rb +431 -0
  533. data/spec/cucumber/cli/drb_client_spec.rb +76 -0
  534. data/spec/cucumber/cli/main_spec.rb +137 -0
  535. data/spec/cucumber/cli/options_spec.rb +358 -0
  536. data/spec/cucumber/cli/profile_loader_spec.rb +35 -0
  537. data/spec/cucumber/configuration_spec.rb +23 -0
  538. data/spec/cucumber/core_ext/proc_spec.rb +68 -0
  539. data/spec/cucumber/formatter/ansicolor_spec.rb +31 -0
  540. data/spec/cucumber/formatter/duration_spec.rb +22 -0
  541. data/spec/cucumber/formatter/html_spec.rb +256 -0
  542. data/spec/cucumber/formatter/junit_spec.rb +125 -0
  543. data/spec/cucumber/formatter/progress_spec.rb +38 -0
  544. data/spec/cucumber/formatter/spec_helper.rb +52 -0
  545. data/spec/cucumber/rake/forked_spec.rb +62 -0
  546. data/spec/cucumber/rake/rcov_spec.rb +71 -0
  547. data/spec/cucumber/rb_support/rb_language_spec.rb +282 -0
  548. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +98 -0
  549. data/spec/cucumber/rb_support/rb_transform_spec.rb +21 -0
  550. data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +18 -0
  551. data/spec/cucumber/runtime/support_code_spec.rb +112 -0
  552. data/spec/cucumber/runtime_spec.rb +41 -0
  553. data/spec/cucumber/sell_cucumbers.feature +19 -0
  554. data/spec/cucumber/step_match_spec.rb +69 -0
  555. data/spec/cucumber/wire_support/configuration_spec.rb +51 -0
  556. data/spec/cucumber/wire_support/connection_spec.rb +46 -0
  557. data/spec/cucumber/wire_support/wire_exception_spec.rb +44 -0
  558. data/spec/cucumber/wire_support/wire_language_spec.rb +47 -0
  559. data/spec/cucumber/wire_support/wire_packet_spec.rb +40 -0
  560. data/spec/cucumber/wire_support/wire_step_definition_spec.rb +20 -0
  561. data/spec/cucumber/world/pending_spec.rb +46 -0
  562. data/spec/spec_helper.rb +22 -0
  563. metadata +1044 -0
@@ -0,0 +1,126 @@
1
+ require 'cucumber/core_ext/string'
2
+ require 'cucumber/step_match'
3
+
4
+ module Cucumber
5
+ module Ast
6
+ class Step #:nodoc:
7
+ attr_reader :line, :keyword, :name
8
+ attr_writer :step_collection, :options
9
+ attr_accessor :feature_element, :exception, :multiline_arg
10
+
11
+ INDENT = 2
12
+
13
+ def initialize(line, keyword, name, multiline_arg=nil)
14
+ @line, @keyword, @name, @multiline_arg = line, keyword, name, multiline_arg
15
+ end
16
+
17
+ attr_reader :gherkin_statement
18
+ def gherkin_statement(statement=nil)
19
+ @gherkin_statement ||= statement
20
+ end
21
+
22
+ def background?
23
+ false
24
+ end
25
+
26
+ def status
27
+ # Step always has status skipped, because Step is always in a ScenarioOutline
28
+ :skipped
29
+ end
30
+
31
+ def step_invocation
32
+ StepInvocation.new(self, @name, @multiline_arg, [])
33
+ end
34
+
35
+ def step_invocation_from_cells(cells)
36
+ matched_cells = matched_cells(cells)
37
+
38
+ delimited_arguments = delimit_argument_names(cells.to_hash)
39
+ name = replace_name_arguments(delimited_arguments)
40
+ multiline_arg = @multiline_arg.nil? ? nil : @multiline_arg.arguments_replaced(delimited_arguments)
41
+
42
+ StepInvocation.new(self, name, multiline_arg, matched_cells)
43
+ end
44
+
45
+ def accept(visitor)
46
+ return if Cucumber.wants_to_quit
47
+ # The only time a Step is visited is when it is in a ScenarioOutline.
48
+ # Otherwise it's always StepInvocation that gets visited instead.
49
+ visit_step_result(visitor, first_match(visitor), @multiline_arg, :skipped, nil, nil)
50
+ end
51
+
52
+ def visit_step_result(visitor, step_match, multiline_arg, status, exception, background)
53
+ visitor.visit_step_result(@keyword, step_match, @multiline_arg, status, exception, source_indent, background)
54
+ end
55
+
56
+ def first_match(visitor)
57
+ # @feature_element is always a ScenarioOutline in this case
58
+ @feature_element.each_example_row do |cells|
59
+ argument_hash = cells.to_hash
60
+ delimited_arguments = delimit_argument_names(argument_hash)
61
+ name = replace_name_arguments(delimited_arguments)
62
+ step_match = visitor.step_mother.step_match(name, @name) rescue nil
63
+ return step_match if step_match
64
+ end
65
+ NoStepMatch.new(self, @name)
66
+ end
67
+
68
+ def to_sexp
69
+ [:step, @line, @keyword, @name, (@multiline_arg.nil? ? nil : @multiline_arg.to_sexp)].compact
70
+ end
71
+
72
+ def source_indent
73
+ @feature_element.source_indent(text_length)
74
+ end
75
+
76
+ def text_length(name=@name)
77
+ INDENT + INDENT + @keyword.unpack('U*').length + name.unpack('U*').length
78
+ end
79
+
80
+ def backtrace_line
81
+ @backtrace_line ||= @feature_element.backtrace_line("#{@keyword}#{@name}", @line) unless @feature_element.nil?
82
+ end
83
+
84
+ def file_colon_line
85
+ @file_colon_line ||= @feature_element.file_colon_line(@line) unless @feature_element.nil?
86
+ end
87
+
88
+ def language
89
+ @feature_element.language
90
+ end
91
+
92
+ def dom_id
93
+ @dom_id ||= file_colon_line.gsub(/\//, '_').gsub(/\./, '_').gsub(/:/, '_')
94
+ end
95
+
96
+ private
97
+
98
+ def matched_cells(cells)
99
+ col_index = 0
100
+ cells.select do |cell|
101
+ header_cell = cell.table.header_cell(col_index)
102
+ col_index += 1
103
+ delimited = delimited(header_cell.value)
104
+ @name.index(delimited) || (@multiline_arg && @multiline_arg.has_text?(delimited))
105
+ end
106
+ end
107
+
108
+ def delimit_argument_names(argument_hash)
109
+ argument_hash.inject({}) { |h,(name,value)| h[delimited(name)] = value; h }
110
+ end
111
+
112
+ def delimited(s)
113
+ "<#{s}>"
114
+ end
115
+
116
+ def replace_name_arguments(argument_hash)
117
+ name_with_arguments_replaced = @name
118
+ argument_hash.each do |name, value|
119
+ value ||= ''
120
+ name_with_arguments_replaced = name_with_arguments_replaced.gsub(name, value)
121
+ end
122
+ name_with_arguments_replaced
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,76 @@
1
+ module Cucumber
2
+ module Ast
3
+ # Holds an Array of Step or StepDefinition
4
+ class StepCollection #:nodoc:
5
+ include Enumerable
6
+
7
+ def initialize(steps)
8
+ @steps = steps
9
+ @steps.each{|step| step.step_collection = self}
10
+ end
11
+
12
+ def accept(visitor, &proc)
13
+ return if Cucumber.wants_to_quit
14
+ @steps.each do |step|
15
+ visitor.visit_step(step) if proc.nil? || proc.call(step)
16
+ end
17
+ end
18
+
19
+ def step_invocations(background = false)
20
+ StepCollection.new(@steps.map{ |step|
21
+ i = step.step_invocation
22
+ i.background = background
23
+ i
24
+ })
25
+ end
26
+
27
+ def step_invocations_from_cells(cells)
28
+ @steps.map{|step| step.step_invocation_from_cells(cells)}
29
+ end
30
+
31
+ # Duplicates this instance and adds +step_invocations+ to the end
32
+ def dup(step_invocations = [])
33
+ StepCollection.new(@steps + step_invocations)
34
+ end
35
+
36
+ def each(&proc)
37
+ @steps.each(&proc)
38
+ end
39
+
40
+ def previous_step(step)
41
+ i = @steps.index(step) || -1
42
+ @steps[i-1]
43
+ end
44
+
45
+ def empty?
46
+ @steps.empty?
47
+ end
48
+
49
+ def max_line_length(feature_element)
50
+ lengths = (@steps + [feature_element]).map{|e| e.text_length}
51
+ lengths.max
52
+ end
53
+
54
+ def exception
55
+ @exception ||= ((failed = @steps.detect {|step| step.exception}) && failed.exception)
56
+ end
57
+
58
+ def failed?
59
+ status == :failed
60
+ end
61
+
62
+ def passed?
63
+ status == :passed
64
+ end
65
+
66
+ def status
67
+ @steps.each{|step_invocation| return step_invocation.status if step_invocation.status != :passed}
68
+ :passed
69
+ end
70
+
71
+ def to_sexp
72
+ @steps.map{|step| step.to_sexp}
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,206 @@
1
+ require 'cucumber/errors'
2
+ require 'cucumber/step_match'
3
+ require 'cucumber/ast/table'
4
+ require 'gherkin/rubify'
5
+
6
+ module Cucumber
7
+ module Ast
8
+ class StepInvocation #:nodoc:
9
+ include Gherkin::Rubify
10
+
11
+ attr_writer :step_collection, :background
12
+ attr_reader :name, :matched_cells, :status, :reported_exception
13
+ attr_accessor :exception
14
+
15
+ class << self
16
+ SEVERITY = [:passed, :undefined, :pending, :skipped, :failed]
17
+ def worst_status(statuses)
18
+ SEVERITY[statuses.map{|status| SEVERITY.index(status)}.max]
19
+ end
20
+ end
21
+
22
+ def initialize(step, name, multiline_arg, matched_cells)
23
+ @step, @name, @multiline_arg, @matched_cells = step, name, multiline_arg, matched_cells
24
+ status!(:skipped)
25
+ @skip_invoke = @exception = @step_match = @different_table = @reported_exception = @background = nil
26
+ end
27
+
28
+ def background?
29
+ @background
30
+ end
31
+
32
+ def skip_invoke!
33
+ @skip_invoke = true
34
+ end
35
+
36
+ def accept(visitor)
37
+ return if Cucumber.wants_to_quit
38
+ invoke(visitor.step_mother, visitor.configuration)
39
+ visit_step_result(visitor)
40
+ end
41
+
42
+ def visit_step_result(visitor)
43
+ visitor.visit_step_result(
44
+ keyword,
45
+ @step_match,
46
+ (@different_table || @multiline_arg),
47
+ @status,
48
+ @reported_exception,
49
+ source_indent,
50
+ @background
51
+ )
52
+ end
53
+
54
+ def invoke(step_mother, configuration)
55
+ find_step_match!(step_mother, configuration)
56
+ unless @skip_invoke || configuration.dry_run? || @exception || @step_collection.exception
57
+ @skip_invoke = true
58
+ begin
59
+ @step_match.invoke(@multiline_arg)
60
+ step_mother.after_step
61
+ status!(:passed)
62
+ rescue Pending => e
63
+ failed(configuration, e, false)
64
+ status!(:pending)
65
+ rescue Undefined => e
66
+ failed(configuration, e, false)
67
+ status!(:undefined)
68
+ rescue Cucumber::Ast::Table::Different => e
69
+ @different_table = e.table
70
+ failed(configuration, e, false)
71
+ status!(:failed)
72
+ rescue Exception => e
73
+ failed(configuration, e, false)
74
+ status!(:failed)
75
+ end
76
+ end
77
+ end
78
+
79
+ def find_step_match!(step_mother, configuration)
80
+ return if @step_match
81
+ begin
82
+ @step_match = step_mother.step_match(@name)
83
+ rescue Undefined => e
84
+ failed(configuration, e, true)
85
+ status!(:undefined)
86
+ @step_match = NoStepMatch.new(@step, @name)
87
+ rescue Ambiguous => e
88
+ failed(configuration, e, false)
89
+ status!(:failed)
90
+ @step_match = NoStepMatch.new(@step, @name)
91
+ end
92
+ step_mother.step_visited(self)
93
+ end
94
+
95
+ def failed(configuration, e, clear_backtrace)
96
+ if Cucumber::JRUBY && e.class.name == 'NativeException'
97
+ # JRuby's NativeException ignores #set_backtrace.
98
+ # We're fixing it.
99
+ e.instance_eval do
100
+ def set_backtrace(backtrace)
101
+ @backtrace = backtrace
102
+ end
103
+
104
+ def backtrace
105
+ @backtrace
106
+ end
107
+ end
108
+ end
109
+
110
+ e.set_backtrace([]) if e.backtrace.nil? || clear_backtrace
111
+ e.backtrace << @step.backtrace_line unless @step.backtrace_line.nil?
112
+ e = filter_backtrace(e)
113
+ @exception = e
114
+ if(configuration.strict? || !(Undefined === e) || e.nested?)
115
+ @reported_exception = e
116
+ else
117
+ @reported_exception = nil
118
+ end
119
+ end
120
+
121
+ # This constant is appended to by Cuke4Duke. Do not change its name
122
+ BACKTRACE_FILTER_PATTERNS = [/vendor\/rails|lib\/cucumber|bin\/cucumber:|lib\/rspec|gems\/|minitest|test\/unit/]
123
+ PWD_PATTERN = /#{Regexp.escape(Dir.pwd)}\//m
124
+
125
+ # This is to work around double ":in " segments in JRuby backtraces. JRuby bug?
126
+ def filter_backtrace(e)
127
+ return e if Cucumber.use_full_backtrace
128
+ e.backtrace.each{|line| line.gsub!(PWD_PATTERN, "./")}
129
+
130
+ filtered = (e.backtrace || []).reject do |line|
131
+ BACKTRACE_FILTER_PATTERNS.detect { |p| line =~ p }
132
+ end
133
+
134
+ if ENV['CUCUMBER_TRUNCATE_OUTPUT']
135
+ # Strip off file locations
136
+ filtered = filtered.map do |line|
137
+ line =~ /(.*):in `/ ? $1 : line
138
+ end
139
+ end
140
+
141
+ e.set_backtrace(filtered)
142
+ e
143
+ end
144
+
145
+ def status!(status)
146
+ @status = status
147
+ @matched_cells.each do |cell|
148
+ cell.status = status
149
+ end
150
+ end
151
+
152
+ def previous
153
+ @step_collection.previous_step(self)
154
+ end
155
+
156
+ def actual_keyword
157
+ repeat_keywords = rubify([language.keywords('but'), language.keywords('and')]).flatten.uniq.reject{|kw| kw == '* '}
158
+ if repeat_keywords.index(@step.keyword) && previous
159
+ previous.actual_keyword
160
+ else
161
+ keyword == '* ' ? language.code_keywords.first : keyword
162
+ end
163
+ end
164
+
165
+ def source_indent
166
+ @step.feature_element.source_indent(text_length)
167
+ end
168
+
169
+ def text_length
170
+ @step.text_length(@name)
171
+ end
172
+
173
+ def keyword
174
+ @step.keyword
175
+ end
176
+
177
+ def multiline_arg
178
+ @step.multiline_arg
179
+ end
180
+
181
+ def file_colon_line
182
+ @step.file_colon_line
183
+ end
184
+
185
+ def dom_id
186
+ @step.dom_id
187
+ end
188
+
189
+ def backtrace_line
190
+ @step.backtrace_line
191
+ end
192
+
193
+ def language
194
+ @step.language
195
+ end
196
+
197
+ def gherkin_statement
198
+ @step.gherkin_statement
199
+ end
200
+
201
+ def to_sexp
202
+ [:step_invocation, @step.line, @step.keyword, @name, (@multiline_arg.nil? ? nil : @multiline_arg.to_sexp)].compact
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,689 @@
1
+ require 'gherkin/rubify'
2
+ require 'gherkin/lexer/i18n_lexer'
3
+ require 'gherkin/formatter/escaping'
4
+
5
+ module Cucumber
6
+ module Ast
7
+ # Step Definitions that match a plain text Step with a multiline argument table
8
+ # will receive it as an instance of Table. A Table object holds the data of a
9
+ # table parsed from a feature file and lets you access and manipulate the data
10
+ # in different ways.
11
+ #
12
+ # For example:
13
+ #
14
+ # Given I have:
15
+ # | a | b |
16
+ # | c | d |
17
+ #
18
+ # And a matching StepDefinition:
19
+ #
20
+ # Given /I have:/ do |table|
21
+ # data = table.raw
22
+ # end
23
+ #
24
+ # This will store <tt>[['a', 'b'], ['c', 'd']]</tt> in the <tt>data</tt> variable.
25
+ #
26
+ class Table
27
+ class Different < StandardError
28
+ attr_reader :table
29
+
30
+ def initialize(table)
31
+ super('Tables were not identical')
32
+ @table = table
33
+ end
34
+ end
35
+
36
+ class Builder
37
+ attr_reader :rows
38
+
39
+ def initialize
40
+ @rows = []
41
+ end
42
+
43
+ def row(row, line_number)
44
+ @rows << row
45
+ end
46
+
47
+ def eof
48
+ end
49
+ end
50
+
51
+ include Enumerable
52
+ include Gherkin::Rubify
53
+
54
+ NULL_CONVERSIONS = Hash.new(lambda{ |cell_value| cell_value }).freeze
55
+
56
+ attr_accessor :file
57
+
58
+ def self.default_arg_name #:nodoc:
59
+ "table"
60
+ end
61
+
62
+ def self.parse(text, uri, offset)
63
+ builder = Builder.new
64
+ lexer = Gherkin::Lexer::I18nLexer.new(builder)
65
+ lexer.scan(text)
66
+ new(builder.rows)
67
+ end
68
+
69
+ # Creates a new instance. +raw+ should be an Array of Array of String
70
+ # or an Array of Hash (similar to what #hashes returns).
71
+ # You don't typically create your own Table objects - Cucumber will do
72
+ # it internally and pass them to your Step Definitions.
73
+ #
74
+ def initialize(raw, conversion_procs = NULL_CONVERSIONS.dup)
75
+ @cells_class = Cells
76
+ @cell_class = Cell
77
+ raw = ensure_array_of_array(rubify(raw))
78
+ # Verify that it's square
79
+ transposed = raw.transpose
80
+ create_cell_matrix(raw)
81
+ @conversion_procs = conversion_procs
82
+ end
83
+
84
+ def to_step_definition_arg
85
+ dup
86
+ end
87
+
88
+ # Creates a copy of this table, inheriting any column mappings.
89
+ # registered with #map_headers!
90
+ #
91
+ def dup
92
+ self.class.new(raw.dup, @conversion_procs.dup)
93
+ end
94
+
95
+ # Returns a new, transposed table. Example:
96
+ #
97
+ # | a | 7 | 4 |
98
+ # | b | 9 | 2 |
99
+ #
100
+ # Gets converted into the following:
101
+ #
102
+ # | a | b |
103
+ # | 7 | 9 |
104
+ # | 4 | 2 |
105
+ #
106
+ def transpose
107
+ self.class.new(raw.transpose, @conversion_procs.dup)
108
+ end
109
+
110
+ # Converts this table into an Array of Hash where the keys of each
111
+ # Hash are the headers in the table. For example, a Table built from
112
+ # the following plain text:
113
+ #
114
+ # | a | b | sum |
115
+ # | 2 | 3 | 5 |
116
+ # | 7 | 9 | 16 |
117
+ #
118
+ # Gets converted into the following:
119
+ #
120
+ # [{'a' => '2', 'b' => '3', 'sum' => '5'}, {'a' => '7', 'b' => '9', 'sum' => '16'}]
121
+ #
122
+ # Use #map_column! to specify how values in a column are converted.
123
+ #
124
+ def hashes
125
+ @hashes ||= cells_rows[1..-1].map do |row|
126
+ row.to_hash
127
+ end
128
+ end
129
+
130
+ # Converts this table into a Hash where the first column is
131
+ # used as keys and the second column is used as values
132
+ #
133
+ # | a | 2 |
134
+ # | b | 3 |
135
+ #
136
+ # Gets converted into the following:
137
+ #
138
+ # {'a' => '2', 'b' => '3'}
139
+ #
140
+ # The table must be exactly two columns wide
141
+ #
142
+ def rows_hash
143
+ return @rows_hash if @rows_hash
144
+ verify_table_width(2)
145
+ @rows_hash = self.transpose.hashes[0]
146
+ end
147
+
148
+ # Gets the raw data of this table. For example, a Table built from
149
+ # the following plain text:
150
+ #
151
+ # | a | b |
152
+ # | c | d |
153
+ #
154
+ # gets converted into the following:
155
+ #
156
+ # [['a', 'b'], ['c', 'd']]
157
+ #
158
+ def raw
159
+ cell_matrix.map do |row|
160
+ row.map do |cell|
161
+ cell.value
162
+ end
163
+ end
164
+ end
165
+
166
+ def column_names #:nodoc:
167
+ @col_names ||= cell_matrix[0].map { |cell| cell.value }
168
+ end
169
+
170
+ def rows
171
+ hashes.map do |hash|
172
+ hash.values_at *headers
173
+ end
174
+ end
175
+
176
+ def each_cells_row(&proc) #:nodoc:
177
+ cells_rows.each(&proc)
178
+ end
179
+
180
+ def accept(visitor) #:nodoc:
181
+ return if Cucumber.wants_to_quit
182
+ cells_rows.each do |row|
183
+ visitor.visit_table_row(row)
184
+ end
185
+ nil
186
+ end
187
+
188
+ # Matches +pattern+ against the header row of the table.
189
+ # This is used especially for argument transforms.
190
+ #
191
+ # Example:
192
+ # | column_1_name | column_2_name |
193
+ # | x | y |
194
+ #
195
+ # table.match(/table:column_1_name,column_2_name/) #=> non-nil
196
+ #
197
+ # Note: must use 'table:' prefix on match
198
+ def match(pattern)
199
+ header_to_match = "table:#{headers.join(',')}"
200
+ pattern.match(header_to_match)
201
+ end
202
+
203
+ # For testing only
204
+ def to_sexp #:nodoc:
205
+ [:table, *cells_rows.map{|row| row.to_sexp}]
206
+ end
207
+
208
+ # Redefines the table headers. This makes it possible to use
209
+ # prettier and more flexible header names in the features. The
210
+ # keys of +mappings+ are Strings or regular expressions
211
+ # (anything that responds to #=== will work) that may match
212
+ # column headings in the table. The values of +mappings+ are
213
+ # desired names for the columns.
214
+ #
215
+ # Example:
216
+ #
217
+ # | Phone Number | Address |
218
+ # | 123456 | xyz |
219
+ # | 345678 | abc |
220
+ #
221
+ # A StepDefinition receiving this table can then map the columns
222
+ # with both Regexp and String:
223
+ #
224
+ # table.map_headers!(/phone( number)?/i => :phone, 'Address' => :address)
225
+ # table.hashes
226
+ # # => [{:phone => '123456', :address => 'xyz'}, {:phone => '345678', :address => 'abc'}]
227
+ #
228
+ # You may also pass in a block if you wish to convert all of the headers:
229
+ #
230
+ # table.map_headers! { |header| header.downcase }
231
+ # table.hashes.keys
232
+ # # => ['phone number', 'address']
233
+ #
234
+ # When a block is passed in along with a hash then the mappings in the hash take precendence:
235
+ #
236
+ # table.map_headers!('Address' => 'ADDRESS') { |header| header.downcase }
237
+ # table.hashes.keys
238
+ # # => ['phone number', 'ADDRESS']
239
+ #
240
+ def map_headers!(mappings={}, &block)
241
+ header_cells = cell_matrix[0]
242
+
243
+ if block_given?
244
+ header_values = header_cells.map { |cell| cell.value } - mappings.keys
245
+ mappings = mappings.merge(Hash[*header_values.zip(header_values.map(&block)).flatten])
246
+ end
247
+
248
+ mappings.each_pair do |pre, post|
249
+ mapped_cells = header_cells.select{|cell| pre === cell.value}
250
+ raise "No headers matched #{pre.inspect}" if mapped_cells.empty?
251
+ raise "#{mapped_cells.length} headers matched #{pre.inspect}: #{mapped_cells.map{|c| c.value}.inspect}" if mapped_cells.length > 1
252
+ mapped_cells[0].value = post
253
+ if @conversion_procs.has_key?(pre)
254
+ @conversion_procs[post] = @conversion_procs.delete(pre)
255
+ end
256
+ end
257
+ end
258
+
259
+ # Returns a new Table where the headers are redefined. See #map_headers!
260
+ def map_headers(mappings={})
261
+ table = self.dup
262
+ table.map_headers!(mappings)
263
+ table
264
+ end
265
+
266
+ # Change how #hashes converts column values. The +column_name+ argument identifies the column
267
+ # and +conversion_proc+ performs the conversion for each cell in that column. If +strict+ is
268
+ # true, an error will be raised if the column named +column_name+ is not found. If +strict+
269
+ # is false, no error will be raised. Example:
270
+ #
271
+ # Given /^an expense report for (.*) with the following posts:$/ do |table|
272
+ # posts_table.map_column!('amount') { |a| a.to_i }
273
+ # posts_table.hashes.each do |post|
274
+ # # post['amount'] is a Fixnum, rather than a String
275
+ # end
276
+ # end
277
+ #
278
+ def map_column!(column_name, strict=true, &conversion_proc)
279
+ verify_column(column_name.to_s) if strict
280
+ @conversion_procs[column_name.to_s] = conversion_proc
281
+ self
282
+ end
283
+
284
+ # Compares +other_table+ to self. If +other_table+ contains columns
285
+ # and/or rows that are not in self, new columns/rows are added at the
286
+ # relevant positions, marking the cells in those rows/columns as
287
+ # <tt>surplus</tt>. Likewise, if +other_table+ lacks columns and/or
288
+ # rows that are present in self, these are marked as <tt>missing</tt>.
289
+ #
290
+ # <tt>surplus</tt> and <tt>missing</tt> cells are recognised by formatters
291
+ # and displayed so that it's easy to read the differences.
292
+ #
293
+ # Cells that are different, but <em>look</em> identical (for example the
294
+ # boolean true and the string "true") are converted to their Object#inspect
295
+ # representation and preceded with (i) - to make it easier to identify
296
+ # where the difference actually is.
297
+ #
298
+ # Since all tables that are passed to StepDefinitions always have String
299
+ # objects in their cells, you may want to use #map_column! before calling
300
+ # #diff!. You can use #map_column! on either of the tables.
301
+ #
302
+ # A Different error is raised if there are missing rows or columns, or
303
+ # surplus rows. An error is <em>not</em> raised for surplus columns.
304
+ # Whether to raise or not raise can be changed by setting values in
305
+ # +options+ to true or false:
306
+ #
307
+ # * <tt>missing_row</tt> : Raise on missing rows (defaults to true)
308
+ # * <tt>surplus_row</tt> : Raise on surplus rows (defaults to true)
309
+ # * <tt>missing_col</tt> : Raise on missing columns (defaults to true)
310
+ # * <tt>surplus_col</tt> : Raise on surplus columns (defaults to false)
311
+ #
312
+ # The +other_table+ argument can be another Table, an Array of Array or
313
+ # an Array of Hash (similar to the structure returned by #hashes).
314
+ #
315
+ # Calling this method is particularly useful in <tt>Then</tt> steps that take
316
+ # a Table argument, if you want to compare that table to some actual values.
317
+ #
318
+ def diff!(other_table, options={})
319
+ options = {:missing_row => true, :surplus_row => true, :missing_col => true, :surplus_col => false}.merge(options)
320
+
321
+ other_table = ensure_table(other_table)
322
+ other_table.convert_columns!
323
+ ensure_green!
324
+
325
+ original_width = cell_matrix[0].length
326
+ other_table_cell_matrix = pad!(other_table.cell_matrix)
327
+ padded_width = cell_matrix[0].length
328
+
329
+ missing_col = cell_matrix[0].detect{|cell| cell.status == :undefined}
330
+ surplus_col = padded_width > original_width
331
+
332
+ require_diff_lcs
333
+ cell_matrix.extend(Diff::LCS)
334
+ convert_columns!
335
+ changes = cell_matrix.diff(other_table_cell_matrix).flatten
336
+
337
+ inserted = 0
338
+ missing = 0
339
+
340
+ row_indices = Array.new(other_table_cell_matrix.length) {|n| n}
341
+
342
+ last_change = nil
343
+ missing_row_pos = nil
344
+ insert_row_pos = nil
345
+
346
+ changes.each do |change|
347
+ if(change.action == '-')
348
+ missing_row_pos = change.position + inserted
349
+ cell_matrix[missing_row_pos].each{|cell| cell.status = :undefined}
350
+ row_indices.insert(missing_row_pos, nil)
351
+ missing += 1
352
+ else # '+'
353
+ insert_row_pos = change.position + missing
354
+ inserted_row = change.element
355
+ inserted_row.each{|cell| cell.status = :comment}
356
+ cell_matrix.insert(insert_row_pos, inserted_row)
357
+ row_indices[insert_row_pos] = nil
358
+ inspect_rows(cell_matrix[missing_row_pos], inserted_row) if last_change && last_change.action == '-'
359
+ inserted += 1
360
+ end
361
+ last_change = change
362
+ end
363
+
364
+ other_table_cell_matrix.each_with_index do |other_row, i|
365
+ row_index = row_indices.index(i)
366
+ row = cell_matrix[row_index] if row_index
367
+ if row
368
+ (original_width..padded_width).each do |col_index|
369
+ surplus_cell = other_row[col_index]
370
+ row[col_index].value = surplus_cell.value if row[col_index]
371
+ end
372
+ end
373
+ end
374
+
375
+ clear_cache!
376
+ should_raise =
377
+ missing_row_pos && options[:missing_row] ||
378
+ insert_row_pos && options[:surplus_row] ||
379
+ missing_col && options[:missing_col] ||
380
+ surplus_col && options[:surplus_col]
381
+ raise Different.new(self) if should_raise
382
+ end
383
+
384
+ def to_hash(cells) #:nodoc:
385
+ hash = Hash.new do |hash, key|
386
+ hash[key.to_s] if key.is_a?(Symbol)
387
+ end
388
+ column_names.each_with_index do |column_name, column_index|
389
+ value = @conversion_procs[column_name].call(cells.value(column_index))
390
+ hash[column_name] = value
391
+ end
392
+ hash
393
+ end
394
+
395
+ def index(cells) #:nodoc:
396
+ cells_rows.index(cells)
397
+ end
398
+
399
+ def verify_column(column_name) #:nodoc:
400
+ raise %{The column named "#{column_name}" does not exist} unless raw[0].include?(column_name)
401
+ end
402
+
403
+ def verify_table_width(width) #:nodoc:
404
+ raise %{The table must have exactly #{width} columns} unless raw[0].size == width
405
+ end
406
+
407
+ def arguments_replaced(arguments) #:nodoc:
408
+ raw_with_replaced_args = raw.map do |row|
409
+ row.map do |cell|
410
+ cell_with_replaced_args = cell
411
+ arguments.each do |name, value|
412
+ if cell_with_replaced_args && cell_with_replaced_args.include?(name)
413
+ cell_with_replaced_args = value ? cell_with_replaced_args.gsub(name, value) : nil
414
+ end
415
+ end
416
+ cell_with_replaced_args
417
+ end
418
+ end
419
+ Table.new(raw_with_replaced_args)
420
+ end
421
+
422
+ def has_text?(text) #:nodoc:
423
+ raw.flatten.compact.detect{|cell_value| cell_value.index(text)}
424
+ end
425
+
426
+ def cells_rows #:nodoc:
427
+ @rows ||= cell_matrix.map do |cell_row|
428
+ @cells_class.new(self, cell_row)
429
+ end
430
+ end
431
+
432
+ def headers #:nodoc:
433
+ raw.first
434
+ end
435
+
436
+ def header_cell(col) #:nodoc:
437
+ cells_rows[0][col]
438
+ end
439
+
440
+ def cell_matrix #:nodoc:
441
+ @cell_matrix
442
+ end
443
+
444
+ def col_width(col) #:nodoc:
445
+ columns[col].__send__(:width)
446
+ end
447
+
448
+ def to_s(options = {}) #:nodoc:
449
+ require 'cucumber/formatter/pretty'
450
+ options = {:color => true, :indent => 2, :prefixes => TO_S_PREFIXES}.merge(options)
451
+ io = StringIO.new
452
+
453
+ c = Term::ANSIColor.coloring?
454
+ Term::ANSIColor.coloring = options[:color]
455
+ formatter = Formatter::Pretty.new(nil, io, options)
456
+ formatter.instance_variable_set('@indent', options[:indent])
457
+ TreeWalker.new(nil, [formatter]).visit_multiline_arg(self)
458
+
459
+ Term::ANSIColor.coloring = c
460
+ io.rewind
461
+ s = "\n" + io.read + (" " * (options[:indent] - 2))
462
+ s
463
+ end
464
+
465
+ private
466
+
467
+ TO_S_PREFIXES = Hash.new(' ')
468
+ TO_S_PREFIXES[:comment] = '(+) '
469
+ TO_S_PREFIXES[:undefined] = '(-) '
470
+
471
+ protected
472
+
473
+ def inspect_rows(missing_row, inserted_row) #:nodoc:
474
+ missing_row.each_with_index do |missing_cell, col|
475
+ inserted_cell = inserted_row[col]
476
+ if(missing_cell.value != inserted_cell.value && (missing_cell.value.to_s == inserted_cell.value.to_s))
477
+ missing_cell.inspect!
478
+ inserted_cell.inspect!
479
+ end
480
+ end
481
+ end
482
+
483
+ def create_cell_matrix(raw) #:nodoc:
484
+ @cell_matrix = raw.map do |raw_row|
485
+ line = raw_row.line rescue -1
486
+ raw_row.map do |raw_cell|
487
+ new_cell(raw_cell, line)
488
+ end
489
+ end
490
+ end
491
+
492
+ def convert_columns! #:nodoc:
493
+ cell_matrix.transpose.each do |col|
494
+ conversion_proc = @conversion_procs[col[0].value]
495
+ col[1..-1].each do |cell|
496
+ cell.value = conversion_proc.call(cell.value)
497
+ end
498
+ end
499
+ end
500
+
501
+ def require_diff_lcs #:nodoc:
502
+ begin
503
+ require 'diff/lcs'
504
+ rescue LoadError => e
505
+ e.message << "\n Please gem install diff-lcs\n"
506
+ raise e
507
+ end
508
+ end
509
+
510
+ def clear_cache! #:nodoc:
511
+ @hashes = @rows_hash = @rows = @columns = nil
512
+ end
513
+
514
+ def columns #:nodoc:
515
+ @columns ||= cell_matrix.transpose.map do |cell_row|
516
+ @cells_class.new(self, cell_row)
517
+ end
518
+ end
519
+
520
+ def new_cell(raw_cell, line) #:nodoc:
521
+ @cell_class.new(raw_cell, self, line)
522
+ end
523
+
524
+ # Pads our own cell_matrix and returns a cell matrix of same
525
+ # column width that can be used for diffing
526
+ def pad!(other_cell_matrix) #:nodoc:
527
+ clear_cache!
528
+ cols = cell_matrix.transpose
529
+ unmapped_cols = other_cell_matrix.transpose
530
+
531
+ mapped_cols = []
532
+
533
+ cols.each_with_index do |col, col_index|
534
+ header = col[0]
535
+ candidate_cols, unmapped_cols = unmapped_cols.partition do |other_col|
536
+ other_col[0] == header
537
+ end
538
+ raise "More than one column has the header #{header}" if candidate_cols.size > 2
539
+
540
+ other_padded_col = if candidate_cols.size == 1
541
+ # Found a matching column
542
+ candidate_cols[0]
543
+ else
544
+ mark_as_missing(cols[col_index])
545
+ (0...other_cell_matrix.length).map do |row|
546
+ val = row == 0 ? header.value : nil
547
+ SurplusCell.new(val, self, -1)
548
+ end
549
+ end
550
+ mapped_cols.insert(col_index, other_padded_col)
551
+ end
552
+
553
+ unmapped_cols.each_with_index do |col, col_index|
554
+ empty_col = (0...cell_matrix.length).map do |row|
555
+ SurplusCell.new(nil, self, -1)
556
+ end
557
+ cols << empty_col
558
+ end
559
+
560
+ @cell_matrix = cols.transpose
561
+ (mapped_cols + unmapped_cols).transpose
562
+ end
563
+
564
+ def ensure_table(table_or_array) #:nodoc:
565
+ return table_or_array if Table === table_or_array
566
+ Table.new(table_or_array)
567
+ end
568
+
569
+ def ensure_array_of_array(array)
570
+ Hash === array[0] ? hashes_to_array(array) : array
571
+ end
572
+
573
+ def hashes_to_array(hashes) #:nodoc:
574
+ header = hashes[0].keys
575
+ [header] + hashes.map{|hash| header.map{|key| hash[key]}}
576
+ end
577
+
578
+ def ensure_green! #:nodoc:
579
+ each_cell{|cell| cell.status = :passed}
580
+ end
581
+
582
+ def each_cell(&proc) #:nodoc:
583
+ cell_matrix.each{|row| row.each(&proc)}
584
+ end
585
+
586
+ def mark_as_missing(col) #:nodoc:
587
+ col.each do |cell|
588
+ cell.status = :undefined
589
+ end
590
+ end
591
+
592
+ # Represents a row of cells or columns of cells
593
+ class Cells #:nodoc:
594
+ include Enumerable
595
+ include Gherkin::Formatter::Escaping
596
+
597
+ attr_reader :exception
598
+
599
+ def initialize(table, cells)
600
+ @table, @cells = table, cells
601
+ end
602
+
603
+ def accept(visitor)
604
+ return if Cucumber.wants_to_quit
605
+ each do |cell|
606
+ visitor.visit_table_cell(cell)
607
+ end
608
+ nil
609
+ end
610
+
611
+ # For testing only
612
+ def to_sexp #:nodoc:
613
+ [:row, line, *@cells.map{|cell| cell.to_sexp}]
614
+ end
615
+
616
+ def to_hash #:nodoc:
617
+ @to_hash ||= @table.to_hash(self)
618
+ end
619
+
620
+ def value(n) #:nodoc:
621
+ self[n].value
622
+ end
623
+
624
+ def [](n)
625
+ @cells[n]
626
+ end
627
+
628
+ def line
629
+ @cells[0].line
630
+ end
631
+
632
+ def dom_id
633
+ "row_#{line}"
634
+ end
635
+
636
+ private
637
+
638
+ def index
639
+ @table.index(self)
640
+ end
641
+
642
+ def width
643
+ map{|cell| cell.value ? escape_cell(cell.value.to_s).unpack('U*').length : 0}.max
644
+ end
645
+
646
+ def each(&proc)
647
+ @cells.each(&proc)
648
+ end
649
+ end
650
+
651
+ class Cell #:nodoc:
652
+ attr_reader :line, :table
653
+ attr_accessor :status, :value
654
+
655
+ def initialize(value, table, line)
656
+ @value, @table, @line = value, table, line
657
+ end
658
+
659
+ def accept(visitor)
660
+ return if Cucumber.wants_to_quit
661
+ visitor.visit_table_cell_value(value, status)
662
+ end
663
+
664
+ def inspect!
665
+ @value = "(i) #{value.inspect}"
666
+ end
667
+
668
+ def ==(o)
669
+ SurplusCell === o || value == o.value
670
+ end
671
+
672
+ # For testing only
673
+ def to_sexp #:nodoc:
674
+ [:cell, @value]
675
+ end
676
+ end
677
+
678
+ class SurplusCell < Cell #:nodoc:
679
+ def status
680
+ :comment
681
+ end
682
+
683
+ def ==(o)
684
+ true
685
+ end
686
+ end
687
+ end
688
+ end
689
+ end