dwaite-cucumber 0.3.101

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 (454) hide show
  1. data/History.txt +1067 -0
  2. data/License.txt +22 -0
  3. data/Manifest.txt +453 -0
  4. data/README.txt +4 -0
  5. data/Rakefile +9 -0
  6. data/bin/cucumber +17 -0
  7. data/config/hoe.rb +78 -0
  8. data/config/requirements.rb +15 -0
  9. data/cucumber.yml +2 -0
  10. data/examples/cs/README.textile +1 -0
  11. data/examples/cs/Rakefile +12 -0
  12. data/examples/cs/compile.bat +1 -0
  13. data/examples/cs/features/addition.feature +16 -0
  14. data/examples/cs/features/step_definitons/calculator_steps.rb +19 -0
  15. data/examples/cs/src/demo/Calculator.cs +20 -0
  16. data/examples/dos_line_endings/Rakefile +6 -0
  17. data/examples/dos_line_endings/features/dos_line_endings.feature +9 -0
  18. data/examples/i18n/README.textile +18 -0
  19. data/examples/i18n/Rakefile +32 -0
  20. data/examples/i18n/ar/Rakefile +6 -0
  21. data/examples/i18n/ar/features/addition.feature +17 -0
  22. data/examples/i18n/ar/features/step_definitons/calculator_steps.rb +24 -0
  23. data/examples/i18n/ar/lib/calculator.rb +11 -0
  24. data/examples/i18n/bg/Rakefile +6 -0
  25. data/examples/i18n/bg/features/addition.feature +12 -0
  26. data/examples/i18n/bg/features/consecutive_calculations.feature +19 -0
  27. data/examples/i18n/bg/features/division.feature +17 -0
  28. data/examples/i18n/bg/features/step_definitons/calculator_steps.rb +24 -0
  29. data/examples/i18n/bg/features/support/env.rb +6 -0
  30. data/examples/i18n/bg/features/support/world.rb +8 -0
  31. data/examples/i18n/bg/lib/calculator.rb +24 -0
  32. data/examples/i18n/cat/Rakefile +6 -0
  33. data/examples/i18n/cat/features/step_definitons/calculator_steps.rb +21 -0
  34. data/examples/i18n/cat/features/suma.feature +17 -0
  35. data/examples/i18n/cat/lib/calculadora.rb +16 -0
  36. data/examples/i18n/da/Rakefile +6 -0
  37. data/examples/i18n/da/features/step_definitons/kalkulator_steps.rb +24 -0
  38. data/examples/i18n/da/features/summering.feature +18 -0
  39. data/examples/i18n/da/lib/kalkulator.rb +11 -0
  40. data/examples/i18n/de/Rakefile +6 -0
  41. data/examples/i18n/de/features/addition.feature +17 -0
  42. data/examples/i18n/de/features/division.feature +10 -0
  43. data/examples/i18n/de/features/step_definitons/calculator_steps.rb +24 -0
  44. data/examples/i18n/de/lib/calculator.rb +14 -0
  45. data/examples/i18n/en/Rakefile +6 -0
  46. data/examples/i18n/en/features/addition.feature +17 -0
  47. data/examples/i18n/en/features/division.feature +10 -0
  48. data/examples/i18n/en/features/step_definitons/calculator_steps.rb +24 -0
  49. data/examples/i18n/en/lib/calculator.rb +14 -0
  50. data/examples/i18n/en-lol/Rakefile +6 -0
  51. data/examples/i18n/en-lol/features/step_definitions/cucumbrz_steps.rb +16 -0
  52. data/examples/i18n/en-lol/features/stuffing.feature +8 -0
  53. data/examples/i18n/en-lol/features/support/env.rb +8 -0
  54. data/examples/i18n/en-lol/lib/basket.rb +12 -0
  55. data/examples/i18n/en-lol/lib/belly.rb +11 -0
  56. data/examples/i18n/es/Rakefile +6 -0
  57. data/examples/i18n/es/features/adicion.feature +17 -0
  58. data/examples/i18n/es/features/step_definitons/calculador_steps.rb +21 -0
  59. data/examples/i18n/es/lib/calculador.rb +14 -0
  60. data/examples/i18n/et/Rakefile +6 -0
  61. data/examples/i18n/et/features/jagamine.feature +10 -0
  62. data/examples/i18n/et/features/liitmine.feature +17 -0
  63. data/examples/i18n/et/features/step_definitions/kalkulaator_steps.rb +24 -0
  64. data/examples/i18n/et/lib/kalkulaator.rb +14 -0
  65. data/examples/i18n/fi/Rakefile +6 -0
  66. data/examples/i18n/fi/features/jakolasku.feature +10 -0
  67. data/examples/i18n/fi/features/step_definitons/laskin_steps.rb +24 -0
  68. data/examples/i18n/fi/features/yhteenlasku.feature +17 -0
  69. data/examples/i18n/fi/lib/laskin.rb +14 -0
  70. data/examples/i18n/fr/Rakefile +6 -0
  71. data/examples/i18n/fr/features/addition.feature +18 -0
  72. data/examples/i18n/fr/features/step_definitions/calculatrice_steps.rb +25 -0
  73. data/examples/i18n/fr/lib/calculatrice.rb +10 -0
  74. data/examples/i18n/he/Rakefile +6 -0
  75. data/examples/i18n/he/features/addition.feature +17 -0
  76. data/examples/i18n/he/features/division.feature +10 -0
  77. data/examples/i18n/he/features/step_definitons/calculator_steps.rb +24 -0
  78. data/examples/i18n/he/lib/calculator.rb +14 -0
  79. data/examples/i18n/hu/Rakefile +6 -0
  80. data/examples/i18n/hu/features/addition.feature +17 -0
  81. data/examples/i18n/hu/features/division.feature +10 -0
  82. data/examples/i18n/hu/features/step_definitons/calculator_steps.rb +25 -0
  83. data/examples/i18n/hu/lib/calculator.rb +14 -0
  84. data/examples/i18n/id/Rakefile +6 -0
  85. data/examples/i18n/id/features/addition.feature +17 -0
  86. data/examples/i18n/id/features/division.feature +10 -0
  87. data/examples/i18n/id/features/step_definitons/calculator_steps.rb +24 -0
  88. data/examples/i18n/id/lib/calculator.rb +14 -0
  89. data/examples/i18n/it/Rakefile +6 -0
  90. data/examples/i18n/it/features/somma.feature +11 -0
  91. data/examples/i18n/it/features/step_definitons/calcolatrice_steps.rb +24 -0
  92. data/examples/i18n/it/lib/calcolatrice.rb +11 -0
  93. data/examples/i18n/ja/Rakefile +6 -0
  94. data/examples/i18n/ja/features/addition.feature +17 -0
  95. data/examples/i18n/ja/features/division.feature +10 -0
  96. data/examples/i18n/ja/features/step_definitons/calculator_steps.rb +24 -0
  97. data/examples/i18n/ja/lib/calculator.rb +14 -0
  98. data/examples/i18n/ko/Rakefile +6 -0
  99. data/examples/i18n/ko/features/addition.feature +17 -0
  100. data/examples/i18n/ko/features/division.feature +11 -0
  101. data/examples/i18n/ko/features/step_definitons/calculator_steps.rb +24 -0
  102. data/examples/i18n/ko/lib/calculator.rb +14 -0
  103. data/examples/i18n/lt/Rakefile +6 -0
  104. data/examples/i18n/lt/features/addition.feature +17 -0
  105. data/examples/i18n/lt/features/division.feature +10 -0
  106. data/examples/i18n/lt/features/step_definitons/calculator_steps.rb +24 -0
  107. data/examples/i18n/lt/lib/calculator.rb +14 -0
  108. data/examples/i18n/lv/Rakefile +6 -0
  109. data/examples/i18n/lv/features/addition.feature +17 -0
  110. data/examples/i18n/lv/features/division.feature +10 -0
  111. data/examples/i18n/lv/features/step_definitons/calculator_steps.rb +24 -0
  112. data/examples/i18n/lv/lib/calculator.rb +14 -0
  113. data/examples/i18n/no/Rakefile +6 -0
  114. data/examples/i18n/no/features/step_definitons/kalkulator_steps.rb +17 -0
  115. data/examples/i18n/no/features/summering.feature +19 -0
  116. data/examples/i18n/no/features/support/env.rb +6 -0
  117. data/examples/i18n/no/lib/kalkulator.rb +11 -0
  118. data/examples/i18n/pl/Rakefile +6 -0
  119. data/examples/i18n/pl/features/addition.feature +17 -0
  120. data/examples/i18n/pl/features/division.feature +10 -0
  121. data/examples/i18n/pl/features/step_definitons/calculator_steps.rb +24 -0
  122. data/examples/i18n/pl/features/support/env.rb +6 -0
  123. data/examples/i18n/pl/lib/calculator.rb +14 -0
  124. data/examples/i18n/pt/Rakefile +6 -0
  125. data/examples/i18n/pt/features/adicao.feature +11 -0
  126. data/examples/i18n/pt/features/step_definitions/calculadora_steps.rb +20 -0
  127. data/examples/i18n/pt/features/support/env.rb +6 -0
  128. data/examples/i18n/pt/lib/calculadora.rb +10 -0
  129. data/examples/i18n/ro/Rakefile +6 -0
  130. data/examples/i18n/ro/features/step_definitons/calculator_steps.rb +24 -0
  131. data/examples/i18n/ro/features/suma.feature +11 -0
  132. data/examples/i18n/ro/lib/calculator.rb +11 -0
  133. data/examples/i18n/ru/Rakefile +6 -0
  134. data/examples/i18n/ru/features/addition.feature +11 -0
  135. data/examples/i18n/ru/features/consecutive_calculations.feature +17 -0
  136. data/examples/i18n/ru/features/division.feature +16 -0
  137. data/examples/i18n/ru/features/step_definitons/calculator_steps.rb +19 -0
  138. data/examples/i18n/ru/features/support/env.rb +6 -0
  139. data/examples/i18n/ru/features/support/world.rb +8 -0
  140. data/examples/i18n/ru/lib/calculator.rb +24 -0
  141. data/examples/i18n/se/Rakefile +6 -0
  142. data/examples/i18n/se/features/step_definitons/kalkulator_steps.rb +24 -0
  143. data/examples/i18n/se/features/summering.feature +18 -0
  144. data/examples/i18n/se/lib/kalkulator.rb +11 -0
  145. data/examples/i18n/sk/Rakefile +6 -0
  146. data/examples/i18n/sk/features/addition.feature +17 -0
  147. data/examples/i18n/sk/features/division.feature +10 -0
  148. data/examples/i18n/sk/features/step_definitons/calculator_steps.rb +24 -0
  149. data/examples/i18n/sk/lib/calculator.rb +14 -0
  150. data/examples/i18n/uz/Rakefile +6 -0
  151. data/examples/i18n/uz/features/addition.feature +10 -0
  152. data/examples/i18n/uz/features/consecutive_calculations.feature +17 -0
  153. data/examples/i18n/uz/features/division.feature +17 -0
  154. data/examples/i18n/uz/features/step_definitons/calculator_steps.rb +19 -0
  155. data/examples/i18n/uz/features/support/env.rb +6 -0
  156. data/examples/i18n/uz/features/support/world.rb +8 -0
  157. data/examples/i18n/uz/lib/calculator.rb +24 -0
  158. data/examples/i18n/zh-CN/Rakefile +6 -0
  159. data/examples/i18n/zh-CN/features/addition.feature +18 -0
  160. data/examples/i18n/zh-CN/features/step_definitons/calculator_steps.rb +26 -0
  161. data/examples/i18n/zh-CN/lib/calculator.rb +10 -0
  162. data/examples/i18n/zh-TW/Rakefile +6 -0
  163. data/examples/i18n/zh-TW/features/addition.feature +17 -0
  164. data/examples/i18n/zh-TW/features/division.feature +11 -0
  165. data/examples/i18n/zh-TW/features/step_definitons/calculator_steps.rb +24 -0
  166. data/examples/i18n/zh-TW/lib/calculator.rb +14 -0
  167. data/examples/java/README.textile +18 -0
  168. data/examples/java/build.xml +33 -0
  169. data/examples/java/features/hello.feature +11 -0
  170. data/examples/java/features/step_definitons/hello_steps.rb +23 -0
  171. data/examples/java/features/step_definitons/tree_steps.rb +14 -0
  172. data/examples/java/features/tree.feature +9 -0
  173. data/examples/java/src/cucumber/demo/Hello.java +16 -0
  174. data/examples/junit/features/one_passing_one_failing.feature +8 -0
  175. data/examples/junit/features/pending.feature +5 -0
  176. data/examples/junit/features/step_definitions/steps.rb +11 -0
  177. data/examples/pure_java/README.textile +5 -0
  178. data/examples/python/features/fibonacci.feature +19 -0
  179. data/examples/python/features/step_definitions/fib_steps.py +3 -0
  180. data/examples/python/features/step_definitions/fib_steps.rb +7 -0
  181. data/examples/python/features/support/env.rb +21 -0
  182. data/examples/python/lib/fib.py +7 -0
  183. data/examples/selenium/Rakefile +6 -0
  184. data/examples/selenium/features/search.feature +9 -0
  185. data/examples/selenium/features/step_definitons/search_steps.rb +13 -0
  186. data/examples/selenium/features/support/env.rb +19 -0
  187. data/examples/selenium_webrat/Rakefile +6 -0
  188. data/examples/selenium_webrat/config.ru +0 -0
  189. data/examples/selenium_webrat/features/search.feature +9 -0
  190. data/examples/selenium_webrat/features/step_definitons/search_steps.rb +13 -0
  191. data/examples/selenium_webrat/features/support/env.rb +45 -0
  192. data/examples/self_test/README.textile +6 -0
  193. data/examples/self_test/Rakefile +6 -0
  194. data/examples/self_test/features/background/background_tagged_before_on_outline.feature +12 -0
  195. data/examples/self_test/features/background/background_with_name.feature +7 -0
  196. data/examples/self_test/features/background/failing_background.feature +12 -0
  197. data/examples/self_test/features/background/failing_background_after_success.feature +11 -0
  198. data/examples/self_test/features/background/multiline_args_background.feature +32 -0
  199. data/examples/self_test/features/background/passing_background.feature +10 -0
  200. data/examples/self_test/features/background/pending_background.feature +10 -0
  201. data/examples/self_test/features/background/scenario_outline_failing_background.feature +16 -0
  202. data/examples/self_test/features/background/scenario_outline_passing_background.feature +16 -0
  203. data/examples/self_test/features/call_undefined_step_from_step_def.feature +7 -0
  204. data/examples/self_test/features/failing_expectation.feature +4 -0
  205. data/examples/self_test/features/lots_of_undefined.feature +8 -0
  206. data/examples/self_test/features/multiline_name.feature +27 -0
  207. data/examples/self_test/features/outline_sample.feature +15 -0
  208. data/examples/self_test/features/sample.feature +21 -0
  209. data/examples/self_test/features/search_sample.feature +32 -0
  210. data/examples/self_test/features/step_definitions/sample_steps.rb +93 -0
  211. data/examples/self_test/features/support/env.rb +24 -0
  212. data/examples/self_test/features/tags_sample.feature +17 -0
  213. data/examples/self_test/features/tons_of_cukes.feature +52 -0
  214. data/examples/self_test/features/transform_sample.feature +10 -0
  215. data/examples/self_test/features/undefined_multiline_args.feature +12 -0
  216. data/examples/self_test/list-of-features.txt +1 -0
  217. data/examples/sinatra/README.textile +13 -0
  218. data/examples/sinatra/Rakefile +6 -0
  219. data/examples/sinatra/app.rb +14 -0
  220. data/examples/sinatra/features/add.feature +11 -0
  221. data/examples/sinatra/features/step_definitions/add_steps.rb +15 -0
  222. data/examples/sinatra/features/support/env.rb +32 -0
  223. data/examples/sinatra/views/add.erb +5 -0
  224. data/examples/sinatra/views/layout.erb +8 -0
  225. data/examples/steps_library/features/step_definitions/steps_lib1.rb +8 -0
  226. data/examples/steps_library/features/step_definitions/steps_lib2.rb +8 -0
  227. data/examples/test_unit/Rakefile +6 -0
  228. data/examples/test_unit/features/step_definitions/test_unit_steps.rb +23 -0
  229. data/examples/test_unit/features/test_unit.feature +9 -0
  230. data/examples/tickets/Rakefile +16 -0
  231. data/examples/tickets/features/172.feature +28 -0
  232. data/examples/tickets/features/177/1.feature +29 -0
  233. data/examples/tickets/features/177/2.feature +21 -0
  234. data/examples/tickets/features/177/3.feature +18 -0
  235. data/examples/tickets/features/180.feature +7 -0
  236. data/examples/tickets/features/229/tagged_hooks.feature +8 -0
  237. data/examples/tickets/features/229/tagged_hooks.rb +14 -0
  238. data/examples/tickets/features/236.feature +13 -0
  239. data/examples/tickets/features/241.feature +13 -0
  240. data/examples/tickets/features/246.feature +4 -0
  241. data/examples/tickets/features/248.feature +11 -0
  242. data/examples/tickets/features/270/back.feature +14 -0
  243. data/examples/tickets/features/270/back.steps.rb +14 -0
  244. data/examples/tickets/features/272/hooks.feature +26 -0
  245. data/examples/tickets/features/272/hooks_steps.rb +53 -0
  246. data/examples/tickets/features/279/py_string_indent.feature +25 -0
  247. data/examples/tickets/features/279/py_string_indent.steps.rb +12 -0
  248. data/examples/tickets/features/279/wrong.feature_ +11 -0
  249. data/examples/tickets/features/301/filter_background_tagged_hooks.feature +6 -0
  250. data/examples/tickets/features/301/filter_background_tagged_hooks_steps.rb +12 -0
  251. data/examples/tickets/features/306/only_background.feature +4 -0
  252. data/examples/tickets/features/lib/eatting_machine.rb +18 -0
  253. data/examples/tickets/features/lib/pantry.rb +20 -0
  254. data/examples/tickets/features/scenario_outline.feature +95 -0
  255. data/examples/tickets/features/step_definitons/246_steps.rb +3 -0
  256. data/examples/tickets/features/step_definitons/248_steps.rb +15 -0
  257. data/examples/tickets/features/step_definitons/scenario_outline_steps.rb +42 -0
  258. data/examples/tickets/features/step_definitons/tickets_steps.rb +81 -0
  259. data/examples/tickets/features/table_diffing.feature +13 -0
  260. data/examples/tickets/features/tickets.feature +28 -0
  261. data/examples/watir/README.textile +16 -0
  262. data/examples/watir/Rakefile +6 -0
  263. data/examples/watir/features/search.feature +12 -0
  264. data/examples/watir/features/step_definitons/search_steps.rb +26 -0
  265. data/examples/watir/features/support/env.rb +32 -0
  266. data/features/background.feature +311 -0
  267. data/features/bug_371.feature +32 -0
  268. data/features/cucumber_cli.feature +667 -0
  269. data/features/cucumber_cli_diff_disabled.feature +54 -0
  270. data/features/cucumber_cli_outlines.feature +109 -0
  271. data/features/custom_formatter.feature +11 -0
  272. data/features/drb_server_integration.feature +173 -0
  273. data/features/exception_in_after_block.feature +102 -0
  274. data/features/exception_in_after_step_block.feature +104 -0
  275. data/features/exception_in_before_block.feature +47 -0
  276. data/features/exclude_files.feature +20 -0
  277. data/features/expand.feature +49 -0
  278. data/features/html_formatter/a.html +183 -0
  279. data/features/html_formatter.feature +7 -0
  280. data/features/junit_formatter.feature +89 -0
  281. data/features/language_from_header.feature +30 -0
  282. data/features/multiline_names.feature +43 -0
  283. data/features/post_configuration_hook.feature +37 -0
  284. data/features/profiles.feature +112 -0
  285. data/features/rake_task.feature +178 -0
  286. data/features/report_called_undefined_steps.feature +35 -0
  287. data/features/snippet.feature +22 -0
  288. data/features/step_definitions/cucumber_steps.rb +154 -0
  289. data/features/step_definitions/extra_steps.rb +2 -0
  290. data/features/steps_formatter.feature +25 -0
  291. data/features/support/env.rb +139 -0
  292. data/features/table_diffing.feature +45 -0
  293. data/features/transform.feature +24 -0
  294. data/features/unicode_table.feature +35 -0
  295. data/features/usage.feature +132 -0
  296. data/features/work_in_progress.feature +158 -0
  297. data/gem_tasks/contributors.rake +12 -0
  298. data/gem_tasks/deployment.rake +11 -0
  299. data/gem_tasks/environment.rake +7 -0
  300. data/gem_tasks/features.rake +11 -0
  301. data/gem_tasks/fix_cr_lf.rake +10 -0
  302. data/gem_tasks/flog.rake +4 -0
  303. data/gem_tasks/gemspec.rake +10 -0
  304. data/gem_tasks/rspec.rake +45 -0
  305. data/gem_tasks/sass.rake +4 -0
  306. data/gem_tasks/sdoc.rake +7 -0
  307. data/lib/README.rdoc +12 -0
  308. data/lib/autotest/cucumber.rb +6 -0
  309. data/lib/autotest/cucumber_mixin.rb +125 -0
  310. data/lib/autotest/cucumber_rails.rb +6 -0
  311. data/lib/autotest/cucumber_rails_rspec.rb +6 -0
  312. data/lib/autotest/cucumber_rspec.rb +6 -0
  313. data/lib/autotest/discover.rb +9 -0
  314. data/lib/cucumber/ast/background.rb +63 -0
  315. data/lib/cucumber/ast/comment.rb +31 -0
  316. data/lib/cucumber/ast/examples.rb +32 -0
  317. data/lib/cucumber/ast/feature.rb +81 -0
  318. data/lib/cucumber/ast/feature_element.rb +61 -0
  319. data/lib/cucumber/ast/features.rb +40 -0
  320. data/lib/cucumber/ast/outline_table.rb +146 -0
  321. data/lib/cucumber/ast/py_string.rb +57 -0
  322. data/lib/cucumber/ast/scenario.rb +108 -0
  323. data/lib/cucumber/ast/scenario_outline.rb +96 -0
  324. data/lib/cucumber/ast/step.rb +116 -0
  325. data/lib/cucumber/ast/step_collection.rb +76 -0
  326. data/lib/cucumber/ast/step_invocation.rb +166 -0
  327. data/lib/cucumber/ast/table.rb +626 -0
  328. data/lib/cucumber/ast/tags.rb +44 -0
  329. data/lib/cucumber/ast/visitor.rb +115 -0
  330. data/lib/cucumber/ast.rb +29 -0
  331. data/lib/cucumber/broadcaster.rb +13 -0
  332. data/lib/cucumber/cli/configuration.rb +190 -0
  333. data/lib/cucumber/cli/drb_client.rb +26 -0
  334. data/lib/cucumber/cli/language_help_formatter.rb +61 -0
  335. data/lib/cucumber/cli/main.rb +116 -0
  336. data/lib/cucumber/cli/options.rb +394 -0
  337. data/lib/cucumber/cli/profile_loader.rb +70 -0
  338. data/lib/cucumber/constantize.rb +28 -0
  339. data/lib/cucumber/core_ext/instance_exec.rb +93 -0
  340. data/lib/cucumber/core_ext/proc.rb +29 -0
  341. data/lib/cucumber/core_ext/string.rb +48 -0
  342. data/lib/cucumber/feature_file.rb +54 -0
  343. data/lib/cucumber/filter.rb +52 -0
  344. data/lib/cucumber/formatter/ansicolor.rb +143 -0
  345. data/lib/cucumber/formatter/color_io.rb +23 -0
  346. data/lib/cucumber/formatter/console.rb +185 -0
  347. data/lib/cucumber/formatter/cucumber.css +132 -0
  348. data/lib/cucumber/formatter/cucumber.sass +139 -0
  349. data/lib/cucumber/formatter/duration.rb +13 -0
  350. data/lib/cucumber/formatter/html.rb +261 -0
  351. data/lib/cucumber/formatter/junit.rb +121 -0
  352. data/lib/cucumber/formatter/ordered_xml_markup.rb +24 -0
  353. data/lib/cucumber/formatter/pdf.rb +217 -0
  354. data/lib/cucumber/formatter/pretty.rb +222 -0
  355. data/lib/cucumber/formatter/profile.rb +78 -0
  356. data/lib/cucumber/formatter/progress.rb +67 -0
  357. data/lib/cucumber/formatter/rerun.rb +46 -0
  358. data/lib/cucumber/formatter/steps.rb +50 -0
  359. data/lib/cucumber/formatter/tag_cloud.rb +29 -0
  360. data/lib/cucumber/formatter/unicode.rb +35 -0
  361. data/lib/cucumber/formatter/usage.rb +86 -0
  362. data/lib/cucumber/formatters/unicode.rb +7 -0
  363. data/lib/cucumber/language_support/language_methods.rb +75 -0
  364. data/lib/cucumber/language_support/step_definition_methods.rb +46 -0
  365. data/lib/cucumber/language_support.rb +30 -0
  366. data/lib/cucumber/languages.yml +561 -0
  367. data/lib/cucumber/parser/feature.rb +1838 -0
  368. data/lib/cucumber/parser/feature.tt +351 -0
  369. data/lib/cucumber/parser/i18n.tt +42 -0
  370. data/lib/cucumber/parser/natural_language.rb +72 -0
  371. data/lib/cucumber/parser/table.rb +417 -0
  372. data/lib/cucumber/parser/table.tt +71 -0
  373. data/lib/cucumber/parser/treetop_ext.rb +53 -0
  374. data/lib/cucumber/parser.rb +6 -0
  375. data/lib/cucumber/platform.rb +27 -0
  376. data/lib/cucumber/py_support/py_dsl.py +8 -0
  377. data/lib/cucumber/py_support/py_language.py +2 -0
  378. data/lib/cucumber/py_support/py_language.rb +68 -0
  379. data/lib/cucumber/rails/rspec.rb +10 -0
  380. data/lib/cucumber/rails/world.rb +100 -0
  381. data/lib/cucumber/rake/task.rb +241 -0
  382. data/lib/cucumber/rb_support/rb_dsl.rb +100 -0
  383. data/lib/cucumber/rb_support/rb_hook.rb +18 -0
  384. data/lib/cucumber/rb_support/rb_language.rb +153 -0
  385. data/lib/cucumber/rb_support/rb_step_definition.rb +60 -0
  386. data/lib/cucumber/rb_support/rb_world.rb +93 -0
  387. data/lib/cucumber/rspec_neuter.rb +23 -0
  388. data/lib/cucumber/step_match.rb +61 -0
  389. data/lib/cucumber/step_mother.rb +307 -0
  390. data/lib/cucumber/version.rb +10 -0
  391. data/lib/cucumber/webrat/element_locator.rb +87 -0
  392. data/lib/cucumber/webrat/table_locator.rb +1 -0
  393. data/lib/cucumber.rb +10 -0
  394. data/rails_generators/cucumber/USAGE +11 -0
  395. data/rails_generators/cucumber/cucumber_generator.rb +70 -0
  396. data/rails_generators/cucumber/templates/cucumber +9 -0
  397. data/rails_generators/cucumber/templates/cucumber.rake +36 -0
  398. data/rails_generators/cucumber/templates/cucumber_environment.rb +26 -0
  399. data/rails_generators/cucumber/templates/env.rb +27 -0
  400. data/rails_generators/cucumber/templates/paths.rb +27 -0
  401. data/rails_generators/cucumber/templates/spork_env.rb +35 -0
  402. data/rails_generators/cucumber/templates/webrat_steps.rb +236 -0
  403. data/rails_generators/feature/USAGE +12 -0
  404. data/rails_generators/feature/feature_generator.rb +40 -0
  405. data/rails_generators/feature/templates/feature.erb +31 -0
  406. data/rails_generators/feature/templates/steps.erb +14 -0
  407. data/spec/cucumber/ast/background_spec.rb +60 -0
  408. data/spec/cucumber/ast/feature_element_spec.rb +40 -0
  409. data/spec/cucumber/ast/feature_factory.rb +62 -0
  410. data/spec/cucumber/ast/feature_spec.rb +44 -0
  411. data/spec/cucumber/ast/py_string_spec.rb +51 -0
  412. data/spec/cucumber/ast/scenario_outline_spec.rb +72 -0
  413. data/spec/cucumber/ast/scenario_spec.rb +43 -0
  414. data/spec/cucumber/ast/step_collection_spec.rb +17 -0
  415. data/spec/cucumber/ast/step_spec.rb +66 -0
  416. data/spec/cucumber/ast/table_spec.rb +394 -0
  417. data/spec/cucumber/broadcaster_spec.rb +15 -0
  418. data/spec/cucumber/cli/configuration_spec.rb +396 -0
  419. data/spec/cucumber/cli/drb_client_spec.rb +77 -0
  420. data/spec/cucumber/cli/main_spec.rb +172 -0
  421. data/spec/cucumber/cli/options_spec.rb +331 -0
  422. data/spec/cucumber/cli/profile_loader_spec.rb +10 -0
  423. data/spec/cucumber/core_ext/proc_spec.rb +68 -0
  424. data/spec/cucumber/core_ext/string_spec.rb +43 -0
  425. data/spec/cucumber/formatter/ansicolor_spec.rb +31 -0
  426. data/spec/cucumber/formatter/color_io_spec.rb +27 -0
  427. data/spec/cucumber/formatter/duration_spec.rb +22 -0
  428. data/spec/cucumber/formatter/html_spec.rb +18 -0
  429. data/spec/cucumber/formatter/progress_spec.rb +33 -0
  430. data/spec/cucumber/parser/feature_parser_spec.rb +396 -0
  431. data/spec/cucumber/parser/table_parser_spec.rb +52 -0
  432. data/spec/cucumber/rails/stubs/mini_rails.rb +18 -0
  433. data/spec/cucumber/rails/stubs/test_help.rb +1 -0
  434. data/spec/cucumber/rails/world_spec.rb +16 -0
  435. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +123 -0
  436. data/spec/cucumber/sell_cucumbers.feature +19 -0
  437. data/spec/cucumber/step_mother_spec.rb +282 -0
  438. data/spec/cucumber/treetop_parser/empty_feature.feature +4 -0
  439. data/spec/cucumber/treetop_parser/empty_scenario.feature +9 -0
  440. data/spec/cucumber/treetop_parser/empty_scenario_outline.feature +3 -0
  441. data/spec/cucumber/treetop_parser/fit_scenario.feature +8 -0
  442. data/spec/cucumber/treetop_parser/given_scenario.feature +9 -0
  443. data/spec/cucumber/treetop_parser/invalid_scenario_outlines.feature +7 -0
  444. data/spec/cucumber/treetop_parser/multiline_steps.feature +17 -0
  445. data/spec/cucumber/treetop_parser/multiple_tables.feature +27 -0
  446. data/spec/cucumber/treetop_parser/scenario_outline.feature +16 -0
  447. data/spec/cucumber/treetop_parser/spaces.feature +12 -0
  448. data/spec/cucumber/treetop_parser/test_dos.feature +25 -0
  449. data/spec/cucumber/treetop_parser/with_comments.feature +23 -0
  450. data/spec/cucumber/treetop_parser/with_tags.feature +18 -0
  451. data/spec/cucumber/world/pending_spec.rb +46 -0
  452. data/spec/spec.opts +4 -0
  453. data/spec/spec_helper.rb +18 -0
  454. metadata +561 -0
