cucumber 3.0.0.pre.1 → 3.0.0.pre.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (316) hide show
  1. checksums.yaml +4 -4
  2. data/.cucumberproignore +6 -0
  3. data/.rubocop.yml +13 -0
  4. data/.rubocop_todo.yml +1075 -0
  5. data/.travis.yml +42 -8
  6. data/CONTRIBUTING.md +8 -1
  7. data/Gemfile +16 -10
  8. data/History.md +96 -36
  9. data/README.md +12 -3
  10. data/Rakefile +12 -2
  11. data/appveyor.yml +26 -0
  12. data/cucumber.gemspec +15 -10
  13. data/cucumber.yml +9 -10
  14. data/examples/i18n/Rakefile +1 -1
  15. data/examples/i18n/ar/features/step_definitions/calculator_steps.rb +2 -2
  16. data/examples/i18n/ar/lib/calculator.rb +2 -2
  17. data/examples/i18n/bg/features/step_definitions/calculator_steps.rb +6 -6
  18. data/examples/i18n/ca/features/step_definitions/calculator_steps.rb +4 -4
  19. data/examples/i18n/ca/lib/calculadora.rb +2 -2
  20. data/examples/i18n/cs/features/step_definitions/calculator_steps.rb +4 -4
  21. data/examples/i18n/cs/lib/calculator.rb +3 -3
  22. data/examples/i18n/da/features/step_definitions/lommeregner_steps.rb +4 -4
  23. data/examples/i18n/da/lib/lommeregner.rb +2 -2
  24. data/examples/i18n/de/features/step_definitions/calculator_steps.rb +4 -4
  25. data/examples/i18n/de/lib/calculator.rb +2 -2
  26. data/examples/i18n/el/features/step_definitions/calculator_steps.rb +5 -5
  27. data/examples/i18n/el/lib/calculator.rb +2 -2
  28. data/examples/i18n/en-lol/features/step_definitions/cucumbrz_steps.rb +4 -4
  29. data/examples/i18n/en-lol/lib/basket.rb +2 -2
  30. data/examples/i18n/en-lol/lib/belly.rb +2 -2
  31. data/examples/i18n/en/features/step_definitions/calculator_steps.rb +4 -4
  32. data/examples/i18n/en/lib/calculator.rb +2 -2
  33. data/examples/i18n/eo/features/step_definitions/calculator_steps.rb +4 -4
  34. data/examples/i18n/eo/lib/calculator.rb +2 -2
  35. data/examples/i18n/es/features/step_definitions/calculador_steps.rb +5 -5
  36. data/examples/i18n/es/lib/calculador.rb +2 -2
  37. data/examples/i18n/et/features/step_definitions/kalkulaator_steps.rb +4 -4
  38. data/examples/i18n/et/lib/kalkulaator.rb +3 -3
  39. data/examples/i18n/fi/features/step_definitions/laskin_steps.rb +3 -3
  40. data/examples/i18n/fi/lib/laskin.rb +1 -1
  41. data/examples/i18n/fr/features/step_definitions/calculatrice_steps.rb +8 -8
  42. data/examples/i18n/fr/features/support/env.rb +1 -1
  43. data/examples/i18n/fr/lib/calculatrice.rb +2 -2
  44. data/examples/i18n/he/features/step_definitions/calculator_steps.rb +4 -4
  45. data/examples/i18n/he/lib/calculator.rb +1 -1
  46. data/examples/i18n/hi/features/step_definitions/calculator_steps.rb +3 -3
  47. data/examples/i18n/hi/lib/calculator.rb +1 -1
  48. data/examples/i18n/ht/features/step_definitions/kalkilatris_steps.rb +4 -4
  49. data/examples/i18n/ht/lib/kalkilatris.rb +2 -2
  50. data/examples/i18n/hu/features/step_definitions/calculator_steps.rb +4 -4
  51. data/examples/i18n/hu/lib/calculator.rb +1 -1
  52. data/examples/i18n/id/features/step_definitions/calculator_steps.rb +4 -4
  53. data/examples/i18n/id/lib/calculator.rb +2 -2
  54. data/examples/i18n/it/features/step_definitions/calcolatrice_steps.rb +4 -4
  55. data/examples/i18n/it/lib/calcolatrice.rb +3 -3
  56. data/examples/i18n/ja/features/step_definitions/calculator_steps.rb +3 -3
  57. data/examples/i18n/ja/features/support/env.rb +1 -1
  58. data/examples/i18n/ja/lib/calculator.rb +2 -2
  59. data/examples/i18n/ko/features/step_definitions/calculator_steps.rb +4 -4
  60. data/examples/i18n/ko/lib/calculator.rb +2 -2
  61. data/examples/i18n/lt/features/step_definitions/calculator_steps.rb +4 -4
  62. data/examples/i18n/lt/lib/calculator.rb +2 -2
  63. data/examples/i18n/lv/features/step_definitions/calculator_steps.rb +4 -4
  64. data/examples/i18n/lv/lib/calculator.rb +2 -2
  65. data/examples/i18n/no/features/step_definitions/kalkulator_steps.rb +3 -3
  66. data/examples/i18n/no/features/support/env.rb +1 -1
  67. data/examples/i18n/no/lib/kalkulator.rb +2 -2
  68. data/examples/i18n/pl/features/step_definitions/calculator_steps.rb +4 -4
  69. data/examples/i18n/pl/lib/calculator.rb +2 -2
  70. data/examples/i18n/pt/features/step_definitions/calculadora_steps.rb +3 -3
  71. data/examples/i18n/pt/features/support/env.rb +1 -1
  72. data/examples/i18n/pt/lib/calculadora.rb +1 -1
  73. data/examples/i18n/ro/features/step_definitions/calculator_steps.rb +5 -5
  74. data/examples/i18n/ro/lib/calculator.rb +1 -1
  75. data/examples/i18n/ru/features/step_definitions/calculator_steps.rb +5 -5
  76. data/examples/i18n/sk/features/step_definitions/calculator_steps.rb +4 -4
  77. data/examples/i18n/sk/lib/calculator.rb +2 -2
  78. data/examples/i18n/sr-Cyrl/features/step_definitions/calculator_steps.rb +3 -3
  79. data/examples/i18n/sr-Cyrl/features/support/env.rb +1 -1
  80. data/examples/i18n/sr-Cyrl/lib/calculator.rb +2 -2
  81. data/examples/i18n/sr-Latn/features/step_definitions/calculator_steps.rb +4 -4
  82. data/examples/i18n/sr-Latn/lib/calculator.rb +2 -2
  83. data/examples/i18n/sv/features/step_definitions/kalkulator_steps.rb +3 -3
  84. data/examples/i18n/sv/lib/kalkulator.rb +2 -2
  85. data/examples/i18n/tr/features/step_definitions/hesap_makinesi_adimlari.rb +4 -4
  86. data/examples/i18n/tr/lib/hesap_makinesi.rb +2 -2
  87. data/examples/i18n/uk/features/step_definitions/calculator_steps.rb +4 -4
  88. data/examples/i18n/uz/features/step_definitions/calculator_steps.rb +4 -4
  89. data/examples/i18n/zh-CN/features/step_definitions/calculator_steps.rb +5 -5
  90. data/examples/i18n/zh-CN/lib/calculator.rb +2 -2
  91. data/examples/i18n/zh-TW/features/step_definitions/calculator_steps.rb +4 -4
  92. data/examples/i18n/zh-TW/lib/calculator.rb +2 -2
  93. data/examples/rspec_doubles/features/step_definitions/calvin_steps.rb +3 -3
  94. data/examples/sinatra/features/step_definitions/add_steps.rb +4 -4
  95. data/examples/tcl/features/step_definitions/fib_steps.rb +2 -2
  96. data/examples/test_unit/features/step_definitions/test_unit_steps.rb +4 -4
  97. data/examples/watir/features/step_definitions/search_steps.rb +3 -3
  98. data/examples/watir/features/support/screenshots.rb +5 -5
  99. data/features/docs/api/list_step_defs_as_json.feature +21 -7
  100. data/features/docs/api/listen_for_events.feature +1 -1
  101. data/features/docs/api/run_cli_main_with_existing_runtime.feature +1 -0
  102. data/features/docs/cli/dry_run.feature +3 -0
  103. data/features/docs/cli/execute_with_tag_filter.feature +4 -4
  104. data/features/docs/cli/fail_fast.feature +2 -0
  105. data/features/docs/{gherkin/language_help.feature → cli/i18n.feature} +6 -6
  106. data/features/docs/cli/randomize.feature +2 -2
  107. data/features/docs/cli/retry_failing_tests.feature +28 -3
  108. data/features/docs/cli/run_scenarios_matching_name.feature +1 -0
  109. data/features/docs/cli/specifying_multiple_formatters.feature +3 -0
  110. data/features/docs/cli/strict_mode.feature +6 -0
  111. data/features/docs/defining_steps/nested_steps.feature +5 -1
  112. data/features/docs/defining_steps/nested_steps_i18n.feature +1 -0
  113. data/features/docs/defining_steps/nested_steps_with_second_arg.feature +2 -0
  114. data/features/docs/defining_steps/printing_messages.feature +1 -1
  115. data/features/docs/defining_steps/skip_scenario.feature +1 -0
  116. data/features/docs/defining_steps/snippets.feature +18 -18
  117. data/features/docs/events/gherkin_source_read_event.feature +43 -0
  118. data/features/docs/events/step_activated_event.feature +36 -0
  119. data/features/docs/events/step_definition_registered_event.feature +29 -0
  120. data/features/docs/events/test_case_finished_event.feature +35 -0
  121. data/features/docs/events/test_case_starting_event.feature +54 -0
  122. data/features/docs/events/test_run_finished_event.feature +40 -0
  123. data/features/docs/events/test_run_starting_event.feature +41 -0
  124. data/features/docs/events/test_step_finished_event.feature +47 -0
  125. data/features/docs/events/test_step_starting_event.feature +43 -0
  126. data/features/docs/exception_in_after_hook.feature +3 -2
  127. data/features/docs/exception_in_after_step_hook.feature +2 -0
  128. data/features/docs/exception_in_around_hook.feature +2 -0
  129. data/features/docs/exception_in_before_hook.feature +3 -1
  130. data/features/docs/extending_cucumber/custom_formatter.feature +21 -1
  131. data/features/docs/formatters/json_formatter.feature +4 -4
  132. data/features/docs/formatters/junit_formatter.feature +7 -6
  133. data/features/docs/formatters/pretty_formatter.feature +1 -0
  134. data/features/docs/formatters/progress_formatter.feature +1 -0
  135. data/features/docs/formatters/rerun_formatter.feature +2 -0
  136. data/features/docs/formatters/summary_formatter.feature +1 -0
  137. data/features/docs/formatters/usage_formatter.feature +3 -0
  138. data/features/docs/getting_started.feature +2 -1
  139. data/features/docs/gherkin/background.feature +5 -5
  140. data/features/docs/gherkin/doc_strings.feature +2 -0
  141. data/features/docs/gherkin/expand_option_for_outlines.feature +1 -0
  142. data/features/docs/gherkin/outlines.feature +4 -0
  143. data/features/docs/gherkin/unicode_table.feature +1 -0
  144. data/features/docs/gherkin/using_descriptions.feature +1 -0
  145. data/features/docs/gherkin/using_star_notation.feature +1 -1
  146. data/features/docs/post_configuration_hook.feature +1 -1
  147. data/features/docs/rake_task.feature +5 -0
  148. data/features/docs/raketask.feature +3 -1
  149. data/features/docs/work_in_progress.feature +5 -2
  150. data/features/docs/writing_support_code/after_step_hooks.feature +3 -1
  151. data/features/docs/writing_support_code/around_hooks.feature +6 -0
  152. data/features/docs/writing_support_code/before_hook.feature +1 -0
  153. data/features/docs/writing_support_code/hook_order.feature +3 -1
  154. data/features/docs/writing_support_code/parameter_types.feature +75 -0
  155. data/features/docs/writing_support_code/tagged_hooks.feature +1 -1
  156. data/features/lib/step_definitions/aruba_steps.rb +4 -10
  157. data/features/lib/step_definitions/cli_steps.rb +2 -2
  158. data/features/lib/step_definitions/cucumber_steps.rb +8 -12
  159. data/features/lib/step_definitions/iso-8859-1_steps.rb +2 -2
  160. data/features/lib/step_definitions/json_steps.rb +1 -1
  161. data/features/lib/step_definitions/junit_steps.rb +1 -1
  162. data/features/lib/step_definitions/language_steps.rb +2 -2
  163. data/features/lib/step_definitions/profile_steps.rb +6 -6
  164. data/features/lib/step_definitions/retry_steps.rb +3 -3
  165. data/features/lib/step_definitions/ruby_steps.rb +1 -1
  166. data/features/lib/support/env.rb +1 -1
  167. data/features/lib/support/fake_wire_server.rb +7 -2
  168. data/features/lib/support/feature_factory.rb +1 -1
  169. data/features/lib/support/normalise_output.rb +13 -12
  170. data/features/lib/support/parameter_types.rb +8 -0
  171. data/gem_tasks/contributors.rake +9 -6
  172. data/gem_tasks/environment.rake +1 -5
  173. data/gem_tasks/examples.rake +1 -1
  174. data/gem_tasks/fix_cr_lf.rake +1 -1
  175. data/gem_tasks/flog.rake +2 -2
  176. data/gem_tasks/rspec.rake +1 -1
  177. data/lib/autotest/cucumber_mixin.rb +15 -15
  178. data/lib/autotest/discover.rb +2 -2
  179. data/lib/cucumber/cli/configuration.rb +7 -13
  180. data/lib/cucumber/cli/main.rb +6 -6
  181. data/lib/cucumber/cli/options.rb +163 -126
  182. data/lib/cucumber/cli/profile_loader.rb +24 -20
  183. data/lib/cucumber/configuration.rb +12 -17
  184. data/lib/cucumber/constantize.rb +1 -1
  185. data/lib/cucumber/core_ext/string.rb +1 -1
  186. data/lib/cucumber/deprecate.rb +1 -1
  187. data/lib/cucumber/events.rb +11 -1
  188. data/lib/cucumber/events/gherkin_source_read.rb +17 -0
  189. data/lib/cucumber/events/{step_match.rb → step_activated.rb} +2 -2
  190. data/lib/cucumber/events/step_definition_registered.rb +1 -1
  191. data/lib/cucumber/events/test_case_finished.rb +18 -0
  192. data/lib/cucumber/events/test_case_starting.rb +15 -0
  193. data/lib/cucumber/events/test_run_starting.rb +16 -0
  194. data/lib/cucumber/events/test_step_finished.rb +20 -0
  195. data/lib/cucumber/events/test_step_starting.rb +17 -0
  196. data/lib/cucumber/filters.rb +1 -0
  197. data/lib/cucumber/filters/activate_steps.rb +1 -1
  198. data/lib/cucumber/filters/broadcast_test_run_starting_event.rb +27 -0
  199. data/lib/cucumber/filters/retry.rb +1 -1
  200. data/lib/cucumber/filters/tag_limits.rb +3 -3
  201. data/lib/cucumber/filters/tag_limits/verifier.rb +1 -1
  202. data/lib/cucumber/formatter/ansicolor.rb +8 -11
  203. data/lib/cucumber/formatter/backtrace_filter.rb +19 -7
  204. data/lib/cucumber/formatter/console.rb +16 -19
  205. data/lib/cucumber/formatter/console_counts.rb +8 -21
  206. data/lib/cucumber/formatter/console_issues.rb +30 -9
  207. data/lib/cucumber/formatter/duration.rb +1 -1
  208. data/lib/cucumber/formatter/fail_fast.rb +1 -1
  209. data/lib/cucumber/formatter/html.rb +168 -242
  210. data/lib/cucumber/formatter/html_builder.rb +110 -0
  211. data/lib/cucumber/formatter/inline-js.js +30 -0
  212. data/lib/cucumber/formatter/interceptor.rb +2 -2
  213. data/lib/cucumber/formatter/json.rb +12 -12
  214. data/lib/cucumber/formatter/junit.rb +11 -11
  215. data/lib/cucumber/formatter/legacy_api/adapter.rb +27 -27
  216. data/lib/cucumber/formatter/legacy_api/ast.rb +16 -20
  217. data/lib/cucumber/formatter/legacy_api/results.rb +6 -8
  218. data/lib/cucumber/formatter/pretty.rb +17 -17
  219. data/lib/cucumber/formatter/progress.rb +11 -12
  220. data/lib/cucumber/formatter/rerun.rb +1 -1
  221. data/lib/cucumber/formatter/steps.rb +1 -1
  222. data/lib/cucumber/formatter/unicode.rb +1 -1
  223. data/lib/cucumber/formatter/usage.rb +12 -12
  224. data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +1 -1
  225. data/lib/cucumber/gherkin/formatter/escaping.rb +1 -1
  226. data/lib/cucumber/{rb_support/rb_dsl.rb → glue/dsl.rb} +44 -17
  227. data/lib/cucumber/glue/hook.rb +43 -0
  228. data/lib/cucumber/glue/invoke_in_world.rb +70 -0
  229. data/lib/cucumber/glue/proto_world.rb +225 -0
  230. data/lib/cucumber/{rb_support/rb_language.rb → glue/registry_and_more.rb} +45 -86
  231. data/lib/cucumber/{rb_support → glue}/snippet.rb +62 -25
  232. data/lib/cucumber/glue/step_definition.rb +143 -0
  233. data/lib/cucumber/glue/world_factory.rb +23 -0
  234. data/lib/cucumber/hooks.rb +4 -4
  235. data/lib/cucumber/multiline_argument.rb +2 -2
  236. data/lib/cucumber/multiline_argument/data_table.rb +40 -178
  237. data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +158 -0
  238. data/lib/cucumber/platform.rb +3 -5
  239. data/lib/cucumber/rake/task.rb +11 -11
  240. data/lib/cucumber/rspec/disable_option_parser.rb +1 -1
  241. data/lib/cucumber/rspec/doubles.rb +1 -1
  242. data/lib/cucumber/running_test_case.rb +2 -2
  243. data/lib/cucumber/runtime.rb +46 -34
  244. data/lib/cucumber/runtime/after_hooks.rb +1 -1
  245. data/lib/cucumber/runtime/for_programming_languages.rb +1 -36
  246. data/lib/cucumber/runtime/support_code.rb +19 -15
  247. data/lib/cucumber/runtime/user_interface.rb +4 -11
  248. data/lib/cucumber/step_argument.rb +0 -2
  249. data/lib/cucumber/step_definition_light.rb +1 -0
  250. data/lib/cucumber/step_match.rb +16 -15
  251. data/lib/cucumber/step_match_search.rb +2 -3
  252. data/lib/cucumber/term/ansicolor.rb +1 -1
  253. data/lib/cucumber/version +1 -1
  254. data/lib/simplecov_setup.rb +1 -1
  255. data/scripts/invite-collaborator +40 -0
  256. data/scripts/update-history +83 -0
  257. data/spec/cucumber/cli/configuration_spec.rb +95 -97
  258. data/spec/cucumber/cli/main_spec.rb +7 -7
  259. data/spec/cucumber/cli/options_spec.rb +112 -78
  260. data/spec/cucumber/cli/profile_loader_spec.rb +24 -5
  261. data/spec/cucumber/cli/rerun_spec.rb +20 -20
  262. data/spec/cucumber/configuration_spec.rb +47 -47
  263. data/spec/cucumber/constantize_spec.rb +2 -2
  264. data/spec/cucumber/events_spec.rb +9 -0
  265. data/spec/cucumber/file_specs_spec.rb +25 -25
  266. data/spec/cucumber/filters/activate_steps_spec.rb +16 -16
  267. data/spec/cucumber/filters/gated_receiver_spec.rb +6 -6
  268. data/spec/cucumber/filters/retry_spec.rb +22 -9
  269. data/spec/cucumber/filters/tag_limits/test_case_index_spec.rb +11 -11
  270. data/spec/cucumber/filters/tag_limits/verifier_spec.rb +14 -14
  271. data/spec/cucumber/filters/tag_limits_spec.rb +8 -8
  272. data/spec/cucumber/formatter/ansicolor_spec.rb +9 -9
  273. data/spec/cucumber/formatter/backtrace_filter_spec.rb +32 -0
  274. data/spec/cucumber/formatter/console_counts_spec.rb +1 -1
  275. data/spec/cucumber/formatter/duration_spec.rb +3 -3
  276. data/spec/cucumber/formatter/fail_fast_spec.rb +21 -21
  277. data/spec/cucumber/formatter/html_spec.rb +58 -58
  278. data/spec/cucumber/formatter/json_spec.rb +44 -46
  279. data/spec/cucumber/formatter/junit_spec.rb +43 -45
  280. data/spec/cucumber/formatter/legacy_api/adapter_spec.rb +43 -43
  281. data/spec/cucumber/formatter/pretty_spec.rb +107 -107
  282. data/spec/cucumber/formatter/progress_spec.rb +20 -20
  283. data/spec/cucumber/formatter/rerun_spec.rb +1 -1
  284. data/spec/cucumber/formatter/spec_helper.rb +6 -5
  285. data/spec/cucumber/{rb_support/rb_world_spec.rb → glue/proto_world_spec.rb} +20 -5
  286. data/spec/cucumber/glue/registry_and_more_spec.rb +213 -0
  287. data/spec/cucumber/{rb_support → glue}/snippet_spec.rb +61 -25
  288. data/spec/cucumber/glue/step_definition_spec.rb +207 -0
  289. data/spec/cucumber/hooks_spec.rb +3 -3
  290. data/spec/cucumber/multiline_argument/data_table_spec.rb +177 -133
  291. data/spec/cucumber/project_initializer_spec.rb +10 -10
  292. data/spec/cucumber/rake/forked_spec.rb +10 -10
  293. data/spec/cucumber/rake/task_spec.rb +20 -20
  294. data/spec/cucumber/running_test_case_spec.rb +35 -35
  295. data/spec/cucumber/runtime/for_programming_languages_spec.rb +1 -30
  296. data/spec/cucumber/runtime_spec.rb +2 -2
  297. data/spec/cucumber/step_argument_spec.rb +5 -5
  298. data/spec/cucumber/step_match_search_spec.rb +31 -41
  299. data/spec/cucumber/step_match_spec.rb +33 -33
  300. data/spec/cucumber/world/pending_spec.rb +10 -10
  301. metadata +117 -47
  302. data/features/docs/formatters/debug_formatter.feature +0 -47
  303. data/features/docs/writing_support_code/transforms.feature +0 -98
  304. data/features/lib/step_definitions/wire_steps.rb +0 -59
  305. data/gem_tasks/cucumber.rake +0 -26
  306. data/lib/cucumber/core_ext/instance_exec.rb +0 -71
  307. data/lib/cucumber/formatter/debug.rb +0 -36
  308. data/lib/cucumber/rb_support/rb_hook.rb +0 -20
  309. data/lib/cucumber/rb_support/rb_step_definition.rb +0 -132
  310. data/lib/cucumber/rb_support/rb_transform.rb +0 -60
  311. data/lib/cucumber/rb_support/rb_world.rb +0 -171
  312. data/spec/cucumber/core_ext/instance_exec_spec.rb +0 -5
  313. data/spec/cucumber/formatter/debug_spec.rb +0 -65
  314. data/spec/cucumber/rb_support/rb_language_spec.rb +0 -321
  315. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +0 -200
  316. data/spec/cucumber/rb_support/rb_transform_spec.rb +0 -47
