kosmas58-cucumber 0.3.11.3 → 0.3.11.6

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 (120) hide show
  1. data/History.txt +36 -0
  2. data/Manifest.txt +9 -0
  3. data/config/hoe.rb +1 -2
  4. data/examples/i18n/ar/Rakefile +1 -1
  5. data/examples/i18n/ar/features/addition.feature +1 -0
  6. data/examples/i18n/bg/Rakefile +1 -1
  7. data/examples/i18n/bg/features/addition.feature +1 -0
  8. data/examples/i18n/bg/features/consecutive_calculations.feature +1 -0
  9. data/examples/i18n/bg/features/division.feature +1 -0
  10. data/examples/i18n/cat/Rakefile +1 -1
  11. data/examples/i18n/cat/features/suma.feature +1 -0
  12. data/examples/i18n/da/Rakefile +1 -1
  13. data/examples/i18n/da/features/summering.feature +1 -0
  14. data/examples/i18n/de/Rakefile +1 -1
  15. data/examples/i18n/de/features/addition.feature +1 -0
  16. data/examples/i18n/de/features/division.feature +1 -0
  17. data/examples/i18n/en/Rakefile +1 -1
  18. data/examples/i18n/en/features/addition.feature +1 -0
  19. data/examples/i18n/en/features/division.feature +1 -0
  20. data/examples/i18n/en-lol/features/stuffing.feature +1 -1
  21. data/examples/i18n/es/Rakefile +1 -1
  22. data/examples/i18n/es/features/adicion.feature +1 -0
  23. data/examples/i18n/et/Rakefile +1 -1
  24. data/examples/i18n/et/features/jagamine.feature +1 -0
  25. data/examples/i18n/et/features/liitmine.feature +1 -0
  26. data/examples/i18n/fi/Rakefile +1 -1
  27. data/examples/i18n/fi/features/jakolasku.feature +1 -0
  28. data/examples/i18n/fr/Rakefile +1 -1
  29. data/examples/i18n/fr/features/addition.feature +2 -1
  30. data/examples/i18n/he/Rakefile +1 -1
  31. data/examples/i18n/he/features/addition.feature +1 -0
  32. data/examples/i18n/he/features/division.feature +1 -0
  33. data/examples/i18n/hu/Rakefile +1 -1
  34. data/examples/i18n/hu/features/addition.feature +1 -0
  35. data/examples/i18n/hu/features/division.feature +1 -0
  36. data/examples/i18n/id/Rakefile +1 -1
  37. data/examples/i18n/id/features/addition.feature +1 -0
  38. data/examples/i18n/id/features/division.feature +1 -0
  39. data/examples/i18n/it/Rakefile +1 -1
  40. data/examples/i18n/it/features/somma.feature +1 -0
  41. data/examples/i18n/ja/Rakefile +1 -1
  42. data/examples/i18n/ja/features/addition.feature +1 -0
  43. data/examples/i18n/ja/features/division.feature +1 -0
  44. data/examples/i18n/ko/Rakefile +1 -1
  45. data/examples/i18n/ko/features/addition.feature +1 -0
  46. data/examples/i18n/ko/features/division.feature +1 -0
  47. data/examples/i18n/lt/Rakefile +1 -1
  48. data/examples/i18n/lt/features/addition.feature +1 -0
  49. data/examples/i18n/lt/features/division.feature +1 -0
  50. data/examples/i18n/lv/Rakefile +1 -1
  51. data/examples/i18n/lv/features/addition.feature +1 -0
  52. data/examples/i18n/lv/features/division.feature +1 -0
  53. data/examples/i18n/no/Rakefile +1 -1
  54. data/examples/i18n/no/features/summering.feature +1 -0
  55. data/examples/i18n/pl/Rakefile +1 -1
  56. data/examples/i18n/pl/features/addition.feature +1 -0
  57. data/examples/i18n/pl/features/division.feature +1 -0
  58. data/examples/i18n/pt/Rakefile +1 -1
  59. data/examples/i18n/pt/features/adicao.feature +1 -0
  60. data/examples/i18n/ro/Rakefile +1 -1
  61. data/examples/i18n/ro/features/suma.feature +1 -0
  62. data/examples/i18n/ru/Rakefile +1 -1
  63. data/examples/i18n/ru/features/addition.feature +1 -0
  64. data/examples/i18n/ru/features/consecutive_calculations.feature +1 -0
  65. data/examples/i18n/ru/features/division.feature +1 -0
  66. data/examples/i18n/se/Rakefile +1 -1
  67. data/examples/i18n/se/features/summering.feature +1 -0
  68. data/examples/i18n/sk/Rakefile +1 -1
  69. data/examples/i18n/sk/features/addition.feature +1 -0
  70. data/examples/i18n/sk/features/division.feature +1 -0
  71. data/examples/i18n/zh-CN/features/addition.feature +1 -0
  72. data/examples/i18n/zh-TW/features/addition.feature +1 -0
  73. data/examples/i18n/zh-TW/features/division.feature +1 -0
  74. data/examples/sinatra/features/step_definitions/add_steps.rb +1 -1
  75. data/examples/sinatra/features/support/env.rb +13 -5
  76. data/features/after_block_exceptions.feature +4 -1
  77. data/features/after_step_block_exceptions.feature +4 -1
  78. data/features/background.feature +6 -0
  79. data/features/cucumber_cli.feature +11 -1
  80. data/features/cucumber_cli_diff_disabled.feature +7 -1
  81. data/features/drb_server_integration.feature +5 -4
  82. data/features/expand.feature +2 -1
  83. data/features/html_formatter/a.html +12 -14
  84. data/features/junit_formatter.feature +4 -4
  85. data/features/step_definitions/cucumber_steps.rb +2 -2
  86. data/features/support/env.rb +7 -4
  87. data/features/work_in_progress.feature +3 -0
  88. data/lib/cucumber/ast/comment.rb +1 -1
  89. data/lib/cucumber/ast/feature.rb +2 -2
  90. data/lib/cucumber/ast/feature_element.rb +4 -0
  91. data/lib/cucumber/ast/scenario.rb +5 -3
  92. data/lib/cucumber/ast/scenario_outline.rb +6 -1
  93. data/lib/cucumber/ast/step.rb +4 -0
  94. data/lib/cucumber/ast/step_invocation.rb +6 -1
  95. data/lib/cucumber/cli/configuration.rb +37 -26
  96. data/lib/cucumber/cli/main.rb +4 -5
  97. data/lib/cucumber/formatter/console.rb +12 -0
  98. data/lib/cucumber/formatter/html.rb +3 -2
  99. data/lib/cucumber/formatter/junit.rb +3 -6
  100. data/lib/cucumber/formatter/pretty.rb +2 -4
  101. data/lib/cucumber/formatter/profile.rb +1 -1
  102. data/lib/cucumber/languages.yml +3 -3
  103. data/lib/cucumber/parser/feature.rb +12 -16
  104. data/lib/cucumber/parser/feature.tt +1 -3
  105. data/lib/cucumber/parser/i18n.tt +30 -23
  106. data/lib/cucumber/parser/treetop_ext.rb +12 -83
  107. data/lib/cucumber/parser.rb +1 -33
  108. data/lib/cucumber/platform.rb +6 -0
  109. data/lib/cucumber/step_definition.rb +6 -0
  110. data/lib/cucumber/step_mother.rb +3 -3
  111. data/lib/cucumber/version.rb +1 -1
  112. data/lib/cucumber.rb +0 -57
  113. data/rails_generators/cucumber/templates/cucumber.rake +4 -0
  114. data/spec/cucumber/ast/step_collection_spec.rb +5 -4
  115. data/spec/cucumber/cli/configuration_spec.rb +42 -9
  116. data/spec/cucumber/cli/main_spec.rb +2 -10
  117. data/spec/cucumber/parser/feature_parser_spec.rb +11 -9
  118. data/spec/cucumber/parser/table_parser_spec.rb +1 -1
  119. data/spec/spec_helper.rb +0 -1
  120. metadata +3 -13
