cucumber 0.6.4 → 0.7.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. data/History.txt +11 -0
  2. data/Rakefile +3 -5
  3. data/VERSION.yml +3 -3
  4. data/cucumber.gemspec +35 -55
  5. data/cucumber.yml +3 -2
  6. data/examples/i18n/Rakefile +1 -0
  7. data/examples/i18n/en-lol/features/step_definitions/cucumbrz_steps.rb +1 -1
  8. data/examples/i18n/eo/.gitignore +1 -0
  9. data/examples/i18n/eo/Rakefile +6 -0
  10. data/examples/i18n/eo/features/adicio.feature +17 -0
  11. data/examples/i18n/eo/features/divido.feature +10 -0
  12. data/examples/i18n/eo/features/step_definitons/calculator_steps.rb +24 -0
  13. data/examples/i18n/eo/lib/calculator.rb +14 -0
  14. data/examples/i18n/fr/features/step_definitions/calculatrice_steps.rb +1 -1
  15. data/examples/i18n/ru/features/division.feature +1 -1
  16. data/examples/i18n/uk/Rakefile +6 -0
  17. data/examples/i18n/uk/features/addition.feature +11 -0
  18. data/examples/i18n/uk/features/consecutive_calculations.feature +17 -0
  19. data/examples/i18n/uk/features/division.feature +16 -0
  20. data/examples/i18n/uk/features/step_definitons/calculator_steps.rb +19 -0
  21. data/examples/i18n/uk/features/support/env.rb +5 -0
  22. data/examples/i18n/uk/features/support/world.rb +8 -0
  23. data/examples/i18n/uk/lib/calculator.rb +24 -0
  24. data/examples/i18n/uz/features/step_definitons/calculator_steps.rb +1 -1
  25. data/examples/sinatra/features/add.feature +1 -1
  26. data/examples/sinatra/features/step_definitions/add_steps.rb +1 -1
  27. data/examples/sinatra/features/support/env.rb +2 -19
  28. data/examples/sinatra/views/add.erb +7 -5
  29. data/features/announce.feature +46 -39
  30. data/features/background.feature +3 -0
  31. data/features/call_many_steps.feature +1 -1
  32. data/features/cucumber_cli_outlines.feature +12 -0
  33. data/features/drb_server_integration.feature +1 -1
  34. data/features/exception_in_after_block.feature +3 -0
  35. data/features/exception_in_after_step_block.feature +3 -0
  36. data/features/html_formatter/a.html +29 -29
  37. data/features/language_help.feature +57 -52
  38. data/features/multiline_names.feature +1 -0
  39. data/features/step_definitions/cucumber_steps.rb +2 -1
  40. data/features/usage_and_stepdefs_formatter.feature +30 -30
  41. data/features/wire_protocol.feature +12 -9
  42. data/features/wire_protocol_table_diffing.feature +8 -6
  43. data/features/wire_protocol_timeouts.feature +5 -4
  44. data/gem_tasks/treetop.rake +13 -0
  45. data/lib/autotest/cucumber_mixin.rb +1 -1
  46. data/lib/cucumber/ast.rb +1 -0
  47. data/lib/cucumber/ast/background.rb +14 -4
  48. data/lib/cucumber/ast/examples.rb +2 -0
  49. data/lib/cucumber/ast/feature.rb +26 -5
  50. data/lib/cucumber/ast/feature_element.rb +18 -9
  51. data/lib/cucumber/ast/outline_table.rb +13 -1
  52. data/lib/cucumber/ast/py_string.rb +26 -9
  53. data/lib/cucumber/ast/scenario.rb +13 -7
  54. data/lib/cucumber/ast/scenario_outline.rb +18 -6
  55. data/lib/cucumber/ast/step.rb +4 -4
  56. data/lib/cucumber/ast/step_invocation.rb +5 -2
  57. data/lib/cucumber/ast/table.rb +26 -1
  58. data/lib/cucumber/ast/tags.rb +3 -1
  59. data/lib/cucumber/ast/tree_walker.rb +2 -18
  60. data/lib/cucumber/cli/configuration.rb +2 -2
  61. data/lib/cucumber/cli/options.rb +16 -21
  62. data/lib/cucumber/feature_file.rb +25 -7
  63. data/lib/cucumber/formatter/ansicolor.rb +6 -1
  64. data/lib/cucumber/formatter/console.rb +4 -3
  65. data/lib/cucumber/formatter/html.rb +8 -5
  66. data/lib/cucumber/formatter/junit.rb +5 -4
  67. data/lib/cucumber/formatter/pdf.rb +2 -3
  68. data/lib/cucumber/formatter/pretty.rb +5 -5
  69. data/lib/cucumber/formatter/usage.rb +2 -2
  70. data/lib/cucumber/parser.rb +0 -6
  71. data/lib/cucumber/parser/gherkin_builder.rb +142 -0
  72. data/lib/cucumber/platform.rb +0 -2
  73. data/lib/cucumber/rb_support/rb_language.rb +7 -12
  74. data/lib/cucumber/step_mother.rb +4 -26
  75. data/spec/cucumber/ast/background_spec.rb +0 -1
  76. data/spec/cucumber/ast/feature_factory.rb +2 -4
  77. data/spec/cucumber/ast/feature_spec.rb +0 -2
  78. data/spec/cucumber/ast/py_string_spec.rb +2 -13
  79. data/spec/cucumber/ast/scenario_outline_spec.rb +0 -1
  80. data/spec/cucumber/ast/scenario_spec.rb +0 -1
  81. data/spec/cucumber/ast/step_spec.rb +1 -1
  82. data/spec/cucumber/ast/table_spec.rb +2 -2
  83. data/spec/cucumber/cli/main_spec.rb +1 -1
  84. data/spec/cucumber/cli/options_spec.rb +2 -2
  85. data/spec/cucumber/formatter/html_spec.rb +20 -1
  86. data/spec/cucumber/formatter/junit_spec.rb +1 -0
  87. data/spec/cucumber/formatter/spec_helper.rb +7 -5
  88. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +0 -1
  89. data/spec/cucumber/step_mother_spec.rb +2 -2
  90. data/spec/spec_helper.rb +0 -1
  91. metadata +67 -93
  92. data/lib/cucumber/cli/language_help_formatter.rb +0 -72
  93. data/lib/cucumber/filter.rb +0 -43
  94. data/lib/cucumber/languages.yml +0 -536
  95. data/lib/cucumber/parser/common.rb +0 -182
  96. data/lib/cucumber/parser/common.tt +0 -21
  97. data/lib/cucumber/parser/feature.rb +0 -1591
  98. data/lib/cucumber/parser/feature.tt +0 -287
  99. data/lib/cucumber/parser/i18n.tt +0 -35
  100. data/lib/cucumber/parser/natural_language.rb +0 -118
  101. data/lib/cucumber/parser/py_string.rb +0 -285
  102. data/lib/cucumber/parser/py_string.tt +0 -45
  103. data/lib/cucumber/parser/table.rb +0 -314
  104. data/lib/cucumber/parser/table.tt +0 -60
  105. data/lib/cucumber/parser/treetop_ext.rb +0 -54
  106. data/lib/cucumber/tag_expression.rb +0 -41
  107. data/spec/cucumber/ast/feature_element_spec.rb +0 -41
  108. data/spec/cucumber/ast/step_collection_spec.rb +0 -17
  109. data/spec/cucumber/parser/feature_parser_spec.rb +0 -400
  110. data/spec/cucumber/parser/table_parser_spec.rb +0 -52
  111. data/spec/cucumber/tag_expression_spec.rb +0 -125
  112. data/spec/cucumber/treetop_parser/empty_feature.feature +0 -4
  113. data/spec/cucumber/treetop_parser/empty_scenario.feature +0 -9
  114. data/spec/cucumber/treetop_parser/empty_scenario_outline.feature +0 -3
  115. data/spec/cucumber/treetop_parser/fit_scenario.feature +0 -8
  116. data/spec/cucumber/treetop_parser/given_scenario.feature +0 -9
  117. data/spec/cucumber/treetop_parser/invalid_scenario_outlines.feature +0 -7
  118. data/spec/cucumber/treetop_parser/multiline_steps.feature +0 -17
  119. data/spec/cucumber/treetop_parser/multiple_tables.feature +0 -27
  120. data/spec/cucumber/treetop_parser/scenario_outline.feature +0 -16
  121. data/spec/cucumber/treetop_parser/spaces.feature +0 -12
  122. data/spec/cucumber/treetop_parser/test_dos.feature +0 -25
  123. data/spec/cucumber/treetop_parser/with_comments.feature +0 -23
  124. data/spec/cucumber/treetop_parser/with_tags.feature +0 -18
