cucumber-core 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/HISTORY.md +10 -2
- data/cucumber-core.gemspec +1 -1
- data/lib/cucumber/core/ast/background.rb +3 -6
- data/lib/cucumber/core/ast/data_table.rb +2 -7
- data/lib/cucumber/core/ast/describes_itself.rb +5 -1
- data/lib/cucumber/core/ast/doc_string.rb +2 -2
- data/lib/cucumber/core/ast/examples_table.rb +3 -3
- data/lib/cucumber/core/ast/feature.rb +14 -5
- data/lib/cucumber/core/ast/location.rb +19 -6
- data/lib/cucumber/core/ast/outline_step.rb +4 -5
- data/lib/cucumber/core/ast/scenario.rb +4 -8
- data/lib/cucumber/core/ast/scenario_outline.rb +4 -10
- data/lib/cucumber/core/ast/step.rb +9 -8
- data/lib/cucumber/core/gherkin/ast_builder.rb +241 -217
- data/lib/cucumber/core/gherkin/parser.rb +16 -16
- data/lib/cucumber/core/gherkin/tag_expression.rb +64 -0
- data/lib/cucumber/core/test/case.rb +2 -2
- data/lib/cucumber/core/test/runner.rb +9 -4
- data/lib/cucumber/core/test/step.rb +19 -0
- data/lib/cucumber/core/version.rb +1 -1
- data/spec/cucumber/core/ast/background_spec.rb +1 -1
- data/spec/cucumber/core/ast/location_spec.rb +45 -0
- data/spec/cucumber/core/ast/outline_step_spec.rb +3 -4
- data/spec/cucumber/core/ast/step_spec.rb +22 -20
- data/spec/cucumber/core/gherkin/parser_spec.rb +36 -7
- data/spec/cucumber/core/test/case_spec.rb +10 -0
- data/spec/cucumber/core/test/filters/locations_filter_spec.rb +40 -3
- data/spec/cucumber/core/test/runner_spec.rb +16 -0
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f56999cf96221b9de93c823a5559efeb56bfb34
|
4
|
+
data.tar.gz: 1e955adc2d60f414a53e6775d0e6adc44b4eafa5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 529edb34199a3bea271b93d0f09de3e4b2c24dc7f4c198ff553fe029b7d0b5c1a7a4a18d744586725351d5e1f9795c6caec1e8e35b64e2c77eab858ad3d8052e
|
7
|
+
data.tar.gz: 42aa0c463801d3aaba42d95c2bbdd0519a8d5344da0ef6c594d7a6bd704329947c5265aea47e3eee601e20c043fac8ca31b25afc5e75a9d1630b85ead562bd80
|
data/HISTORY.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
## [In Git](https://github.com/cucumber/cucumber-ruby-core/compare/v1.2.0...master)
|
2
2
|
|
3
|
-
|
3
|
+
### New Features
|
4
|
+
|
5
|
+
* Add factory method to Cucumber::Core::Ast::Location that uses the output from Proc#source_location (@brasmusson)
|
6
|
+
* Integrate Gherkin3 parser (@brassmusson)
|
7
|
+
|
8
|
+
### Bugfixes
|
9
|
+
|
10
|
+
* Make sure that `after_test_step` is sent also when a test step is interrupted by (a timeout in) an around hook ([cucumber/cucumber-ruby#909](https://github.com/cucumber/cucumber-ruby/issues/909) @brasmusson)
|
11
|
+
* Improve the check that a test_step quacks like a Cucumber::Core::Test::Step ([95](https://github.com/cucumber/cucumber-ruby-core/issues/95) @brasmusson)
|
4
12
|
|
5
13
|
## [v1.2.0](https://github.com/cucumber/cucumber-ruby-core/compare/v1.1.3...v1.2.0)
|
6
14
|
|
@@ -68,7 +76,7 @@
|
|
68
76
|
|
69
77
|
### Bugfixes
|
70
78
|
|
71
|
-
* Handle empty feature files (#[77](https://github.com/cucumber/cucumber-ruby-core/pull/77), [cucumber/cucumber#771](https://github.com/cucumber/cucumber/issues/771) [@brasmusson](https://github.com/brasmusson))
|
79
|
+
* Handle empty feature files (#[77](https://github.com/cucumber/cucumber-ruby-core/pull/77), [cucumber/cucumber-ruby#771](https://github.com/cucumber/cucumber-ruby/issues/771) [@brasmusson](https://github.com/brasmusson))
|
72
80
|
* Run after hooks in reverse order (#[69](https://github.com/cucumber/cucumber-ruby-core/pull/69) [@erran](https://github.com/erran))
|
73
81
|
|
74
82
|
## [v1.0.0.beta.3](https://github.com/cucumber/cucumber-ruby-core/compare/v1.0.0.beta.2...v1.0.0.beta.3)
|
data/cucumber-core.gemspec
CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.license = "MIT"
|
15
15
|
s.required_ruby_version = ">= 1.9.3"
|
16
16
|
|
17
|
-
s.add_dependency '
|
17
|
+
s.add_dependency 'gherkin3', '~> 3.1.0'
|
18
18
|
|
19
19
|
s.add_development_dependency 'bundler', '>= 1.3.5'
|
20
20
|
s.add_development_dependency 'rake', '>= 0.9.2'
|
@@ -10,9 +10,7 @@ module Cucumber
|
|
10
10
|
include HasLocation
|
11
11
|
include DescribesItself
|
12
12
|
|
13
|
-
def initialize(
|
14
|
-
@gherkin_statement = gherkin_statement
|
15
|
-
@language = language
|
13
|
+
def initialize(location, comments, keyword, name, description, raw_steps)
|
16
14
|
@location = location
|
17
15
|
@comments = comments
|
18
16
|
@keyword = keyword
|
@@ -21,11 +19,10 @@ module Cucumber
|
|
21
19
|
@raw_steps = raw_steps
|
22
20
|
end
|
23
21
|
|
24
|
-
attr_reader :
|
25
|
-
private :
|
22
|
+
attr_reader :description, :raw_steps
|
23
|
+
private :raw_steps
|
26
24
|
|
27
25
|
attr_reader :comments, :keyword, :location
|
28
|
-
attr_reader :gherkin_statement
|
29
26
|
|
30
27
|
def children
|
31
28
|
raw_steps
|
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'gherkin/rubify'
|
2
|
-
require 'gherkin/lexer/i18n_lexer'
|
3
|
-
require 'gherkin/formatter/escaping'
|
4
1
|
require 'cucumber/core/ast/describes_itself'
|
5
2
|
require 'cucumber/core/ast/location'
|
6
3
|
|
@@ -30,15 +27,13 @@ module Cucumber
|
|
30
27
|
include DescribesItself
|
31
28
|
include HasLocation
|
32
29
|
|
33
|
-
include ::Gherkin::Rubify
|
34
|
-
|
35
30
|
# Creates a new instance. +raw+ should be an Array of Array of String
|
36
31
|
# or an Array of Hash
|
37
32
|
# You don't typically create your own DataTable objects - Cucumber will do
|
38
33
|
# it internally and pass them to your Step Definitions.
|
39
34
|
#
|
40
|
-
def initialize(
|
41
|
-
raw = ensure_array_of_array(
|
35
|
+
def initialize(rows, location)
|
36
|
+
raw = ensure_array_of_array(rows)
|
42
37
|
verify_rows_are_same_length(raw)
|
43
38
|
@raw = raw.freeze
|
44
39
|
@location = location
|
@@ -5,7 +5,11 @@ module Cucumber
|
|
5
5
|
def describe_to(visitor, *args)
|
6
6
|
visitor.send(description_for_visitors, self, *args) do |child_visitor|
|
7
7
|
children.each do |child|
|
8
|
-
|
8
|
+
begin
|
9
|
+
child.describe_to(child_visitor, *args)
|
10
|
+
rescue => e
|
11
|
+
raise e.class, "Failed describing child of #{self.inspect} - #{e.message}", e.backtrace
|
12
|
+
end
|
9
13
|
end
|
10
14
|
end
|
11
15
|
self
|
@@ -25,8 +25,8 @@ module Cucumber
|
|
25
25
|
|
26
26
|
attr_reader :content_type, :content
|
27
27
|
|
28
|
-
def initialize(
|
29
|
-
@content =
|
28
|
+
def initialize(content, content_type, location)
|
29
|
+
@content = content
|
30
30
|
@content_type = content_type
|
31
31
|
@location = location
|
32
32
|
super @content
|
@@ -11,8 +11,7 @@ module Cucumber
|
|
11
11
|
include HasLocation
|
12
12
|
include DescribesItself
|
13
13
|
|
14
|
-
def initialize(
|
15
|
-
@gherkin_statement = gherkin_statement
|
14
|
+
def initialize(location, comments, tags, keyword, name, description, header, example_rows)
|
16
15
|
@location = location
|
17
16
|
@comments = comments
|
18
17
|
@tags = tags
|
@@ -23,7 +22,7 @@ module Cucumber
|
|
23
22
|
@example_rows = example_rows
|
24
23
|
end
|
25
24
|
|
26
|
-
attr_reader :
|
25
|
+
attr_reader :location, :tags, :keyword, :comments,
|
27
26
|
:header, :example_rows
|
28
27
|
|
29
28
|
private
|
@@ -109,6 +108,7 @@ module Cucumber
|
|
109
108
|
end
|
110
109
|
end
|
111
110
|
end
|
111
|
+
class Examples < ExamplesTable; end
|
112
112
|
end
|
113
113
|
end
|
114
114
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'cucumber/core/ast/describes_itself'
|
2
2
|
require 'cucumber/core/ast/names'
|
3
3
|
require 'cucumber/core/ast/location'
|
4
|
+
require 'gherkin3/dialect'
|
4
5
|
|
5
6
|
module Cucumber
|
6
7
|
module Core
|
@@ -11,12 +12,11 @@ module Cucumber
|
|
11
12
|
include HasLocation
|
12
13
|
include DescribesItself
|
13
14
|
|
14
|
-
attr_reader :
|
15
|
+
attr_reader :language, :location, :background,
|
15
16
|
:comments, :tags, :keyword, :description,
|
16
17
|
:feature_elements
|
17
18
|
|
18
|
-
def initialize(
|
19
|
-
@gherkin_statement = gherkin_statement
|
19
|
+
def initialize(language, location, background, comments, tags, keyword, name, description, scenario_definitions)
|
20
20
|
@language = language
|
21
21
|
@location = location
|
22
22
|
@background = background
|
@@ -25,7 +25,7 @@ module Cucumber
|
|
25
25
|
@keyword = keyword
|
26
26
|
@name = name
|
27
27
|
@description = description
|
28
|
-
@feature_elements =
|
28
|
+
@feature_elements = scenario_definitions
|
29
29
|
end
|
30
30
|
|
31
31
|
def children
|
@@ -34,7 +34,7 @@ module Cucumber
|
|
34
34
|
|
35
35
|
def short_name
|
36
36
|
first_line = name.split(/\n/)[0]
|
37
|
-
if first_line =~ /#{language.
|
37
|
+
if first_line =~ /#{language.feature_keywords}:(.*)/
|
38
38
|
$1.strip
|
39
39
|
else
|
40
40
|
first_line
|
@@ -65,6 +65,15 @@ module Cucumber
|
|
65
65
|
self
|
66
66
|
end
|
67
67
|
end
|
68
|
+
|
69
|
+
class LanguageDelegator < SimpleDelegator
|
70
|
+
attr_reader :iso_code
|
71
|
+
|
72
|
+
def initialize(iso_code, obj)
|
73
|
+
super(obj)
|
74
|
+
@iso_code = iso_code
|
75
|
+
end
|
76
|
+
end
|
68
77
|
end
|
69
78
|
end
|
70
79
|
end
|
@@ -13,9 +13,25 @@ module Cucumber
|
|
13
13
|
def_delegator :filepath, :same_as?
|
14
14
|
def_delegator :filepath, :filename, :file
|
15
15
|
|
16
|
-
def self.of_caller
|
17
|
-
|
18
|
-
|
16
|
+
def self.of_caller(additional_depth = 0)
|
17
|
+
from_file_colon_line(*caller[1 + additional_depth])
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.from_file_colon_line(file_colon_line)
|
21
|
+
file, raw_line = file_colon_line.match(/(.*):(\d+)/)[1..2]
|
22
|
+
from_source_location(file, raw_line.to_i)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.from_source_location(file, line)
|
26
|
+
file = File.expand_path(file)
|
27
|
+
pwd = File.expand_path(Dir.pwd)
|
28
|
+
pwd.force_encoding(file.encoding)
|
29
|
+
if file.index(pwd)
|
30
|
+
file = file[pwd.length+1..-1]
|
31
|
+
elsif file =~ /.*\/gems\/(.*\.rb)$/
|
32
|
+
file = $1
|
33
|
+
end
|
34
|
+
new(file, line)
|
19
35
|
end
|
20
36
|
|
21
37
|
def initialize(filepath, raw_lines=WILDCARD)
|
@@ -63,9 +79,6 @@ module Cucumber
|
|
63
79
|
attr_reader :line
|
64
80
|
|
65
81
|
def initialize(raw_data)
|
66
|
-
if Cucumber::JRUBY && raw_data.is_a?(::Java::GherkinFormatterModel::Range)
|
67
|
-
raw_data = Range.new(raw_data.first, raw_data.last)
|
68
|
-
end
|
69
82
|
super Array(raw_data).to_set
|
70
83
|
@line = data.first
|
71
84
|
end
|
@@ -10,15 +10,14 @@ module Cucumber
|
|
10
10
|
include HasLocation
|
11
11
|
include DescribesItself
|
12
12
|
|
13
|
-
attr_reader :
|
13
|
+
attr_reader :language, :location, :comments, :keyword, :name, :multiline_arg
|
14
14
|
|
15
|
-
def initialize(
|
16
|
-
@
|
17
|
-
@language || raise("Language is required!")
|
15
|
+
def initialize(language, location, comments, keyword, text, multiline_arg)
|
16
|
+
@language, @location, @comments, @keyword, @name, @multiline_arg = language, location, comments, keyword, text, multiline_arg
|
18
17
|
end
|
19
18
|
|
20
19
|
def to_step(row)
|
21
|
-
Ast::ExpandedOutlineStep.new(self,
|
20
|
+
Ast::ExpandedOutlineStep.new(self, language, row.location, comments, keyword, row.expand(name), replace_multiline_arg(row))
|
22
21
|
end
|
23
22
|
|
24
23
|
def inspect
|
@@ -11,23 +11,19 @@ module Cucumber
|
|
11
11
|
include HasLocation
|
12
12
|
include DescribesItself
|
13
13
|
|
14
|
-
attr_reader :
|
15
|
-
:comments, :tags, :
|
14
|
+
attr_reader :location, :background,
|
15
|
+
:comments, :tags, :keyword,
|
16
16
|
:description, :raw_steps
|
17
17
|
private :raw_steps
|
18
18
|
|
19
|
-
def initialize(
|
20
|
-
@gherkin_statement = gherkin_statement
|
21
|
-
@language = language
|
19
|
+
def initialize(location, comments, tags, keyword, name, description, steps)
|
22
20
|
@location = location
|
23
|
-
@background = background
|
24
21
|
@comments = comments
|
25
22
|
@tags = tags
|
26
|
-
@feature_tags = feature_tags
|
27
23
|
@keyword = keyword
|
28
24
|
@name = name
|
29
25
|
@description = description
|
30
|
-
@raw_steps =
|
26
|
+
@raw_steps = steps
|
31
27
|
end
|
32
28
|
|
33
29
|
def children
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'cucumber/core/ast/names'
|
2
2
|
require 'cucumber/core/ast/location'
|
3
|
-
require 'cucumber/core/ast/empty_background'
|
4
3
|
require 'cucumber/core/ast/describes_itself'
|
5
4
|
|
6
5
|
module Cucumber
|
@@ -13,24 +12,19 @@ module Cucumber
|
|
13
12
|
|
14
13
|
MissingExamples = Class.new(StandardError)
|
15
14
|
|
16
|
-
attr_reader :
|
17
|
-
:tags, :feature_tags, :keyword,
|
15
|
+
attr_reader :comments, :tags, :keyword,
|
18
16
|
:steps, :examples_tables, :line
|
19
|
-
private :
|
17
|
+
private :line
|
20
18
|
|
21
|
-
def initialize(
|
22
|
-
@gherkin_statement = gherkin_statement
|
23
|
-
@language = language
|
19
|
+
def initialize(location, comments, tags, keyword, name, description, steps, examples)
|
24
20
|
@location = location
|
25
|
-
@background = background
|
26
21
|
@comments = comments
|
27
22
|
@tags = tags
|
28
|
-
@feature_tags = feature_tags
|
29
23
|
@keyword = keyword
|
30
24
|
@name = name
|
31
25
|
@description = description
|
32
26
|
@steps = steps
|
33
|
-
@examples_tables =
|
27
|
+
@examples_tables = examples
|
34
28
|
end
|
35
29
|
|
36
30
|
private
|
@@ -8,10 +8,10 @@ module Cucumber
|
|
8
8
|
include HasLocation
|
9
9
|
include DescribesItself
|
10
10
|
|
11
|
-
attr_reader :keyword, :name, :language, :comments, :exception, :multiline_arg
|
11
|
+
attr_reader :keyword, :name, :language, :comments, :exception, :multiline_arg
|
12
12
|
|
13
|
-
def initialize(
|
14
|
-
@
|
13
|
+
def initialize(language, location, comments, keyword, name, multiline_arg)
|
14
|
+
@language, @location, @comments, @keyword, @name, @multiline_arg = language, location, comments, keyword, name, multiline_arg
|
15
15
|
end
|
16
16
|
|
17
17
|
def to_sexp
|
@@ -23,9 +23,9 @@ module Cucumber
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def actual_keyword(previous_step_keyword = nil)
|
26
|
-
if [language.
|
26
|
+
if [language.and_keywords, language.but_keywords].flatten.uniq.include? keyword
|
27
27
|
if previous_step_keyword.nil?
|
28
|
-
language.
|
28
|
+
language.given_keywords.reject{|kw| kw == '* '}[0]
|
29
29
|
else
|
30
30
|
previous_step_keyword
|
31
31
|
end
|
@@ -52,14 +52,15 @@ module Cucumber
|
|
52
52
|
|
53
53
|
class ExpandedOutlineStep < Step
|
54
54
|
|
55
|
-
def initialize(outline_step,
|
56
|
-
@outline_step, @
|
55
|
+
def initialize(outline_step, language, location, comments, keyword, name, multiline_arg)
|
56
|
+
@outline_step, @language, @location, @comments, @keyword, @name, @multiline_arg = outline_step, language, location, comments, keyword, name, multiline_arg
|
57
57
|
end
|
58
58
|
|
59
59
|
alias :self_match_locations? :match_locations?
|
60
60
|
|
61
61
|
def match_locations?(queried_locations)
|
62
|
-
self_match_locations?(queried_locations)
|
62
|
+
return true if self_match_locations?(queried_locations)
|
63
|
+
@outline_step.match_locations?(queried_locations)
|
63
64
|
end
|
64
65
|
|
65
66
|
alias :step_backtrace_line :backtrace_line
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'cucumber/core/ast'
|
2
2
|
require 'cucumber/core/platform'
|
3
|
-
require 'gherkin/rubify'
|
4
3
|
|
5
4
|
module Cucumber
|
6
5
|
module Core
|
@@ -9,339 +8,364 @@ module Cucumber
|
|
9
8
|
# Gherkin parser.
|
10
9
|
class AstBuilder
|
11
10
|
|
12
|
-
def initialize(
|
13
|
-
@
|
14
|
-
@feature_builder = nil
|
11
|
+
def initialize(uri)
|
12
|
+
@uri = uri
|
15
13
|
end
|
16
14
|
|
17
|
-
def
|
18
|
-
|
19
|
-
@feature_builder.result(language)
|
20
|
-
end
|
21
|
-
|
22
|
-
def language=(language)
|
23
|
-
@language = language
|
24
|
-
end
|
25
|
-
|
26
|
-
def uri(uri)
|
27
|
-
@path = uri
|
28
|
-
end
|
29
|
-
|
30
|
-
def feature(node)
|
31
|
-
@feature_builder = FeatureBuilder.new(file, node)
|
32
|
-
end
|
33
|
-
|
34
|
-
def background(node)
|
35
|
-
builder = BackgroundBuilder.new(file, node)
|
36
|
-
@feature_builder.background_builder = builder
|
37
|
-
@current = builder
|
38
|
-
end
|
39
|
-
|
40
|
-
def scenario(node)
|
41
|
-
builder = ScenarioBuilder.new(file, node)
|
42
|
-
@feature_builder.add_child builder
|
43
|
-
@current = builder
|
44
|
-
end
|
45
|
-
|
46
|
-
def scenario_outline(node)
|
47
|
-
builder = ScenarioOutlineBuilder.new(file, node)
|
48
|
-
@feature_builder.add_child builder
|
49
|
-
@current = builder
|
50
|
-
end
|
51
|
-
|
52
|
-
def examples(node)
|
53
|
-
@current.add_examples file, node
|
54
|
-
end
|
55
|
-
|
56
|
-
def step(node)
|
57
|
-
@current.add_step file, node
|
58
|
-
end
|
59
|
-
|
60
|
-
def eof
|
61
|
-
end
|
62
|
-
|
63
|
-
def syntax_error(state, event, legal_events, line)
|
64
|
-
# raise "SYNTAX ERROR"
|
15
|
+
def feature(attributes)
|
16
|
+
FeatureBuilder.new(file, attributes).result
|
65
17
|
end
|
66
18
|
|
67
19
|
private
|
68
20
|
|
69
|
-
def language
|
70
|
-
@language || raise("Language has not been set")
|
71
|
-
end
|
72
|
-
|
73
21
|
def file
|
74
|
-
@
|
22
|
+
@uri
|
75
23
|
end
|
76
24
|
|
77
25
|
class Builder
|
78
|
-
attr_reader :file, :
|
79
|
-
private :file, :
|
26
|
+
attr_reader :file, :attributes, :comments, :line
|
27
|
+
private :file, :attributes, :comments, :line
|
80
28
|
|
81
|
-
def initialize(file,
|
29
|
+
def initialize(file, attributes)
|
82
30
|
@file = file
|
83
|
-
@
|
31
|
+
@attributes = rubify_keys(attributes.dup)
|
32
|
+
@comments = []
|
33
|
+
@line = @attributes[:location][:line]
|
34
|
+
end
|
35
|
+
|
36
|
+
def handle_comments(comments)
|
37
|
+
remaining_comments = []
|
38
|
+
comments.each do |comment|
|
39
|
+
if line > comment.location.line
|
40
|
+
@comments << comment
|
41
|
+
else
|
42
|
+
remaining_comments << comment
|
43
|
+
end
|
44
|
+
end
|
45
|
+
children.each { |child| remaining_comments = child.handle_comments(remaining_comments) }
|
46
|
+
remaining_comments
|
84
47
|
end
|
85
48
|
|
86
49
|
private
|
87
50
|
|
51
|
+
def keyword
|
52
|
+
attributes[:keyword]
|
53
|
+
end
|
54
|
+
|
55
|
+
def name
|
56
|
+
attributes[:name]
|
57
|
+
end
|
58
|
+
|
59
|
+
def description
|
60
|
+
attributes[:description] ||= ""
|
61
|
+
end
|
62
|
+
|
88
63
|
def tags
|
89
|
-
|
64
|
+
attributes[:tags].map do |tag|
|
90
65
|
Ast::Tag.new(
|
91
|
-
Ast::Location.new(file, tag
|
92
|
-
tag
|
66
|
+
Ast::Location.new(file, tag[:location][:line]),
|
67
|
+
tag[:name])
|
93
68
|
end
|
94
69
|
end
|
95
70
|
|
96
71
|
def location
|
97
|
-
Ast::Location.new(file,
|
72
|
+
Ast::Location.new(file, attributes[:location][:line])
|
98
73
|
end
|
99
74
|
|
100
|
-
def
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
75
|
+
def children
|
76
|
+
[]
|
77
|
+
end
|
78
|
+
|
79
|
+
def rubify_keys(hash)
|
80
|
+
hash.keys.each do |key|
|
81
|
+
if key.downcase != key
|
82
|
+
hash[underscore(key).to_sym] = hash.delete(key)
|
83
|
+
end
|
106
84
|
end
|
85
|
+
return hash
|
86
|
+
end
|
87
|
+
|
88
|
+
def underscore(string)
|
89
|
+
string.to_s.gsub(/::/, '/').
|
90
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
91
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
92
|
+
tr("-", "_").
|
93
|
+
downcase
|
107
94
|
end
|
108
95
|
end
|
109
96
|
|
110
97
|
class FeatureBuilder < Builder
|
111
|
-
|
112
|
-
private :background_builder
|
98
|
+
attr_reader :language, :background_builder, :scenario_definition_builders
|
113
99
|
|
114
100
|
def initialize(*)
|
115
101
|
super
|
116
|
-
@
|
102
|
+
@language = Ast::LanguageDelegator.new(attributes[:language], ::Gherkin3::Dialect.for(attributes[:language]))
|
103
|
+
@background_builder = BackgroundBuilder.new(file, attributes[:background]) if attributes[:background]
|
104
|
+
@scenario_definition_builders = attributes[:scenario_definitions].map do |sd|
|
105
|
+
sd[:type] == :Scenario ? ScenarioBuilder.new(file, sd) : ScenarioOutlineBuilder.new(file, sd)
|
106
|
+
end
|
117
107
|
end
|
118
108
|
|
119
|
-
def result
|
120
|
-
|
109
|
+
def result
|
110
|
+
handle_comments(all_comments)
|
121
111
|
Ast::Feature.new(
|
122
|
-
node,
|
123
112
|
language,
|
124
113
|
location,
|
125
114
|
background,
|
126
115
|
comments,
|
127
116
|
tags,
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
117
|
+
keyword,
|
118
|
+
name,
|
119
|
+
description,
|
120
|
+
scenario_definitions
|
132
121
|
)
|
133
122
|
end
|
134
123
|
|
135
|
-
|
136
|
-
|
124
|
+
private
|
125
|
+
|
126
|
+
def background
|
127
|
+
return Ast::EmptyBackground.new unless background_builder
|
128
|
+
background_builder.result(language)
|
137
129
|
end
|
138
130
|
|
139
|
-
def
|
140
|
-
|
131
|
+
def scenario_definitions
|
132
|
+
scenario_definition_builders.map { |builder| builder.result(language) }
|
141
133
|
end
|
142
134
|
|
143
|
-
|
135
|
+
def all_comments
|
136
|
+
attributes[:comments].map do |comment|
|
137
|
+
Ast::Comment.new(
|
138
|
+
Ast::Location.new(file, comment[:location][:line]),
|
139
|
+
comment[:text]
|
140
|
+
)
|
141
|
+
end
|
142
|
+
end
|
144
143
|
|
145
|
-
def
|
146
|
-
|
147
|
-
@background ||= background_builder.result(language)
|
144
|
+
def children
|
145
|
+
(background_builder ? [background_builder] : []) + scenario_definition_builders
|
148
146
|
end
|
149
147
|
end
|
150
148
|
|
151
149
|
class BackgroundBuilder < Builder
|
150
|
+
attr_reader :step_builders
|
151
|
+
|
152
|
+
def initialize(*)
|
153
|
+
super
|
154
|
+
@step_builders = attributes[:steps].map { |step| StepBuilder.new(file, step) }
|
155
|
+
end
|
156
|
+
|
152
157
|
def result(language)
|
153
158
|
Ast::Background.new(
|
154
|
-
node,
|
155
|
-
language,
|
156
159
|
location,
|
157
160
|
comments,
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
+
keyword,
|
162
|
+
name,
|
163
|
+
description,
|
161
164
|
steps(language)
|
162
165
|
)
|
163
166
|
end
|
164
167
|
|
165
|
-
def add_step(file, node)
|
166
|
-
step_builders << ScenarioBuilder::StepBuilder.new(file, node)
|
167
|
-
end
|
168
|
-
|
169
|
-
private
|
170
|
-
|
171
168
|
def steps(language)
|
172
|
-
step_builders.map { |
|
169
|
+
step_builders.map { |builder| builder.result(language) }
|
173
170
|
end
|
174
171
|
|
175
|
-
def
|
176
|
-
|
172
|
+
def children
|
173
|
+
step_builders
|
177
174
|
end
|
178
|
-
|
179
175
|
end
|
180
176
|
|
181
177
|
class ScenarioBuilder < Builder
|
182
|
-
|
178
|
+
attr_reader :step_builders
|
179
|
+
|
180
|
+
def initialize(*)
|
181
|
+
super
|
182
|
+
@step_builders = attributes[:steps].map { |step| StepBuilder.new(file, step) }
|
183
|
+
end
|
184
|
+
|
185
|
+
def result(language)
|
183
186
|
Ast::Scenario.new(
|
184
|
-
node,
|
185
|
-
language,
|
186
187
|
location,
|
187
|
-
background,
|
188
188
|
comments,
|
189
189
|
tags,
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
node.description,
|
190
|
+
keyword,
|
191
|
+
name,
|
192
|
+
description,
|
194
193
|
steps(language)
|
195
194
|
)
|
196
195
|
end
|
197
196
|
|
198
|
-
def
|
199
|
-
step_builders
|
197
|
+
def steps(language)
|
198
|
+
step_builders.map { |builder| builder.result(language) }
|
200
199
|
end
|
201
200
|
|
202
|
-
|
201
|
+
def children
|
202
|
+
step_builders
|
203
|
+
end
|
204
|
+
end
|
203
205
|
|
204
|
-
|
205
|
-
|
206
|
+
class StepBuilder < Builder
|
207
|
+
attr_reader :multiline_argument_builder
|
208
|
+
|
209
|
+
def initialize(*)
|
210
|
+
super
|
211
|
+
@multiline_argument_builder = attributes[:argument] ? argument_builder(attributes[:argument]) : nil
|
206
212
|
end
|
207
213
|
|
208
|
-
def
|
209
|
-
|
214
|
+
def result(language)
|
215
|
+
Ast::Step.new(
|
216
|
+
language,
|
217
|
+
location,
|
218
|
+
comments,
|
219
|
+
keyword,
|
220
|
+
attributes[:text],
|
221
|
+
multiline_argument
|
222
|
+
)
|
210
223
|
end
|
211
224
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
+
def multiline_argument
|
226
|
+
return Ast::EmptyMultilineArgument.new unless multiline_argument_builder
|
227
|
+
multiline_argument_builder.result
|
228
|
+
end
|
229
|
+
|
230
|
+
def children
|
231
|
+
return [] unless multiline_argument_builder
|
232
|
+
[multiline_argument_builder]
|
233
|
+
end
|
234
|
+
|
235
|
+
private
|
236
|
+
|
237
|
+
def argument_builder(attributes)
|
238
|
+
attributes[:type] == :DataTable ? DataTableBuilder.new(file, attributes) : DocStringBuilder.new(file, attributes)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
class OutlineStepBuilder < StepBuilder
|
243
|
+
def result(language)
|
244
|
+
Ast::OutlineStep.new(
|
245
|
+
language,
|
246
|
+
location,
|
247
|
+
comments,
|
248
|
+
keyword,
|
249
|
+
attributes[:text],
|
250
|
+
multiline_argument
|
251
|
+
)
|
225
252
|
end
|
226
253
|
end
|
227
254
|
|
228
255
|
class ScenarioOutlineBuilder < Builder
|
229
|
-
|
230
|
-
|
256
|
+
attr_reader :step_builders, :example_builders
|
257
|
+
|
258
|
+
def initialize(*)
|
259
|
+
super
|
260
|
+
@step_builders = attributes[:steps].map { |step| OutlineStepBuilder.new(file, step) }
|
261
|
+
@example_builders = attributes[:examples].map { |example| ExamplesTableBuilder.new(file, example) }
|
262
|
+
end
|
263
|
+
|
264
|
+
def result(language)
|
231
265
|
Ast::ScenarioOutline.new(
|
232
|
-
node,
|
233
|
-
language,
|
234
266
|
location,
|
235
|
-
background,
|
236
267
|
comments,
|
237
268
|
tags,
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
node.description,
|
269
|
+
keyword,
|
270
|
+
name,
|
271
|
+
description,
|
242
272
|
steps(language),
|
243
|
-
|
273
|
+
examples(language)
|
244
274
|
)
|
245
275
|
end
|
246
276
|
|
247
|
-
def
|
248
|
-
|
277
|
+
def steps(language)
|
278
|
+
step_builders.map { |builder| builder.result(language) }
|
249
279
|
end
|
250
280
|
|
251
|
-
def
|
252
|
-
|
281
|
+
def examples(language)
|
282
|
+
example_builders.map { |builder| builder.result(language) }
|
253
283
|
end
|
254
284
|
|
255
|
-
|
256
|
-
|
257
|
-
def steps(language)
|
258
|
-
step_builders.map { |step_builder| step_builder.result(language) }
|
285
|
+
def children
|
286
|
+
step_builders + example_builders
|
259
287
|
end
|
288
|
+
end
|
260
289
|
|
261
|
-
|
262
|
-
|
263
|
-
end
|
290
|
+
class ExamplesTableBuilder < Builder
|
291
|
+
attr_reader :header_builder, :example_rows_builders
|
264
292
|
|
265
|
-
def
|
266
|
-
|
293
|
+
def initialize(*)
|
294
|
+
super
|
295
|
+
@header_builder = HeaderBuilder.new(file, attributes[:table_header])
|
296
|
+
@example_rows_builders = attributes[:table_body].map do |row_attributes|
|
297
|
+
ExampleRowBuilder.new(file, row_attributes)
|
298
|
+
end
|
267
299
|
end
|
268
300
|
|
269
|
-
def
|
270
|
-
|
301
|
+
def result(language)
|
302
|
+
Ast::Examples.new(
|
303
|
+
location,
|
304
|
+
comments,
|
305
|
+
tags,
|
306
|
+
keyword,
|
307
|
+
name,
|
308
|
+
description,
|
309
|
+
header,
|
310
|
+
example_rows(language)
|
311
|
+
)
|
271
312
|
end
|
272
313
|
|
273
|
-
|
314
|
+
private
|
274
315
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
location,
|
279
|
-
comments,
|
280
|
-
tags,
|
281
|
-
node.keyword,
|
282
|
-
node.name,
|
283
|
-
node.description,
|
284
|
-
header,
|
285
|
-
example_rows(language)
|
286
|
-
)
|
287
|
-
end
|
316
|
+
def header
|
317
|
+
@header = header_builder.result
|
318
|
+
end
|
288
319
|
|
289
|
-
|
320
|
+
def example_rows(language)
|
321
|
+
example_rows_builders.each.with_index.map { |builder, index| builder.result(language, header, index) }
|
322
|
+
end
|
290
323
|
|
291
|
-
|
292
|
-
|
293
|
-
|
324
|
+
class HeaderBuilder < Builder
|
325
|
+
def result
|
326
|
+
cells = attributes[:cells].map { |c| c[:value] }
|
327
|
+
Ast::ExamplesTable::Header.new(cells, location, comments)
|
294
328
|
end
|
329
|
+
end
|
295
330
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
header.build_row(row.cells, index + 1, location.on_line(row.line), language, row_comments(row))
|
300
|
-
end
|
301
|
-
end
|
331
|
+
def children
|
332
|
+
[header_builder] + example_rows_builders
|
333
|
+
end
|
302
334
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
comment.value
|
308
|
-
)
|
309
|
-
end
|
335
|
+
class ExampleRowBuilder < Builder
|
336
|
+
def result(language, header, index)
|
337
|
+
cells = attributes[:cells].map { |c| c[:value] }
|
338
|
+
header.build_row(cells, index + 1, location, language, comments)
|
310
339
|
end
|
311
340
|
end
|
341
|
+
end
|
312
342
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
)
|
324
|
-
end
|
343
|
+
class DataTableBuilder < Builder
|
344
|
+
def result
|
345
|
+
Ast::DataTable.new(
|
346
|
+
rows,
|
347
|
+
location
|
348
|
+
)
|
349
|
+
end
|
350
|
+
|
351
|
+
def rows
|
352
|
+
attributes[:rows] = attributes[:rows].map { |r| r[:cells].map { |c| c[:value] } }
|
325
353
|
end
|
326
354
|
end
|
327
355
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
else
|
342
|
-
raise ArgumentError, "Don't know how to convert #{argument.inspect} into a MultilineArgument"
|
343
|
-
end
|
344
|
-
end
|
356
|
+
class DocStringBuilder < Builder
|
357
|
+
def result
|
358
|
+
Ast::DocString.new(
|
359
|
+
attributes[:content],
|
360
|
+
attributes[:content_type],
|
361
|
+
doc_string_location
|
362
|
+
)
|
363
|
+
end
|
364
|
+
|
365
|
+
def doc_string_location
|
366
|
+
start_line = attributes[:location][:line]
|
367
|
+
end_line = start_line + attributes[:content].each_line.to_a.length + 1
|
368
|
+
Ast::Location.new(file, start_line..end_line)
|
345
369
|
end
|
346
370
|
end
|
347
371
|
|