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.
- data/History.txt +36 -0
- data/Manifest.txt +9 -0
- data/config/hoe.rb +1 -2
- data/examples/i18n/ar/Rakefile +1 -1
- data/examples/i18n/ar/features/addition.feature +1 -0
- data/examples/i18n/bg/Rakefile +1 -1
- data/examples/i18n/bg/features/addition.feature +1 -0
- data/examples/i18n/bg/features/consecutive_calculations.feature +1 -0
- data/examples/i18n/bg/features/division.feature +1 -0
- data/examples/i18n/cat/Rakefile +1 -1
- data/examples/i18n/cat/features/suma.feature +1 -0
- data/examples/i18n/da/Rakefile +1 -1
- data/examples/i18n/da/features/summering.feature +1 -0
- data/examples/i18n/de/Rakefile +1 -1
- data/examples/i18n/de/features/addition.feature +1 -0
- data/examples/i18n/de/features/division.feature +1 -0
- data/examples/i18n/en/Rakefile +1 -1
- data/examples/i18n/en/features/addition.feature +1 -0
- data/examples/i18n/en/features/division.feature +1 -0
- data/examples/i18n/en-lol/features/stuffing.feature +1 -1
- data/examples/i18n/es/Rakefile +1 -1
- data/examples/i18n/es/features/adicion.feature +1 -0
- data/examples/i18n/et/Rakefile +1 -1
- data/examples/i18n/et/features/jagamine.feature +1 -0
- data/examples/i18n/et/features/liitmine.feature +1 -0
- data/examples/i18n/fi/Rakefile +1 -1
- data/examples/i18n/fi/features/jakolasku.feature +1 -0
- data/examples/i18n/fr/Rakefile +1 -1
- data/examples/i18n/fr/features/addition.feature +2 -1
- data/examples/i18n/he/Rakefile +1 -1
- data/examples/i18n/he/features/addition.feature +1 -0
- data/examples/i18n/he/features/division.feature +1 -0
- data/examples/i18n/hu/Rakefile +1 -1
- data/examples/i18n/hu/features/addition.feature +1 -0
- data/examples/i18n/hu/features/division.feature +1 -0
- data/examples/i18n/id/Rakefile +1 -1
- data/examples/i18n/id/features/addition.feature +1 -0
- data/examples/i18n/id/features/division.feature +1 -0
- data/examples/i18n/it/Rakefile +1 -1
- data/examples/i18n/it/features/somma.feature +1 -0
- data/examples/i18n/ja/Rakefile +1 -1
- data/examples/i18n/ja/features/addition.feature +1 -0
- data/examples/i18n/ja/features/division.feature +1 -0
- data/examples/i18n/ko/Rakefile +1 -1
- data/examples/i18n/ko/features/addition.feature +1 -0
- data/examples/i18n/ko/features/division.feature +1 -0
- data/examples/i18n/lt/Rakefile +1 -1
- data/examples/i18n/lt/features/addition.feature +1 -0
- data/examples/i18n/lt/features/division.feature +1 -0
- data/examples/i18n/lv/Rakefile +1 -1
- data/examples/i18n/lv/features/addition.feature +1 -0
- data/examples/i18n/lv/features/division.feature +1 -0
- data/examples/i18n/no/Rakefile +1 -1
- data/examples/i18n/no/features/summering.feature +1 -0
- data/examples/i18n/pl/Rakefile +1 -1
- data/examples/i18n/pl/features/addition.feature +1 -0
- data/examples/i18n/pl/features/division.feature +1 -0
- data/examples/i18n/pt/Rakefile +1 -1
- data/examples/i18n/pt/features/adicao.feature +1 -0
- data/examples/i18n/ro/Rakefile +1 -1
- data/examples/i18n/ro/features/suma.feature +1 -0
- data/examples/i18n/ru/Rakefile +1 -1
- data/examples/i18n/ru/features/addition.feature +1 -0
- data/examples/i18n/ru/features/consecutive_calculations.feature +1 -0
- data/examples/i18n/ru/features/division.feature +1 -0
- data/examples/i18n/se/Rakefile +1 -1
- data/examples/i18n/se/features/summering.feature +1 -0
- data/examples/i18n/sk/Rakefile +1 -1
- data/examples/i18n/sk/features/addition.feature +1 -0
- data/examples/i18n/sk/features/division.feature +1 -0
- data/examples/i18n/zh-CN/features/addition.feature +1 -0
- data/examples/i18n/zh-TW/features/addition.feature +1 -0
- data/examples/i18n/zh-TW/features/division.feature +1 -0
- data/examples/sinatra/features/step_definitions/add_steps.rb +1 -1
- data/examples/sinatra/features/support/env.rb +13 -5
- data/features/after_block_exceptions.feature +4 -1
- data/features/after_step_block_exceptions.feature +4 -1
- data/features/background.feature +6 -0
- data/features/cucumber_cli.feature +11 -1
- data/features/cucumber_cli_diff_disabled.feature +7 -1
- data/features/drb_server_integration.feature +5 -4
- data/features/expand.feature +2 -1
- data/features/html_formatter/a.html +12 -14
- data/features/junit_formatter.feature +4 -4
- data/features/step_definitions/cucumber_steps.rb +2 -2
- data/features/support/env.rb +7 -4
- data/features/work_in_progress.feature +3 -0
- data/lib/cucumber/ast/comment.rb +1 -1
- data/lib/cucumber/ast/feature.rb +2 -2
- data/lib/cucumber/ast/feature_element.rb +4 -0
- data/lib/cucumber/ast/scenario.rb +5 -3
- data/lib/cucumber/ast/scenario_outline.rb +6 -1
- data/lib/cucumber/ast/step.rb +4 -0
- data/lib/cucumber/ast/step_invocation.rb +6 -1
- data/lib/cucumber/cli/configuration.rb +37 -26
- data/lib/cucumber/cli/main.rb +4 -5
- data/lib/cucumber/formatter/console.rb +12 -0
- data/lib/cucumber/formatter/html.rb +3 -2
- data/lib/cucumber/formatter/junit.rb +3 -6
- data/lib/cucumber/formatter/pretty.rb +2 -4
- data/lib/cucumber/formatter/profile.rb +1 -1
- data/lib/cucumber/languages.yml +3 -3
- data/lib/cucumber/parser/feature.rb +12 -16
- data/lib/cucumber/parser/feature.tt +1 -3
- data/lib/cucumber/parser/i18n.tt +30 -23
- data/lib/cucumber/parser/treetop_ext.rb +12 -83
- data/lib/cucumber/parser.rb +1 -33
- data/lib/cucumber/platform.rb +6 -0
- data/lib/cucumber/step_definition.rb +6 -0
- data/lib/cucumber/step_mother.rb +3 -3
- data/lib/cucumber/version.rb +1 -1
- data/lib/cucumber.rb +0 -57
- data/rails_generators/cucumber/templates/cucumber.rake +4 -0
- data/spec/cucumber/ast/step_collection_spec.rb +5 -4
- data/spec/cucumber/cli/configuration_spec.rb +42 -9
- data/spec/cucumber/cli/main_spec.rb +2 -10
- data/spec/cucumber/parser/feature_parser_spec.rb +11 -9
- data/spec/cucumber/parser/table_parser_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -1
- 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
|
-
|
29
|
-
skip_invoke! if
|
30
|
-
|
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(
|
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
|
data/lib/cucumber/ast/step.rb
CHANGED
@@ -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
|
-
|
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'
|
8
|
-
'pretty'
|
9
|
-
'profile'
|
10
|
-
'progress'
|
11
|
-
'rerun'
|
12
|
-
'usage'
|
13
|
-
'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
|
-
|
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:
|
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
|
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][
|
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
|
-
|
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 |
|
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 =>
|
412
|
+
:lang => nil,
|
402
413
|
:dry_run => false,
|
403
|
-
:formats =>
|
414
|
+
:formats => [],
|
404
415
|
:excludes => [],
|
405
416
|
:include_tags => [],
|
406
417
|
:exclude_tags => [],
|
data/lib/cucumber/cli/main.rb
CHANGED
@@ -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
|
-
|
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
|
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.
|
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
|
@@ -17,7 +17,7 @@ module Cucumber
|
|
17
17
|
super
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
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
|
|
data/lib/cucumber/languages.yml
CHANGED
@@ -91,14 +91,14 @@
|
|
91
91
|
native: Česky
|
92
92
|
encoding: UTF-8
|
93
93
|
feature: Požadavek
|
94
|
-
background:
|
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 || :
|
13
|
+
@root || :feature_sub
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
include Table
|
19
|
-
|
20
|
-
module Feature0
|
16
|
+
module FeatureSub0
|
21
17
|
end
|
22
18
|
|
23
|
-
module
|
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
|
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
|
73
|
+
def _nt_feature_sub
|
78
74
|
start_index = index
|
79
|
-
if node_cache[:
|
80
|
-
cached = node_cache[:
|
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(
|
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(
|
185
|
-
r0.extend(
|
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[:
|
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
|
1345
|
+
self.text_value.split("\n").map{|s| s.strip}.join("\n")
|
1350
1346
|
end
|
1351
1347
|
end
|
1352
1348
|
|
data/lib/cucumber/parser/i18n.tt
CHANGED
@@ -1,35 +1,42 @@
|
|
1
1
|
module Cucumber
|
2
2
|
module Parser
|
3
|
-
|
3
|
+
module I18n
|
4
|
+
grammar <%= keywords('grammar_name', true) %>
|
5
|
+
include Feature
|
6
|
+
include Table
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
+
rule feature
|
9
|
+
feature_sub
|
10
|
+
end
|
8
11
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
+
rule background_keyword
|
13
|
+
(<%= keywords('background') %>) ':'
|
14
|
+
end
|
12
15
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
rule scenario_keyword
|
17
|
+
(<%= keywords('scenario') %>) ':'
|
18
|
+
end
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
26
|
-
|
27
|
-
|
24
|
+
rule step_keyword
|
25
|
+
(<%= keywords('given') %>) /
|
26
|
+
(<%= keywords('when') %>) /
|
27
|
+
(<%= keywords('then') %>) /
|
28
|
+
(<%= keywords('and') %>) /
|
29
|
+
(<%= keywords('but') %>)
|
30
|
+
end
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
16
|
-
def initialize(
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
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
|
data/lib/cucumber/parser.rb
CHANGED
@@ -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'
|