@@ -1,3 +1,5 @@
1
+ require 'gherkin/parser/tag_expression'
2
+
1
3
  module Cucumber
2
4
  module Ast
3
5
  class Tags #:nodoc:
@@ -15,7 +17,7 @@ module Cucumber
15
17
  end
16
18
 
17
19
  def accept_hook?(hook)
18
- TagExpression.parse(hook.tag_expressions).eval(@tag_names)
20
+ Gherkin::Parser::TagExpression.new(hook.tag_expressions).eval(@tag_names)
19
21
  end
20
22
 
21
23
  def to_sexp
@@ -41,8 +41,8 @@ module Cucumber
41
41
  broadcast(tag_name)
42
42
  end
43
43
 
44
- def visit_feature_name(name)
45
- broadcast(name)
44
+ def visit_feature_name(keyword, name)
45
+ broadcast(keyword, name)
46
46
  end
47
47
 
48
48
  # +feature_element+ is either Scenario or ScenarioOutline
@@ -75,22 +75,6 @@ module Cucumber
75
75
  end
76
76
 
77
77
  def visit_examples_name(keyword, name)
78
- unless keyword =~ /:$/
79
- message = <<EOS
80
-
81
-
82
- (::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)
83
-
84
- DEPRECATION WARNING
85
-
86
- Future versions of Cucumber will not recognize #{keyword}
87
- unless it is followed by a colon. Make this change in
88
- your features now to prevent this warning from appearing.
89
-
90
- (::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)
91
- EOS
92
- announce(message)
93
- end
94
78
  broadcast(keyword, name)
