casecumber 1.0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (563) hide show
  1. data/.gitattributes +1 -0
  2. data/.gitignore +26 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +7 -0
  6. data/.yardopts +0 -0
  7. data/Gemfile +2 -0
  8. data/Gemfile.lock +115 -0
  9. data/History.md +1702 -0
  10. data/LICENSE +22 -0
  11. data/README.md +25 -0
  12. data/Rakefile +12 -0
  13. data/bin/cucumber +22 -0
  14. data/cucumber.gemspec +60 -0
  15. data/cucumber.yml +20 -0
  16. data/examples/i18n/README.textile +18 -0
  17. data/examples/i18n/Rakefile +33 -0
  18. data/examples/i18n/ar/Rakefile +6 -0
  19. data/examples/i18n/ar/features/addition.feature +17 -0
  20. data/examples/i18n/ar/features/step_definitons/calculator_steps.rb +24 -0
  21. data/examples/i18n/ar/lib/calculator.rb +11 -0
  22. data/examples/i18n/bg/Rakefile +6 -0
  23. data/examples/i18n/bg/features/addition.feature +12 -0
  24. data/examples/i18n/bg/features/consecutive_calculations.feature +19 -0
  25. data/examples/i18n/bg/features/division.feature +17 -0
  26. data/examples/i18n/bg/features/step_definitons/calculator_steps.rb +24 -0
  27. data/examples/i18n/bg/features/support/env.rb +5 -0
  28. data/examples/i18n/bg/features/support/world.rb +8 -0
  29. data/examples/i18n/bg/lib/calculator.rb +24 -0
  30. data/examples/i18n/ca/Rakefile +6 -0
  31. data/examples/i18n/ca/features/step_definitons/calculator_steps.rb +21 -0
  32. data/examples/i18n/ca/features/suma.feature +17 -0
  33. data/examples/i18n/ca/lib/calculadora.rb +16 -0
  34. data/examples/i18n/da/Rakefile +6 -0
  35. data/examples/i18n/da/features/sammenlaegning.feature +18 -0
  36. data/examples/i18n/da/features/step_definitons/lommeregner_steps.rb +24 -0
  37. data/examples/i18n/da/lib/lommeregner.rb +11 -0
  38. data/examples/i18n/de/.gitignore +1 -0
  39. data/examples/i18n/de/Rakefile +6 -0
  40. data/examples/i18n/de/features/addition.feature +17 -0
  41. data/examples/i18n/de/features/division.feature +10 -0
  42. data/examples/i18n/de/features/step_definitons/calculator_steps.rb +24 -0
  43. data/examples/i18n/de/lib/calculator.rb +14 -0
  44. data/examples/i18n/en-lol/Rakefile +4 -0
  45. data/examples/i18n/en-lol/features/step_definitions/cucumbrz_steps.rb +16 -0
  46. data/examples/i18n/en-lol/features/stuffing.feature +8 -0
  47. data/examples/i18n/en-lol/features/support/env.rb +7 -0
  48. data/examples/i18n/en-lol/lib/basket.rb +12 -0
  49. data/examples/i18n/en-lol/lib/belly.rb +11 -0
  50. data/examples/i18n/en/.gitignore +1 -0
  51. data/examples/i18n/en/Rakefile +6 -0
  52. data/examples/i18n/en/features/addition.feature +17 -0
  53. data/examples/i18n/en/features/division.feature +10 -0
  54. data/examples/i18n/en/features/step_definitons/calculator_steps.rb +24 -0
  55. data/examples/i18n/en/lib/calculator.rb +14 -0
  56. data/examples/i18n/eo/.gitignore +1 -0
  57. data/examples/i18n/eo/Rakefile +6 -0
  58. data/examples/i18n/eo/features/adicio.feature +17 -0
  59. data/examples/i18n/eo/features/divido.feature +10 -0
  60. data/examples/i18n/eo/features/step_definitons/calculator_steps.rb +24 -0
  61. data/examples/i18n/eo/lib/calculator.rb +14 -0
  62. data/examples/i18n/es/Rakefile +6 -0
  63. data/examples/i18n/es/features/adicion.feature +17 -0
  64. data/examples/i18n/es/features/step_definitons/calculador_steps.rb +21 -0
  65. data/examples/i18n/es/lib/calculador.rb +14 -0
  66. data/examples/i18n/et/Rakefile +6 -0
  67. data/examples/i18n/et/features/jagamine.feature +10 -0
  68. data/examples/i18n/et/features/liitmine.feature +17 -0
  69. data/examples/i18n/et/features/step_definitions/kalkulaator_steps.rb +24 -0
  70. data/examples/i18n/et/lib/kalkulaator.rb +14 -0
  71. data/examples/i18n/fi/.gitignore +1 -0
  72. data/examples/i18n/fi/Rakefile +6 -0
  73. data/examples/i18n/fi/features/jakolasku.feature +10 -0
  74. data/examples/i18n/fi/features/step_definitons/laskin_steps.rb +24 -0
  75. data/examples/i18n/fi/features/yhteenlasku.feature +17 -0
  76. data/examples/i18n/fi/lib/laskin.rb +14 -0
  77. data/examples/i18n/fr/Rakefile +6 -0
  78. data/examples/i18n/fr/features/addition.feature +18 -0
  79. data/examples/i18n/fr/features/addition2.feature +17 -0
  80. data/examples/i18n/fr/features/step_definitions/calculatrice_steps.rb +32 -0
  81. data/examples/i18n/fr/features/support/env.rb +5 -0
  82. data/examples/i18n/fr/lib/calculatrice.rb +10 -0
  83. data/examples/i18n/he/Rakefile +6 -0
  84. data/examples/i18n/he/features/addition.feature +17 -0
  85. data/examples/i18n/he/features/division.feature +10 -0
  86. data/examples/i18n/he/features/step_definitons/calculator_steps.rb +24 -0
  87. data/examples/i18n/he/lib/calculator.rb +15 -0
  88. data/examples/i18n/hu/.gitignore +1 -0
  89. data/examples/i18n/hu/Rakefile +6 -0
  90. data/examples/i18n/hu/features/osszeadas.feature +17 -0
  91. data/examples/i18n/hu/features/osztas.feature +10 -0
  92. data/examples/i18n/hu/features/step_definitons/calculator_steps.rb +25 -0
  93. data/examples/i18n/hu/lib/calculator.rb +14 -0
  94. data/examples/i18n/id/.gitignore +1 -0
  95. data/examples/i18n/id/Rakefile +6 -0
  96. data/examples/i18n/id/features/addition.feature +17 -0
  97. data/examples/i18n/id/features/division.feature +10 -0
  98. data/examples/i18n/id/features/step_definitons/calculator_steps.rb +24 -0
  99. data/examples/i18n/id/lib/calculator.rb +14 -0
  100. data/examples/i18n/it/Rakefile +6 -0
  101. data/examples/i18n/it/features/somma.feature +11 -0
  102. data/examples/i18n/it/features/step_definitons/calcolatrice_steps.rb +24 -0
  103. data/examples/i18n/it/lib/calcolatrice.rb +11 -0
  104. data/examples/i18n/ja/.gitignore +1 -0
  105. data/examples/i18n/ja/Rakefile +6 -0
  106. data/examples/i18n/ja/features/addition.feature +17 -0
  107. data/examples/i18n/ja/features/division.feature +10 -0
  108. data/examples/i18n/ja/features/step_definitons/calculator_steps.rb +19 -0
  109. data/examples/i18n/ja/features/support/env.rb +5 -0
  110. data/examples/i18n/ja/lib/calculator.rb +14 -0
  111. data/examples/i18n/ko/.gitignore +1 -0
  112. data/examples/i18n/ko/Rakefile +6 -0
  113. data/examples/i18n/ko/features/addition.feature +17 -0
  114. data/examples/i18n/ko/features/division.feature +11 -0
  115. data/examples/i18n/ko/features/step_definitons/calculator_steps.rb +24 -0
  116. data/examples/i18n/ko/lib/calculator.rb +14 -0
  117. data/examples/i18n/lt/.gitignore +1 -0
  118. data/examples/i18n/lt/Rakefile +6 -0
  119. data/examples/i18n/lt/features/addition.feature +17 -0
  120. data/examples/i18n/lt/features/division.feature +10 -0
  121. data/examples/i18n/lt/features/step_definitons/calculator_steps.rb +24 -0
  122. data/examples/i18n/lt/lib/calculator.rb +14 -0
  123. data/examples/i18n/lv/Rakefile +6 -0
  124. data/examples/i18n/lv/features/addition.feature +17 -0
  125. data/examples/i18n/lv/features/division.feature +10 -0
  126. data/examples/i18n/lv/features/step_definitons/calculator_steps.rb +24 -0
  127. data/examples/i18n/lv/lib/calculator.rb +14 -0
  128. data/examples/i18n/no/Rakefile +6 -0
  129. data/examples/i18n/no/features/step_definitons/kalkulator_steps.rb +17 -0
  130. data/examples/i18n/no/features/summering.feature +19 -0
  131. data/examples/i18n/no/features/support/env.rb +6 -0
  132. data/examples/i18n/no/lib/kalkulator.rb +11 -0
  133. data/examples/i18n/pl/.gitignore +1 -0
  134. data/examples/i18n/pl/Rakefile +6 -0
  135. data/examples/i18n/pl/features/addition.feature +17 -0
  136. data/examples/i18n/pl/features/division.feature +10 -0
  137. data/examples/i18n/pl/features/step_definitons/calculator_steps.rb +24 -0
  138. data/examples/i18n/pl/features/support/env.rb +5 -0
  139. data/examples/i18n/pl/lib/calculator.rb +14 -0
  140. data/examples/i18n/pt/Rakefile +6 -0
  141. data/examples/i18n/pt/features/adicao.feature +11 -0
  142. data/examples/i18n/pt/features/step_definitions/calculadora_steps.rb +20 -0
  143. data/examples/i18n/pt/features/support/env.rb +5 -0
  144. data/examples/i18n/pt/lib/calculadora.rb +10 -0
  145. data/examples/i18n/ro/Rakefile +6 -0
  146. data/examples/i18n/ro/features/adunare.feature +12 -0
  147. data/examples/i18n/ro/features/step_definitons/calculator_steps.rb +21 -0
  148. data/examples/i18n/ro/lib/calculator.rb +11 -0
  149. data/examples/i18n/ru/Rakefile +6 -0
  150. data/examples/i18n/ru/features/addition.feature +11 -0
  151. data/examples/i18n/ru/features/consecutive_calculations.feature +17 -0
  152. data/examples/i18n/ru/features/division.feature +16 -0
  153. data/examples/i18n/ru/features/step_definitons/calculator_steps.rb +19 -0
  154. data/examples/i18n/ru/features/support/env.rb +5 -0
  155. data/examples/i18n/ru/features/support/world.rb +8 -0
  156. data/examples/i18n/ru/lib/calculator.rb +24 -0
  157. data/examples/i18n/sk/.gitignore +1 -0
  158. data/examples/i18n/sk/Rakefile +6 -0
  159. data/examples/i18n/sk/features/addition.feature +17 -0
  160. data/examples/i18n/sk/features/division.feature +10 -0
  161. data/examples/i18n/sk/features/step_definitons/calculator_steps.rb +24 -0
  162. data/examples/i18n/sk/lib/calculator.rb +14 -0
  163. data/examples/i18n/sr-Cyrl/Rakefile +6 -0
  164. data/examples/i18n/sr-Cyrl/features/sabiranje.feature +18 -0
  165. data/examples/i18n/sr-Cyrl/features/step_definitons/calculator_steps.rb +20 -0
  166. data/examples/i18n/sr-Cyrl/features/support/env.rb +5 -0
  167. data/examples/i18n/sr-Cyrl/lib/calculator.rb +12 -0
  168. data/examples/i18n/sr-Latn/Rakefile +6 -0
  169. data/examples/i18n/sr-Latn/features/sabiranje.feature +18 -0
  170. data/examples/i18n/sr-Latn/features/step_definitons/calculator_steps.rb +24 -0
  171. data/examples/i18n/sr-Latn/lib/calculator.rb +12 -0
  172. data/examples/i18n/sv/Rakefile +6 -0
  173. data/examples/i18n/sv/features/step_definitons/kalkulator_steps.rb +24 -0
  174. data/examples/i18n/sv/features/summering.feature +18 -0
  175. data/examples/i18n/sv/lib/kalkulator.rb +11 -0
  176. data/examples/i18n/tr/.gitignore +1 -0
  177. data/examples/i18n/tr/Rakefile +6 -0
  178. data/examples/i18n/tr/features/bolme.feature +10 -0
  179. data/examples/i18n/tr/features/step_definitons/hesap_makinesi_adimlari.rb +24 -0
  180. data/examples/i18n/tr/features/toplama.feature +18 -0
  181. data/examples/i18n/tr/lib/hesap_makinesi.rb +15 -0
  182. data/examples/i18n/uk/Rakefile +6 -0
  183. data/examples/i18n/uk/features/addition.feature +11 -0
  184. data/examples/i18n/uk/features/consecutive_calculations.feature +17 -0
  185. data/examples/i18n/uk/features/division.feature +16 -0
  186. data/examples/i18n/uk/features/step_definitons/calculator_steps.rb +19 -0
  187. data/examples/i18n/uk/features/support/env.rb +5 -0
  188. data/examples/i18n/uk/features/support/world.rb +8 -0
  189. data/examples/i18n/uk/lib/calculator.rb +24 -0
  190. data/examples/i18n/uz/Rakefile +6 -0
  191. data/examples/i18n/uz/features/addition.feature +10 -0
  192. data/examples/i18n/uz/features/consecutive_calculations.feature +17 -0
  193. data/examples/i18n/uz/features/division.feature +17 -0
  194. data/examples/i18n/uz/features/step_definitons/calculator_steps.rb +19 -0
  195. data/examples/i18n/uz/features/support/env.rb +5 -0
  196. data/examples/i18n/uz/features/support/world.rb +8 -0
  197. data/examples/i18n/uz/lib/calculator.rb +24 -0
  198. data/examples/i18n/zh-CN/Rakefile +4 -0
  199. data/examples/i18n/zh-CN/features/addition.feature +18 -0
  200. data/examples/i18n/zh-CN/features/step_definitons/calculator_steps.rb +26 -0
  201. data/examples/i18n/zh-CN/lib/calculator.rb +10 -0
  202. data/examples/i18n/zh-TW/.gitignore +1 -0
  203. data/examples/i18n/zh-TW/Rakefile +4 -0
  204. data/examples/i18n/zh-TW/features/addition.feature +17 -0
  205. data/examples/i18n/zh-TW/features/division.feature +11 -0
  206. data/examples/i18n/zh-TW/features/step_definitons/calculator_steps.rb +24 -0
  207. data/examples/i18n/zh-TW/lib/calculator.rb +14 -0
  208. data/examples/python/README.textile +7 -0
  209. data/examples/python/Rakefile +4 -0
  210. data/examples/python/features/fibonacci.feature +19 -0
  211. data/examples/python/features/step_definitions/fib_steps.py +11 -0
  212. data/examples/python/lib/.gitignore +1 -0
  213. data/examples/python/lib/fib.py +7 -0
  214. data/examples/ramaze/README.textile +7 -0
  215. data/examples/ramaze/Rakefile +6 -0
  216. data/examples/ramaze/app.rb +21 -0
  217. data/examples/ramaze/features/add.feature +11 -0
  218. data/examples/ramaze/features/step_definitions/add_steps.rb +15 -0
  219. data/examples/ramaze/features/support/env.rb +32 -0
  220. data/examples/ramaze/layout/default.html.erb +8 -0
  221. data/examples/ramaze/view/index.html.erb +5 -0
  222. data/examples/rspec_doubles/Rakefile +4 -0
  223. data/examples/rspec_doubles/features/mocking.feature +9 -0
  224. data/examples/rspec_doubles/features/step_definitions/calvin_steps.rb +19 -0
  225. data/examples/rspec_doubles/features/support/env.rb +12 -0
  226. data/examples/ruby2python/README.textile +7 -0
  227. data/examples/ruby2python/Rakefile +4 -0
  228. data/examples/ruby2python/features/fibonacci.feature +19 -0
  229. data/examples/ruby2python/features/step_definitions/fib_steps.rb +7 -0
  230. data/examples/ruby2python/features/support/env.rb +21 -0
  231. data/examples/ruby2python/lib/.gitignore +1 -0
  232. data/examples/ruby2python/lib/fib.py +7 -0
  233. data/examples/sinatra/README.textile +13 -0
  234. data/examples/sinatra/Rakefile +6 -0
  235. data/examples/sinatra/app.rb +14 -0
  236. data/examples/sinatra/features/add.feature +11 -0
  237. data/examples/sinatra/features/step_definitions/add_steps.rb +15 -0
  238. data/examples/sinatra/features/support/env.rb +10 -0
  239. data/examples/sinatra/views/add.erb +7 -0
  240. data/examples/sinatra/views/layout.erb +8 -0
  241. data/examples/tcl/README.textile +11 -0
  242. data/examples/tcl/Rakefile +6 -0
  243. data/examples/tcl/features/fibonnacci.feature +17 -0
  244. data/examples/tcl/features/step_definitions/fib_steps.rb +7 -0
  245. data/examples/tcl/features/support/env.rb +6 -0
  246. data/examples/tcl/src/fib.tcl +3 -0
  247. data/examples/test_unit/Rakefile +6 -0
  248. data/examples/test_unit/features/step_definitions/test_unit_steps.rb +23 -0
  249. data/examples/test_unit/features/test_unit.feature +9 -0
  250. data/examples/v8/Rakefile +6 -0
  251. data/examples/v8/features/fibonacci.feature +43 -0
  252. data/examples/v8/features/step_definitions/fib_steps.js +49 -0
  253. data/examples/v8/features/support/env.js +14 -0
  254. data/examples/v8/lib/fibonacci.js +19 -0
  255. data/examples/watir/.gitignore +2 -0
  256. data/examples/watir/README.textile +16 -0
  257. data/examples/watir/Rakefile +12 -0
  258. data/examples/watir/cucumber.yml +1 -0
  259. data/examples/watir/features/search.feature +12 -0
  260. data/examples/watir/features/step_definitions/search_steps.rb +26 -0
  261. data/examples/watir/features/support/env.rb +32 -0
  262. data/examples/watir/features/support/screenshots.rb +47 -0
  263. data/features/background.feature +498 -0
  264. data/features/bootstrap.feature +13 -0
  265. data/features/custom_formatter.feature +41 -0
  266. data/features/execute_with_tag_filter.feature +63 -0
  267. data/features/hooks.feature +59 -0
  268. data/features/iso-8859-1.feature +6 -0
  269. data/features/json_formatter.feature +248 -0
  270. data/features/stats_formatters.feature +70 -0
  271. data/features/step_definitions/cucumber-features/cucumber_ruby_mappings.rb +168 -0
  272. data/features/step_definitions/cucumber_steps.rb +23 -0
  273. data/features/step_definitions/iso-8859-1_steps.rb +24 -0
  274. data/features/support/env.rb +26 -0
  275. data/features/tagged_hooks.feature +217 -0
  276. data/features/transforms.feature +63 -0
  277. data/fixtures/json/features/background.feature +7 -0
  278. data/fixtures/json/features/embed.feature +4 -0
  279. data/fixtures/json/features/one_passing_one_failing.feature +11 -0
  280. data/fixtures/json/features/step_definitions/steps.rb +32 -0
  281. data/fixtures/json/features/tables.feature +13 -0
  282. data/fixtures/junit/features/one_passing_one_failing.feature +8 -0
  283. data/fixtures/junit/features/pending.feature +7 -0
  284. data/fixtures/junit/features/scenario_outline.feature +9 -0
  285. data/fixtures/junit/features/some_subdirectory/one_passing_one_failing.feature +8 -0
  286. data/fixtures/junit/features/step_definitions/steps.rb +11 -0
  287. data/fixtures/self_test/.gitignore +1 -0
  288. data/fixtures/self_test/README.textile +6 -0
  289. data/fixtures/self_test/Rakefile +6 -0
  290. data/fixtures/self_test/features/call_undefined_step_from_step_def.feature +7 -0
  291. data/fixtures/self_test/features/failing_expectation.feature +4 -0
  292. data/fixtures/self_test/features/lots_of_undefined.feature +8 -0
  293. data/fixtures/self_test/features/multiline_name.feature +27 -0
  294. data/fixtures/self_test/features/outline_sample.feature +15 -0
  295. data/fixtures/self_test/features/sample.feature +21 -0
  296. data/fixtures/self_test/features/search_sample.feature +32 -0
  297. data/fixtures/self_test/features/step_definitions/sample_steps.rb +84 -0
  298. data/fixtures/self_test/features/support/bubble_256x256.png +0 -0
  299. data/fixtures/self_test/features/support/env.rb +26 -0
  300. data/fixtures/self_test/features/tags_sample.feature +17 -0
  301. data/fixtures/self_test/features/tons_of_cukes.feature +52 -0
  302. data/fixtures/self_test/features/undefined_multiline_args.feature +12 -0
  303. data/fixtures/self_test/list-of-features.txt +1 -0
  304. data/fixtures/steps_library/features/step_definitions/steps_lib1.rb +8 -0
  305. data/fixtures/steps_library/features/step_definitions/steps_lib2.rb +8 -0
  306. data/fixtures/tickets/Rakefile +20 -0
  307. data/fixtures/tickets/features.html +138 -0
  308. data/fixtures/tickets/features/172.feature +28 -0
  309. data/fixtures/tickets/features/177/1.feature +28 -0
  310. data/fixtures/tickets/features/177/2.feature +20 -0
  311. data/fixtures/tickets/features/177/3.feature +18 -0
  312. data/fixtures/tickets/features/180.feature +7 -0
  313. data/fixtures/tickets/features/229/tagged_hooks.feature +8 -0
  314. data/fixtures/tickets/features/229/tagged_hooks.rb +14 -0
  315. data/fixtures/tickets/features/236.feature +13 -0
  316. data/fixtures/tickets/features/241.feature +12 -0
  317. data/fixtures/tickets/features/246.feature +4 -0
  318. data/fixtures/tickets/features/248.feature +11 -0
  319. data/fixtures/tickets/features/270/back.feature +14 -0
  320. data/fixtures/tickets/features/270/back.steps.rb +14 -0
  321. data/fixtures/tickets/features/272/hooks.feature +26 -0
  322. data/fixtures/tickets/features/272/hooks_steps.rb +53 -0
  323. data/fixtures/tickets/features/279/py_string_indent.feature +25 -0
  324. data/fixtures/tickets/features/279/py_string_indent.steps.rb +12 -0
  325. data/fixtures/tickets/features/279/wrong.feature_ +11 -0
  326. data/fixtures/tickets/features/301/filter_background_tagged_hooks.feature +6 -0
  327. data/fixtures/tickets/features/301/filter_background_tagged_hooks_steps.rb +12 -0
  328. data/fixtures/tickets/features/306/only_background.feature +4 -0
  329. data/fixtures/tickets/features/around_timeout.feature +6 -0
  330. data/fixtures/tickets/features/gherkin_67.feature +12 -0
  331. data/fixtures/tickets/features/gherkin_68.feature +4 -0
  332. data/fixtures/tickets/features/half_manual.feature +11 -0
  333. data/fixtures/tickets/features/lib/eatting_machine.rb +18 -0
  334. data/fixtures/tickets/features/lib/pantry.rb +20 -0
  335. data/fixtures/tickets/features/scenario_outline.feature +95 -0
  336. data/fixtures/tickets/features/step_definitons/246_steps.rb +3 -0
  337. data/fixtures/tickets/features/step_definitons/248_steps.rb +15 -0
  338. data/fixtures/tickets/features/step_definitons/around_timeout_steps.rb +9 -0
  339. data/fixtures/tickets/features/step_definitons/half_manual_steps.rb +11 -0
  340. data/fixtures/tickets/features/step_definitons/scenario_outline_steps.rb +42 -0
  341. data/fixtures/tickets/features/step_definitons/tickets_steps.rb +88 -0
  342. data/fixtures/tickets/features/table_diffing.feature +13 -0
  343. data/fixtures/tickets/features/tickets.feature +28 -0
  344. data/gem_tasks/contributors.rake +15 -0
  345. data/gem_tasks/cucumber.rake +21 -0
  346. data/gem_tasks/downloads.rb +7 -0
  347. data/gem_tasks/environment.rake +7 -0
  348. data/gem_tasks/examples.rake +11 -0
  349. data/gem_tasks/fix_cr_lf.rake +10 -0
  350. data/gem_tasks/flog.rake +4 -0
  351. data/gem_tasks/rspec.rake +8 -0
  352. data/gem_tasks/sass.rake +4 -0
  353. data/gem_tasks/stats +14 -0
  354. data/gem_tasks/versions.txt +74 -0
  355. data/gem_tasks/yard.rake +0 -0
  356. data/gem_tasks/yard/default/layout/html/bubble_32x32.png +0 -0
  357. data/gem_tasks/yard/default/layout/html/footer.erb +5 -0
  358. data/gem_tasks/yard/default/layout/html/index.erb +1 -0
  359. data/gem_tasks/yard/default/layout/html/layout.erb +25 -0
  360. data/gem_tasks/yard/default/layout/html/logo.erb +1 -0
  361. data/gem_tasks/yard/default/layout/html/setup.rb +4 -0
  362. data/legacy_features/announce.feature +152 -0
  363. data/legacy_features/api/list_step_defs_as_json.feature +50 -0
  364. data/legacy_features/api/run_cli_main_with_existing_runtime.feature +34 -0
  365. data/legacy_features/around_hooks.feature +232 -0
  366. data/legacy_features/bug_371.feature +32 -0
  367. data/legacy_features/bug_464.feature +16 -0
  368. data/legacy_features/bug_475.feature +42 -0
  369. data/legacy_features/bug_585_tab_indentation.feature +22 -0
  370. data/legacy_features/bug_600.feature +73 -0
  371. data/legacy_features/call_steps_from_stepdefs.feature +154 -0
  372. data/legacy_features/cucumber_cli.feature +591 -0
  373. data/legacy_features/cucumber_cli_outlines.feature +117 -0
  374. data/legacy_features/default_snippets.feature +42 -0
  375. data/legacy_features/diffing.feature +25 -0
  376. data/legacy_features/drb_server_integration.feature +174 -0
  377. data/legacy_features/exception_in_after_block.feature +127 -0
  378. data/legacy_features/exception_in_after_step_block.feature +104 -0
  379. data/legacy_features/exception_in_before_block.feature +98 -0
  380. data/legacy_features/exclude_files.feature +20 -0
  381. data/legacy_features/expand.feature +60 -0
  382. data/legacy_features/html_formatter.feature +8 -0
  383. data/legacy_features/html_formatter/a.html +561 -0
  384. data/legacy_features/junit_formatter.feature +164 -0
  385. data/legacy_features/language_from_header.feature +30 -0
  386. data/legacy_features/language_help.feature +77 -0
  387. data/legacy_features/listener_debugger_formatter.feature +42 -0
  388. data/legacy_features/multiline_names.feature +44 -0
  389. data/legacy_features/post_configuration_hook.feature +50 -0
  390. data/legacy_features/profiles.feature +126 -0
  391. data/legacy_features/rake_task.feature +152 -0
  392. data/legacy_features/report_called_undefined_steps.feature +34 -0
  393. data/legacy_features/rerun_formatter.feature +52 -0
  394. data/legacy_features/simplest.feature +11 -0
  395. data/legacy_features/snippet.feature +23 -0
  396. data/legacy_features/snippets_when_using_star_keyword.feature +36 -0
  397. data/legacy_features/step_definitions/cucumber_steps.rb +172 -0
  398. data/legacy_features/step_definitions/extra_steps.rb +2 -0
  399. data/legacy_features/step_definitions/simplest_steps.rb +3 -0
  400. data/legacy_features/step_definitions/wire_steps.rb +34 -0
  401. data/legacy_features/support/env.rb +157 -0
  402. data/legacy_features/support/env.rb.simplest +7 -0
  403. data/legacy_features/support/fake_wire_server.rb +77 -0
  404. data/legacy_features/table_diffing.feature +45 -0
  405. data/legacy_features/table_mapping.feature +34 -0
  406. data/legacy_features/transform.feature +245 -0
  407. data/legacy_features/unicode_table.feature +35 -0
  408. data/legacy_features/wire_protocol.feature +332 -0
  409. data/legacy_features/wire_protocol_erb.feature +57 -0
  410. data/legacy_features/wire_protocol_table_diffing.feature +119 -0
  411. data/legacy_features/wire_protocol_tags.feature +87 -0
  412. data/legacy_features/wire_protocol_timeouts.feature +63 -0
  413. data/legacy_features/work_in_progress.feature +156 -0
  414. data/lib/README.rdoc +12 -0
  415. data/lib/autotest/cucumber.rb +6 -0
  416. data/lib/autotest/cucumber_mixin.rb +135 -0
  417. data/lib/autotest/cucumber_rails.rb +6 -0
  418. data/lib/autotest/cucumber_rails_rspec.rb +6 -0
  419. data/lib/autotest/cucumber_rails_rspec2.rb +6 -0
  420. data/lib/autotest/cucumber_rspec.rb +6 -0
  421. data/lib/autotest/cucumber_rspec2.rb +6 -0
  422. data/lib/autotest/discover.rb +9 -0
  423. data/lib/cucumber.rb +27 -0
  424. data/lib/cucumber/ast.rb +30 -0
  425. data/lib/cucumber/ast/background.rb +101 -0
  426. data/lib/cucumber/ast/comment.rb +31 -0
  427. data/lib/cucumber/ast/doc_string.rb +80 -0
  428. data/lib/cucumber/ast/examples.rb +46 -0
  429. data/lib/cucumber/ast/feature.rb +106 -0
  430. data/lib/cucumber/ast/feature_element.rb +78 -0
  431. data/lib/cucumber/ast/features.rb +35 -0
  432. data/lib/cucumber/ast/names.rb +13 -0
  433. data/lib/cucumber/ast/outline_table.rb +187 -0
  434. data/lib/cucumber/ast/scenario.rb +119 -0
  435. data/lib/cucumber/ast/scenario_outline.rb +125 -0
  436. data/lib/cucumber/ast/step.rb +126 -0
  437. data/lib/cucumber/ast/step_collection.rb +76 -0
  438. data/lib/cucumber/ast/step_invocation.rb +206 -0
  439. data/lib/cucumber/ast/table.rb +689 -0
  440. data/lib/cucumber/ast/tags.rb +28 -0
  441. data/lib/cucumber/ast/tree_walker.rb +183 -0
  442. data/lib/cucumber/ast/visitor.rb +11 -0
  443. data/lib/cucumber/broadcaster.rb +13 -0
  444. data/lib/cucumber/cli/configuration.rb +209 -0
  445. data/lib/cucumber/cli/drb_client.rb +43 -0
  446. data/lib/cucumber/cli/main.rb +78 -0
  447. data/lib/cucumber/cli/options.rb +410 -0
  448. data/lib/cucumber/cli/profile_loader.rb +91 -0
  449. data/lib/cucumber/configuration.rb +49 -0
  450. data/lib/cucumber/constantize.rb +34 -0
  451. data/lib/cucumber/core_ext/disable_mini_and_test_unit_autorun.rb +25 -0
  452. data/lib/cucumber/core_ext/instance_exec.rb +98 -0
  453. data/lib/cucumber/core_ext/proc.rb +34 -0
  454. data/lib/cucumber/core_ext/string.rb +9 -0
  455. data/lib/cucumber/errors.rb +40 -0
  456. data/lib/cucumber/feature_file.rb +101 -0
  457. data/lib/cucumber/formatter/ansicolor.rb +160 -0
  458. data/lib/cucumber/formatter/console.rb +187 -0
  459. data/lib/cucumber/formatter/cucumber.css +279 -0
  460. data/lib/cucumber/formatter/cucumber.sass +247 -0
  461. data/lib/cucumber/formatter/debug.rb +33 -0
  462. data/lib/cucumber/formatter/duration.rb +13 -0
  463. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +83 -0
  464. data/lib/cucumber/formatter/gpretty.rb +24 -0
  465. data/lib/cucumber/formatter/html.rb +649 -0
  466. data/lib/cucumber/formatter/io.rb +31 -0
  467. data/lib/cucumber/formatter/jquery-min.js +154 -0
  468. data/lib/cucumber/formatter/json.rb +31 -0
  469. data/lib/cucumber/formatter/json_pretty.rb +13 -0
  470. data/lib/cucumber/formatter/junit.rb +155 -0
  471. data/lib/cucumber/formatter/ordered_xml_markup.rb +24 -0
  472. data/lib/cucumber/formatter/pdf.rb +244 -0
  473. data/lib/cucumber/formatter/pretty.rb +237 -0
  474. data/lib/cucumber/formatter/progress.rb +92 -0
  475. data/lib/cucumber/formatter/rerun.rb +68 -0
  476. data/lib/cucumber/formatter/stepdefs.rb +14 -0
  477. data/lib/cucumber/formatter/steps.rb +49 -0
  478. data/lib/cucumber/formatter/summary.rb +35 -0
  479. data/lib/cucumber/formatter/unicode.rb +79 -0
  480. data/lib/cucumber/formatter/usage.rb +127 -0
  481. data/lib/cucumber/js_support/js_dsl.js +57 -0
  482. data/lib/cucumber/js_support/js_language.rb +185 -0
  483. data/lib/cucumber/js_support/js_snippets.rb +27 -0
  484. data/lib/cucumber/language_support.rb +30 -0
  485. data/lib/cucumber/language_support/language_methods.rb +129 -0
  486. data/lib/cucumber/parser.rb +2 -0
  487. data/lib/cucumber/parser/gherkin_builder.rb +129 -0
  488. data/lib/cucumber/platform.rb +29 -0
  489. data/lib/cucumber/py_support/py_dsl.py +10 -0
  490. data/lib/cucumber/py_support/py_language.py +10 -0
  491. data/lib/cucumber/py_support/py_language.rb +84 -0
  492. data/lib/cucumber/rake/task.rb +225 -0
  493. data/lib/cucumber/rb_support/rb_dsl.rb +112 -0
  494. data/lib/cucumber/rb_support/rb_hook.rb +18 -0
  495. data/lib/cucumber/rb_support/rb_language.rb +195 -0
  496. data/lib/cucumber/rb_support/rb_step_definition.rb +82 -0
  497. data/lib/cucumber/rb_support/rb_transform.rb +54 -0
  498. data/lib/cucumber/rb_support/rb_world.rb +103 -0
  499. data/lib/cucumber/rb_support/regexp_argument_matcher.rb +21 -0
  500. data/lib/cucumber/rspec/disable_option_parser.rb +23 -0
  501. data/lib/cucumber/rspec/doubles.rb +16 -0
  502. data/lib/cucumber/runtime.rb +145 -0
  503. data/lib/cucumber/runtime/features_loader.rb +62 -0
  504. data/lib/cucumber/runtime/for_programming_languages.rb +67 -0
  505. data/lib/cucumber/runtime/results.rb +64 -0
  506. data/lib/cucumber/runtime/support_code.rb +203 -0
  507. data/lib/cucumber/runtime/user_interface.rb +81 -0
  508. data/lib/cucumber/step_argument.rb +9 -0
  509. data/lib/cucumber/step_definition_light.rb +20 -0
  510. data/lib/cucumber/step_definitions.rb +14 -0
  511. data/lib/cucumber/step_match.rb +115 -0
  512. data/lib/cucumber/step_mother.rb +10 -0
  513. data/lib/cucumber/wire_support/configuration.rb +31 -0
  514. data/lib/cucumber/wire_support/connection.rb +55 -0
  515. data/lib/cucumber/wire_support/request_handler.rb +32 -0
  516. data/lib/cucumber/wire_support/wire_exception.rb +32 -0
  517. data/lib/cucumber/wire_support/wire_language.rb +54 -0
  518. data/lib/cucumber/wire_support/wire_packet.rb +32 -0
  519. data/lib/cucumber/wire_support/wire_protocol.rb +44 -0
  520. data/lib/cucumber/wire_support/wire_protocol/requests.rb +123 -0
  521. data/lib/cucumber/wire_support/wire_step_definition.rb +26 -0
  522. data/spec/cucumber/ast/background_spec.rb +115 -0
  523. data/spec/cucumber/ast/doc_string_spec.rb +40 -0
  524. data/spec/cucumber/ast/feature_factory.rb +61 -0
  525. data/spec/cucumber/ast/feature_spec.rb +63 -0
  526. data/spec/cucumber/ast/outline_table_spec.rb +21 -0
  527. data/spec/cucumber/ast/scenario_outline_spec.rb +69 -0
  528. data/spec/cucumber/ast/step_spec.rb +66 -0
  529. data/spec/cucumber/ast/table_spec.rb +484 -0
  530. data/spec/cucumber/ast/tree_walker_spec.rb +11 -0
  531. data/spec/cucumber/broadcaster_spec.rb +15 -0
  532. data/spec/cucumber/cli/configuration_spec.rb +431 -0
  533. data/spec/cucumber/cli/drb_client_spec.rb +76 -0
  534. data/spec/cucumber/cli/main_spec.rb +137 -0
  535. data/spec/cucumber/cli/options_spec.rb +358 -0
  536. data/spec/cucumber/cli/profile_loader_spec.rb +35 -0
  537. data/spec/cucumber/configuration_spec.rb +23 -0
  538. data/spec/cucumber/core_ext/proc_spec.rb +68 -0
  539. data/spec/cucumber/formatter/ansicolor_spec.rb +31 -0
  540. data/spec/cucumber/formatter/duration_spec.rb +22 -0
  541. data/spec/cucumber/formatter/html_spec.rb +256 -0
  542. data/spec/cucumber/formatter/junit_spec.rb +125 -0
  543. data/spec/cucumber/formatter/progress_spec.rb +38 -0
  544. data/spec/cucumber/formatter/spec_helper.rb +52 -0
  545. data/spec/cucumber/rake/forked_spec.rb +62 -0
  546. data/spec/cucumber/rake/rcov_spec.rb +71 -0
  547. data/spec/cucumber/rb_support/rb_language_spec.rb +282 -0
  548. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +98 -0
  549. data/spec/cucumber/rb_support/rb_transform_spec.rb +21 -0
  550. data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +18 -0
  551. data/spec/cucumber/runtime/support_code_spec.rb +112 -0
  552. data/spec/cucumber/runtime_spec.rb +41 -0
  553. data/spec/cucumber/sell_cucumbers.feature +19 -0
  554. data/spec/cucumber/step_match_spec.rb +69 -0
  555. data/spec/cucumber/wire_support/configuration_spec.rb +51 -0
  556. data/spec/cucumber/wire_support/connection_spec.rb +46 -0
  557. data/spec/cucumber/wire_support/wire_exception_spec.rb +44 -0
  558. data/spec/cucumber/wire_support/wire_language_spec.rb +47 -0
  559. data/spec/cucumber/wire_support/wire_packet_spec.rb +40 -0
  560. data/spec/cucumber/wire_support/wire_step_definition_spec.rb +20 -0
  561. data/spec/cucumber/world/pending_spec.rb +46 -0
  562. data/spec/spec_helper.rb +22 -0
  563. metadata +1044 -0
