kosmas58-cucumber 0.3.11.3 → 0.3.11.6
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|