95
79
  end
96
80
 
@@ -1,7 +1,7 @@
1
1
  require 'logger'
2
2
  require 'cucumber/cli/options'
3
3
  require 'cucumber/constantize'
4
- require 'cucumber/tag_expression'
4
+ require 'gherkin/parser/tag_expression'
5
5
 
6
6
  module Cucumber
7
7
  module Cli
@@ -26,7 +26,7 @@ module Cucumber
26
26
  arrange_formats
27
27
  raise("You can't use both --strict and --wip") if strict? && wip?
28
28
 
29
- @options[:tag_expression] = TagExpression.parse(@options[:tag_expressions])
29
+ @options[:tag_expression] = Gherkin::Parser::TagExpression.new(@options[:tag_expressions])
30
30
  return @args.replace(@options.expanded_args_without_drb) if drb?
31
31
 
32
32
  set_environment_variables
@@ -1,6 +1,6 @@
1
1
  require 'cucumber/cli/profile_loader'
2
2
  require 'cucumber/formatter/ansicolor'
3
- require 'cucumber/tag_expression'
3
+ require 'gherkin/parser/tag_expression'
4
4
 
5
5
  module Cucumber
6
6
  module Cli
@@ -279,6 +279,10 @@ module Cucumber
279
279
  @profiles - [@default_profile]
280
280
  end
281
281
 
282
+ def filters
283
+ @options.values_at(:name_regexps, :tag_expressions).select{|v| !v.empty?}.first || []
284
+ end
285
+
282
286
  protected
283
287
 
284
288
  attr_reader :options, :profiles, :expanded_args
@@ -286,15 +290,15 @@ module Cucumber
286
290
 
287
291
  private
288
292
 
289
- def non_stdout_formats
290
- @options[:formats].select {|format, output| output != @out_stream }
291
- end
293
+ def non_stdout_formats
294
+ @options[:formats].select {|format, output| output != @out_stream }
295
+ end
292
296
 
293
- def stdout_formats
294
- @options[:formats].select {|format, output| output == @out_stream }
295
- end
297
+ def stdout_formats
298
+ @options[:formats].select {|format, output| output == @out_stream }
299
+ end
296
300
 
297
- def extract_environment_variables
301
+ def extract_environment_variables
298
302
  @args.delete_if do |arg|
299
303
  if arg =~ /^(\w+)=(.*)$/
300
304
  @options[:env_vars][$1] = $2