@@ -2,11 +2,11 @@
2
2
  Autotest.add_discovery do
3
3
  if File.directory?('features')
4
4
  if ENV['AUTOFEATURE'] =~ /true/i
5
- "cucumber"
5
+ 'cucumber'
6
6
  elsif ENV['AUTOFEATURE'] =~ /false/i
7
7
  # noop
8
8
  else
9
- puts "(Not running features. To run features in autotest, set AUTOFEATURE=true.)"
9
+ puts '(Not running features. To run features in autotest, set AUTOFEATURE=true.)'
10
10
  end
11
11
  end
12
12
  end
@@ -3,7 +3,6 @@ require 'logger'
3
3
  require 'cucumber/cli/options'
4
4
  require 'cucumber/cli/rerun_file'
5
5
  require 'cucumber/constantize'
6
- require 'cucumber/core/gherkin/tag_expression'
7
6
  require 'cucumber'
8
7
 
9
8
  module Cucumber
@@ -28,8 +27,6 @@ module Cucumber
28
27
  @options.parse!(args)
29
28
  arrange_formats
30
29
  raise("You can't use both --strict and --wip") if strict? && wip?
31
- # todo: remove
32
- @options[:tag_expression] = Cucumber::Core::Gherkin::TagExpression.new(@options[:tag_expressions])
33
30
  set_environment_variables