@@ -25,12 +25,14 @@ module Cucumber
25
25
  visitor.visit_tags(@tags)
26
26
  visitor.visit_scenario_name(@keyword, @name, file_colon_line(@line), source_indent(first_line_length))
27
27
 
28
- skip = @background && @background.failed?
29
- skip_invoke! if skip
30
- visitor.step_mother.before_and_after(self, skip) do
28
+ background_failed = @background && @background.failed?
29
+ skip_invoke! if background_failed
30
+ skip_hooks = background_failed || @executed
31
+ visitor.step_mother.before_and_after(self, skip_hooks) do
31
32
  visitor.visit_steps(@steps)
32
33
  end
33
34
  visitor.visit_exception(@exception, :failed) if @exception
35
+ @executed = true
34
36
  end
35
37
 
36
38
  # Returns true if one or more steps failed
@@ -69,7 +69,12 @@ module Cucumber
69
69
  end
70
70
 
71
71
  def visit_scenario_name(visitor, row)
72
- visitor.visit_scenario_name(Cucumber.scenario_keyword, row.name, file_colon_line(row.line), source_indent(first_line_length))
72
+ visitor.visit_scenario_name(
73
+ @feature.language.scenario_keyword,
74
+ row.name,
75
+ file_colon_line(row.line),
76
+ source_indent(first_line_length)
77
+ )
73
78
  end