@@ -303,10 +307,6 @@ module Cucumber
303
307
  end
304
308
  end
305
309
 
306
- def tag_filter(tag_string)
307
- tags = TagExpression.parse(tag_string)
308
- end
309
-
310
310
  def disable_profile_loading?
311
311
  @disable_profile_loading
312
312
  end
@@ -325,7 +325,6 @@ module Cucumber
325
325
  Options.parse(profile_args, @out_stream, @error_stream, :skip_profile_information => true)
326
326
  )
327
327
  end
328
-
329
328
  end
330
329
 
331
330
  def default_profile_should_be_used?
@@ -367,19 +366,15 @@ module Cucumber
367
366
  self
368
367
  end
369
368
 
370
- # TODO: Move to Language
371
369
  def list_keywords_and_exit(lang)
372
- unless Cucumber::LANGUAGES[lang]
373
- raise("No language with key #{lang}")
374
- end
375
- require 'cucumber/cli/language_help_formatter'
376
- LanguageHelpFormatter.list_keywords(@out_stream, lang)
370
+ require 'gherkin/i18n'
371
+ @out_stream.write(Gherkin::I18n.get(lang).keyword_table)
377
372
  Kernel.exit(0)
378
373
  end
379
374
 
380
375
  def list_languages_and_exit
381
- require 'cucumber/cli/language_help_formatter'
382
- LanguageHelpFormatter.list_languages(@out_stream)
376
+ require 'gherkin/i18n'
377
+ @out_stream.write(Gherkin::I18n.language_table)
383
378
  Kernel.exit(0)
384
379
  end
385
380
 
@@ -1,5 +1,7 @@
1
- require 'cucumber/parser/natural_language'
2
- require 'cucumber/filter'
1
+ require 'cucumber/parser/gherkin_builder'
2
+ require 'gherkin/parser/filter_listener'
3
+ require 'gherkin/parser/parser'
4
+ require 'gherkin/i18n_lexer'
3
5
 
4
6
  module Cucumber
5
7
  class FeatureFile
@@ -22,11 +24,26 @@ module Cucumber
22
24
  # If +options+ contains tags, the result will
23
25
  # be filtered.
24
26
  def parse(step_mother, options)
25
- filter = Filter.new(@lines, options)
26
- language = Parser::NaturalLanguage.get(step_mother, (lang || 'en'))
27
- language.parse(source, @path, filter)
27
+ filters = @lines || options.filters
28
+
29
+ builder = Cucumber::Parser::GherkinBuilder.new
30
+ filter_listener = Gherkin::Parser::FilterListener.new(builder, filters)
31
+ parser = Gherkin::Parser::Parser.new(filter_listener, true, "root")
32
+ lexer = Gherkin::I18nLexer.new(parser, false)
33
+
34
+ begin
35
+ lexer.scan(source)
36
+ ast = builder.ast
37
+ return nil if ast.nil? # Filter caused nothing to match
38
+ ast.language = lexer.i18n_language
39
+ ast.file = @path
40
+ ast
41
+ rescue Gherkin::LexingError => e
42
+ e.message.insert(0, "#{@path}: ")
43
+ raise e
44
+ end
28
45
  end
29
-
46
+
30
47
  def source
31
48
  @source ||= if @path =~ /^http/
32
49
  require 'open-uri'
@@ -43,6 +60,7 @@ module Cucumber
43
60
  end
44
61
 
45
62
  def lang
63
+ # TODO: Gherkin has logic for this. Remove.
46
64
  line_one = source.split(/\n/)[0]
47
65
  if line_one =~ LANGUAGE_PATTERN
48
66
  $1.strip
@@ -51,4 +69,4 @@ module Cucumber
51
69
  end
52
70
  end
53
71
  end
54
- end
72
+ end
@@ -1,4 +1,9 @@
1
- require 'term/ansicolor'
1
+ begin
2
+ require 'term/ansicolor'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'term/ansicolor'
6
+ end
2
7
  require 'cucumber/platform'
3
8
 
4
9
  if Cucumber::IRONRUBY
@@ -22,7 +22,7 @@ module Cucumber
22
22
  end
23
23
 
24
24
  format = format_for(status, :param)
25
- line = keyword + " " + step_match.format_args(format) + comment
25
+ line = keyword + step_match.format_args(format) + comment
26
26
  format_string(line, status)