34
31
  end
35
32
 
@@ -74,7 +71,7 @@ module Cucumber
74
71
  end
75
72
 
76
73
  def snippet_type
77
- @options[:snippet_type] || :regexp
74
+ @options[:snippet_type] || :cucumber_expression
78
75
  end
79
76
 
80
77
  def log
@@ -85,13 +82,8 @@ module Cucumber
85
82
  logger
86
83
  end
87
84
 
88
- # todo: remove
89
- def tag_expression
90
- Cucumber::Core::Gherkin::TagExpression.new(@options[:tag_expressions])
91
- end
92
-
93
85
  def tag_limits
94
- tag_expression.limits.to_hash
86
+ @options[:tag_limits]
95
87
  end
96
88
 
97
89
  def tag_expressions
@@ -121,7 +113,7 @@ module Cucumber
121
113
  private
122
114
 
123
115
  class LogFormatter < ::Logger::Formatter
124
- def call(severity, time, progname, msg)
116
+ def call(_severity, _time, _progname, msg)
125
117
  msg
126
118
  end
127
119
  end
@@ -133,8 +125,10 @@ module Cucumber
133
125
  end
134
126
 
135
127
  def arrange_formats
136
- @options[:formats] << ['pretty', @out_stream] if @options[:formats].empty?
137
- @options[:formats] = @options[:formats].sort_by{|f| f[1] == @out_stream ? -1 : 1}
128
+ @options[:formats] << ['pretty', {}, @out_stream] if @options[:formats].empty?
129
+ @options[:formats] = @options[:formats].sort_by do |f|
130
+ f[2] == @out_stream ? -1 : 1
131
+ end
138
132
  @options[:formats].uniq!