@@ -0,0 +1,247 @@
1
+ /* cucumber.css is generated from cucumber.sass */
2
+ /* Regenerate with rake sass */
3
+
4
+ $step_left: 5px solid
5
+ $step_bottom: 1px solid
6
+
7
+ $failed: #fffbd3
8
+ $failed_border: #c20000
9
+ $failed_text: #c20000
10
+
11
+ $passed: #dbffb4
12
+ $passed_border: #65c400
13
+ $passed_text: #3d7700
14
+
15
+ $skipped: #e0ffff
16
+ $skipped_border: aqua
17
+ $skipped_text: #001111
18
+
19
+ $pending: #fcfb98
20
+ $pending_border: #faf834
21
+ $pending_text: #131313
22
+
23
+ $undefined: #fcfb98
24
+ $undefined_border: #faf834
25
+ $undefined_text: #131313
26
+
27
+ $message: #e0ffff
28
+ $message_border: aqua
29
+ $message_text: #001111
30
+
31
+ body
32
+ font-size: 0px
33
+ color: white
34
+ margin: 0px
35
+ padding: 0px
36
+
37
+ .cucumber,td,th
38
+ font: normal 11px "Lucida Grande", Helvetica, sans-serif
39
+ background: white
40
+ color: black
41
+ #cucumber-header
42
+ background: #65c400
43
+ color: white
44
+ height: 6em
45
+ #expand-collapse
46
+ p
47
+ float: right
48
+ margin: 0 0 0 10px
49
+ .scenario
50
+ h3
51
+ font-size: 11px
52
+ padding: 3px
53
+ margin: 0
54
+ background: #65c400
55
+ color: white
56
+ font-weight: bold
57
+ h1
58
+ margin: 0px 10px 0px 10px
59
+ padding: 10px
60
+ font-family: "Lucida Grande", Helvetica, sans-serif
61
+ font-size: 2em
62
+ position: absolute
63
+ h4
64
+ margin-bottom: 2px
65
+ div.feature
66
+ padding: 2px
67
+ margin: 0px 10px 5px 10px
68
+ div.examples
69
+ padding: 0em 0em 0em 1em
70
+ .stats
71
+ margin: 2em
72
+ .summary
73
+ ul.features
74
+ li
75
+ display: inline
76
+ .step_name
77
+ float: left
78
+ .step_file
79
+ text-align: right
80
+ color: #999999
81
+ a
82
+ color: #999999
83
+ .scenario_file
84
+ float: right
85
+ color: #999999
86
+ .tag
87
+ font-weight: bold
88
+ color: #246ac1
89
+ .backtrace
90
+ margin-top: 0
91
+ margin-bottom: 0
92
+ margin-left: 1em
93
+ color: black
94
+ a
95
+ text-decoration: none
96
+ color: #be5c00
97
+ &:hover
98
+ text-decoration: underline
99
+ &:visited
100
+ font-weight: normal
101
+ div.examples
102
+ margin: 5px 0px 5px 15px
103
+ color: black
104
+ .outline
105
+ table
106
+ margin: 0px 0px 5px 10px
107
+ table
108
+ border-collapse: collapse
109
+ td
110
+ padding: 3px 3px 3px 5px
111
+ td.failed, td.passed, td.skipped, td.pending, td.undefined
112
+ padding-left: 18px
113
+ padding-right: 10px
114
+ td.failed
115
+ border-left: $step_left $failed_border
116
+ border-bottom: $step_bottom $failed_border
117
+ background: $failed
118
+ color: $failed_text
119
+ td.passed
120
+ border-left: $step_left $passed_border
121
+ border-bottom: $step_bottom $passed_border
122
+ background: $passed
123
+ color: $passed_text
124
+ td.skipped
125
+ border-left: $step_left $skipped_border
126
+ border-bottom: $step_bottom $skipped_border
127
+ background: $skipped
128
+ color: $skipped_text
129
+ td.pending
130
+ border-left: $step_left $pending_border
131
+ border-bottom: $step_bottom $pending_border
132
+ background: $pending
133
+ color: $pending_text
134
+ td.undefined
135
+ border-left: $step_left $undefined_border
136
+ border-bottom: $step_bottom $undefined_border
137
+ background: $undefined
138
+ color: $undefined_text
139
+ td.message
140
+ border-left: $step_left $message_border
141
+ border-bottom: $step_bottom $message_border
142
+ background: $message
143
+ color: $message_text
144
+ ol
145
+ list-style: none
146
+ margin: 0px
147
+ padding: 0px
148
+ li.step
149
+ padding: 3px 3px 3px 18px
150
+ margin: 5px 0px 5px 5px
151
+ li
152
+ margin: 0em 0em 0em 1em
153
+ padding: 0em 0em 0em 0.2em
154
+ span.param
155
+ font-weight: bold
156
+ li.failed
157
+ border-left: $step_left $failed_border
158
+ border-bottom: $step_bottom $failed_border
159
+ background: $failed
160
+ color: $failed_text
161
+ li.passed
162
+ border-left: $step_left $passed_border
163
+ border-bottom: $step_bottom $passed_border
164
+ background: $passed
165
+ color: $passed_text
166
+ li.skipped
167
+ border-left: $step_left $skipped_border
168
+ border-bottom: $step_bottom $skipped_border
169
+ background: $skipped
170
+ color: $skipped_text
171
+ li.pending
172
+ border-left: $step_left $pending_border
173
+ border-bottom: $step_bottom $pending_border
174
+ background: $pending
175
+ color: $pending_text
176
+ li.undefined
177
+ border-left: $step_left $undefined_border
178
+ border-bottom: $step_bottom $undefined_border
179
+ background: $undefined
180
+ color: $undefined_text
181
+ li.message
182
+ border-left: $step_left $message_border
183
+ border-bottom: $step_bottom $message_border
184
+ background: $message
185
+ color: $message_text
186
+ margin-left: 10px
187
+ #summary
188
+ margin: 0px
189
+ padding: 5px 10px
190
+ text-align: right
191
+ top: 0px
192
+ right: 0px
193
+ float: right
194
+ p
195
+ margin: 0 0 0 2px
196
+ #totals
197
+ font-size: 1.2em
198
+
199
+ .ruby
200
+ font-size: 12px
201
+ font-family: monospace
202
+ color: white
203
+ background: black
204
+ padding: 0.1em 0 0.2em 0
205
+ .keyword
206
+ color: #ff6600
207
+ .constant
208
+ color: #339999
209
+ .attribute
210
+ color: white
211
+ .global
212
+ color: white
213
+ .module
214
+ color: white
215
+ .class
216
+ color: white
217
+ .string
218
+ color: #66ff00
219
+ .ident
220
+ color: white
221
+ .method
222
+ color: #ffcc00
223
+ .number
224
+ color: white
225
+ .char
226
+ color: white
227
+ .comment
228
+ color: #9933cc
229
+ .symbol
230
+ color: white
231
+ .regex
232
+ color: #44b4cc
233
+ .punct
234
+ color: white
235
+ .escape
236
+ color: white
237
+ .interp
238
+ color: white
239
+ .expr
240
+ color: white
241
+ .offending
242
+ background: #333333
243
+ .linenum
244
+ width: 75px
245
+ padding: 0.1em 1em 0.2em 0
246
+ color: black
247
+ background: #fffbd3
@@ -0,0 +1,33 @@
1
+ require 'cucumber/formatter/progress'
2
+ require 'cucumber/step_definition_light'
3
+
4
+ module Cucumber
5
+ module Formatter
6
+ class Debug
7
+ def initialize(step_mother, io, options)
8
+ @io = io
9
+ @indent = 0
10
+ end
11
+
12
+ def respond_to?(*args)
13
+ true
14
+ end
15
+
16
+ def method_missing(name, *args)
17
+ @indent -= 2 if name.to_s =~ /^after/
18
+ print(name)
19
+ @indent += 2 if name.to_s =~ /^before/
20
+ end
21
+
22
+ private
23
+
24
+ def print(text)
25
+ @io.puts "#{indent}#{text}"
26
+ end
27
+
28
+ def indent
29
+ (' ' * @indent)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ module Cucumber
2
+ module Formatter
3
+ module Duration
4
+ # Helper method for formatters that need to
5
+ # format a duration in seconds to the UNIX
6
+ # <tt>time</tt> format.
7
+ def format_duration(seconds)
8
+ m, s = seconds.divmod(60)
9
+ "#{m}m#{'%.3f' % s}s"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,83 @@
1
+ require 'cucumber/formatter/io'
2
+ require 'gherkin/formatter/argument'
3
+
4
+ module Cucumber
5
+ module Formatter
6
+ # Adapts Cucumber formatter events to Gherkin formatter events
7
+ # This class will disappear when Cucumber is based on Gherkin's model.
8
+ class GherkinFormatterAdapter
9
+ def initialize(gherkin_formatter, print_emtpy_match)
10
+ @gf = gherkin_formatter
11
+ @print_emtpy_match = print_emtpy_match
12
+ end
13
+
14
+ def before_feature(feature)
15
+ @gf.uri(feature.file)
16
+ @gf.feature(feature.gherkin_statement)
17
+ end
18
+
19
+ def before_background(background)
20
+ @outline = false
21
+ @gf.background(background.gherkin_statement)
22
+ end
23
+
24
+ def before_feature_element(feature_element)
25
+ case(feature_element)
26
+ when Ast::Scenario
27
+ @outline = false
28
+ @gf.scenario(feature_element.gherkin_statement)
29
+ when Ast::ScenarioOutline
30
+ @outline = true
31
+ @gf.scenario_outline(feature_element.gherkin_statement)
32
+ else
33
+ raise "Bad type: #{feature_element.class}"
34
+ end
35
+ end
36
+
37
+ def before_step(step)
38
+ @gf.step(step.gherkin_statement)
39
+ if @print_emtpy_match
40
+ if(@outline)
41
+ match = Gherkin::Formatter::Model::Match.new(step.gherkin_statement.outline_args, nil)
42
+ else
43
+ match = Gherkin::Formatter::Model::Match.new([], nil)
44
+ end
45
+ @gf.match(match)
46
+ end
47
+ end
48
+
49
+ def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
50
+ arguments = step_match.step_arguments.map{|a| Gherkin::Formatter::Argument.new(a.byte_offset, a.val)}
51
+ location = step_match.file_colon_line
52
+ match = Gherkin::Formatter::Model::Match.new(arguments, location)
53
+ if @print_emtpy_match
54
+ # Trick the formatter to believe that's what was printed previously so we get arg highlights on #result
55
+ @gf.instance_variable_set('@match', match)
56
+ else
57
+ @gf.match(match)
58
+ end
59
+
60
+ error_message = exception ? "#{exception.message} (#{exception.class})\n#{exception.backtrace.join("\n")}" : nil
61
+ unless @outline
62
+ @gf.result(Gherkin::Formatter::Model::Result.new(status, nil, error_message))
63
+ end
64
+ end
65
+
66
+ def before_examples(examples)
67
+ @gf.examples(examples.gherkin_statement)
68
+ end
69
+
70
+ def after_feature(feature)
71
+ @gf.eof
72
+ end
73
+
74
+ def embed(file, mime_type, label)
75
+ data = File.read(file)
76
+ if defined?(JRUBY_VERSION)
77
+ data = data.to_java_bytes
78
+ end
79
+ @gf.embedding(mime_type, data)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,24 @@
1
+ require 'cucumber/formatter/gherkin_formatter_adapter'
2
+ require 'cucumber/formatter/io'
3
+ require 'gherkin/formatter/argument'
4
+ require 'gherkin/formatter/pretty_formatter'
5
+
6
+ module Cucumber
7
+ module Formatter
8
+ # The formatter used for <tt>--format gpretty</tt>
9
+ class Gpretty < GherkinFormatterAdapter
10
+ include Io
11
+
12
+ def initialize(step_mother, io, options)
13
+ @io = ensure_io(io, "json")
14
+ super(Gherkin::Formatter::PrettyFormatter.new(@io, false), true)
15
+ end
16
+
17
+ def after_feature(feature)
18
+ super
19
+ @io.puts
20
+ end
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,649 @@
1
+ require 'erb'
2
+ require 'cucumber/formatter/ordered_xml_markup'
3
+ require 'cucumber/formatter/duration'
4
+ require 'cucumber/formatter/io'
5
+
6
+ module Cucumber
7
+ module Formatter
8
+ class Html
9
+ include ERB::Util # for the #h method
10
+ include Duration
11
+ include Io
12
+
13
+ def initialize(step_mother, path_or_io, options)
14
+ @io = ensure_io(path_or_io, "html")
15
+ @step_mother = step_mother
16
+ @options = options
17
+ @buffer = {}
18
+ @builder = create_builder(@io)
19
+ @feature_number = 0
20
+ @scenario_number = 0
21
+ @step_number = 0
22
+ @header_red = nil
23
+ @delayed_messages = []
24
+ @img_id = 0
25
+ end
26
+
27
+ def embed(src, mime_type, label)
28
+ case(mime_type)
29
+ when /^image\/(png|gif|jpg|jpeg)/
30
+ embed_image(src, label)
31
+ end
32
+ end
33
+
34
+ def embed_image(src, label)
35
+ id = "img_#{@img_id}"
36
+ @img_id += 1
37
+ @builder.span(:class => 'embed') do |pre|
38
+ pre << %{<a href="" onclick="img=document.getElementById('#{id}'); img.style.display = (img.style.display == 'none' ? 'block' : 'none');return false">#{label}</a><br>&nbsp;
39
+ <img id="#{id}" style="display: none" src="#{src}"/>}
40
+ end
41
+ end
42
+
43
+
44
+ def before_features(features)
45
+ @step_count = get_step_count(features)
46
+
47
+ # <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
48
+ @builder.declare!(
49
+ :DOCTYPE,
50
+ :html,
51
+ :PUBLIC,
52
+ '-//W3C//DTD XHTML 1.0 Strict//EN',
53
+ 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'
54
+ )
55
+
56
+ @builder << '<html xmlns ="http://www.w3.org/1999/xhtml">'
57
+ @builder.head do
58
+ @builder.meta(:content => 'text/html;charset=utf-8')
59
+ @builder.title 'Cucumber'
60
+ inline_css
61
+ inline_js
62
+ end
63
+ @builder << '<body>'
64
+ @builder << "<!-- Step count #{@step_count}-->"
65
+ @builder << '<div class="cucumber">'
66
+ @builder.div(:id => 'cucumber-header') do
67
+ @builder.div(:id => 'label') do
68
+ @builder.h1('Cucumber Features')
69
+ end
70
+ @builder.div(:id => 'summary') do
71
+ @builder.p('',:id => 'totals')
72
+ @builder.p('',:id => 'duration')
73
+ @builder.div(:id => 'expand-collapse') do
74
+ @builder.p('Expand All', :id => 'expander')
75
+ @builder.p('Collapse All', :id => 'collapser')
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ def after_features(features)
82
+ print_stats(features)
83
+ @builder << '</div>'
84
+ @builder << '</body>'
85
+ @builder << '</html>'
86
+ end
87
+
88
+ def before_feature(feature)
89
+ @exceptions = []
90
+ @builder << '<div class="feature">'
91
+ end
92
+
93
+ def after_feature(feature)
94
+ @builder << '</div>'
95
+ end
96
+
97
+ def before_comment(comment)
98
+ @builder << '<pre class="comment">'
99
+ end
100
+
101
+ def after_comment(comment)
102
+ @builder << '</pre>'
103
+ end
104
+
105
+ def comment_line(comment_line)
106
+ @builder.text!(comment_line)
107
+ @builder.br
108
+ end
109
+
110
+ def after_tags(tags)
111
+ @tag_spacer = nil
112
+ end
113
+
114
+ def tag_name(tag_name)
115
+ @builder.text!(@tag_spacer) if @tag_spacer
116
+ @tag_spacer = ' '
117
+ @builder.span(tag_name, :class => 'tag')
118
+ end
119
+
120
+ def feature_name(keyword, name)
121
+ lines = name.split(/\r?\n/)
122
+ return if lines.empty?
123
+ @builder.h2 do |h2|
124
+ @builder.span(keyword + ': ' + lines[0], :class => 'val')
125
+ end
126
+ @builder.p(:class => 'narrative') do
127
+ lines[1..-1].each do |line|
128
+ @builder.text!(line.strip)
129
+ @builder.br
130
+ end
131
+ end
132
+ end
133
+
134
+ def before_background(background)
135
+ @in_background = true
136
+ @builder << '<div class="background">'
137
+ end
138
+
139
+ def after_background(background)
140
+ @in_background = nil
141
+ @builder << '</div>'
142
+ end
143
+
144
+ def background_name(keyword, name, file_colon_line, source_indent)
145
+ @listing_background = true
146
+ @builder.h3 do |h3|
147
+ @builder.span(keyword, :class => 'keyword')
148
+ @builder.text!(' ')
149
+ @builder.span(name, :class => 'val')
150
+ end
151
+ end
152
+
153
+ def before_feature_element(feature_element)
154
+ @scenario_number+=1
155
+ @scenario_red = false
156
+ css_class = {
157
+ Ast::Scenario => 'scenario',
158
+ Ast::ScenarioOutline => 'scenario outline'
159
+ }[feature_element.class]
160
+ @builder << "<div class='#{css_class}'>"
161
+ end
162
+
163
+ def after_feature_element(feature_element)
164
+ @builder << '</div>'
165
+ @open_step_list = true
166
+ end
167
+
168
+ def scenario_name(keyword, name, file_colon_line, source_indent)
169
+ @builder.span(:class => 'scenario_file') do
170
+ @builder << file_colon_line
171
+ end
172
+ @listing_background = false
173
+ @builder.h3(:id => "scenario_#{@scenario_number}") do
174
+ @builder.span(keyword + ':', :class => 'keyword')
175
+ @builder.text!(' ')
176
+ @builder.span(name, :class => 'val')
177
+ end
178
+ end
179
+
180
+ def before_outline_table(outline_table)
181
+ @outline_row = 0
182
+ @builder << '<table>'
183
+ end
184
+
185
+ def after_outline_table(outline_table)
186
+ @builder << '</table>'
187
+ @outline_row = nil
188
+ end
189
+
190
+ def before_examples(examples)
191
+ @builder << '<div class="examples">'
192
+ end
193
+
194
+ def after_examples(examples)
195
+ @builder << '</div>'
196
+ end
197
+
198
+ def examples_name(keyword, name)
199
+ @builder.h4 do
200
+ @builder.span(keyword, :class => 'keyword')
201
+ @builder.text!(' ')
202
+ @builder.span(name, :class => 'val')
203
+ end
204
+ end
205
+
206
+ def before_steps(steps)
207
+ @builder << '<ol>'
208
+ end
209
+
210
+ def after_steps(steps)
211
+ @builder << '</ol>'
212
+ end
213
+
214
+ def before_step(step)
215
+ @step_id = step.dom_id
216
+ @step_number += 1
217
+ @step = step
218
+ end
219
+
220
+ def after_step(step)
221
+ move_progress
222
+ end
223
+
224
+ def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
225
+ @step_match = step_match
226
+ @hide_this_step = false
227
+ if exception
228
+ if @exceptions.include?(exception)
229
+ @hide_this_step = true
230
+ return
231
+ end
232
+ @exceptions << exception
233
+ end
234
+ if status != :failed && @in_background ^ background
235
+ @hide_this_step = true
236
+ return
237
+ end
238
+ @status = status
239
+ return if @hide_this_step
240
+ set_scenario_color(status)
241
+ @builder << "<li id='#{@step_id}' class='step #{status}'>"
242
+ end
243
+
244
+ def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
245
+ return if @hide_this_step
246
+ # print snippet for undefined steps
247
+ if status == :undefined
248
+ step_multiline_class = @step.multiline_arg ? @step.multiline_arg.class : nil
249
+ @builder.pre do |pre|
250
+ pre << @step_mother.snippet_text(@step.actual_keyword,step_match.instance_variable_get("@name") || '',step_multiline_class)
251
+ end
252
+ end
253
+ @builder << '</li>'
254
+ print_messages
255
+ end
256
+
257
+ def step_name(keyword, step_match, status, source_indent, background)
258
+ @step_matches ||= []
259
+ background_in_scenario = background && !@listing_background
260
+ @skip_step = @step_matches.index(step_match) || background_in_scenario
261
+ @step_matches << step_match
262
+
263
+ unless @skip_step
264
+ build_step(keyword, step_match, status)
265
+ end
266
+ end
267
+
268
+ def exception(exception, status)
269
+ build_exception_detail(exception)
270
+ end
271
+
272
+ def extra_failure_content(file_colon_line)
273
+ @snippet_extractor ||= SnippetExtractor.new
274
+ "<pre class=\"ruby\"><code>#{@snippet_extractor.snippet(file_colon_line)}</code></pre>"
275
+ end
276
+
277
+ def before_multiline_arg(multiline_arg)
278
+ return if @hide_this_step || @skip_step
279
+ if Ast::Table === multiline_arg
280
+ @builder << '<table>'
281
+ end
282
+ end
283
+
284
+ def after_multiline_arg(multiline_arg)
285
+ return if @hide_this_step || @skip_step
286
+ if Ast::Table === multiline_arg
287
+ @builder << '</table>'
288
+ end
289
+ end
290
+
291
+ def doc_string(string)
292
+ return if @hide_this_step
293
+ @builder.pre(:class => 'val') do |pre|
294
+ @builder << h(string.gsub("\n", '&#x000A;'))
295
+ end
296
+ end
297
+
298
+
299
+ def before_table_row(table_row)
300
+ @row_id = table_row.dom_id
301
+ @col_index = 0
302
+ return if @hide_this_step
303
+ @builder << "<tr class='step' id='#{@row_id}'>"
304
+ end
305
+
306
+ def after_table_row(table_row)
307
+ return if @hide_this_step
308
+ print_table_row_messages
309
+ @builder << '</tr>'
310
+ if table_row.exception
311
+ @builder.tr do
312
+ @builder.td(:colspan => @col_index.to_s, :class => 'failed') do
313
+ @builder.pre do |pre|
314
+ pre << format_exception(table_row.exception)
315
+ end
316
+ end
317
+ end
318
+ set_scenario_color_failed
319
+ end
320
+ if @outline_row
321
+ @outline_row += 1
322
+ end
323
+ @step_number += 1
324
+ move_progress
325
+ end
326
+
327
+ def table_cell_value(value, status)
328
+ return if @hide_this_step
329
+
330
+ @cell_type = @outline_row == 0 ? :th : :td
331
+ attributes = {:id => "#{@row_id}_#{@col_index}", :class => 'step'}
332
+ attributes[:class] += " #{status}" if status
333
+ build_cell(@cell_type, value, attributes)
334
+ set_scenario_color(status)
335
+ @col_index += 1
336
+ end
337
+
338
+ def puts(message)
339
+ @delayed_messages << message
340
+ #@builder.pre(message, :class => 'message')
341
+ end
342
+
343
+ def print_messages
344
+ return if @delayed_messages.empty?
345
+
346
+ #@builder.ol do
347
+ @delayed_messages.each do |ann|
348
+ @builder.li(:class => 'step message') do
349
+ @builder << ann
350
+ end
351
+ end
352
+ #end
353
+ empty_messages
354
+ end
355
+
356
+ def print_table_row_messages
357
+ return if @delayed_messages.empty?
358
+
359
+ @builder.td(:class => 'message') do
360
+ @builder << @delayed_messages.join(", ")
361
+ end
362
+ empty_messages
363
+ end
364
+
365
+ def empty_messages
366
+ @delayed_messages = []
367
+ end
368
+
369
+ protected
370
+
371
+ def build_exception_detail(exception)
372
+ backtrace = Array.new
373
+ @builder.div(:class => 'message') do
374
+ message = exception.message
375
+ if defined?(RAILS_ROOT) && message.include?('Exception caught')
376
+ matches = message.match(/Showing <i>(.+)<\/i>(?:.+) #(\d+)/)
377
+ backtrace += ["#{RAILS_ROOT}/#{matches[1]}:#{matches[2]}"] if matches
378
+ message = message.match(/<code>([^(\/)]+)<\//m)[1]
379
+ end
380
+ @builder.pre do
381
+ @builder.text!(message)
382
+ end
383
+ end
384
+ @builder.div(:class => 'backtrace') do
385
+ @builder.pre do
386
+ backtrace = exception.backtrace
387
+ backtrace.delete_if { |x| x =~ /\/gems\/(cucumber|rspec)/ }
388
+ @builder << backtrace_line(backtrace.join("\n"))
389
+ end
390
+ end
391
+ extra = extra_failure_content(backtrace)
392
+ @builder << extra unless extra == ""
393
+ end
394
+
395
+ def set_scenario_color(status)
396
+ if status == :undefined or status == :pending
397
+ set_scenario_color_pending
398
+ end
399
+ if status == :failed
400
+ set_scenario_color_failed
401
+ end
402
+ end
403
+
404
+ def set_scenario_color_failed
405
+ @builder.script do
406
+ @builder.text!("makeRed('cucumber-header');") unless @header_red
407
+ @header_red = true
408
+ @builder.text!("makeRed('scenario_#{@scenario_number}');") unless @scenario_red
409
+ @scenario_red = true
410
+ end
411
+ end
412
+
413
+ def set_scenario_color_pending
414
+ @builder.script do
415
+ @builder.text!("makeYellow('cucumber-header');") unless @header_red
416
+ @builder.text!("makeYellow('scenario_#{@scenario_number}');") unless @scenario_red
417
+ end
418
+ end
419
+
420
+ def get_step_count(features)
421
+ count = 0
422
+ features = features.instance_variable_get("@features")
423
+ features.each do |feature|
424
+ #get background steps
425
+ if feature.instance_variable_get("@background")
426
+ background = feature.instance_variable_get("@background")
427
+ background.init
428
+ background_steps = background.instance_variable_get("@steps").instance_variable_get("@steps")
429
+ count += background_steps.size
430
+ end
431
+ #get scenarios
432
+ feature.instance_variable_get("@feature_elements").each do |scenario|
433
+ scenario.init
434
+ #get steps
435
+ steps = scenario.instance_variable_get("@steps").instance_variable_get("@steps")
436
+ count += steps.size
437
+
438
+ #get example table
439
+ examples = scenario.instance_variable_get("@examples_array")
440
+ unless examples.nil?
441
+ examples.each do |example|
442
+ example_matrix = example.instance_variable_get("@outline_table").instance_variable_get("@cell_matrix")
443
+ count += example_matrix.size
444
+ end
445
+ end
446
+
447
+ #get multiline step tables
448
+ steps.each do |step|
449
+ multi_arg = step.instance_variable_get("@multiline_arg")
450
+ next if multi_arg.nil?
451
+ matrix = multi_arg.instance_variable_get("@cell_matrix")
452
+ count += matrix.size unless matrix.nil?
453
+ end
454
+ end
455
+ end
456
+ return count
457
+ end
458
+
459
+ def build_step(keyword, step_match, status)
460
+ step_name = step_match.format_args(lambda{|param| %{<span class="param">#{param}</span>}})
461
+ @builder.div(:class => 'step_name') do |div|
462
+ @builder.span(keyword, :class => 'keyword')
463
+ @builder.span(:class => 'step val') do |name|
464
+ name << h(step_name).gsub(/&lt;span class=&quot;(.*?)&quot;&gt;/, '<span class="\1">').gsub(/&lt;\/span&gt;/, '</span>')
465
+ end
466
+ end
467
+
468
+ step_file = step_match.file_colon_line
469
+ step_file.gsub(/^([^:]*\.rb):(\d*)/) do
470
+ if ENV['TM_PROJECT_DIRECTORY']
471
+ step_file = "<a href=\"txmt://open?url=file://#{File.expand_path($1)}&line=#{$2}\">#{$1}:#{$2}</a> "
472
+ end
473
+ end
474
+
475
+ @builder.div(:class => 'step_file') do |div|
476
+ @builder.span do
477
+ @builder << step_file
478
+ end
479
+ end
480
+ end
481
+
482
+ def build_cell(cell_type, value, attributes)
483
+ @builder.__send__(cell_type, attributes) do
484
+ @builder.div do
485
+ @builder.span(value,:class => 'step param')
486
+ end
487
+ end
488
+ end
489
+
490
+ def inline_css
491
+ @builder.style(:type => 'text/css') do
492
+ @builder << File.read(File.dirname(__FILE__) + '/cucumber.css')
493
+ end
494
+ end
495
+
496
+ def inline_js
497
+ @builder.script(:type => 'text/javascript') do
498
+ @builder << inline_jquery
499
+ @builder << inline_js_content
500
+ end
501
+ end
502
+
503
+ def inline_jquery
504
+ File.read(File.dirname(__FILE__) + '/jquery-min.js')
505
+ end
506
+
507
+ def inline_js_content
508
+ <<-EOF
509
+
510
+ SCENARIOS = "h3[id^='scenario_']";
511
+
512
+ $(document).ready(function() {
513
+ $(SCENARIOS).css('cursor', 'pointer');
514
+ $(SCENARIOS).click(function() {
515
+ $(this).siblings().toggle(250);
516
+ });
517
+
518
+ $("#collapser").css('cursor', 'pointer');
519
+ $("#collapser").click(function() {
520
+ $(SCENARIOS).siblings().hide();
521
+ });
522
+
523
+ $("#expander").css('cursor', 'pointer');
524
+ $("#expander").click(function() {
525
+ $(SCENARIOS).siblings().show();
526
+ });
527
+ })
528
+
529
+ function moveProgressBar(percentDone) {
530
+ $("cucumber-header").css('width', percentDone +"%");
531
+ }
532
+ function makeRed(element_id) {
533
+ $('#'+element_id).css('background', '#C40D0D');
534
+ $('#'+element_id).css('color', '#FFFFFF');
535
+ }
536
+ function makeYellow(element_id) {
537
+ $('#'+element_id).css('background', '#FAF834');
538
+ $('#'+element_id).css('color', '#000000');
539
+ }
540
+
541
+ EOF
542
+ end
543
+
544
+ def move_progress
545
+ @builder << " <script type=\"text/javascript\">moveProgressBar('#{percent_done}');</script>"
546
+ end
547
+
548
+ def percent_done
549
+ result = 100.0
550
+ if @step_count != 0
551
+ result = ((@step_number).to_f / @step_count.to_f * 1000).to_i / 10.0
552
+ end
553
+ result
554
+ end
555
+
556
+ def format_exception(exception)
557
+ (["#{exception.message}"] + exception.backtrace).join("\n")
558
+ end
559
+
560
+ def backtrace_line(line)
561
+ line.gsub(/\A([^:]*\.(?:rb|feature|haml)):(\d*).*\z/) do
562
+ if ENV['TM_PROJECT_DIRECTORY']
563
+ "<a href=\"txmt://open?url=file://#{File.expand_path($1)}&line=#{$2}\">#{$1}:#{$2}</a> "
564
+ else
565
+ line
566
+ end
567
+ end
568
+ end
569
+
570
+ def print_stats(features)
571
+ @builder << "<script type=\"text/javascript\">document.getElementById('duration').innerHTML = \"Finished in <strong>#{format_duration(features.duration)} seconds</strong>\";</script>"
572
+ @builder << "<script type=\"text/javascript\">document.getElementById('totals').innerHTML = \"#{print_stat_string(features)}\";</script>"
573
+ end
574
+
575
+ def print_stat_string(features)
576
+ string = String.new
577
+ string << dump_count(@step_mother.scenarios.length, "scenario")
578
+ scenario_count = print_status_counts{|status| @step_mother.scenarios(status)}
579
+ string << scenario_count if scenario_count
580
+ string << "<br />"
581
+ string << dump_count(@step_mother.steps.length, "step")
582
+ step_count = print_status_counts{|status| @step_mother.steps(status)}
583
+ string << step_count if step_count
584
+ end
585
+
586
+ def print_status_counts
587
+ counts = [:failed, :skipped, :undefined, :pending, :passed].map do |status|
588
+ elements = yield status
589
+ elements.any? ? "#{elements.length} #{status.to_s}" : nil
590
+ end.compact
591
+ return " (#{counts.join(', ')})" if counts.any?
592
+ end
593
+
594
+ def dump_count(count, what, state=nil)
595
+ [count, state, "#{what}#{count == 1 ? '' : 's'}"].compact.join(" ")
596
+ end
597
+
598
+ def create_builder(io)
599
+ OrderedXmlMarkup.new(:target => io, :indent => 0)
600
+ end
601
+
602
+ class SnippetExtractor #:nodoc:
603
+ class NullConverter; def convert(code, pre); code; end; end #:nodoc:
604
+ begin; require 'syntax/convertors/html'; @@converter = Syntax::Convertors::HTML.for_syntax "ruby"; rescue LoadError => e; @@converter = NullConverter.new; end
605
+
606
+ def snippet(error)
607
+ raw_code, line = snippet_for(error[0])
608
+ highlighted = @@converter.convert(raw_code, false)
609
+ highlighted << "\n<span class=\"comment\"># gem install syntax to get syntax highlighting</span>" if @@converter.is_a?(NullConverter)
610
+ post_process(highlighted, line)
611
+ end
612
+
613
+ def snippet_for(error_line)
614
+ if error_line =~ /(.*):(\d+)/
615
+ file = $1
616
+ line = $2.to_i
617
+ [lines_around(file, line), line]
618
+ else
619
+ ["# Couldn't get snippet for #{error_line}", 1]
620
+ end
621
+ end
622
+
623
+ def lines_around(file, line)
624
+ if File.file?(file)
625
+ lines = File.open(file).read.split("\n")
626
+ min = [0, line-3].max
627
+ max = [line+1, lines.length-1].min
628
+ selected_lines = []
629
+ selected_lines.join("\n")
630
+ lines[min..max].join("\n")
631
+ else
632
+ "# Couldn't get snippet for #{file}"
633
+ end
634
+ end
635
+
636
+ def post_process(highlighted, offending_line)
637
+ new_lines = []
638
+ highlighted.split("\n").each_with_index do |line, i|
639
+ new_line = "<span class=\"linenum\">#{offending_line+i-2}</span>#{line}"
640
+ new_line = "<span class=\"offending\">#{new_line}</span>" if i == 2
641
+ new_lines << new_line
642
+ end
643
+ new_lines.join("\n")
644
+ end
645
+
646
+ end
647
+ end
648
+ end
649
+ end