74
79
 
75
80
  def to_sexp
@@ -74,6 +74,10 @@ module Cucumber
74
74
  @file_colon_line ||= @feature_element.file_colon_line(@line) unless @feature_element.nil?
75
75
  end
76
76
 
77
+ def language
78
+ @feature_element.language
79
+ end
80
+
77
81
  def dom_id
78
82
  @dom_id ||= file_colon_line.gsub(/\//, '_').gsub(/\./, '_').gsub(/:/, '_')
79
83
  end
@@ -88,7 +88,8 @@ module Cucumber
88
88
  end
89
89
 
90
90
  def actual_keyword
91
- if [Cucumber.keyword_hash['and'], Cucumber.keyword_hash['but']].index(@step.keyword) && previous
91
+ repeat_keywords = [language.but_keywords, language.and_keywords].flatten
92
+ if repeat_keywords.index(@step.keyword) && previous
92
93
  previous.actual_keyword
93
94
  else
94
95
  keyword
@@ -123,6 +124,10 @@ module Cucumber
123
124
  @step.backtrace_line
124
125
  end
125
126
 
127
+ def language
128
+ @step.language
129
+ end
130
+
126
131
  def to_sexp
127
132
  [:step_invocation, @step.line, @step.keyword, @name, (@multiline_arg.nil? ? nil : @multiline_arg.to_sexp)].compact
128
133
  end
@@ -4,15 +4,16 @@ module Cucumber
4
4
 
5
5
  class Configuration
6
6
  BUILTIN_FORMATS = {
7
- 'html' => 'Cucumber::Formatter::Html',
8
- 'pretty' => 'Cucumber::Formatter::Pretty',
9
- 'profile' => 'Cucumber::Formatter::Profile',
10
- 'progress' => 'Cucumber::Formatter::Progress',
11
- 'rerun' => 'Cucumber::Formatter::Rerun',
12
- 'usage' => 'Cucumber::Formatter::Usage',
13
- 'junit' => 'Cucumber::Formatter::Junit'
7
+ 'html' => 'Cucumber::Formatter::Html',
8
+ 'pretty' => 'Cucumber::Formatter::Pretty',
9
+ 'profile' => 'Cucumber::Formatter::Profile',
10
+ 'progress' => 'Cucumber::Formatter::Progress',
11
+ 'rerun' => 'Cucumber::Formatter::Rerun',
12
+ 'usage' => 'Cucumber::Formatter::Usage',
13
+ 'junit' => 'Cucumber::Formatter::Junit',
14
+ 'tag_cloud' => 'Cucumber::Formatter::TagCloud',
15
+ 'steps' => 'Cucumber::Formatter::Steps'
14
16
  }
15
- DEFAULT_FORMAT = 'pretty'
16
17
  DRB_FLAG = '--drb'
17
18
  PROFILE_SHORT_FLAG = '-p'
18
19
  PROFILE_LONG_FLAG = '--profile'
@@ -26,15 +27,21 @@ module Cucumber
26
27
 
27
28
  @paths = []
28
29
  @options = default_options
29
-
30
- @active_format = DEFAULT_FORMAT
31
30
  end
32
31
 
33
32
  def parse!(args)
34
- @args = args.empty? ? args_from_profile('default') : args
33
+ args.concat(%w{--profile default}) if args.empty?
34
+ @args = args
35
35
  expand_profiles_into_args
36
36
  return if parse_drb
37
37
 
38
+ @args.each do |arg|
39
+ if arg =~ /^(\w+)=(.*)$/
40
+ ENV[$1] = $2
41
+ @args.delete(arg)
42
+ end
43
+ end
44
+
38
45
  @args.extend(::OptionParser::Arguable)
39
46
 
40
47
  @args.options do |opts|
@@ -69,7 +76,7 @@ module Cucumber
69
76
  end
70
77
  end
71
78
  opts.on("-f FORMAT", "--format FORMAT",
72
- "How to format features (Default: #{DEFAULT_FORMAT})",
79
+ "How to format features (Default: pretty)",
73
80
  "Available formats: #{BUILTIN_FORMATS.keys.sort.join(", ")}",
74
81
  "FORMAT can also be the fully qualified class name of",
75
82
  "your own custom formatter. If the class isn't loaded,",
@@ -79,7 +86,7 @@ module Cucumber
79
86
  "foo/bar_zap.rb. You can place the file with this relative",
80
87
  "path underneath your features/support directory or anywhere",
81
88
  "on Ruby's LOAD_PATH, for example in a Ruby gem.") do |v|
82
- @options[:formats][v] = @out_stream
89
+ @options[:formats] << [v, @out_stream]
83
90
  @active_format = v
84
91
  end
85
92
  opts.on("-o", "--out [FILE|DIR]",
@@ -87,7 +94,8 @@ module Cucumber
87
94
  "applies to the previously specified --format, or the",
88
95
  "default format if no format is specified. Check the specific",
89
96
  "formatter's docs to see whether to pass a file or a dir.") do |v|
90
- @options[:formats][@active_format] = v
97
+ @options[:formats] << ['pretty', nil] if @options[:formats].empty?
98
+ @options[:formats][-1][1] = v
91
99
  end
92
100
  opts.on("-t TAGS", "--tags TAGS",
93
101
  "Only execute the features or scenarios with the specified tags.",
@@ -176,7 +184,7 @@ module Cucumber
176
184
  end
177
185
  end.parse!
178
186
 
179
- @options[:formats]['pretty'] = @out_stream if @options[:formats].empty?
187
+ arrange_formats
180
188
 
181
189
  @options[:snippets] = true if !@quiet && @options[:snippets].nil?
182
190
  @options[:source] = true if !@quiet && @options[:source].nil?
@@ -211,14 +219,6 @@ module Cucumber
211
219
  @drb
212
220
  end
213
221
 
214
- def load_language
215
- if Cucumber.language_incomplete?(@options[:lang])
216
- list_keywords_and_exit(@options[:lang])
217
- else
218
- Cucumber.load_language(@options[:lang])
219
- end
220
- end
221
-
222
222
  def parse_tags(tag_string)
223
223
  tag_names = tag_string.split(",")
224
224
  excludes, includes = tag_names.partition{|tag| tag =~ /^~/}
@@ -232,7 +232,9 @@ module Cucumber
232
232
 
233
233
  def build_formatter_broadcaster(step_mother)
234
234
  return Formatter::Pretty.new(step_mother, nil, @options) if @options[:autoformat]
235
- formatters = @options[:formats].map do |format, out|
235
+ formatters = @options[:formats].map do |format_and_out|
236
+ format = format_and_out[0]
237
+ out = format_and_out[1]
236
238
  if String === out # file name
237
239
  unless File.directory?(out)
238
240
  out = File.open(out, Cucumber.file_mode('w'))
@@ -292,6 +294,14 @@ module Cucumber
292
294
 
293
295
  protected
294
296
 
297
+ def arrange_formats
298
+ @options[:formats] << ['pretty', @out_stream] if @options[:formats].empty?
299
+ @options[:formats] = @options[:formats].sort_by{|f| f[1] == @out_stream ? -1 : 1}
300
+ if @options[:formats].length > 1 && @options[:formats][1][1] == @out_stream
301
+ raise "All but one formatter must use --out, only one can print to STDOUT"
302
+ end
303
+ end
304
+
295
305
  def remove_excluded_files_from(files)
296
306
  files.reject! {|path| @options[:excludes].detect {|pattern| path =~ pattern } }
297
307
  end
@@ -377,6 +387,7 @@ Defined profiles in cucumber.yml:
377
387
  return @cucumber_yml
378
388
  end
379
389
 
390
+ # TODO: Move to Language
380
391
  def list_keywords_and_exit(lang)
381
392
  unless Cucumber::LANGUAGES[lang]
382
393
  raise("No language with key #{lang}")
@@ -398,9 +409,9 @@ Defined profiles in cucumber.yml:
398
409
  {
399
410
  :strict => false,
400
411
  :require => nil,
401
- :lang => 'en',
412
+ :lang => nil,
402
413
  :dry_run => false,
403
- :formats => {},
414
+ :formats => [],
404
415
  :excludes => [],
405
416
  :include_tags => [],
406
417
  :exclude_tags => [],
@@ -2,6 +2,7 @@ require 'optparse'
2
2
  require 'cucumber'
3
3
  require 'ostruct'
4
4
  require 'cucumber/parser'
5
+ require 'cucumber/feature_file'
5
6
  require 'cucumber/formatter/color_io'
6
7
  require 'cucumber/cli/language_help_formatter'
7
8
  require 'cucumber/cli/configuration'
@@ -41,13 +42,11 @@ module Cucumber
41
42
  configuration.parse!(@args)
42
43
  end
43
44
  end
44
- configuration.load_language
45
45
  step_mother.options = configuration.options
46
46
 
47
+ features = load_plain_text_features
47
48
  require_files
48
49
  enable_diffing
49
-
50
- features = load_plain_text_features
51
50
 
52
51
  visitor = configuration.build_formatter_broadcaster(step_mother)
53
52
  step_mother.visitor = visitor # Needed to support World#announce
@@ -63,11 +62,11 @@ module Cucumber
63
62
 
64
63
  def load_plain_text_features
65
64
  features = Ast::Features.new
66
- parser = Parser::FeatureParser.new
67
65
 
68
66
  verbose_log("Features:")
69
67
  configuration.feature_files.each do |f|
70
- feature = parser.parse_file(f, configuration.options)
68
+ feature_file = FeatureFile.new(f)
69
+ feature = feature_file.parse(configuration.options)
71
70
  if feature
72
71
  features.add_feature(feature)
73
72
  verbose_log(" * #{f}")
@@ -59,6 +59,18 @@ module Cucumber
59
59
  end
60
60
 
61
61
  def print_stats(features)
62
+
63
+ @failures = step_mother.scenarios(:failed).select { |s| s.is_a?(Cucumber::Ast::Scenario) }
64
+
65
+ if !@failures.empty?
66
+ @io.puts format_string("Failing Scenarios:", :failed)
67
+ @failures.each do |failure|
68
+ @io.puts format_string("cucumber " + failure.file_colon_line, :failed) +
69
+ format_string(" # Scenario: " + failure.name, :comment)
70
+ end
71
+ @io.puts
72
+ end
73
+
62
74
  @io.print dump_count(step_mother.scenarios.length, "scenario")
63
75
  print_status_counts{|status| step_mother.scenarios(status)}
64
76
 
@@ -54,7 +54,8 @@ module Cucumber
54
54
  end
55
55
 
56
56
  def visit_comment_line(comment_line)
57
- @builder.text!(comment_line.strip + "\n")
57
+ @builder.text!(comment_line)
58
+ @builder.br
58
59
  end
59
60
 
60
61
  def visit_feature(feature)
@@ -73,7 +74,7 @@ module Cucumber
73
74
  @builder.h2 do |h2|
74
75
  @builder.span(lines[0], :class => 'val')
75
76
  end
76
- @builder.p do
77
+ @builder.p(:class => 'narrative') do
77
78
  lines[1..-1].each do |line|
78
79
  @builder.text!(line.strip)
79
80
  @builder.br
@@ -31,13 +31,14 @@ module Cucumber
31
31
  @testsuite << @builder.target!
32
32
  end
33
33
 
34
- File.open(@feature_filename, 'w') { |file| file.write(@testsuite.target!) }
34
+ basename = File.basename(feature.file)[0...-File.extname(feature.file).length]
35
+ feature_filename = File.join(@reportdir, "TEST-#{basename}.xml")
36
+ File.open(feature_filename, 'w') { |file| file.write(@testsuite.target!) }
35
37
  end
36
38
 
37
39
  def visit_feature_name(name)
38
40
  lines = name.split(/\r?\n/)
39
41
  @feature_name = lines[0].sub(/Feature\:/, '').strip
40
- @feature_filename = convert_to_file_name(@feature_name)
41
42
  end
42
43
 
43
44
  def visit_scenario_name(keyword, name, file_colon_line, source_indent)
@@ -65,10 +66,6 @@ module Cucumber
65
66
 
66
67
  private
67
68
 
68
- def convert_to_file_name(feature_name)
69
- File.join(@reportdir, "TEST-" + feature_name.gsub(/[^\w_\.]/, '_') + ".xml")
70
- end
71
-
72
69
  def format_exception(exception)
73
70
  (["#{exception.message} (#{exception.class})"] + exception.backtrace).join("\n")
74
71
  end
@@ -48,10 +48,8 @@ module Cucumber
48
48
  end
49
49
 
50
50
  def visit_comment_line(comment_line)
51
- unless comment_line.blank?
52
- @io.puts(comment_line.indent(@indent))
53
- @io.flush
54
- end
51
+ @io.puts(comment_line.indent(@indent))
52
+ @io.flush
55
53
  end
56
54
 
57
55
  def visit_tags(tags)
@@ -17,7 +17,7 @@ module Cucumber
17
17
  super
18
18
  end
19
19
 
20
- def visit_step_name(keyword, step_match, status, source_indent, background)
20
+ def visit_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
21
21
  duration = Time.now - @step_duration
22
22
  super
23
23
 
@@ -91,14 +91,14 @@
91
91
  native: Česky
92
92
  encoding: UTF-8
93
93
  feature: Požadavek
94
- background: Pozadí
94
+ background: Pozadí|Kontext
95
95
  scenario: Scénář
96
- scenario_outline: Náčrt Scénáře
96
+ scenario_outline: Náčrt Scénáře|Osnova scénáře
97
97
  examples: Příklady
98
98
  given: Pokud
99
99
  when: Když
100
100
  then: Pak
101
- and: A
101
+ and: A|A také
102
102
  but: Ale
103
103
  space_after_keyword: true
104
104
  "da":
@@ -10,17 +10,13 @@ module Cucumber
10
10
  include Treetop::Runtime
11
11
 
12
12
  def root
13
- @root || :feature
13
+ @root || :feature_sub
14
14
  end
15
15
 
16
- include I18n
17
-
18
- include Table
19
-
20
- module Feature0
16
+ module FeatureSub0
21
17
  end
22
18
 
23
- module Feature1
19
+ module FeatureSub1
24
20
  def white
25
21
  elements[0]
26
22
  end
@@ -55,7 +51,7 @@ module Cucumber
55
51
 
56
52
  end
57
53
 
58
- module Feature2
54
+ module FeatureSub2
59
55
  def has_tags?(tag_names)
60
56
  tags.has_tags?(tag_names)
61
57
  end
@@ -74,10 +70,10 @@ module Cucumber
74
70
  end
75
71
  end
76
72
 
77
- def _nt_feature
73
+ def _nt_feature_sub
78
74
  start_index = index
79
- if node_cache[:feature].has_key?(index)
80
- cached = node_cache[:feature][index]
75
+ if node_cache[:feature_sub].has_key?(index)
76
+ cached = node_cache[:feature_sub][index]
81
77
  @index = cached.interval.end if cached
82
78
  return cached
83
79
  end
@@ -139,7 +135,7 @@ module Cucumber
139
135
  end
140
136
  if s7.last
141
137
  r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
142
- r7.extend(Feature0)
138
+ r7.extend(FeatureSub0)
143
139
  else
144
140
  self.index = i7
145
141
  r7 = nil
@@ -181,14 +177,14 @@ module Cucumber
181
177
  end
182
178
  if s0.last
183
179
  r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
184
- r0.extend(Feature1)
185
- r0.extend(Feature2)
180
+ r0.extend(FeatureSub1)
181
+ r0.extend(FeatureSub2)
186
182
  else
187
183
  self.index = i0
188
184
  r0 = nil
189
185
  end
190
186
 
191
- node_cache[:feature][start_index] = r0
187
+ node_cache[:feature_sub][start_index] = r0
192
188
 
193
189
  return r0
194
190
  end
@@ -1346,7 +1342,7 @@ module Cucumber
1346
1342
 
1347
1343
  module LinesToKeyword2
1348
1344
  def build
1349
- self.text_value.split("\n").map{|s| s.strip }.join("\n")
1345
+ self.text_value.split("\n").map{|s| s.strip}.join("\n")
1350
1346
  end
1351
1347
  end
1352
1348
 
@@ -7,10 +7,8 @@ module Cucumber
7
7
  # Treetop will then generate the parser in-memory. When you're happy, just generate
8
8
  # the rb file with tt feature.tt
9
9
  grammar Feature
10
- include I18n
11
- include Table
12
10
 
13
- rule feature
11
+ rule feature_sub
14
12
  white
15
13
  comment
16
14
  white
@@ -1,35 +1,42 @@
1
1
  module Cucumber
2
2
  module Parser
3
- grammar I18n
3
+ module I18n
4
+ grammar <%= keywords('grammar_name', true) %>
5
+ include Feature
6
+ include Table
4
7
 
5
- rule background_keyword
6
- (<%= keywords('background') %>) ':'
7
- end
8
+ rule feature
9
+ feature_sub
10
+ end
8
11
 
9
- rule scenario_keyword
10
- (<%= keywords('scenario') %>) ':'
11
- end
12
+ rule background_keyword
13
+ (<%= keywords('background') %>) ':'
14
+ end
12
15
 
13
- rule scenario_outline_keyword
14
- (<%= keywords('scenario_outline') %>) ':'
15
- end
16
+ rule scenario_keyword
17
+ (<%= keywords('scenario') %>) ':'
18
+ end
16
19
 
17
- rule step_keyword
18
- (<%= keywords('given') %>) /
19
- (<%= keywords('when') %>) /
20
- (<%= keywords('then') %>) /
21
- (<%= keywords('and') %>) /
22
- (<%= keywords('but') %>)
23
- end
20
+ rule scenario_outline_keyword
21
+ (<%= keywords('scenario_outline') %>) ':'
22
+ end
24
23
 
25
- rule keyword_space
26
- <%= keywords('space_after_keyword', true) ? 'space+' : 'space*' %>
27
- end
24
+ rule step_keyword
25
+ (<%= keywords('given') %>) /
26
+ (<%= keywords('when') %>) /
27
+ (<%= keywords('then') %>) /
28
+ (<%= keywords('and') %>) /
29
+ (<%= keywords('but') %>)
30
+ end
28
31
 
29
- rule examples_keyword
30
- (<%= keywords('examples') %>) ':'?
31
- end
32
+ rule keyword_space
33
+ <%= keywords('space_after_keyword', true) ? 'space+' : 'space*' %>
34
+ end
32
35
 
36
+ rule examples_keyword
37
+ (<%= keywords('examples') %>) ':'?
38
+ end
39
+ end
33
40
  end
34
41
  end
35
42
  end
@@ -12,80 +12,19 @@ end
12
12
 
13
13
  module Cucumber
14
14
  module Parser
15
- class Filter
16
- def initialize(lines, options)
17
- @lines = lines
18
- @include_tags = options[:include_tags] || []
19
- @exclude_tags = options[:exclude_tags] || []
20
- @name_regexps = options[:name_regexps] || []
21
- end
22
-
23
- def accept?(syntax_node)
24
- at_line?(syntax_node) &&
25
- matches_tags?(syntax_node) &&
26
- matches_names?(syntax_node)
27
- end
28
-
29
- def accept_example?(syntax_node, outline)
30
- (at_line?(syntax_node) || outline_at_line?(outline)) &&
31
- (matches_names?(syntax_node) || outline_matches_names?(outline))
32
- end
33
-
34
- def at_line?(syntax_node)
35
- @lines.nil? || @lines.empty? || @lines.detect{|line| syntax_node.at_line?(line)}
36
- end
37
-
38
- def outline_at_line?(syntax_node)
39
- @lines.nil? || @lines.empty? || @lines.detect{|line| syntax_node.outline_at_line?(line)}
40
- end
41
-
42
- def matches_tags?(syntax_node)
43
- !excluded_by_tags?(syntax_node) &&
44
- included_by_tags?(syntax_node)
45
- end
46
-
47
- def included_by_tags?(syntax_node)
48
- @include_tags.empty? || syntax_node.has_tags?(@include_tags)
49
- end
50
-
51
- def excluded_by_tags?(syntax_node)
52
- @exclude_tags.any? && syntax_node.has_tags?(@exclude_tags)
53
- end
54
-
55
- def outline_matches_names?(syntax_node)
56
- @name_regexps.nil? || @name_regexps.empty? || @name_regexps.detect{|name_regexp| syntax_node.outline_matches_name?(name_regexp)}
57
- end
58
-
59
- def matches_names?(syntax_node)
60
- @name_regexps.nil? || @name_regexps.empty? || @name_regexps.detect{|name_regexp| syntax_node.matches_name?(name_regexp)}
15
+ class SyntaxError < StandardError
16
+ def initialize(parser, file, line_offset)
17
+ tf = parser.terminal_failures
18
+ expected = tf.size == 1 ? tf[0].expected_string.inspect : "one of #{tf.map{|f| f.expected_string.inspect}.uniq*', '}"
19
+ line = parser.failure_line + line_offset
20
+ message = "#{file}:#{line}:#{parser.failure_column}: Parse error, expected #{expected}."
21
+ super(message)
61
22
  end
62
23
  end
63
-
64
- module TreetopExt
65
- FILE_COLON_LINE_PATTERN = /^([\w\W]*?):([\d:]+)$/
66
-
67
- # Parses a file and returns a Cucumber::Ast
68
- def parse_file(file, options)
69
- _, path, lines = *FILE_COLON_LINE_PATTERN.match(file)
70
- if path
71
- lines = lines.split(':').map { |line| line.to_i }
72
- else
73
- path = file
74
- end
75
- filter = Filter.new(lines, options)
76
-
77
- loader = lambda { |io| parse_or_fail(io.read, filter, path) }
78
- feature = if path =~ /^http/
79
- require 'open-uri'
80
- open(path, &loader)
81
- else
82
- File.open(path, Cucumber.file_mode('r'), &loader)
83
- end
84
- feature
85
- end
86
-
87
- def parse_or_fail(string, filter=nil, file=nil, line_offset=0)
88
- parse_tree = parse(string)
24
+
25
+ module TreetopExt
26
+ def parse_or_fail(source, file=nil, filter=nil, line_offset=0)
27
+ parse_tree = parse(source)
89
28
  if parse_tree.nil?
90
29
  raise Cucumber::Parser::SyntaxError.new(self, file, line_offset)
91
30
  else
@@ -95,16 +34,6 @@ module Cucumber
95
34
  end
96
35
  end
97
36
  end
98
-
99
- class SyntaxError < StandardError
100
- def initialize(parser, file, line_offset)
101
- tf = parser.terminal_failures
102
- expected = tf.size == 1 ? tf[0].expected_string.inspect : "one of #{tf.map{|f| f.expected_string.inspect}.uniq*', '}"
103
- line = parser.failure_line + line_offset
104
- message = "#{file}:#{line}:#{parser.failure_column}: Parse error, expected #{expected}."
105
- super(message)
106
- end
107
- end
108
37
  end
109
38
  end
110
39
 
@@ -115,7 +44,7 @@ module Treetop
115
44
  input.line_of(interval.first)
116
45
  end
117
46
  end
118
-
47
+
119
48
  class CompiledParser
120
49
  include Cucumber::Parser::TreetopExt
121
50
  end
@@ -3,36 +3,4 @@ require 'cucumber/platform'
3
3
  require 'cucumber/ast'
4
4
  require 'cucumber/parser/treetop_ext'
5
5
  require 'cucumber/parser/table'
6
-
7
- module Cucumber
8
- # Classes in this module parse feature files and translate the parse tree
9
- # (concrete syntax tree) into an abstract syntax tree (AST) using
10
- # <a href="http://martinfowler.com/dslwip/EmbeddedTranslation.html">Embedded translation</a>.
11
- #
12
- # The AST is built by the various <tt>#build</tt> methods in the parse tree.
13
- #
14
- # The AST classes are defined in the Cucumber::Ast module.
15
- module Parser
16
- def self.load_parser(keywords)
17
- Loader.new(keywords)
18
- end
19
-
20
- class Loader
21
- def initialize(keywords)
22
- @keywords = keywords
23
- i18n_tt = File.expand_path(File.dirname(__FILE__) + '/parser/i18n.tt')
24
- template = File.open(i18n_tt, Cucumber.file_mode('r')).read
25
- erb = ERB.new(template)
26
- grammar = erb.result(binding)
27
- Treetop.load_from_string(grammar)
28
- require 'cucumber/parser/feature'
29
- end
30
-
31
- def keywords(key, raw=false)
32
- return @keywords[key] if raw
33
- values = @keywords[key].split('|')
34
- values.map{|value| "'#{value}'"}.join(" / ")
35
- end
36
- end
37
- end
38
- end
6
+ require 'cucumber/parser/feature'