139
133
  @options.check_formatter_stream_conflicts()
140
134
  end
@@ -24,11 +24,11 @@ module Cucumber
24
24
  trap_interrupt
25
25
 
26
26
  runtime = if existing_runtime
27
- existing_runtime.configure(configuration)
28
- existing_runtime
29
- else
30
- Runtime.new(configuration)
31
- end
27
+ existing_runtime.configure(configuration)
28
+ existing_runtime
29
+ else
30
+ Runtime.new(configuration)
31
+ end
32
32
 
33
33
  runtime.run!
34
34
  if Cucumber.wants_to_quit
@@ -47,7 +47,7 @@ module Cucumber
47
47
  @err.puts("Couldn't open #{e.path}")
48
48
  exit_unable_to_finish
49
49
  rescue FeatureFolderNotFoundException => e
50
- @err.puts(e.message + ". You can use `cucumber --init` to get started.")
50
+ @err.puts(e.message + '. You can use `cucumber --init` to get started.')
51
51
  exit_unable_to_finish
52
52
  rescue ProfilesNotDefinedError, YmlLoadError, ProfileNotFound => e
53
53
  @err.puts(e.message)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require 'cucumber/cli/profile_loader'
3
3
  require 'cucumber/formatter/ansicolor'
4
- require 'cucumber/rb_support/rb_language'
4
+ require 'cucumber/glue/registry_and_more'
5
5
  require 'cucumber/project_initializer'
6
6
 
7
7
  module Cucumber
@@ -24,19 +24,18 @@ module Cucumber
24
24
  'junit' => ['Cucumber::Formatter::Junit', 'Generates a report similar to Ant+JUnit.'],
