cucumber-core 1.2.0 → 1.3.0
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.
- 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
|
|