27
27
  end
28
28
 
@@ -63,9 +63,10 @@ module Cucumber
63
63
  end
64
64
 
65
65
  def print_stats(features, profiles = [])
66
- @failures = step_mother.scenarios(:failed).select { |s| s.is_a?(Cucumber::Ast::Scenario) }
66
+ @failures = step_mother.scenarios(:failed).select { |s| s.is_a?(Cucumber::Ast::Scenario) || s.is_a?(Cucumber::Ast::OutlineTable::ExampleRow) }
67
+ @failures.collect! { |s| (s.is_a?(Cucumber::Ast::OutlineTable::ExampleRow)) ? s.scenario_outline : s }
67
68
 
68
- if !@failures.empty?
69
+ if !@failures.empty?
69
70
  @io.puts format_string("Failing Scenarios:", :failed)
70
71
  @failures.each do |failure|
71
72
  profiles_string = profiles.empty? ? '' : (profiles.map{|profile| "-p #{profile}" }).join(' ') + ' '
@@ -1,3 +1,4 @@
1
+ require 'erb'
1
2
  require 'cucumber/formatter/ordered_xml_markup'
2
3
  require 'cucumber/formatter/duration'
3
4
  require 'cucumber/formatter/io'
@@ -109,11 +110,11 @@ module Cucumber
109
110
  @builder.span(tag_name, :class => 'tag')
110
111
  end
111
112
 
112
- def feature_name(name)
113
+ def feature_name(keyword, name)
113
114
  lines = name.split(/\r?\n/)
114
115
  return if lines.empty?
115
116
  @builder.h2 do |h2|
116
- @builder.span(lines[0], :class => 'val')
117
+ @builder.span(keyword + ': ' + lines[0], :class => 'val')
117
118
  end
118
119
  @builder.p(:class => 'narrative') do
119
120
  lines[1..-1].each do |line|
@@ -383,11 +384,14 @@ module Cucumber
383
384
  features.each do |feature|
384
385
  #get background steps
385
386
  if feature.instance_variable_get("@background")
386
- background = feature.instance_variable_get("@background").instance_variable_get("@steps").instance_variable_get("@steps")
387
- count += background.size
387
+ background = feature.instance_variable_get("@background")
388
+ background.init
389
+ background_steps = background.instance_variable_get("@steps").instance_variable_get("@steps")
390
+ count += background_steps.size
388
391
  end
389
392
  #get scenarios
390
393
  feature.instance_variable_get("@feature_elements").each do |scenario|
394
+ scenario.init
391
395
  #get steps
392
396
  steps = scenario.instance_variable_get("@steps").instance_variable_get("@steps")
393
397
  count += steps.size