25
25
  'json' => ['Cucumber::Formatter::Json', 'Prints the feature as JSON'],
26
26
  'json_pretty' => ['Cucumber::Formatter::JsonPretty', 'Prints the feature as prettified JSON'],
27
- 'debug' => ['Cucumber::Formatter::Debug', 'For developing formatters - prints the calls made to the listeners.'],
28
27
  'summary' => ['Cucumber::Formatter::Summary', 'Summary output of feature and scenarios']
29
28
  }
30
29
  max = BUILTIN_FORMATS.keys.map{|s| s.length}.max
31
- FORMAT_HELP_MSG = ["Use --format rerun --out rerun.txt to write out failing",
32
- "features. You can rerun them with cucumber @rerun.txt.",
33
- "FORMAT can also be the fully qualified class name of",
30
+ FORMAT_HELP_MSG = ['Use --format rerun --out rerun.txt to write out failing',
31
+ 'features. You can rerun them with cucumber @rerun.txt.',
32
+ 'FORMAT can also be the fully qualified class name of',
34
33
  "your own custom formatter. If the class isn't loaded,",
35
- "Cucumber will attempt to require a file with a relative",
36
- "file name that is the underscore name of the class name.",
37
- "Example: --format Foo::BarZap -> Cucumber will look for",
38
- "foo/bar_zap.rb. You can place the file with this relative",
39
- "path underneath your features/support directory or anywhere",
34
+ 'Cucumber will attempt to require a file with a relative',
35
+ 'file name that is the underscore name of the class name.',
36
+ 'Example: --format Foo::BarZap -> Cucumber will look for',
37
+ 'foo/bar_zap.rb. You can place the file with this relative',
38
+ 'path underneath your features/support directory or anywhere',
40
39
  "on Ruby's LOAD_PATH, for example in a Ruby gem."
41
40
  ]
42
41
 
@@ -49,12 +48,13 @@ module Cucumber
49
48
  NO_PROFILE_LONG_FLAG = '--no-profile'
50
49
  FAIL_FAST_FLAG = '--fail-fast'
51
50
  RETRY_FLAG = '--retry'
52
- OPTIONS_WITH_ARGS = ['-r', '--require', '--i18n', '-f', '--format', '-o', '--out',
51
+ OPTIONS_WITH_ARGS = ['-r', '--require', '--i18n-keywords', '-f', '--format', '-o', '--out',
53
52
  '-t', '--tags', '-n', '--name', '-e', '--exclude',
54
53
  PROFILE_SHORT_FLAG, PROFILE_LONG_FLAG, RETRY_FLAG,
55
54
  '-l', '--lines', '--port',
56
55
  '-I', '--snippet-type']
57
56
  ORDER_TYPES = %w{defined random}
57
+ TAG_LIMIT_MATCHER = /(?<tag_name>\@\w+):(?<limit>\d+)/x
58
58
 
59
59
  def self.parse(args, out_stream, error_stream, options = {})
60
60
  new(out_stream, error_stream, options).parse!(args)
@@ -82,7 +82,7 @@ module Cucumber
82
82
  @options[key] = value
83
83
  end
84
84
 
85
- def parse!(args)
85
+ def parse!(args) # rubocop:disable Metrics/AbcSize
86
86
  @args = args
87
87
  @expanded_args = @args.dup
88
88
 
@@ -90,54 +90,57 @@ module Cucumber
90
90
 
91
91
  @args.options do |opts|
92
92
  opts.banner = banner
93
- opts.on("-r LIBRARY|DIR", "--require LIBRARY|DIR", *require_files_msg) {|lib| require_files(lib) }
93
+ opts.on('-r LIBRARY|DIR', '--require LIBRARY|DIR', *require_files_msg) {|lib| require_files(lib) }
94
94
 
95
95
  if(Cucumber::JRUBY)
96
- opts.on("-j DIR", "--jars DIR", "Load all the jars under DIR") {|jars| load_jars(jars) }
96
+ opts.on('-j DIR', '--jars DIR', 'Load all the jars under DIR') {|jars| load_jars(jars) }
97
97
  end
98
98
 
99
99
  opts.on("#{RETRY_FLAG} ATTEMPTS", *retry_msg) {|v| set_option :retry, v.to_i }
100
- opts.on("--i18n LANG", *i18n_msg) {|lang| set_language lang }
101
- opts.on(FAIL_FAST_FLAG, "Exit immediately following the first failing scenario") { set_option :fail_fast }
102
- opts.on("-f FORMAT", "--format FORMAT", *format_msg, *FORMAT_HELP) {|v| add_option :formats, [v, @out_stream] }
100
+ opts.on('--i18n-languages', *i18n_languages_msg) { list_languages_and_exit }
101
+ opts.on('--i18n-keywords LANG', *i18n_keywords_msg) {|lang| set_language lang }
102
+ opts.on(FAIL_FAST_FLAG, 'Exit immediately following the first failing scenario') { set_option :fail_fast }
103
+ opts.on('-f FORMAT', '--format FORMAT', *format_msg, *FORMAT_HELP) do |v|
104
+ add_option :formats, [*parse_formats(v), @out_stream]
105
+ end
103
106
  opts.on('--init', *init_msg) {|v| initialize_project }
104
- opts.on("-o", "--out [FILE|DIR]", *out_msg) {|v| set_out_stream v }
105
- opts.on("-t TAG_EXPRESSION", "--tags TAG_EXPRESSION", *tags_msg) {|v| add_option :tag_expressions, v }
106
- opts.on("-n NAME", "--name NAME", *name_msg) {|v| add_option :name_regexps, /#{v}/ }
107
- opts.on("-e", "--exclude PATTERN", *exclude_msg) {|v| add_option :excludes, Regexp.new(v) }
107
+ opts.on('-o', '--out [FILE|DIR]', *out_msg) {|v| set_out_stream v }
108
+ opts.on('-t TAG_EXPRESSION', '--tags TAG_EXPRESSION', *tags_msg) {|v| add_tag v }
109
+ opts.on('-n NAME', '--name NAME', *name_msg) {|v| add_option :name_regexps, /#{v}/ }
110
+ opts.on('-e', '--exclude PATTERN', *exclude_msg) {|v| add_option :excludes, Regexp.new(v) }
108
111
  opts.on(PROFILE_SHORT_FLAG, "#{PROFILE_LONG_FLAG} PROFILE", *profile_short_flag_msg) {|v| add_profile v }
109
112
  opts.on(NO_PROFILE_SHORT_FLAG, NO_PROFILE_LONG_FLAG, *no_profile_short_flag_msg) {|v| disable_profile_loading }
110
- opts.on("-c", "--[no-]color", *color_msg) {|v| set_color v }
111
- opts.on("-d", "--dry-run", *dry_run_msg) { set_dry_run_and_duration }
112
- opts.on("-m", "--no-multiline", "Don't print multiline strings and tables under steps.") { set_option :no_multiline }
113
- opts.on("-s", "--no-source", "Don't print the file and line of the step definition with the steps.") { set_option :source, false }
114
- opts.on("-i", "--no-snippets", "Don't print snippets for pending steps.") { set_option :snippets, false }
115
- opts.on("-I", "--snippet-type TYPE", *snippet_type_msg) {|v| set_option :snippet_type, v.to_sym }
116
- opts.on("-q", "--quiet", "Alias for --no-snippets --no-source.") { shut_up }
117
- opts.on("--no-duration", "Don't print the duration at the end of the summary") { set_option :duration, false }
118
- opts.on("-b", "--backtrace", "Show full backtrace for all errors.") { Cucumber.use_full_backtrace = true }
119
- opts.on("-S", "--strict", "Fail if there are any undefined or pending steps.") { set_option :strict }
120
- opts.on("-w", "--wip", "Fail if there are any passing scenarios.") { set_option :wip }
121
- opts.on("-v", "--verbose", "Show the files and features loaded.") { set_option :verbose }
122
- opts.on("-g", "--guess", "Guess best match for Ambiguous steps.") { set_option :guess }
123
- opts.on("-l", "--lines LINES", *lines_msg) {|lines| set_option :lines, lines }
124
- opts.on("-x", "--expand", "Expand Scenario Outline Tables in output.") { set_option :expand }
125
-
126
- opts.on("--order TYPE[:SEED]", "Run examples in the specified order. Available types:",
113
+ opts.on('-c', '--[no-]color', *color_msg) {|v| set_color v }
114
+ opts.on('-d', '--dry-run', *dry_run_msg) { set_dry_run_and_duration }
115
+ opts.on('-m', '--no-multiline', "Don't print multiline strings and tables under steps.") { set_option :no_multiline }
116
+ opts.on('-s', '--no-source', "Don't print the file and line of the step definition with the steps.") { set_option :source, false }
117
+ opts.on('-i', '--no-snippets', "Don't print snippets for pending steps.") { set_option :snippets, false }
118
+ opts.on('-I', '--snippet-type TYPE', *snippet_type_msg) {|v| set_option :snippet_type, v.to_sym }
119
+ opts.on('-q', '--quiet', 'Alias for --no-snippets --no-source.') { shut_up }
120
+ opts.on('--no-duration', "Don't print the duration at the end of the summary") { set_option :duration, false }
121
+ opts.on('-b', '--backtrace', 'Show full backtrace for all errors.') { Cucumber.use_full_backtrace = true }
122
+ opts.on('-S', '--strict', 'Fail if there are any undefined or pending steps.') { set_option :strict }
123
+ opts.on('-w', '--wip', 'Fail if there are any passing scenarios.') { set_option :wip }
124
+ opts.on('-v', '--verbose', 'Show the files and features loaded.') { set_option :verbose }
125
+ opts.on('-g', '--guess', 'Guess best match for Ambiguous steps.') { set_option :guess }
126
+ opts.on('-l', '--lines LINES', *lines_msg) {|lines| set_option :lines, lines }
127
+ opts.on('-x', '--expand', 'Expand Scenario Outline Tables in output.') { set_option :expand }
128
+
129
+ opts.on('--order TYPE[:SEED]', 'Run examples in the specified order. Available types:',
127
130
  *<<-TEXT.split("\n")) do |order|
128
131
  [defined] Run scenarios in the order they were defined (default).
129
132
  [random] Shuffle scenarios before running.
130
133
  Specify SEED to reproduce the shuffling from a previous run.
131
134
  e.g. --order random:5738
132
135
  TEXT
133
- @options[:order], @options[:seed] = *order.split(":")
136
+ @options[:order], @options[:seed] = *order.split(':')
134
137
  unless ORDER_TYPES.include?(@options[:order])
135
138
  fail "'#{@options[:order]}' is not a recognised order type. Please use one of #{ORDER_TYPES.join(", ")}."
136
139
  end
137
140
  end
138
141
 
139
- opts.on_tail("--version", "Show version.") { exit_ok(Cucumber::VERSION) }
140
- opts.on_tail("-h", "--help", "You're looking at it.") { exit_ok(opts.help) }
142
+ opts.on_tail('--version', 'Show version.') { exit_ok(Cucumber::VERSION) }
143
+ opts.on_tail('-h', '--help', "You're looking at it.") { exit_ok(opts.help) }
141
144
  end.parse!
142
145
 
143
146
  @args.map! { |a| "#{a}:#{@options[:lines]}" } if @options[:lines]
@@ -161,34 +164,33 @@ TEXT
161
164
  end
162
165
 
163
166
  def check_formatter_stream_conflicts()
164
- streams = @options[:formats].uniq.map { |(_, stream)| stream }
165
- if streams != streams.uniq
166
- raise "All but one formatter must use --out, only one can print to each stream (or STDOUT)"
167
- end
167
+ streams = @options[:formats].uniq.map { |(_, _, stream)| stream }
168
+ return if streams == streams.uniq
169
+ raise 'All but one formatter must use --out, only one can print to each stream (or STDOUT)'
168
170
  end
169
171
 
170
172
  def to_hash
171
173
  Hash(@options)
172
174
  end
173
175
 
174
- protected
176
+ protected
175
177
 
176
178
  attr_reader :options, :profiles, :expanded_args
177
179
  protected :options, :profiles, :expanded_args
178
180
 
179
- private
181
+ private
180
182
 
181
183
  def color_msg
182
184
  [
183
- "Whether or not to use ANSI color in the output. Cucumber decides",
184
- "based on your platform and the output destination if not specified."
185
+ 'Whether or not to use ANSI color in the output. Cucumber decides',
186
+ 'based on your platform and the output destination if not specified.'
185
187
  ]
186
188
  end
187
189
 
188
190
  def dry_run_msg
189
191
  [
190
- "Invokes formatters without executing the steps.",
191
- "This also omits the loading of your support/env.rb file if it exists."
192
+ 'Invokes formatters without executing the steps.',
193
+ 'This also omits the loading of your support/env.rb file if it exists.'
192
194
  ]
193
195
  end
194
196
 
@@ -197,12 +199,18 @@ TEXT
197
199
  end
198
200
 
199
201
  def format_msg
200
- [ "How to format features (Default: pretty). Available formats:" ]
202
+ [ 'How to format features (Default: pretty). Available formats:' ]
203
+ end
204
+
205
+ def i18n_languages_msg
206
+ [
207
+ 'List all available languages'
208
+ ]
201
209
  end
202
210
 
203
- def i18n_msg
211
+ def i18n_keywords_msg
204
212
  [
205
- "List keywords for in a particular language",
213
+ 'List keywords for in a particular language',
206
214
  %{Run with "--i18n help" to see all languages}
207
215
  ]
208
216
  end
@@ -215,7 +223,7 @@ TEXT
215
223
  end
216
224
 
217
225
  def lines_msg
218
- [ "Run given line numbers. Equivalent to FILE:LINE syntax" ]
226
+ [ 'Run given line numbers. Equivalent to FILE:LINE syntax' ]
219
227
  end
220
228
 
221
229
  def no_profile_short_flag_msg
@@ -226,96 +234,104 @@ TEXT
226
234
 
227
235
  def profile_short_flag_msg
228
236
  [
229
- "Pull commandline arguments from cucumber.yml which can be defined as",
237
+ 'Pull commandline arguments from cucumber.yml which can be defined as',
230
238
  "strings or arrays. When a 'default' profile is defined and no profile",
231
- "is specified it is always used. (Unless disabled, see -P below.)",
232
- "When feature files are defined in a profile and on the command line",
233
- "then only the ones from the command line are used."
239
+ 'is specified it is always used. (Unless disabled, see -P below.)',
240
+ 'When feature files are defined in a profile and on the command line',
241
+ 'then only the ones from the command line are used.'
234
242
  ]
235
243
  end
236
244
 
237
245
  def retry_msg
238
- [ "Specify the number of times to retry failing tests (default: 0)" ]
246
+ [ 'Specify the number of times to retry failing tests (default: 0)' ]
239
247
  end
240
248
 
241
249
  def name_msg
242
250
  [
243
- "Only execute the feature elements which match part of the given name.",
244
- "If this option is given more than once, it will match against all the",
245
- "given names."
251
+ 'Only execute the feature elements which match part of the given name.',
252
+ 'If this option is given more than once, it will match against all the',
253
+ 'given names.'
246
254
  ]
247
255
  end
248
256
 
257
+ def parse_formats(v)
258
+ formatter, *formatter_options = v.split(',')
259
+ options_hash = Hash[formatter_options.map { |s| s.split('=') }]
260
+ [formatter, options_hash]
261
+ end
262
+
249
263
  def set_out_stream(v)
250
- @options[:formats] << ['pretty', nil] if @options[:formats].empty?
251
- @options[:formats][-1][1] = v
264
+ @options[:formats] << ['pretty', {}, nil] if @options[:formats].empty?
265
+ @options[:formats][-1][2] = v
252
266
  end
253
267
 
254
268
  def tags_msg
255
269
  [
256
- "Only execute the features or scenarios with tags matching TAG_EXPRESSION.",
257
- "Scenarios inherit tags declared on the Feature level. The simplest",
258
- "TAG_EXPRESSION is simply a tag. Example: --tags @dev. When a tag in a tag",
259
- "expression starts with a ~, this represents boolean NOT. Example: --tags ~@dev.",
260
- "A tag expression can have several tags separated by a comma, which represents",
261
- "logical OR. Example: --tags @dev,@wip. The --tags option can be specified",
262
- "several times, and this represents logical AND. Example: --tags @foo,~@bar --tags @zap.",
263
- "This represents the boolean expression (@foo || !@bar) && @zap.",
270
+ 'Only execute the features or scenarios with tags matching TAG_EXPRESSION.',
271
+ 'Scenarios inherit tags declared on the Feature level. The simplest',
272
+ 'TAG_EXPRESSION is simply a tag. Example: --tags @dev. To represent',
273
+ "boolean NOT preceed the tag with 'not '. Example: --tags 'not @dev'.",
274
+ 'A tag expression can have several tags separated by an or which represents',
275
+ "logical OR. Example: --tags '@dev or @wip'. The --tags option can be specified",
276
+ 'A tag expression can have several tags separated by an and which represents',
277
+ "logical AND. Example: --tags '@dev and @wip'. The --tags option can be specified",
278
+ 'several times, and this also represents logical AND.',
279
+ "Example: --tags '@foo or not @bar' --tags @zap. This represents the boolean",
280
+ 'expression (@foo || !@bar) && @zap.',
264
281
  "\n",
265
- "Beware that if you want to use several negative tags to exclude several tags",
266
- "you have to use logical AND: --tags ~@fixme --tags ~@buggy.",
282
+ 'Beware that if you want to use several negative tags to exclude several tags',
283
+ "you have to use logical AND: --tags 'not @fixme and not @buggy'.",
267
284
  "\n",
268
- "Positive tags can be given a threshold to limit the number of occurrences.",
269
- "Example: --tags @qa:3 will fail if there are more than 3 occurrences of the @qa tag.",
270
- "This can be practical if you are practicing Kanban or CONWIP."
285
+ 'Tags can be given a threshold to limit the number of occurrences.',
286
+ 'Example: --tags @qa:3 will fail if there are more than 3 occurrences of the @qa tag.',
287
+ 'This can be practical if you are practicing Kanban or CONWIP.'
271
288
  ]
272
289
  end
273
290
 
274
291
  def out_msg
275
292
  [
276
- "Write output to a file/directory instead of STDOUT. This option",
277
- "applies to the previously specified --format, or the",
278
- "default format if no format is specified. Check the specific",
293
+ 'Write output to a file/directory instead of STDOUT. This option',
294
+ 'applies to the previously specified --format, or the',
295
+ 'default format if no format is specified. Check the specific',
279
296
  "formatter's docs to see whether to pass a file or a dir."
280
297
  ]
281
298
  end
282
299
 
283
300
  def require_files_msg
284
301
  [
285
- "Require files before executing the features. If this",
286
- "option is not specified, all *.rb files that are",
287
- "siblings or below the features will be loaded auto-",
288
- "matically. Automatic loading is disabled when this",
289
- "option is specified, and all loading becomes explicit.",
290
- "Files under directories named \"support\" are always",
291
- "loaded first.",
292
- "This option can be specified multiple times."
302
+ 'Require files before executing the features. If this',
303
+ 'option is not specified, all *.rb files that are',
304
+ 'siblings or below the features will be loaded auto-',
305
+ 'matically. Automatic loading is disabled when this',
306
+ 'option is specified, and all loading becomes explicit.',
307
+ 'Files under directories named "support" are always',
308
+ 'loaded first.',
309
+ 'This option can be specified multiple times.'
293
310
  ]
294
311
  end
295
312
 
296
313
  def snippet_type_msg
297
314
  [
298
- "Use different snippet type (Default: regexp). Available types:",
299
- Cucumber::RbSupport::RbLanguage.cli_snippet_type_options
315
+ 'Use different snippet type (Default: cucumber_expression). Available types:',
316
+ Cucumber::Glue::RegistryAndMore.cli_snippet_type_options
300
317
  ].flatten
301
318
  end
302
319
 
303
320
  def banner
304
- ["Usage: cucumber [options] [ [FILE|DIR|URL][:LINE[:LINE]*] ]+", "",
305
- "Examples:",
306
- "cucumber examples/i18n/en/features",
307
- "cucumber @rerun.txt (See --format rerun)",
308
- "cucumber examples/i18n/it/features/somma.feature:6:98:113",
309
- "cucumber -s -i http://rubyurl.com/eeCl", "", "",
321
+ ['Usage: cucumber [options] [ [FILE|DIR|URL][:LINE[:LINE]*] ]+', '',
322
+ 'Examples:',
323
+ 'cucumber examples/i18n/en/features',
324
+ 'cucumber @rerun.txt (See --format rerun)',
325
+ 'cucumber examples/i18n/it/features/somma.feature:6:98:113',
326
+ 'cucumber -s -i http://rubyurl.com/eeCl', '', ''
310
327
  ].join("\n")
311
328
  end
312
329
 
313
330
  def require_files(v)
314
331
  @options[:require] << v
315
- if(Cucumber::JRUBY && File.directory?(v))
316
- require 'java'
317
- $CLASSPATH << v
318
- end
332
+ return unless Cucumber::JRUBY && File.directory?(v)
333
+ require 'java'
334
+ $CLASSPATH << v
319
335
  end
320
336
 
321
337
  def require_jars(jars)
@@ -325,13 +341,8 @@ TEXT
325
341
  def set_language(lang)
326
342
  require 'gherkin/dialect'
327
343
 
328
- if lang == 'help'
329
- list_languages_and_exit
330
- elsif !::Gherkin::DIALECTS.keys.include? lang
331
- indicate_invalid_language_and_exit(lang)
332
- else
333
- list_keywords_and_exit(lang)
334
- end
344
+ return indicate_invalid_language_and_exit(lang) unless ::Gherkin::DIALECTS.keys.include? lang
345
+ list_keywords_and_exit(lang)
335
346
  end
336
347
 
337
348
  def disable_profile_loading
@@ -339,13 +350,33 @@ TEXT
339
350
  end
340
351
 
341
352
  def non_stdout_formats
342
- @options[:formats].select {|format, output| output != @out_stream }
353
+ @options[:formats].select { |_, _, output| output != @out_stream }
343
354
  end
344
355
 
345
356
  def add_option(option, value)
346
357
  @options[option] << value
347
358
  end
348
359
 
360
+ def add_tag(value)
361
+ warn("Deprecated: Found tags option '#{value}'. Support for '~@tag' will be removed from the next release of Cucumber. Please use 'not @tag' instead.") if value.include?('~')
362
+ warn("Deprecated: Found tags option '#{value}'. Support for '@tag1,@tag2' will be removed from the next release of Cucumber. Please use '@tag or @tag2' instead.") if value.include?(',')
363
+ @options[:tag_expressions] << value.gsub(/(@\w+)(:\d+)?/, '\1')
364
+ add_tag_limits(value)
365
+ end
366
+
367
+ def add_tag_limits(value)
368
+ value.split(/[, ]/).map { |part| TAG_LIMIT_MATCHER.match(part) }.compact.each do |matchdata|
369
+ add_tag_limit(@options[:tag_limits], matchdata[:tag_name], matchdata[:limit].to_i)
370
+ end
371
+ end
372
+
373
+ def add_tag_limit(tag_limits, tag_name, limit)
374
+ if tag_limits[tag_name] && tag_limits[tag_name] != limit
375
+ raise "Inconsistent tag limits for #{tag_name}: #{tag_limits[tag_name]} and #{limit}"
376
+ end
377
+ tag_limits[tag_name] = limit
378
+ end
379
+
349
380
  def set_color(color)
350
381
  Cucumber::Term::ANSIColor.coloring = color
351
382
  end
@@ -379,7 +410,7 @@ TEXT
379
410
  end
380
411
 
381
412
  def stdout_formats
382
- @options[:formats].select {|format, output| output == @out_stream }
413
+ @options[:formats].select { |_, _, output| output == @out_stream }
383
414
  end
384
415
 
385
416
  def extract_environment_variables
@@ -397,7 +428,7 @@ TEXT
397
428
 
398
429
  def merge_profiles
399
430
  if @disable_profile_loading
400
- @out_stream.puts "Disabling profiles..."
431
+ @out_stream.puts 'Disabling profiles...'
401
432
  return
402
433
  end
403
434
 
@@ -436,6 +467,7 @@ TEXT
436
467
  @options[:excludes] += other_options[:excludes]
437
468
  @options[:name_regexps] += other_options[:name_regexps]
438
469
  @options[:tag_expressions] += other_options[:tag_expressions]
470
+ merge_tag_limits(@options[:tag_limits], other_options[:tag_limits])
439
471
  @options[:env_vars] = other_options[:env_vars].merge(@options[:env_vars])
440
472
  if @options[:paths].empty?
441
473
  @options[:paths] = other_options[:paths]
@@ -461,6 +493,10 @@ TEXT
461
493
  self
462
494
  end
463
495
 
496
+ def merge_tag_limits(option_limits, other_limits)
497
+ other_limits.each { |key, value| add_tag_limit(option_limits, key, value) }
498
+ end
499
+
464
500
  def indicate_invalid_language_and_exit(lang)
465
501
  @out_stream.write("Invalid language '#{lang}'. Available languages are:\n")
466
502
  list_languages_and_exit
@@ -470,21 +506,21 @@ TEXT
470
506
  require 'gherkin/dialect'
471
507
  language = ::Gherkin::Dialect.for(lang)
472
508
  data = Cucumber::MultilineArgument::DataTable.from(
473
- [["feature", to_keywords_string(language.feature_keywords)],
474
- ["background", to_keywords_string(language.background_keywords)],
475
- ["scenario", to_keywords_string(language.scenario_keywords)],
476
- ["scenario_outline", to_keywords_string(language.scenario_outline_keywords)],
477
- ["examples", to_keywords_string(language.examples_keywords)],
478
- ["given", to_keywords_string(language.given_keywords)],
479
- ["when", to_keywords_string(language.when_keywords)],
480
- ["then", to_keywords_string(language.then_keywords)],
481
- ["and", to_keywords_string(language.and_keywords)],
482
- ["but", to_keywords_string(language.but_keywords)],
483
- ["given (code)", to_code_keywords_string(language.given_keywords)],
484
- ["when (code)", to_code_keywords_string(language.when_keywords)],
485
- ["then (code)", to_code_keywords_string(language.then_keywords)],
486
- ["and (code)", to_code_keywords_string(language.and_keywords)],
487
- ["but (code)", to_code_keywords_string(language.but_keywords)]])
509
+ [['feature', to_keywords_string(language.feature_keywords)],
510
+ ['background', to_keywords_string(language.background_keywords)],
511
+ ['scenario', to_keywords_string(language.scenario_keywords)],
512
+ ['scenario_outline', to_keywords_string(language.scenario_outline_keywords)],
513
+ ['examples', to_keywords_string(language.examples_keywords)],
514
+ ['given', to_keywords_string(language.given_keywords)],
515
+ ['when', to_keywords_string(language.when_keywords)],
516
+ ['then', to_keywords_string(language.then_keywords)],
517
+ ['and', to_keywords_string(language.and_keywords)],
518
+ ['but', to_keywords_string(language.but_keywords)],
519
+ ['given (code)', to_code_keywords_string(language.given_keywords)],
520
+ ['when (code)', to_code_keywords_string(language.when_keywords)],
521
+ ['then (code)', to_code_keywords_string(language.then_keywords)],
522
+ ['and (code)', to_code_keywords_string(language.and_keywords)],
523
+ ['but (code)', to_code_keywords_string(language.but_keywords)]])
488
524
  @out_stream.write(data.to_s({ color: false, prefixes: Hash.new('') }))
489
525
  Kernel.exit(0)
490
526
  end
@@ -515,6 +551,7 @@ TEXT
515
551
  :formats => [],
516
552
  :excludes => [],
517
553
  :tag_expressions => [],
554
+ :tag_limits => {},
518
555
  :name_regexps => [],
519
556
  :env_vars => {},
520
557
  :diff_enabled => true,