stefl-cucumber 0.10.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 (538) hide show
  1. data/.gitattributes +1 -0
  2. data/.gitignore +24 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +7 -0
  5. data/History.txt +1613 -0
  6. data/LICENSE +22 -0
  7. data/README.rdoc +26 -0
  8. data/Rakefile +12 -0
  9. data/bin/cucumber +22 -0
  10. data/cucumber.gemspec +50 -0
  11. data/cucumber.yml +20 -0
  12. data/examples/i18n/README.textile +18 -0
  13. data/examples/i18n/Rakefile +33 -0
  14. data/examples/i18n/ar/Rakefile +6 -0
  15. data/examples/i18n/ar/features/addition.feature +17 -0
  16. data/examples/i18n/ar/features/step_definitons/calculator_steps.rb +24 -0
  17. data/examples/i18n/ar/lib/calculator.rb +11 -0
  18. data/examples/i18n/bg/Rakefile +6 -0
  19. data/examples/i18n/bg/features/addition.feature +12 -0
  20. data/examples/i18n/bg/features/consecutive_calculations.feature +19 -0
  21. data/examples/i18n/bg/features/division.feature +17 -0
  22. data/examples/i18n/bg/features/step_definitons/calculator_steps.rb +24 -0
  23. data/examples/i18n/bg/features/support/env.rb +5 -0
  24. data/examples/i18n/bg/features/support/world.rb +8 -0
  25. data/examples/i18n/bg/lib/calculator.rb +24 -0
  26. data/examples/i18n/ca/Rakefile +6 -0
  27. data/examples/i18n/ca/features/step_definitons/calculator_steps.rb +21 -0
  28. data/examples/i18n/ca/features/suma.feature +17 -0
  29. data/examples/i18n/ca/lib/calculadora.rb +16 -0
  30. data/examples/i18n/da/Rakefile +6 -0
  31. data/examples/i18n/da/features/sammenlaegning.feature +18 -0
  32. data/examples/i18n/da/features/step_definitons/lommeregner_steps.rb +24 -0
  33. data/examples/i18n/da/lib/lommeregner.rb +11 -0
  34. data/examples/i18n/de/.gitignore +1 -0
  35. data/examples/i18n/de/Rakefile +6 -0
  36. data/examples/i18n/de/features/addition.feature +17 -0
  37. data/examples/i18n/de/features/division.feature +10 -0
  38. data/examples/i18n/de/features/step_definitons/calculator_steps.rb +24 -0
  39. data/examples/i18n/de/lib/calculator.rb +14 -0
  40. data/examples/i18n/en-lol/Rakefile +4 -0
  41. data/examples/i18n/en-lol/features/step_definitions/cucumbrz_steps.rb +16 -0
  42. data/examples/i18n/en-lol/features/stuffing.feature +8 -0
  43. data/examples/i18n/en-lol/features/support/env.rb +7 -0
  44. data/examples/i18n/en-lol/lib/basket.rb +12 -0
  45. data/examples/i18n/en-lol/lib/belly.rb +11 -0
  46. data/examples/i18n/en/.gitignore +1 -0
  47. data/examples/i18n/en/Rakefile +6 -0
  48. data/examples/i18n/en/features/addition.feature +17 -0
  49. data/examples/i18n/en/features/division.feature +10 -0
  50. data/examples/i18n/en/features/step_definitons/calculator_steps.rb +24 -0
  51. data/examples/i18n/en/lib/calculator.rb +14 -0
  52. data/examples/i18n/eo/.gitignore +1 -0
  53. data/examples/i18n/eo/Rakefile +6 -0
  54. data/examples/i18n/eo/features/adicio.feature +17 -0
  55. data/examples/i18n/eo/features/divido.feature +10 -0
  56. data/examples/i18n/eo/features/step_definitons/calculator_steps.rb +24 -0
  57. data/examples/i18n/eo/lib/calculator.rb +14 -0
  58. data/examples/i18n/es/Rakefile +6 -0
  59. data/examples/i18n/es/features/adicion.feature +17 -0
  60. data/examples/i18n/es/features/step_definitons/calculador_steps.rb +21 -0
  61. data/examples/i18n/es/lib/calculador.rb +14 -0
  62. data/examples/i18n/et/Rakefile +6 -0
  63. data/examples/i18n/et/features/jagamine.feature +10 -0
  64. data/examples/i18n/et/features/liitmine.feature +17 -0
  65. data/examples/i18n/et/features/step_definitions/kalkulaator_steps.rb +24 -0
  66. data/examples/i18n/et/lib/kalkulaator.rb +14 -0
  67. data/examples/i18n/fi/.gitignore +1 -0
  68. data/examples/i18n/fi/Rakefile +6 -0
  69. data/examples/i18n/fi/features/jakolasku.feature +10 -0
  70. data/examples/i18n/fi/features/step_definitons/laskin_steps.rb +24 -0
  71. data/examples/i18n/fi/features/yhteenlasku.feature +17 -0
  72. data/examples/i18n/fi/lib/laskin.rb +14 -0
  73. data/examples/i18n/fr/Rakefile +6 -0
  74. data/examples/i18n/fr/features/addition.feature +18 -0
  75. data/examples/i18n/fr/features/addition2.feature +17 -0
  76. data/examples/i18n/fr/features/step_definitions/calculatrice_steps.rb +32 -0
  77. data/examples/i18n/fr/features/support/env.rb +5 -0
  78. data/examples/i18n/fr/lib/calculatrice.rb +10 -0
  79. data/examples/i18n/he/Rakefile +6 -0
  80. data/examples/i18n/he/features/addition.feature +17 -0
  81. data/examples/i18n/he/features/division.feature +10 -0
  82. data/examples/i18n/he/features/step_definitons/calculator_steps.rb +24 -0
  83. data/examples/i18n/he/lib/calculator.rb +15 -0
  84. data/examples/i18n/hu/.gitignore +1 -0
  85. data/examples/i18n/hu/Rakefile +6 -0
  86. data/examples/i18n/hu/features/osszeadas.feature +17 -0
  87. data/examples/i18n/hu/features/osztas.feature +10 -0
  88. data/examples/i18n/hu/features/step_definitons/calculator_steps.rb +25 -0
  89. data/examples/i18n/hu/lib/calculator.rb +14 -0
  90. data/examples/i18n/id/.gitignore +1 -0
  91. data/examples/i18n/id/Rakefile +6 -0
  92. data/examples/i18n/id/features/addition.feature +17 -0
  93. data/examples/i18n/id/features/division.feature +10 -0
  94. data/examples/i18n/id/features/step_definitons/calculator_steps.rb +24 -0
  95. data/examples/i18n/id/lib/calculator.rb +14 -0
  96. data/examples/i18n/it/Rakefile +6 -0
  97. data/examples/i18n/it/features/somma.feature +11 -0
  98. data/examples/i18n/it/features/step_definitons/calcolatrice_steps.rb +24 -0
  99. data/examples/i18n/it/lib/calcolatrice.rb +11 -0
  100. data/examples/i18n/ja/.gitignore +1 -0
  101. data/examples/i18n/ja/Rakefile +6 -0
  102. data/examples/i18n/ja/features/addition.feature +17 -0
  103. data/examples/i18n/ja/features/division.feature +10 -0
  104. data/examples/i18n/ja/features/step_definitons/calculator_steps.rb +19 -0
  105. data/examples/i18n/ja/features/support/env.rb +5 -0
  106. data/examples/i18n/ja/lib/calculator.rb +14 -0
  107. data/examples/i18n/ko/.gitignore +1 -0
  108. data/examples/i18n/ko/Rakefile +6 -0
  109. data/examples/i18n/ko/features/addition.feature +17 -0
  110. data/examples/i18n/ko/features/division.feature +11 -0
  111. data/examples/i18n/ko/features/step_definitons/calculator_steps.rb +24 -0
  112. data/examples/i18n/ko/lib/calculator.rb +14 -0
  113. data/examples/i18n/lt/.gitignore +1 -0
  114. data/examples/i18n/lt/Rakefile +6 -0
  115. data/examples/i18n/lt/features/addition.feature +17 -0
  116. data/examples/i18n/lt/features/division.feature +10 -0
  117. data/examples/i18n/lt/features/step_definitons/calculator_steps.rb +24 -0
  118. data/examples/i18n/lt/lib/calculator.rb +14 -0
  119. data/examples/i18n/lv/Rakefile +6 -0
  120. data/examples/i18n/lv/features/addition.feature +17 -0
  121. data/examples/i18n/lv/features/division.feature +10 -0
  122. data/examples/i18n/lv/features/step_definitons/calculator_steps.rb +24 -0
  123. data/examples/i18n/lv/lib/calculator.rb +14 -0
  124. data/examples/i18n/no/Rakefile +6 -0
  125. data/examples/i18n/no/features/step_definitons/kalkulator_steps.rb +17 -0
  126. data/examples/i18n/no/features/summering.feature +19 -0
  127. data/examples/i18n/no/features/support/env.rb +6 -0
  128. data/examples/i18n/no/lib/kalkulator.rb +11 -0
  129. data/examples/i18n/pl/.gitignore +1 -0
  130. data/examples/i18n/pl/Rakefile +6 -0
  131. data/examples/i18n/pl/features/addition.feature +17 -0
  132. data/examples/i18n/pl/features/division.feature +10 -0
  133. data/examples/i18n/pl/features/step_definitons/calculator_steps.rb +24 -0
  134. data/examples/i18n/pl/features/support/env.rb +5 -0
  135. data/examples/i18n/pl/lib/calculator.rb +14 -0
  136. data/examples/i18n/pt/Rakefile +6 -0
  137. data/examples/i18n/pt/features/adicao.feature +11 -0
  138. data/examples/i18n/pt/features/step_definitions/calculadora_steps.rb +20 -0
  139. data/examples/i18n/pt/features/support/env.rb +5 -0
  140. data/examples/i18n/pt/lib/calculadora.rb +10 -0
  141. data/examples/i18n/ro/Rakefile +6 -0
  142. data/examples/i18n/ro/features/step_definitons/calculator_steps.rb +24 -0
  143. data/examples/i18n/ro/features/suma.feature +11 -0
  144. data/examples/i18n/ro/lib/calculator.rb +11 -0
  145. data/examples/i18n/ru/Rakefile +6 -0
  146. data/examples/i18n/ru/features/addition.feature +11 -0
  147. data/examples/i18n/ru/features/consecutive_calculations.feature +17 -0
  148. data/examples/i18n/ru/features/division.feature +16 -0
  149. data/examples/i18n/ru/features/step_definitons/calculator_steps.rb +19 -0
  150. data/examples/i18n/ru/features/support/env.rb +5 -0
  151. data/examples/i18n/ru/features/support/world.rb +8 -0
  152. data/examples/i18n/ru/lib/calculator.rb +24 -0
  153. data/examples/i18n/sk/.gitignore +1 -0
  154. data/examples/i18n/sk/Rakefile +6 -0
  155. data/examples/i18n/sk/features/addition.feature +17 -0
  156. data/examples/i18n/sk/features/division.feature +10 -0
  157. data/examples/i18n/sk/features/step_definitons/calculator_steps.rb +24 -0
  158. data/examples/i18n/sk/lib/calculator.rb +14 -0
  159. data/examples/i18n/sr-Cyrl/Rakefile +6 -0
  160. data/examples/i18n/sr-Cyrl/features/sabiranje.feature +18 -0
  161. data/examples/i18n/sr-Cyrl/features/step_definitons/calculator_steps.rb +20 -0
  162. data/examples/i18n/sr-Cyrl/features/support/env.rb +5 -0
  163. data/examples/i18n/sr-Cyrl/lib/calculator.rb +12 -0
  164. data/examples/i18n/sr-Latn/Rakefile +6 -0
  165. data/examples/i18n/sr-Latn/features/sabiranje.feature +18 -0
  166. data/examples/i18n/sr-Latn/features/step_definitons/calculator_steps.rb +24 -0
  167. data/examples/i18n/sr-Latn/lib/calculator.rb +12 -0
  168. data/examples/i18n/sv/Rakefile +6 -0
  169. data/examples/i18n/sv/features/step_definitons/kalkulator_steps.rb +24 -0
  170. data/examples/i18n/sv/features/summering.feature +18 -0
  171. data/examples/i18n/sv/lib/kalkulator.rb +11 -0
  172. data/examples/i18n/tr/.gitignore +1 -0
  173. data/examples/i18n/tr/Rakefile +6 -0
  174. data/examples/i18n/tr/features/bolme.feature +10 -0
  175. data/examples/i18n/tr/features/step_definitons/hesap_makinesi_adimlari.rb +24 -0
  176. data/examples/i18n/tr/features/toplama.feature +18 -0
  177. data/examples/i18n/tr/lib/hesap_makinesi.rb +15 -0
  178. data/examples/i18n/uk/Rakefile +6 -0
  179. data/examples/i18n/uk/features/addition.feature +11 -0
  180. data/examples/i18n/uk/features/consecutive_calculations.feature +17 -0
  181. data/examples/i18n/uk/features/division.feature +16 -0
  182. data/examples/i18n/uk/features/step_definitons/calculator_steps.rb +19 -0
  183. data/examples/i18n/uk/features/support/env.rb +5 -0
  184. data/examples/i18n/uk/features/support/world.rb +8 -0
  185. data/examples/i18n/uk/lib/calculator.rb +24 -0
  186. data/examples/i18n/uz/Rakefile +6 -0
  187. data/examples/i18n/uz/features/addition.feature +10 -0
  188. data/examples/i18n/uz/features/consecutive_calculations.feature +17 -0
  189. data/examples/i18n/uz/features/division.feature +17 -0
  190. data/examples/i18n/uz/features/step_definitons/calculator_steps.rb +19 -0
  191. data/examples/i18n/uz/features/support/env.rb +5 -0
  192. data/examples/i18n/uz/features/support/world.rb +8 -0
  193. data/examples/i18n/uz/lib/calculator.rb +24 -0
  194. data/examples/i18n/zh-CN/Rakefile +4 -0
  195. data/examples/i18n/zh-CN/features/addition.feature +18 -0
  196. data/examples/i18n/zh-CN/features/step_definitons/calculator_steps.rb +26 -0
  197. data/examples/i18n/zh-CN/lib/calculator.rb +10 -0
  198. data/examples/i18n/zh-TW/.gitignore +1 -0
  199. data/examples/i18n/zh-TW/Rakefile +4 -0
  200. data/examples/i18n/zh-TW/features/addition.feature +17 -0
  201. data/examples/i18n/zh-TW/features/division.feature +11 -0
  202. data/examples/i18n/zh-TW/features/step_definitons/calculator_steps.rb +24 -0
  203. data/examples/i18n/zh-TW/lib/calculator.rb +14 -0
  204. data/examples/python/README.textile +7 -0
  205. data/examples/python/Rakefile +4 -0
  206. data/examples/python/features/fibonacci.feature +19 -0
  207. data/examples/python/features/step_definitions/fib_steps.py +11 -0
  208. data/examples/python/lib/.gitignore +1 -0
  209. data/examples/python/lib/fib.py +7 -0
  210. data/examples/ramaze/README.textile +7 -0
  211. data/examples/ramaze/Rakefile +6 -0
  212. data/examples/ramaze/app.rb +21 -0
  213. data/examples/ramaze/features/add.feature +11 -0
  214. data/examples/ramaze/features/step_definitions/add_steps.rb +15 -0
  215. data/examples/ramaze/features/support/env.rb +32 -0
  216. data/examples/ramaze/layout/default.html.erb +8 -0
  217. data/examples/ramaze/view/index.html.erb +5 -0
  218. data/examples/rspec_doubles/Rakefile +4 -0
  219. data/examples/rspec_doubles/features/mocking.feature +9 -0
  220. data/examples/rspec_doubles/features/step_definitions/calvin_steps.rb +19 -0
  221. data/examples/rspec_doubles/features/support/env.rb +12 -0
  222. data/examples/ruby2python/README.textile +7 -0
  223. data/examples/ruby2python/Rakefile +4 -0
  224. data/examples/ruby2python/features/fibonacci.feature +19 -0
  225. data/examples/ruby2python/features/step_definitions/fib_steps.rb +7 -0
  226. data/examples/ruby2python/features/support/env.rb +21 -0
  227. data/examples/ruby2python/lib/.gitignore +1 -0
  228. data/examples/ruby2python/lib/fib.py +7 -0
  229. data/examples/sinatra/README.textile +13 -0
  230. data/examples/sinatra/Rakefile +6 -0
  231. data/examples/sinatra/app.rb +14 -0
  232. data/examples/sinatra/features/add.feature +11 -0
  233. data/examples/sinatra/features/step_definitions/add_steps.rb +15 -0
  234. data/examples/sinatra/features/support/env.rb +10 -0
  235. data/examples/sinatra/views/add.erb +7 -0
  236. data/examples/sinatra/views/layout.erb +8 -0
  237. data/examples/tcl/README.textile +11 -0
  238. data/examples/tcl/Rakefile +6 -0
  239. data/examples/tcl/features/fibonnacci.feature +17 -0
  240. data/examples/tcl/features/step_definitions/fib_steps.rb +7 -0
  241. data/examples/tcl/features/support/env.rb +6 -0
  242. data/examples/tcl/src/fib.tcl +3 -0
  243. data/examples/test_unit/Rakefile +6 -0
  244. data/examples/test_unit/features/step_definitions/test_unit_steps.rb +23 -0
  245. data/examples/test_unit/features/test_unit.feature +9 -0
  246. data/examples/v8/Rakefile +6 -0
  247. data/examples/v8/features/fibonacci.feature +43 -0
  248. data/examples/v8/features/step_definitions/fib_steps.js +49 -0
  249. data/examples/v8/features/support/env.js +14 -0
  250. data/examples/v8/lib/fibonacci.js +19 -0
  251. data/examples/watir/.gitignore +2 -0
  252. data/examples/watir/README.textile +16 -0
  253. data/examples/watir/Rakefile +12 -0
  254. data/examples/watir/cucumber.yml +1 -0
  255. data/examples/watir/features/search.feature +12 -0
  256. data/examples/watir/features/step_definitions/search_steps.rb +26 -0
  257. data/examples/watir/features/support/env.rb +32 -0
  258. data/examples/watir/features/support/screenshots.rb +47 -0
  259. data/features/background.feature +498 -0
  260. data/features/custom_formatter.feature +41 -0
  261. data/features/execute_with_tag_filter.feature +63 -0
  262. data/features/hooks.feature +59 -0
  263. data/features/json_formatter.feature +249 -0
  264. data/features/stats_formatters.feature +70 -0
  265. data/features/step_definitions/cucumber_steps.rb +8 -0
  266. data/features/support/env.rb +31 -0
  267. data/features/tagged_hooks.feature +217 -0
  268. data/fixtures/json/features/background.feature +7 -0
  269. data/fixtures/json/features/embed.feature +4 -0
  270. data/fixtures/json/features/one_passing_one_failing.feature +11 -0
  271. data/fixtures/json/features/step_definitions/steps.rb +32 -0
  272. data/fixtures/json/features/tables.feature +13 -0
  273. data/fixtures/junit/features/one_passing_one_failing.feature +8 -0
  274. data/fixtures/junit/features/pending.feature +5 -0
  275. data/fixtures/junit/features/step_definitions/steps.rb +11 -0
  276. data/fixtures/self_test/.gitignore +1 -0
  277. data/fixtures/self_test/README.textile +6 -0
  278. data/fixtures/self_test/Rakefile +6 -0
  279. data/fixtures/self_test/features/call_undefined_step_from_step_def.feature +7 -0
  280. data/fixtures/self_test/features/failing_expectation.feature +4 -0
  281. data/fixtures/self_test/features/lots_of_undefined.feature +8 -0
  282. data/fixtures/self_test/features/multiline_name.feature +27 -0
  283. data/fixtures/self_test/features/outline_sample.feature +15 -0
  284. data/fixtures/self_test/features/sample.feature +21 -0
  285. data/fixtures/self_test/features/search_sample.feature +32 -0
  286. data/fixtures/self_test/features/step_definitions/sample_steps.rb +84 -0
  287. data/fixtures/self_test/features/support/env.rb +18 -0
  288. data/fixtures/self_test/features/tags_sample.feature +17 -0
  289. data/fixtures/self_test/features/tons_of_cukes.feature +52 -0
  290. data/fixtures/self_test/features/undefined_multiline_args.feature +12 -0
  291. data/fixtures/self_test/list-of-features.txt +1 -0
  292. data/fixtures/steps_library/features/step_definitions/steps_lib1.rb +8 -0
  293. data/fixtures/steps_library/features/step_definitions/steps_lib2.rb +8 -0
  294. data/fixtures/tickets/Rakefile +20 -0
  295. data/fixtures/tickets/features.html +138 -0
  296. data/fixtures/tickets/features/172.feature +28 -0
  297. data/fixtures/tickets/features/177/1.feature +28 -0
  298. data/fixtures/tickets/features/177/2.feature +20 -0
  299. data/fixtures/tickets/features/177/3.feature +18 -0
  300. data/fixtures/tickets/features/180.feature +7 -0
  301. data/fixtures/tickets/features/229/tagged_hooks.feature +8 -0
  302. data/fixtures/tickets/features/229/tagged_hooks.rb +14 -0
  303. data/fixtures/tickets/features/236.feature +13 -0
  304. data/fixtures/tickets/features/241.feature +12 -0
  305. data/fixtures/tickets/features/246.feature +4 -0
  306. data/fixtures/tickets/features/248.feature +11 -0
  307. data/fixtures/tickets/features/270/back.feature +14 -0
  308. data/fixtures/tickets/features/270/back.steps.rb +14 -0
  309. data/fixtures/tickets/features/272/hooks.feature +26 -0
  310. data/fixtures/tickets/features/272/hooks_steps.rb +53 -0
  311. data/fixtures/tickets/features/279/py_string_indent.feature +25 -0
  312. data/fixtures/tickets/features/279/py_string_indent.steps.rb +12 -0
  313. data/fixtures/tickets/features/279/wrong.feature_ +11 -0
  314. data/fixtures/tickets/features/301/filter_background_tagged_hooks.feature +6 -0
  315. data/fixtures/tickets/features/301/filter_background_tagged_hooks_steps.rb +12 -0
  316. data/fixtures/tickets/features/306/only_background.feature +4 -0
  317. data/fixtures/tickets/features/around_timeout.feature +6 -0
  318. data/fixtures/tickets/features/gherkin_67.feature +12 -0
  319. data/fixtures/tickets/features/gherkin_68.feature +4 -0
  320. data/fixtures/tickets/features/half_manual.feature +11 -0
  321. data/fixtures/tickets/features/lib/eatting_machine.rb +18 -0
  322. data/fixtures/tickets/features/lib/pantry.rb +20 -0
  323. data/fixtures/tickets/features/scenario_outline.feature +95 -0
  324. data/fixtures/tickets/features/step_definitons/246_steps.rb +3 -0
  325. data/fixtures/tickets/features/step_definitons/248_steps.rb +15 -0
  326. data/fixtures/tickets/features/step_definitons/around_timeout_steps.rb +9 -0
  327. data/fixtures/tickets/features/step_definitons/half_manual_steps.rb +11 -0
  328. data/fixtures/tickets/features/step_definitons/scenario_outline_steps.rb +42 -0
  329. data/fixtures/tickets/features/step_definitons/tickets_steps.rb +88 -0
  330. data/fixtures/tickets/features/table_diffing.feature +13 -0
  331. data/fixtures/tickets/features/tickets.feature +28 -0
  332. data/gem_tasks/contributors.rake +15 -0
  333. data/gem_tasks/cucumber.rake +19 -0
  334. data/gem_tasks/environment.rake +7 -0
  335. data/gem_tasks/examples.rake +11 -0
  336. data/gem_tasks/fix_cr_lf.rake +10 -0
  337. data/gem_tasks/flog.rake +4 -0
  338. data/gem_tasks/rspec.rake +8 -0
  339. data/gem_tasks/sass.rake +4 -0
  340. data/gem_tasks/sdoc.rake +12 -0
  341. data/legacy_features/announce.feature +164 -0
  342. data/legacy_features/api/list_step_defs_as_json.feature +50 -0
  343. data/legacy_features/api/run_cli_main_with_existing_runtime.feature +34 -0
  344. data/legacy_features/around_hooks.feature +232 -0
  345. data/legacy_features/bug_371.feature +32 -0
  346. data/legacy_features/bug_464.feature +16 -0
  347. data/legacy_features/bug_475.feature +42 -0
  348. data/legacy_features/bug_585_tab_indentation.feature +22 -0
  349. data/legacy_features/bug_600.feature +67 -0
  350. data/legacy_features/call_steps_from_stepdefs.feature +154 -0
  351. data/legacy_features/cucumber_cli.feature +591 -0
  352. data/legacy_features/cucumber_cli_outlines.feature +117 -0
  353. data/legacy_features/default_snippets.feature +42 -0
  354. data/legacy_features/diffing.feature +25 -0
  355. data/legacy_features/drb_server_integration.feature +174 -0
  356. data/legacy_features/exception_in_after_block.feature +127 -0
  357. data/legacy_features/exception_in_after_step_block.feature +104 -0
  358. data/legacy_features/exception_in_before_block.feature +98 -0
  359. data/legacy_features/exclude_files.feature +20 -0
  360. data/legacy_features/expand.feature +60 -0
  361. data/legacy_features/html_formatter.feature +8 -0
  362. data/legacy_features/html_formatter/a.html +550 -0
  363. data/legacy_features/junit_formatter.feature +92 -0
  364. data/legacy_features/language_from_header.feature +30 -0
  365. data/legacy_features/language_help.feature +78 -0
  366. data/legacy_features/listener_debugger_formatter.feature +42 -0
  367. data/legacy_features/multiline_names.feature +44 -0
  368. data/legacy_features/post_configuration_hook.feature +50 -0
  369. data/legacy_features/profiles.feature +126 -0
  370. data/legacy_features/rake_task.feature +152 -0
  371. data/legacy_features/report_called_undefined_steps.feature +34 -0
  372. data/legacy_features/rerun_formatter.feature +45 -0
  373. data/legacy_features/simplest.feature +11 -0
  374. data/legacy_features/snippet.feature +23 -0
  375. data/legacy_features/snippets_when_using_star_keyword.feature +36 -0
  376. data/legacy_features/step_definitions/cucumber_steps.rb +168 -0
  377. data/legacy_features/step_definitions/extra_steps.rb +2 -0
  378. data/legacy_features/step_definitions/simplest_steps.rb +3 -0
  379. data/legacy_features/step_definitions/wire_steps.rb +34 -0
  380. data/legacy_features/support/env.rb +157 -0
  381. data/legacy_features/support/env.rb.simplest +7 -0
  382. data/legacy_features/support/fake_wire_server.rb +77 -0
  383. data/legacy_features/table_diffing.feature +45 -0
  384. data/legacy_features/table_mapping.feature +34 -0
  385. data/legacy_features/transform.feature +245 -0
  386. data/legacy_features/unicode_table.feature +35 -0
  387. data/legacy_features/wire_protocol.feature +332 -0
  388. data/legacy_features/wire_protocol_table_diffing.feature +119 -0
  389. data/legacy_features/wire_protocol_tags.feature +87 -0
  390. data/legacy_features/wire_protocol_timeouts.feature +63 -0
  391. data/legacy_features/work_in_progress.feature +156 -0
  392. data/lib/README.rdoc +12 -0
  393. data/lib/autotest/cucumber.rb +6 -0
  394. data/lib/autotest/cucumber_mixin.rb +135 -0
  395. data/lib/autotest/cucumber_rails.rb +6 -0
  396. data/lib/autotest/cucumber_rails_rspec.rb +6 -0
  397. data/lib/autotest/cucumber_rails_rspec2.rb +6 -0
  398. data/lib/autotest/cucumber_rspec.rb +6 -0
  399. data/lib/autotest/cucumber_rspec2.rb +6 -0
  400. data/lib/autotest/discover.rb +9 -0
  401. data/lib/cucumber.rb +27 -0
  402. data/lib/cucumber/ast.rb +30 -0
  403. data/lib/cucumber/ast/background.rb +99 -0
  404. data/lib/cucumber/ast/comment.rb +31 -0
  405. data/lib/cucumber/ast/examples.rb +43 -0
  406. data/lib/cucumber/ast/feature.rb +103 -0
  407. data/lib/cucumber/ast/feature_element.rb +78 -0
  408. data/lib/cucumber/ast/features.rb +35 -0
  409. data/lib/cucumber/ast/outline_table.rb +187 -0
  410. data/lib/cucumber/ast/py_string.rb +80 -0
  411. data/lib/cucumber/ast/scenario.rb +117 -0
  412. data/lib/cucumber/ast/scenario_outline.rb +122 -0
  413. data/lib/cucumber/ast/step.rb +126 -0
  414. data/lib/cucumber/ast/step_collection.rb +76 -0
  415. data/lib/cucumber/ast/step_invocation.rb +199 -0
  416. data/lib/cucumber/ast/table.rb +689 -0
  417. data/lib/cucumber/ast/tags.rb +28 -0
  418. data/lib/cucumber/ast/tree_walker.rb +184 -0
  419. data/lib/cucumber/ast/visitor.rb +11 -0
  420. data/lib/cucumber/broadcaster.rb +13 -0
  421. data/lib/cucumber/cli/configuration.rb +209 -0
  422. data/lib/cucumber/cli/drb_client.rb +43 -0
  423. data/lib/cucumber/cli/main.rb +78 -0
  424. data/lib/cucumber/cli/options.rb +406 -0
  425. data/lib/cucumber/cli/profile_loader.rb +91 -0
  426. data/lib/cucumber/configuration.rb +49 -0
  427. data/lib/cucumber/constantize.rb +34 -0
  428. data/lib/cucumber/core_ext/disable_mini_unit_autorun.rb +14 -0
  429. data/lib/cucumber/core_ext/instance_exec.rb +98 -0
  430. data/lib/cucumber/core_ext/proc.rb +34 -0
  431. data/lib/cucumber/core_ext/string.rb +9 -0
  432. data/lib/cucumber/errors.rb +40 -0
  433. data/lib/cucumber/feature_file.rb +62 -0
  434. data/lib/cucumber/formatter/ansicolor.rb +160 -0
  435. data/lib/cucumber/formatter/console.rb +177 -0
  436. data/lib/cucumber/formatter/cucumber.css +275 -0
  437. data/lib/cucumber/formatter/cucumber.sass +271 -0
  438. data/lib/cucumber/formatter/debug.rb +33 -0
  439. data/lib/cucumber/formatter/duration.rb +13 -0
  440. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +84 -0
  441. data/lib/cucumber/formatter/gpretty.rb +24 -0
  442. data/lib/cucumber/formatter/html.rb +644 -0
  443. data/lib/cucumber/formatter/io.rb +31 -0
  444. data/lib/cucumber/formatter/jquery-min.js +154 -0
  445. data/lib/cucumber/formatter/json.rb +29 -0
  446. data/lib/cucumber/formatter/json_pretty.rb +13 -0
  447. data/lib/cucumber/formatter/junit.rb +150 -0
  448. data/lib/cucumber/formatter/ordered_xml_markup.rb +24 -0
  449. data/lib/cucumber/formatter/pdf.rb +244 -0
  450. data/lib/cucumber/formatter/pretty.rb +237 -0
  451. data/lib/cucumber/formatter/progress.rb +92 -0
  452. data/lib/cucumber/formatter/rerun.rb +55 -0
  453. data/lib/cucumber/formatter/stepdefs.rb +14 -0
  454. data/lib/cucumber/formatter/steps.rb +49 -0
  455. data/lib/cucumber/formatter/summary.rb +35 -0
  456. data/lib/cucumber/formatter/unicode.rb +79 -0
  457. data/lib/cucumber/formatter/usage.rb +127 -0
  458. data/lib/cucumber/js_support/js_dsl.js +57 -0
  459. data/lib/cucumber/js_support/js_language.rb +185 -0
  460. data/lib/cucumber/js_support/js_snippets.rb +27 -0
  461. data/lib/cucumber/language_support.rb +30 -0
  462. data/lib/cucumber/language_support/language_methods.rb +129 -0
  463. data/lib/cucumber/parser.rb +2 -0
  464. data/lib/cucumber/parser/gherkin_builder.rb +130 -0
  465. data/lib/cucumber/platform.rb +29 -0
  466. data/lib/cucumber/py_support/py_dsl.py +10 -0
  467. data/lib/cucumber/py_support/py_language.py +10 -0
  468. data/lib/cucumber/py_support/py_language.rb +84 -0
  469. data/lib/cucumber/rake/task.rb +170 -0
  470. data/lib/cucumber/rb_support/rb_dsl.rb +112 -0
  471. data/lib/cucumber/rb_support/rb_hook.rb +18 -0
  472. data/lib/cucumber/rb_support/rb_language.rb +195 -0
  473. data/lib/cucumber/rb_support/rb_step_definition.rb +82 -0
  474. data/lib/cucumber/rb_support/rb_transform.rb +37 -0
  475. data/lib/cucumber/rb_support/rb_world.rb +95 -0
  476. data/lib/cucumber/rb_support/regexp_argument_matcher.rb +21 -0
  477. data/lib/cucumber/rspec/disable_option_parser.rb +23 -0
  478. data/lib/cucumber/rspec/doubles.rb +16 -0
  479. data/lib/cucumber/runtime.rb +145 -0
  480. data/lib/cucumber/runtime/features_loader.rb +62 -0
  481. data/lib/cucumber/runtime/for_programming_languages.rb +65 -0
  482. data/lib/cucumber/runtime/results.rb +64 -0
  483. data/lib/cucumber/runtime/support_code.rb +203 -0
  484. data/lib/cucumber/runtime/user_interface.rb +80 -0
  485. data/lib/cucumber/step_argument.rb +9 -0
  486. data/lib/cucumber/step_definition_light.rb +20 -0
  487. data/lib/cucumber/step_definitions.rb +14 -0
  488. data/lib/cucumber/step_match.rb +115 -0
  489. data/lib/cucumber/step_mother.rb +10 -0
  490. data/lib/cucumber/wire_support/configuration.rb +30 -0
  491. data/lib/cucumber/wire_support/connection.rb +55 -0
  492. data/lib/cucumber/wire_support/request_handler.rb +32 -0
  493. data/lib/cucumber/wire_support/wire_exception.rb +32 -0
  494. data/lib/cucumber/wire_support/wire_language.rb +54 -0
  495. data/lib/cucumber/wire_support/wire_packet.rb +32 -0
  496. data/lib/cucumber/wire_support/wire_protocol.rb +44 -0
  497. data/lib/cucumber/wire_support/wire_protocol/requests.rb +123 -0
  498. data/lib/cucumber/wire_support/wire_step_definition.rb +26 -0
  499. data/spec/cucumber/ast/background_spec.rb +110 -0
  500. data/spec/cucumber/ast/feature_factory.rb +60 -0
  501. data/spec/cucumber/ast/feature_spec.rb +63 -0
  502. data/spec/cucumber/ast/outline_table_spec.rb +21 -0
  503. data/spec/cucumber/ast/py_string_spec.rb +40 -0
  504. data/spec/cucumber/ast/scenario_outline_spec.rb +68 -0
  505. data/spec/cucumber/ast/scenario_spec.rb +43 -0
  506. data/spec/cucumber/ast/step_spec.rb +66 -0
  507. data/spec/cucumber/ast/table_spec.rb +474 -0
  508. data/spec/cucumber/ast/tree_walker_spec.rb +11 -0
  509. data/spec/cucumber/broadcaster_spec.rb +15 -0
  510. data/spec/cucumber/cli/configuration_spec.rb +431 -0
  511. data/spec/cucumber/cli/drb_client_spec.rb +77 -0
  512. data/spec/cucumber/cli/main_spec.rb +137 -0
  513. data/spec/cucumber/cli/options_spec.rb +351 -0
  514. data/spec/cucumber/cli/profile_loader_spec.rb +35 -0
  515. data/spec/cucumber/configuration_spec.rb +23 -0
  516. data/spec/cucumber/core_ext/proc_spec.rb +68 -0
  517. data/spec/cucumber/formatter/ansicolor_spec.rb +31 -0
  518. data/spec/cucumber/formatter/duration_spec.rb +22 -0
  519. data/spec/cucumber/formatter/html_spec.rb +258 -0
  520. data/spec/cucumber/formatter/junit_spec.rb +111 -0
  521. data/spec/cucumber/formatter/progress_spec.rb +38 -0
  522. data/spec/cucumber/formatter/spec_helper.rb +51 -0
  523. data/spec/cucumber/rb_support/rb_language_spec.rb +283 -0
  524. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +99 -0
  525. data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +18 -0
  526. data/spec/cucumber/runtime/support_code_spec.rb +112 -0
  527. data/spec/cucumber/runtime_spec.rb +41 -0
  528. data/spec/cucumber/sell_cucumbers.feature +19 -0
  529. data/spec/cucumber/step_match_spec.rb +69 -0
  530. data/spec/cucumber/wire_support/configuration_spec.rb +51 -0
  531. data/spec/cucumber/wire_support/connection_spec.rb +46 -0
  532. data/spec/cucumber/wire_support/wire_exception_spec.rb +44 -0
  533. data/spec/cucumber/wire_support/wire_language_spec.rb +47 -0
  534. data/spec/cucumber/wire_support/wire_packet_spec.rb +40 -0
  535. data/spec/cucumber/wire_support/wire_step_definition_spec.rb +20 -0
  536. data/spec/cucumber/world/pending_spec.rb +46 -0
  537. data/spec/spec_helper.rb +10 -0
  538. metadata +884 -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,199 @@
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
+ BACKTRACE_FILTER_PATTERNS = [
12
+ /vendor\/rails|lib\/cucumber|bin\/cucumber:|lib\/rspec|gems\//
13
+ ]
14
+
15
+ attr_writer :step_collection, :background
16
+ attr_reader :name, :matched_cells, :status, :reported_exception
17
+ attr_accessor :exception
18
+
19
+ class << self
20
+ SEVERITY = [:passed, :undefined, :pending, :skipped, :failed]
21
+ def worst_status(statuses)
22
+ SEVERITY[statuses.map{|status| SEVERITY.index(status)}.max]
23
+ end
24
+ end
25
+
26
+ def initialize(step, name, multiline_arg, matched_cells)
27
+ @step, @name, @multiline_arg, @matched_cells = step, name, multiline_arg, matched_cells
28
+ status!(:skipped)
29
+ @skip_invoke = @exception = @step_match = @different_table = @reported_exception = @background = nil
30
+ end
31
+
32
+ def background?
33
+ @background
34
+ end
35
+
36
+ def skip_invoke!
37
+ @skip_invoke = true
38
+ end
39
+
40
+ def accept(visitor)
41
+ return if Cucumber.wants_to_quit
42
+ invoke(visitor.step_mother, visitor.configuration)
43
+ visit_step_result(visitor)
44
+ end
45
+
46
+ def visit_step_result(visitor)
47
+ visitor.visit_step_result(
48
+ keyword,
49
+ @step_match,
50
+ (@different_table || @multiline_arg),
51
+ @status,
52
+ @reported_exception,
53
+ source_indent,
54
+ @background
55
+ )
56
+ end
57
+
58
+ def invoke(step_mother, configuration)
59
+ find_step_match!(step_mother, configuration)
60
+ unless @skip_invoke || configuration.dry_run? || @exception || @step_collection.exception
61
+ @skip_invoke = true
62
+ begin
63
+ @step_match.invoke(@multiline_arg)
64
+ step_mother.after_step
65
+ status!(:passed)
66
+ rescue Pending => e
67
+ failed(configuration, e, false)
68
+ status!(:pending)
69
+ rescue Undefined => e
70
+ failed(configuration, e, false)
71
+ status!(:undefined)
72
+ rescue Cucumber::Ast::Table::Different => e
73
+ @different_table = e.table
74
+ failed(configuration, e, false)
75
+ status!(:failed)
76
+ rescue Exception => e
77
+ failed(configuration, e, false)
78
+ status!(:failed)
79
+ end
80
+ end
81
+ end
82
+
83
+ def find_step_match!(step_mother, configuration)
84
+ return if @step_match
85
+ begin
86
+ @step_match = step_mother.step_match(@name)
87
+ rescue Undefined => e
88
+ failed(configuration, e, true)
89
+ status!(:undefined)
90
+ @step_match = NoStepMatch.new(@step, @name)
91
+ rescue Ambiguous => e
92
+ failed(configuration, e, false)
93
+ status!(:failed)
94
+ @step_match = NoStepMatch.new(@step, @name)
95
+ end
96
+ step_mother.step_visited(self)
97
+ end
98
+
99
+ def failed(configuration, e, clear_backtrace)
100
+ e = filter_backtrace(e)
101
+ e.set_backtrace([]) if clear_backtrace
102
+ e.backtrace << @step.backtrace_line unless @step.backtrace_line.nil?
103
+ @exception = e
104
+ if(configuration.strict? || !(Undefined === e) || e.nested?)
105
+ @reported_exception = e
106
+ else
107
+ @reported_exception = nil
108
+ end
109
+ end
110
+
111
+ PWD_PATTERN = /#{Regexp.escape(Dir.pwd)}\//m
112
+
113
+ def filter_backtrace(e)
114
+ return e if Cucumber.use_full_backtrace
115
+ (e.backtrace || []).each{|line| line.gsub!(PWD_PATTERN, "./")}
116
+
117
+ filtered = (e.backtrace || []).reject do |line|
118
+ BACKTRACE_FILTER_PATTERNS.detect { |p| line =~ p }
119
+ end
120
+
121
+ if Cucumber::JRUBY && e.class.name == 'NativeException'
122
+ # JRuby's NativeException ignores #set_backtrace.
123
+ # We're fixing it.
124
+ e.instance_eval do
125
+ def set_backtrace(backtrace)
126
+ @backtrace = backtrace
127
+ end
128
+
129
+ def backtrace
130
+ @backtrace
131
+ end
132
+ end
133
+ end
134
+ e.set_backtrace(filtered)
135
+ e
136
+ end
137
+
138
+ def status!(status)
139
+ @status = status
140
+ @matched_cells.each do |cell|
141
+ cell.status = status
142
+ end
143
+ end
144
+
145
+ def previous
146
+ @step_collection.previous_step(self)
147
+ end
148
+
149
+ def actual_keyword
150
+ repeat_keywords = rubify([language.keywords('but'), language.keywords('and')]).flatten.uniq.reject{|kw| kw == '* '}
151
+ if repeat_keywords.index(@step.keyword) && previous
152
+ previous.actual_keyword
153
+ else
154
+ keyword == '* ' ? language.code_keywords.first : keyword
155
+ end
156
+ end
157
+
158
+ def source_indent
159
+ @step.feature_element.source_indent(text_length)
160
+ end
161
+
162
+ def text_length
163
+ @step.text_length(@name)
164
+ end
165
+
166
+ def keyword
167
+ @step.keyword
168
+ end
169
+
170
+ def multiline_arg
171
+ @step.multiline_arg
172
+ end
173
+
174
+ def file_colon_line
175
+ @step.file_colon_line
176
+ end
177
+
178
+ def dom_id
179
+ @step.dom_id
180
+ end
181
+
182
+ def backtrace_line
183
+ @step.backtrace_line
184
+ end
185
+
186
+ def language
187
+ @step.language
188
+ end
189
+
190
+ def gherkin_statement
191
+ @step.gherkin_statement
192
+ end
193
+
194
+ def to_sexp
195
+ [:step_invocation, @step.line, @step.keyword, @name, (@multiline_arg.nil? ? nil : @multiline_arg.to_sexp)].compact
196
+ end
197
+ end
198
+ end
199
+ 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
+
78
+ raw = ensure_array_of_array(rubify(raw))
79
+ # Verify that it's square
80
+ transposed = raw.transpose
81
+ create_cell_matrix(raw)
82
+ @conversion_procs = conversion_procs
83
+ end
84
+
85
+ def to_step_definition_arg
86
+ dup
87
+ end
88
+
89
+ # Creates a copy of this table, inheriting any column mappings.
90
+ # registered with #map_headers!
91
+ #
92
+ def dup
93
+ self.class.new(raw.dup, @conversion_procs.dup)
94
+ end
95
+
96
+ # Returns a new, transposed table. Example:
97
+ #
98
+ # | a | 7 | 4 |
99
+ # | b | 9 | 2 |
100
+ #
101
+ # Gets converted into the following:
102
+ #
103
+ # | a | b |
104
+ # | 7 | 9 |
105
+ # | 4 | 2 |
106
+ #
107
+ def transpose
108
+ self.class.new(raw.transpose, @conversion_procs.dup)
109
+ end
110
+
111
+ # Converts this table into an Array of Hash where the keys of each
112
+ # Hash are the headers in the table. For example, a Table built from
113
+ # the following plain text:
114
+ #
115
+ # | a | b | sum |
116
+ # | 2 | 3 | 5 |
117
+ # | 7 | 9 | 16 |
118
+ #
119
+ # Gets converted into the following:
120
+ #
121
+ # [{'a' => '2', 'b' => '3', 'sum' => '5'}, {'a' => '7', 'b' => '9', 'sum' => '16'}]
122
+ #
123
+ # Use #map_column! to specify how values in a column are converted.
124
+ #
125
+ def hashes
126
+ @hashes ||= cells_rows[1..-1].map do |row|
127
+ row.to_hash
128
+ end
129
+ end
130
+
131
+ # Converts this table into a Hash where the first column is
132
+ # used as keys and the second column is used as values
133
+ #
134
+ # | a | 2 |
135
+ # | b | 3 |
136
+ #
137
+ # Gets converted into the following:
138
+ #
139
+ # {'a' => '2', 'b' => '3'}
140
+ #
141
+ # The table must be exactly two columns wide
142
+ #
143
+ def rows_hash
144
+ return @rows_hash if @rows_hash
145
+ verify_table_width(2)
146
+ @rows_hash = self.transpose.hashes[0]
147
+ end
148
+
149
+ # Gets the raw data of this table. For example, a Table built from
150
+ # the following plain text:
151
+ #
152
+ # | a | b |
153
+ # | c | d |
154
+ #
155
+ # gets converted into the following:
156
+ #
157
+ # [['a', 'b'], ['c', 'd']]
158
+ #
159
+ def raw
160
+ cell_matrix.map do |row|
161
+ row.map do |cell|
162
+ cell.value
163
+ end
164
+ end
165
+ end
166
+
167
+ def column_names #:nodoc:
168
+ @col_names ||= cell_matrix[0].map { |cell| cell.value }
169
+ end
170
+
171
+ # Same as #raw, but skips the first (header) row
172
+ def rows
173
+ raw[1..-1]
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