@@ -0,0 +1,626 @@
1
+ module Cucumber
2
+ module Ast
3
+ # Step Definitions that match a plain text Step with a multiline argument table
4
+ # will receive it as an instance of Table. A Table object holds the data of a
5
+ # table parsed from a feature file and lets you access and manipulate the data
6
+ # in different ways.
7
+ #
8
+ # For example:
9
+ #
10
+ # Given I have:
11
+ # | a | b |
12
+ # | c | d |
13
+ #
14
+ # And a matching StepDefinition:
15
+ #
16
+ # Given /I have:/ do |table|
17
+ # data = table.raw
18
+ # end
19
+ #
20
+ # This will store <tt>[['a', 'b'], ['c', 'd']]</tt> in the <tt>data</tt> variable.
21
+ #
22
+ class Table
23
+ include Enumerable
24
+
25
+ NULL_CONVERSIONS = Hash.new(lambda{ |cell_value| cell_value }).freeze
26
+
27
+ attr_accessor :file
28
+
29
+ def self.default_arg_name #:nodoc:
30
+ "table"
31
+ end
32
+
33
+ # Creates a new instance. +raw+ should be an Array of Array of String.
34
+ # You don't typically create your own Table objects - Cucumber will do
35
+ # it internally and pass them to your Step Definitions.
36
+ #
37
+ def initialize(raw, conversion_procs = NULL_CONVERSIONS.dup)
38
+ @cells_class = Cells
39
+ @cell_class = Cell
40
+
41
+ # Verify that it's square
42
+ transposed = raw.transpose
43
+ create_cell_matrix(raw)
44
+ @conversion_procs = conversion_procs
45
+ end
46
+
47
+ # Creates a copy of this table, inheriting any column mappings.
48
+ # registered with #map_headers!
49
+ #
50
+ def dup
51
+ self.class.new(raw.dup, @conversion_procs.dup)
52
+ end
53
+
54
+ # Returns a new, transposed table. Example:
55
+ #
56
+ # | a | 7 | 4 |
57
+ # | b | 9 | 2 |
58
+ #
59
+ # Gets converted into the following:
60
+ #
61
+ # | a | b |
62
+ # | 7 | 9 |
63
+ # | 4 | 2 |
64
+ #
65
+ def transpose
66
+ self.class.new(raw.transpose, @conversion_procs.dup)
67
+ end
68
+
69
+ # Converts this table into an Array of Hash where the keys of each
70
+ # Hash are the headers in the table. For example, a Table built from
71
+ # the following plain text:
72
+ #
73
+ # | a | b | sum |
74
+ # | 2 | 3 | 5 |
75
+ # | 7 | 9 | 16 |
76
+ #
77
+ # Gets converted into the following:
78
+ #
79
+ # [{'a' => '2', 'b' => '3', 'sum' => '5'}, {'a' => '7', 'b' => '9', 'sum' => '16'}]
80
+ #
81
+ # Use #map_column! to specify how values in a column are converted.
82
+ #
83
+ def hashes
84
+ @hashes ||= cells_rows[1..-1].map do |row|
85
+ row.to_hash
86
+ end.freeze
87
+ end
88
+
89
+ # Converts this table into a Hash where the first column is
90
+ # used as keys and the second column is used as values
91
+ #
92
+ # | a | 2 |
93
+ # | b | 3 |
94
+ #
95
+ # Gets converted into the following:
96
+ #
97
+ # {'a' => '2', 'b' => '3'}
98
+ #
99
+ # The table must be exactly two columns wide
100
+ #
101
+ def rows_hash
102
+ return @rows_hash if @rows_hash
103
+ verify_table_width(2)
104
+ @rows_hash = self.transpose.hashes[0].freeze
105
+ end
106
+
107
+ # Gets the raw data of this table. For example, a Table built from
108
+ # the following plain text:
109
+ #
110
+ # | a | b |
111
+ # | c | d |
112
+ #
113
+ # gets converted into the following:
114
+ #
115
+ # [['a', 'b], ['c', 'd']]
116
+ #
117
+ def raw
118
+ cell_matrix.map do |row|
119
+ row.map do |cell|
120
+ cell.value
121
+ end
122
+ end
123
+ end
124
+
125
+ # Same as #raw, but skips the first (header) row
126
+ def rows
127
+ raw[1..-1]
128
+ end
129
+
130
+ def each_cells_row(&proc) #:nodoc:
131
+ cells_rows.each(&proc)
132
+ end
133
+
134
+ def accept(visitor) #:nodoc:
135
+ return if $cucumber_interrupted
136
+ cells_rows.each do |row|
137
+ visitor.visit_table_row(row)
138
+ end
139
+ nil
140
+ end
141
+
142
+ # For testing only
143
+ def to_sexp #:nodoc:
144
+ [:table, *cells_rows.map{|row| row.to_sexp}]
145
+ end
146
+
147
+ # Redefines the table headers. This makes it possible to use
148
+ # prettier and more flexible header names in the features. The
149
+ # keys of +mappings+ are Strings or regular expressions
150
+ # (anything that responds to #=== will work) that may match
151
+ # column headings in the table. The values of +mappings+ are
152
+ # desired names for the columns.
153
+ #
154
+ # Example:
155
+ #
156
+ # | Phone Number | Address |
157
+ # | 123456 | xyz |
158
+ # | 345678 | abc |
159
+ #
160
+ # A StepDefinition receiving this table can then map the columns
161
+ # with both Regexp and String:
162
+ #
163
+ # table.map_headers!(/phone( number)?/i => :phone, 'Address' => :address)
164
+ # table.hashes
165
+ # # => [{:phone => '123456', :address => 'xyz'}, {:phone => '345678', :address => 'abc'}]
166
+ #
167
+ # You may also pass in a block if you wish to convert all of the headers:
168
+ #
169
+ # table.map_headers! { |header| header.downcase }
170
+ # table.hashes.keys
171
+ # # => ['phone number', 'address']
172
+ #
173
+ # When a block is passed in along with a hash then the mappings in the hash take precendence:
174
+ #
175
+ # table.map_headers!('Address' => 'ADDRESS') { |header| header.downcase }
176
+ # table.hashes.keys
177
+ # # => ['phone number', 'ADDRESS']
178
+ #
179
+ def map_headers!(mappings={}, &block)
180
+ header_cells = cell_matrix[0]
181
+
182
+ if block_given?
183
+ header_values = header_cells.map { |cell| cell.value } - mappings.keys
184
+ mappings = mappings.merge(Hash[*header_values.zip(header_values.map(&block)).flatten])
185
+ end
186
+
187
+ mappings.each_pair do |pre, post|
188
+ mapped_cells = header_cells.select{|cell| pre === cell.value}
189
+ raise "No headers matched #{pre.inspect}" if mapped_cells.empty?
190
+ raise "#{mapped_cells.length} headers matched #{pre.inspect}: #{mapped_cells.map{|c| c.value}.inspect}" if mapped_cells.length > 1
191
+ mapped_cells[0].value = post
192
+ if @conversion_procs.has_key?(pre)
193
+ @conversion_procs[post] = @conversion_procs.delete(pre)
194
+ end
195
+ end
196
+ end
197
+
198
+ # Returns a new Table where the headers are redefined. See #map_headers!
199
+ def map_headers(mappings={})
200
+ table = self.dup
201
+ table.map_headers!(mappings)
202
+ table
203
+ end
204
+
205
+ # Change how #hashes converts column values. The +column_name+ argument identifies the column
206
+ # and +conversion_proc+ performs the conversion for each cell in that column. If +strict+ is
207
+ # true, an error will be raised if the column named +column_name+ is not found. If +strict+
208
+ # is false, no error will be raised. Example:
209
+ #
210
+ # Given /^an expense report for (.*) with the following posts:$/ do |table|
211
+ # posts_table.map_column!('amount') { |a| a.to_i }
212
+ # posts_table.hashes.each do |post|
213
+ # # post['amount'] is a Fixnum, rather than a String
214
+ # end
215
+ # end
216
+ #
217
+ def map_column!(column_name, strict=true, &conversion_proc)
218
+ verify_column(column_name) if strict
219
+ @conversion_procs[column_name] = conversion_proc
220
+ end
221
+
222
+ # Compares +other_table+ to self. If +other_table+ contains columns
223
+ # and/or rows that are not in self, new columns/rows are added at the
224
+ # relevant positions, marking the cells in those rows/columns as
225
+ # <tt>surplus</tt>. Likewise, if +other_table+ lacks columns and/or
226
+ # rows that are present in self, these are marked as <tt>missing</tt>.
227
+ #
228
+ # <tt>surplus</tt> and <tt>missing</tt> cells are recognised by formatters
229
+ # and displayed so that it's easy to read the differences.
230
+ #
231
+ # Cells that are different, but <em>look</em> identical (for example the
232
+ # boolean true and the string "true") are converted to their Object#inspect
233
+ # representation and preceded with (i) - to make it easier to identify
234
+ # where the difference actually is.
235
+ #
236
+ # Since all tables that are passed to StepDefinitions always have String
237
+ # objects in their cells, you may want to use #map_column! before calling
238
+ # #diff!. You can use #map_column! on either of the tables.
239
+ #
240
+ # An exception is raised if there are missing rows or columns, or
241
+ # surplus rows. An error is <em>not</em> raised for surplus columns.
242
+ # Whether to raise or not raise can be changed by setting values in
243
+ # +options+ to true or false:
244
+ #
245
+ # * <tt>missing_row</tt> : Raise on missing rows (defaults to true)
246
+ # * <tt>surplus_row</tt> : Raise on surplus rows (defaults to true)
247
+ # * <tt>missing_col</tt> : Raise on missing columns (defaults to true)
248
+ # * <tt>surplus_col</tt> : Raise on surplus columns (defaults to false)
249
+ #
250
+ # The +other_table+ argument can be another Table, an Array of Array or
251
+ # an Array of Hash (similar to the structure returned by #hashes).
252
+ #
253
+ # Calling this method is particularly useful in <tt>Then</tt> steps that take
254
+ # a Table argument, if you want to compare that table to some actual values.
255
+ #
256
+ def diff!(other_table, options={})
257
+ options = {:missing_row => true, :surplus_row => true, :missing_col => true, :surplus_col => false}.merge(options)
258
+
259
+ other_table = ensure_table(other_table)
260
+ other_table.convert_columns!
261
+ ensure_green!
262
+
263
+ original_width = cell_matrix[0].length
264
+ other_table_cell_matrix = pad!(other_table.cell_matrix)
265
+ padded_width = cell_matrix[0].length
266
+
267
+ missing_col = cell_matrix[0].detect{|cell| cell.status == :undefined}
268
+ surplus_col = padded_width > original_width
269
+
270
+ require_diff_lcs
271
+ cell_matrix.extend(Diff::LCS)
272
+ convert_columns!
273
+ changes = cell_matrix.diff(other_table_cell_matrix).flatten
274
+
275
+ inserted = 0
276
+ missing = 0
277
+
278
+ row_indices = Array.new(other_table_cell_matrix.length) {|n| n}
279
+
280
+ last_change = nil
281
+ missing_row_pos = nil
282
+ insert_row_pos = nil
283
+
284
+ changes.each do |change|
285
+ if(change.action == '-')
286
+ missing_row_pos = change.position + inserted
287
+ cell_matrix[missing_row_pos].each{|cell| cell.status = :undefined}
288
+ row_indices.insert(missing_row_pos, nil)
289
+ missing += 1
290
+ else # '+'
291
+ insert_row_pos = change.position + missing
292
+ inserted_row = change.element
293
+ inserted_row.each{|cell| cell.status = :comment}
294
+ cell_matrix.insert(insert_row_pos, inserted_row)
295
+ row_indices[insert_row_pos] = nil
296
+ inspect_rows(cell_matrix[missing_row_pos], inserted_row) if last_change && last_change.action == '-'
297
+ inserted += 1
298
+ end
299
+ last_change = change
300
+ end
301
+
302
+ other_table_cell_matrix.each_with_index do |other_row, i|
303
+ row_index = row_indices.index(i)
304
+ row = cell_matrix[row_index] if row_index
305
+ if row
306
+ (original_width..padded_width).each do |col_index|
307
+ surplus_cell = other_row[col_index]
308
+ row[col_index].value = surplus_cell.value if row[col_index]
309
+ end
310
+ end
311
+ end
312
+
313
+ clear_cache!
314
+ should_raise =
315
+ missing_row_pos && options[:missing_row] ||
316
+ insert_row_pos && options[:surplus_row] ||
317
+ missing_col && options[:missing_col] ||
318
+ surplus_col && options[:surplus_col]
319
+ raise 'Tables were not identical' if should_raise
320
+ end
321
+
322
+ def to_hash(cells) #:nodoc:
323
+ hash = Hash.new do |hash, key|
324
+ hash[key.to_s] if key.is_a?(Symbol)
325
+ end
326
+ raw[0].each_with_index do |column_name, column_index|
327
+ value = @conversion_procs[column_name].call(cells.value(column_index))
328
+ hash[column_name] = value
329
+ end
330
+ hash
331
+ end
332
+
333
+ def index(cells) #:nodoc:
334
+ cells_rows.index(cells)
335
+ end
336
+
337
+ def verify_column(column_name) #:nodoc:
338
+ raise %{The column named "#{column_name}" does not exist} unless raw[0].include?(column_name)
339
+ end
340
+
341
+ def verify_table_width(width) #:nodoc:
342
+ raise %{The table must have exactly #{width} columns} unless raw[0].size == width
343
+ end
344
+
345
+ def arguments_replaced(arguments) #:nodoc:
346
+ raw_with_replaced_args = raw.map do |row|
347
+ row.map do |cell|
348
+ cell_with_replaced_args = cell
349
+ arguments.each do |name, value|
350
+ if cell_with_replaced_args && cell_with_replaced_args.include?(name)
351
+ cell_with_replaced_args = value ? cell_with_replaced_args.gsub(name, value) : nil
352
+ end
353
+ end
354
+ cell_with_replaced_args
355
+ end
356
+ end
357
+ Table.new(raw_with_replaced_args)
358
+ end
359
+
360
+ def has_text?(text) #:nodoc:
361
+ raw.flatten.compact.detect{|cell_value| cell_value.index(text)}
362
+ end
363
+
364
+ def cells_rows #:nodoc:
365
+ @rows ||= cell_matrix.map do |cell_row|
366
+ @cells_class.new(self, cell_row)
367
+ end
368
+ end
369
+
370
+ def headers #:nodoc:
371
+ raw.first
372
+ end
373
+
374
+ def header_cell(col) #:nodoc:
375
+ cells_rows[0][col]
376
+ end
377
+
378
+ def cell_matrix #:nodoc:
379
+ @cell_matrix
380
+ end
381
+
382
+ def col_width(col) #:nodoc:
383
+ columns[col].__send__(:width)
384
+ end
385
+
386
+ def to_s(options = {}) #:nodoc:
387
+ options = {:color => true, :indent => 2, :prefixes => TO_S_PREFIXES}.merge(options)
388
+ io = StringIO.new
389
+
390
+ c = Term::ANSIColor.coloring?
391
+ Term::ANSIColor.coloring = options[:color]
392
+ f = Formatter::Pretty.new(nil, io, options)
393
+ f.instance_variable_set('@indent', options[:indent])
394
+ f.visit_multiline_arg(self)
395
+ Term::ANSIColor.coloring = c
396
+
397
+ io.rewind
398
+ s = "\n" + io.read + (" " * (options[:indent] - 2))
399
+ s
400
+ end
401
+
402
+ private
403
+
404
+ TO_S_PREFIXES = Hash.new(' ')
405
+ TO_S_PREFIXES[:comment] = ['(+) ']
406
+ TO_S_PREFIXES[:undefined] = ['(-) ']
407
+
408
+ protected
409
+
410
+ def inspect_rows(missing_row, inserted_row) #:nodoc:
411
+ missing_row.each_with_index do |missing_cell, col|
412
+ inserted_cell = inserted_row[col]
413
+ if(missing_cell.value != inserted_cell.value && (missing_cell.value.to_s == inserted_cell.value.to_s))
414
+ missing_cell.inspect!
415
+ inserted_cell.inspect!
416
+ end
417
+ end
418
+ end
419
+
420
+ def create_cell_matrix(raw) #:nodoc:
421
+ @cell_matrix = raw.map do |raw_row|
422
+ line = raw_row.line rescue -1
423
+ raw_row.map do |raw_cell|
424
+ new_cell(raw_cell, line)
425
+ end
426
+ end
427
+ end
428
+
429
+ def convert_columns! #:nodoc:
430
+ cell_matrix.transpose.each do |col|
431
+ conversion_proc = @conversion_procs[col[0].value]
432
+ col[1..-1].each do |cell|
433
+ cell.value = conversion_proc.call(cell.value)
434
+ end
435
+ end
436
+ end
437
+
438
+ def require_diff_lcs #:nodoc:
439
+ begin
440
+ require 'diff/lcs'
441
+ rescue LoadError => e
442
+ e.message << "\n Please gem install diff-lcs\n"
443
+ raise e
444
+ end
445
+ end
446
+
447
+ def clear_cache! #:nodoc:
448
+ @hashes = @rows_hash = @rows = @columns = nil
449
+ end
450
+
451
+ def columns #:nodoc:
452
+ @columns ||= cell_matrix.transpose.map do |cell_row|
453
+ @cells_class.new(self, cell_row)
454
+ end.freeze
455
+ end
456
+
457
+ def new_cell(raw_cell, line) #:nodoc:
458
+ @cell_class.new(raw_cell, self, line)
459
+ end
460
+
461
+ # Pads our own cell_matrix and returns a cell matrix of same
462
+ # column width that can be used for diffing
463
+ def pad!(other_cell_matrix) #:nodoc:
464
+ clear_cache!
465
+ cols = cell_matrix.transpose
466
+ unmapped_cols = other_cell_matrix.transpose
467
+
468
+ mapped_cols = []
469
+
470
+ cols.each_with_index do |col, col_index|
471
+ header = col[0]
472
+ candidate_cols, unmapped_cols = unmapped_cols.partition do |other_col|
473
+ other_col[0] == header
474
+ end
475
+ raise "More than one column has the header #{header}" if candidate_cols.size > 2
476
+
477
+ other_padded_col = if candidate_cols.size == 1
478
+ # Found a matching column
479
+ candidate_cols[0]
480
+ else
481
+ mark_as_missing(cols[col_index])
482
+ (0...other_cell_matrix.length).map do |row|
483
+ val = row == 0 ? header.value : nil
484
+ SurplusCell.new(val, self, -1)
485
+ end
486
+ end
487
+ mapped_cols.insert(col_index, other_padded_col)
488
+ end
489
+
490
+ unmapped_cols.each_with_index do |col, col_index|
491
+ empty_col = (0...cell_matrix.length).map do |row|
492
+ SurplusCell.new(nil, self, -1)
493
+ end
494
+ cols << empty_col
495
+ end
496
+
497
+ @cell_matrix = cols.transpose
498
+ (mapped_cols + unmapped_cols).transpose
499
+ end
500
+
501
+ def ensure_table(table_or_array) #:nodoc:
502
+ return table_or_array if Table === table_or_array
503
+ table_or_array = hashes_to_array(table_or_array) if Hash === table_or_array[0]
504
+ table_or_array = enumerable_to_array(table_or_array) unless Array == table_or_array[0]
505
+ Table.new(table_or_array)
506
+ end
507
+
508
+ def hashes_to_array(hashes) #:nodoc:
509
+ header = hashes[0].keys
510
+ [header] + hashes.map{|hash| header.map{|key| hash[key]}}
511
+ end
512
+
513
+ def enumerable_to_array(rows) #:nodoc:
514
+ rows.map{|row| row.map{|cell| cell}}
515
+ end
516
+
517
+ def ensure_green! #:nodoc:
518
+ each_cell{|cell| cell.status = :passed}
519
+ end
520
+
521
+ def each_cell(&proc) #:nodoc:
522
+ cell_matrix.each{|row| row.each(&proc)}
523
+ end
524
+
525
+ def mark_as_missing(col) #:nodoc:
526
+ col.each do |cell|
527
+ cell.status = :undefined
528
+ end
529
+ end
530
+
531
+ # Represents a row of cells or columns of cells
532
+ class Cells #:nodoc:
533
+ include Enumerable
534
+ attr_reader :exception
535
+
536
+ def initialize(table, cells)
537
+ @table, @cells = table, cells
538
+ end
539
+
540
+ def accept(visitor)
541
+ return if $cucumber_interrupted
542
+ each do |cell|
543
+ visitor.visit_table_cell(cell)
544
+ end
545
+ nil
546
+ end
547
+
548
+ # For testing only
549
+ def to_sexp #:nodoc:
550
+ [:row, line, *@cells.map{|cell| cell.to_sexp}]
551
+ end
552
+
553
+ def to_hash #:nodoc:
554
+ @to_hash ||= @table.to_hash(self).freeze
555
+ end
556
+
557
+ def value(n) #:nodoc:
558
+ self[n].value
559
+ end
560
+
561
+ def [](n)
562
+ @cells[n]
563
+ end
564
+
565
+ def line
566
+ @cells[0].line
567
+ end
568
+
569
+ def dom_id
570
+ "row_#{line}"
571
+ end
572
+
573
+ private
574
+
575
+ def index
576
+ @table.index(self)
577
+ end
578
+
579
+ def width
580
+ map{|cell| cell.value ? cell.value.to_s.jlength : 0}.max
581
+ end
582
+
583
+ def each(&proc)
584
+ @cells.each(&proc)
585
+ end
586
+ end
587
+
588
+ class Cell #:nodoc:
589
+ attr_reader :line, :table
590
+ attr_accessor :status, :value
591
+
592
+ def initialize(value, table, line)
593
+ @value, @table, @line = value, table, line
594
+ end
595
+
596
+ def accept(visitor)
597
+ return if $cucumber_interrupted
598
+ visitor.visit_table_cell_value(value, status)
599
+ end
600
+
601
+ def inspect!
602
+ @value = "(i) #{value.inspect}"
603
+ end
604
+
605
+ def ==(o)
606
+ SurplusCell === o || value == o.value
607
+ end
608
+
609
+ # For testing only
610
+ def to_sexp #:nodoc:
611
+ [:cell, @value]
612
+ end
613
+ end
614
+
615
+ class SurplusCell < Cell #:nodoc:
616
+ def status
617
+ :comment
618
+ end
619
+
620
+ def ==(o)
621
+ true
622
+ end
623
+ end
624
+ end
625
+ end
626
+ end
@@ -0,0 +1,44 @@
1
+ module Cucumber
2
+ module Ast
3
+ # Holds the names of tags parsed from a feature file:
4
+ #
5
+ # @invoice @release_2
6
+ #
7
+ # This gets stored internally as <tt>["invoice", "release_2"]</tt>
8
+ #
9
+ class Tags #:nodoc:
10
+ def self.strip_prefix(tag_name)
11
+ tag_name =~ /^@(.*)/ ? $1 : tag_name
12
+ end
13
+
14
+ def initialize(line, tag_names)
15
+ @line, @tag_names = line, tag_names
16
+ end
17
+
18
+ def accept(visitor)
19
+ return if $cucumber_interrupted
20
+ @tag_names.each do |tag_name|
21
+ visitor.visit_tag_name(tag_name)
22
+ end
23
+ end
24
+
25
+ def accept_hook?(hook)
26
+ hook.tag_names.empty? || (hook.tag_names.map{|tag| Ast::Tags.strip_prefix(tag)} & @tag_names).any?
27
+ end
28
+
29
+ def count(tag)
30
+ # See discussion:
31
+ # http://github.com/weplay/cucumber/commit/2dc592acdf3f7c1a0c333a8164649936bb82d983
32
+ if @tag_names.respond_to?(:count) && @tag_names.method(:count).arity > 0
33
+ @tag_names.count(tag) # 1.9
34
+ else
35
+ @tag_names.select{|t| t == tag}.length # 1.8
36
+ end
37
+ end
38
+
39
+ def to_sexp
40
+ @tag_names.map{|tag_name| [:tag, tag_name]}
41
+ end
42
+ end
43
+ end
44
+ end