@@ -417,7 +421,6 @@ module Cucumber
417
421
  step_name = step_match.format_args(lambda{|param| %{<span class="param">#{param}</span>}})
418
422
  @builder.div(:class => 'step_name') do |div|
419
423
  @builder.span(keyword, :class => 'keyword')
420
- @builder.text!(' ')
421
424
  @builder.span(:class => 'step val') do |name|
422
425
  name << h(step_name).gsub(/&lt;span class=&quot;(.*?)&quot;&gt;/, '<span class="\1">').gsub(/&lt;\/span&gt;/, '</span>')
423
426
  end
@@ -49,15 +49,16 @@ module Cucumber
49
49
  @in_background = false
50
50
  end
51
51
 
52
- def feature_name(name)
52
+ def feature_name(keyword, name)
53
53
  raise UnNamedFeatureError.new(@current_feature.file) if name.empty?
54
54
  lines = name.split(/\r?\n/)
55
- @feature_name = lines[0].sub(/Feature\:/, '').strip
55
+ @feature_name = lines[0]
56
56
  end
57
57
 
58
58
  def scenario_name(keyword, name, file_colon_line, source_indent)
59
+ # TODO: What's all this ugly weird code doing? Why not just use keyword and name????
59
60
  scenario_name = name.strip.delete(".\r\n")
60
- scenario_name = "Unnamed scenario" if name.blank?
61
+ scenario_name = "Unnamed scenario" if name == ""
61
62
  @scenario = scenario_name
62
63
  description = "Scenario"
63
64
  description << " outline" if keyword.include?('Scenario Outline')
@@ -73,7 +74,7 @@ module Cucumber
73
74
 
74
75
  duration = Time.now - @steps_start
75
76
  if steps.failed?
76
- steps.each { |step| @output += "#{step.keyword} #{step.name}\n" }
77
+ steps.each { |step| @output += "#{step.keyword}#{step.name}\n" }
77
78
  @output += "\nMessage:\n"
78
79
  end
79
80
  build_testcase(duration, steps.status, steps.exception)
@@ -94,12 +94,11 @@ module Cucumber
94
94
  puts "\ndone"
95
95
  end
96
96
 
97
- def feature_name(name)
97
+ def feature_name(keyword, name)
98
98
  @pdf.start_new_page
99
- name["Feature:"] = "" if name["Feature:"]
100
99
  names = name.split("\n")
101
100
  @pdf.fill_color GREY
102
- @pdf.text('Feature', :align => :center)
101
+ @pdf.text(keyword, :align => :center)
103
102
  @pdf.fill_color BLACK
104
103
  names.each_with_index do |nameline, i|
105
104
  case i
@@ -60,8 +60,8 @@ module Cucumber
60
60
  @indent = 1
61
61
  end
62
62
 
63
- def feature_name(name)
64
- @io.puts(name)
63
+ def feature_name(keyword, name)
64
+ @io.puts("#{keyword}: #{name}")
65
65
  @io.puts
66
66
  @io.flush
67
67
  end
@@ -102,7 +102,7 @@ module Cucumber
102
102
  puts unless @visiting_first_example_name
103
103
  @visiting_first_example_name = false
104
104
  names = name.strip.empty? ? [name.strip] : name.split("\n")
105
- @io.puts(" #{keyword} #{names[0]}")
105
+ @io.puts(" #{keyword}: #{names[0]}")
106
106
  names[1..-1].each {|s| @io.puts " #{s}" } unless names.empty?
107
107
  @io.flush
108
108
  @indent = 6
@@ -119,7 +119,7 @@ module Cucumber
119
119
  end
120
120
 
121
121
  def scenario_name(keyword, name, file_colon_line, source_indent)
122
- print_feature_element_name keyword, name, file_colon_line, source_indent
122
+ print_feature_element_name(keyword, name, file_colon_line, source_indent)
123
123
  end
124
124
 
125
125
  def before_step(step)
@@ -210,7 +210,7 @@ module Cucumber
210
210
  def print_feature_element_name(keyword, name, file_colon_line, source_indent)
211
211
  @io.puts if @scenario_indent == 6
212
212
  names = name.empty? ? [name] : name.split("\n")
213
- line = "#{keyword} #{names[0]}".indent(@scenario_indent)
213
+ line = "#{keyword}: #{names[0]}".indent(@scenario_indent)
214
214
  @io.print(line)
215
215
  if @options[:source]
216
216
  line_comment = " # #{file_colon_line}".indent(source_indent)
@@ -69,7 +69,7 @@ module Cucumber
69
69
  @io.print format_string(stepdef_key.regexp_source, stepdef_key.status)
70
70
  if @options[:source]
71
71
  indent = max_length - stepdef_key.regexp_source.jlength
72
- line_comment = " # #{stepdef_key.file_colon_line}".indent(indent)
72
+ line_comment = " # #{stepdef_key.file_colon_line}".indent(indent)
73
73
  @io.print(format_string(line_comment, :comment))
74
74
  end
75
75
  @io.puts
@@ -98,7 +98,7 @@ module Cucumber
98
98
  end
99
99
 
100
100
  def max_step_length
101
- @stepdef_to_match.values.flatten.map do |step|
101
+ @stepdef_to_match.values.to_a.flatten.map do |step|
102
102
  step[:keyword].jlength + step[:step_match].format_args.jlength
103
103
  end.max
104
104
  end
@@ -1,8 +1,2 @@
1
- require 'erb'
2
1
  require 'cucumber/platform'
3
2
  require 'cucumber/ast'
4
- require 'cucumber/parser/treetop_ext'
5
- require 'cucumber/parser/common'
6
- require 'cucumber/parser/table'
7
- require 'cucumber/parser/py_string'
8
- require 'cucumber/parser/feature'
@@ -0,0 +1,142 @@
1
+ require 'cucumber/ast'
2
+
3
+ module Cucumber
4
+ module Parser
5
+ # This class conforms to the Gherkin event API and builds the
6
+ # "legacy" AST. It will be replaced later when we have a new "clean"
7
+ # AST.
8
+ class GherkinBuilder
9
+
10
+ def ast
11
+ @feature || @multiline_arg
12
+ end
13
+
14
+ def tag(name, line)
15
+ @tags ||= []
16
+ @tags << name
17
+ end
18
+
19
+ def comment(content, line)
20
+ @comments ||= []
21
+ @comments << content
22
+ end
23
+
24
+ def feature(keyword, name, line)
25
+ @feature = Ast::Feature.new(
26
+ nil,
27
+ Ast::Comment.new(grab_comments!('')),
28
+ Ast::Tags.new(nil, grab_tags!('')),
29
+ keyword,
30
+ name,
31
+ []
32
+ )
33
+ end
34
+
35
+ def background(keyword, name, line)
36
+ @background = Ast::Background.new(
37
+ Ast::Comment.new(grab_comments!('')),
38
+ line,
39
+ keyword,
40
+ name,
41
+ steps=[]
42
+ )
43
+ @feature.background = @background
44
+ @background.feature = @feature
45
+ @step_container = @background
46
+ end
47
+
48
+ def scenario(keyword, name, line)
49
+ grab_table!
50
+ scenario = Ast::Scenario.new(
51
+ @background,
52
+ Ast::Comment.new(grab_comments!('')),
53
+ Ast::Tags.new(nil, grab_tags!('')),
54
+ line,
55
+ keyword,
56
+ name,
57
+ steps=[]
58
+ )
59
+ @feature.add_feature_element(scenario)
60
+ @background.feature_elements << scenario if @background
61
+ @step_container = scenario
62
+ end
63
+
64
+ def scenario_outline(keyword, name, line)
65
+ grab_table!
66
+ scenario_outline = Ast::ScenarioOutline.new(
67
+ @background,
68
+ Ast::Comment.new(grab_comments!('')),
69
+ Ast::Tags.new(nil, grab_tags!('')),
70
+ line,
71
+ keyword,
72
+ name,
73
+ steps=[],
74
+ example_sections=[]
75
+ )
76
+ @feature.add_feature_element(scenario_outline)
77
+ @background.feature_elements << scenario_outline if @background
78
+ @step_container = scenario_outline
79
+ end
80
+
81
+ def examples(keyword, name, line)
82
+ grab_table!
83
+ @examples_fields = [Ast::Comment.new(grab_comments!('')), line, keyword, name]
84
+ end
85
+
86
+ def step(keyword, name, line)
87
+ grab_table!
88
+ @table_owner = Ast::Step.new(line, keyword, name)
89
+ @step_container.add_step(@table_owner)
90
+ end
91
+
92
+ def row(row, line)
93
+ @rows ||= []
94
+ @rows << row
95
+ class << row
96
+ attr_accessor :line
97
+ end
98
+ row.line = line
99
+ end
100
+
101
+ def py_string(string, line)
102
+ @multiline_arg = Ast::PyString.new(string)
103
+ @table_owner.multiline_arg = @multiline_arg if @table_owner
104
+ end
105
+
106
+ def eof
107
+ grab_table!
108
+ end
109
+
110
+ def syntax_error(state, event, legal_events, line)
111
+ # raise "SYNTAX ERROR"
112
+ end
113
+
114
+ private
115
+
116
+ def grab_table!
117
+ return if @rows.nil?
118
+ if @examples_fields
119
+ @examples_fields << @rows
120
+ @step_container.add_examples(@examples_fields)
121
+ @examples_fields = nil
122
+ else
123
+ @multiline_arg = Ast::Table.new(@rows)
124
+ @table_owner.multiline_arg = @multiline_arg if @table_owner
125
+ end
126
+ @rows = nil
127
+ end
128
+
129
+ def grab_tags!(indent)
130
+ tags = @tags ? @tags : []
131
+ @tags = nil
132
+ tags
133
+ end
134
+
135
+ def grab_comments!(indent)
136
+ comments = @comments ? indent + @comments.join("\n#{indent}") : ''
137
+ @comments = nil
138
+ comments
139
+ end
140
+ end
141
+ end
142
+ end