cuke_modeler 3.3.0 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -1
- data/cuke_modeler.gemspec +23 -14
- data/lib/cuke_modeler.rb +1 -1
- data/lib/cuke_modeler/adapters/gherkin_10_adapter.rb +2 -1
- data/lib/cuke_modeler/adapters/gherkin_11_adapter.rb +2 -1
- data/lib/cuke_modeler/adapters/gherkin_12_adapter.rb +2 -1
- data/lib/cuke_modeler/adapters/gherkin_13_adapter.rb +2 -1
- data/lib/cuke_modeler/adapters/gherkin_14_adapter.rb +2 -1
- data/lib/cuke_modeler/adapters/gherkin_15_adapter.rb +2 -1
- data/lib/cuke_modeler/adapters/gherkin_9_adapter.rb +261 -242
- data/lib/cuke_modeler/containing.rb +31 -89
- data/lib/cuke_modeler/described.rb +40 -1
- data/lib/cuke_modeler/models/background.rb +11 -11
- data/lib/cuke_modeler/models/cell.rb +13 -7
- data/lib/cuke_modeler/models/comment.rb +5 -5
- data/lib/cuke_modeler/models/directory.rb +13 -17
- data/lib/cuke_modeler/models/doc_string.rb +10 -7
- data/lib/cuke_modeler/models/example.rb +63 -45
- data/lib/cuke_modeler/models/feature.rb +23 -16
- data/lib/cuke_modeler/models/feature_file.rb +5 -7
- data/lib/cuke_modeler/models/model.rb +2 -1
- data/lib/cuke_modeler/models/outline.rb +19 -14
- data/lib/cuke_modeler/models/row.rb +10 -7
- data/lib/cuke_modeler/models/rule.rb +11 -9
- data/lib/cuke_modeler/models/scenario.rb +17 -12
- data/lib/cuke_modeler/models/step.rb +40 -18
- data/lib/cuke_modeler/models/table.rb +9 -6
- data/lib/cuke_modeler/models/tag.rb +9 -5
- data/lib/cuke_modeler/named.rb +5 -1
- data/lib/cuke_modeler/nested.rb +22 -18
- data/lib/cuke_modeler/parsed.rb +8 -0
- data/lib/cuke_modeler/parsing.rb +36 -26
- data/lib/cuke_modeler/sourceable.rb +8 -0
- data/lib/cuke_modeler/stepped.rb +8 -0
- data/lib/cuke_modeler/taggable.rb +9 -1
- data/lib/cuke_modeler/version.rb +1 -1
- metadata +53 -33
@@ -18,10 +18,10 @@ module CukeModeler
|
|
18
18
|
def initialize(source_text = nil)
|
19
19
|
super(source_text)
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
return unless source_text
|
22
|
+
|
23
|
+
parsed_tag_data = parse_source(source_text)
|
24
|
+
populate_tag(self, parsed_tag_data)
|
25
25
|
end
|
26
26
|
|
27
27
|
# Returns a string representation of this model. For a tag model,
|
@@ -38,10 +38,14 @@ module CukeModeler
|
|
38
38
|
base_file_string = "\n#{dialect_feature_keyword}: Fake feature to parse"
|
39
39
|
source_text = "# language: #{Parsing.dialect}\n" + source_text + base_file_string
|
40
40
|
|
41
|
-
parsed_file = Parsing
|
41
|
+
parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_tag.feature')
|
42
42
|
|
43
43
|
parsed_file['feature']['tags'].first
|
44
44
|
end
|
45
45
|
|
46
|
+
def populate_name(model, parsed_model_data)
|
47
|
+
model.name = parsed_model_data['name']
|
48
|
+
end
|
49
|
+
|
46
50
|
end
|
47
51
|
end
|
data/lib/cuke_modeler/named.rb
CHANGED
@@ -13,7 +13,11 @@ module CukeModeler
|
|
13
13
|
|
14
14
|
|
15
15
|
def name_output_string
|
16
|
-
|
16
|
+
name.nil? || name.empty? ? '' : " #{name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def populate_name(model, parsed_model_data)
|
20
|
+
model.name = parsed_model_data['name']
|
17
21
|
end
|
18
22
|
|
19
23
|
end
|
data/lib/cuke_modeler/nested.rb
CHANGED
@@ -12,30 +12,34 @@ module CukeModeler
|
|
12
12
|
|
13
13
|
# Returns the ancestor model of this model that matches the given type.
|
14
14
|
def get_ancestor(ancestor_type)
|
15
|
-
|
16
|
-
:feature_file => [FeatureFile],
|
17
|
-
:feature => [Feature],
|
18
|
-
:test => [Scenario, Outline, Background],
|
19
|
-
:background => [Background],
|
20
|
-
:scenario => [Scenario],
|
21
|
-
:outline => [Outline],
|
22
|
-
:step => [Step],
|
23
|
-
:table => [Table],
|
24
|
-
:example => [Example],
|
25
|
-
:row => [Row]
|
26
|
-
}[ancestor_type]
|
15
|
+
target_classes = classes_for_type(ancestor_type)
|
27
16
|
|
28
|
-
raise(ArgumentError, "Unknown ancestor type '#{ancestor_type}'.") if
|
17
|
+
raise(ArgumentError, "Unknown ancestor type '#{ancestor_type}'.") if target_classes.nil?
|
29
18
|
|
19
|
+
ancestor = parent_model
|
20
|
+
ancestor = ancestor.parent_model until target_classes.include?(ancestor.class) || ancestor.nil?
|
30
21
|
|
31
|
-
ancestor
|
22
|
+
ancestor
|
23
|
+
end
|
32
24
|
|
33
|
-
until target_type.include?(ancestor.class) || ancestor.nil?
|
34
|
-
ancestor = ancestor.parent_model
|
35
|
-
end
|
36
25
|
|
26
|
+
private
|
37
27
|
|
38
|
-
|
28
|
+
|
29
|
+
def classes_for_type(type)
|
30
|
+
{
|
31
|
+
directory: [Directory],
|
32
|
+
feature_file: [FeatureFile],
|
33
|
+
feature: [Feature],
|
34
|
+
test: [Scenario, Outline, Background],
|
35
|
+
background: [Background],
|
36
|
+
scenario: [Scenario],
|
37
|
+
outline: [Outline],
|
38
|
+
step: [Step],
|
39
|
+
table: [Table],
|
40
|
+
example: [Example],
|
41
|
+
row: [Row]
|
42
|
+
}[type]
|
39
43
|
end
|
40
44
|
|
41
45
|
end
|
data/lib/cuke_modeler/parsed.rb
CHANGED
@@ -8,5 +8,13 @@ module CukeModeler
|
|
8
8
|
# The parsing data for this element that was generated by the parsing engine (i.e. the *gherkin* gem)
|
9
9
|
attr_accessor :parsing_data
|
10
10
|
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
|
15
|
+
def populate_parsing_data(model, parsed_model_data)
|
16
|
+
model.parsing_data = parsed_model_data['cuke_modeler_parsing_data']
|
17
|
+
end
|
18
|
+
|
11
19
|
end
|
12
20
|
end
|
data/lib/cuke_modeler/parsing.rb
CHANGED
@@ -1,13 +1,6 @@
|
|
1
1
|
# Have to at least load some version of the gem before which version of the gem has been loaded can
|
2
|
-
# be determined and the rest of the needed files can be loaded.
|
3
|
-
|
4
|
-
begin
|
5
|
-
# Gherkin 9.x
|
6
|
-
require 'gherkin'
|
7
|
-
rescue LoadError => e
|
8
|
-
# Add other entry points again if things change again
|
9
|
-
raise e
|
10
|
-
end
|
2
|
+
# be determined and the rest of the needed files can be loaded.
|
3
|
+
require 'gherkin'
|
11
4
|
|
12
5
|
|
13
6
|
# The *cucumber-gherkin* gem loads differently and has different grammar rules across major versions. Parsing
|
@@ -16,12 +9,16 @@ end
|
|
16
9
|
gherkin_version = Gem.loaded_specs['cucumber-gherkin'].version.version
|
17
10
|
gherkin_major_version = gherkin_version.match(/^(\d+)\./)[1].to_i
|
18
11
|
|
12
|
+
# Previous versions of the gem did not use the conventional entry point, so I'm leaving this here in case it
|
13
|
+
# changes again
|
14
|
+
# rubocop:disable Lint/EmptyWhen
|
19
15
|
case gherkin_major_version
|
20
16
|
when 9, 10, 11, 12, 13, 14, 15
|
21
17
|
# Currently nothing else to load beyond the entry point to the gem
|
22
18
|
else
|
23
19
|
raise("Unknown Gherkin version: '#{gherkin_version}'")
|
24
20
|
end
|
21
|
+
# rubocop:enable Lint/EmptyWhen
|
25
22
|
|
26
23
|
require "cuke_modeler/adapters/gherkin_#{gherkin_major_version}_adapter"
|
27
24
|
|
@@ -45,18 +42,16 @@ module CukeModeler
|
|
45
42
|
|
46
43
|
# The dialects currently known by the gherkin gem
|
47
44
|
def dialects
|
48
|
-
|
49
|
-
@dialects = Gherkin::DIALECTS
|
50
|
-
end
|
51
|
-
|
52
|
-
@dialects
|
45
|
+
@dialects ||= Gherkin::DIALECTS
|
53
46
|
end
|
54
47
|
|
55
48
|
# Parses the Cucumber feature given in *source_text* and returns a hash representation of
|
56
49
|
# its logical structure. This is a standardized AST that should remain consistent across
|
57
50
|
# different versions of `cucumber-gherkin`
|
58
51
|
def parse_text(source_text, filename = 'cuke_modeler_fake_file.feature')
|
59
|
-
|
52
|
+
unless source_text.is_a?(String)
|
53
|
+
raise(ArgumentError, "Text to parse must be a String but got #{source_text.class}")
|
54
|
+
end
|
60
55
|
|
61
56
|
begin
|
62
57
|
parsed_result = parsing_method(source_text.encode('UTF-8'), filename)
|
@@ -71,13 +66,20 @@ module CukeModeler
|
|
71
66
|
gherkin_version = Gem.loaded_specs['cucumber-gherkin'].version.version
|
72
67
|
gherkin_major_version = gherkin_version.match(/^(\d+)\./)[1].to_i
|
73
68
|
|
69
|
+
# Previous versions of the gem had more variation between their parsing methods and so it was more
|
70
|
+
# understandable to have different methods instead of a single method with lots of conditional statements
|
71
|
+
# inside of it, so I'm leaving this here in case it changes again
|
72
|
+
# rubocop:disable Lint/DuplicateMethods
|
74
73
|
case gherkin_major_version
|
75
74
|
when 13, 14, 15
|
76
|
-
#
|
75
|
+
# TODO: make these methods private?
|
77
76
|
# NOT A PART OF THE PUBLIC API
|
78
77
|
# The method to use for parsing Gherkin text
|
79
78
|
def parsing_method(source_text, filename)
|
80
|
-
messages = Gherkin.from_source(filename,
|
79
|
+
messages = Gherkin.from_source(filename,
|
80
|
+
source_text,
|
81
|
+
{ include_gherkin_document: true })
|
82
|
+
.to_a.map(&:to_hash)
|
81
83
|
|
82
84
|
error_message = messages.find { |message| message[:parse_error] }
|
83
85
|
gherkin_ast_message = messages.find { |message| message[:gherkin_document] }
|
@@ -87,33 +89,39 @@ module CukeModeler
|
|
87
89
|
gherkin_ast_message[:gherkin_document]
|
88
90
|
end
|
89
91
|
when 12
|
90
|
-
#
|
92
|
+
# TODO: make these methods private?
|
91
93
|
# NOT A PART OF THE PUBLIC API
|
92
94
|
# The method to use for parsing Gherkin text
|
93
95
|
def parsing_method(source_text, filename)
|
94
|
-
messages = Gherkin.from_source(filename,
|
96
|
+
messages = Gherkin.from_source(filename,
|
97
|
+
source_text,
|
98
|
+
{ include_gherkin_document: true })
|
99
|
+
.to_a.map(&:to_hash)
|
95
100
|
|
96
101
|
potential_error_message = messages.find { |message| message[:attachment] }
|
97
102
|
gherkin_ast_message = messages.find { |message| message[:gherkin_document] }
|
98
103
|
|
99
|
-
if potential_error_message
|
100
|
-
raise potential_error_message[:attachment][:body]
|
104
|
+
if potential_error_message && potential_error_message[:attachment][:body] =~ /expected.*got/
|
105
|
+
raise potential_error_message[:attachment][:body]
|
101
106
|
end
|
102
107
|
|
103
108
|
gherkin_ast_message[:gherkin_document]
|
104
109
|
end
|
105
110
|
when 9, 10, 11
|
106
|
-
#
|
111
|
+
# TODO: make these methods private?
|
107
112
|
# NOT A PART OF THE PUBLIC API
|
108
113
|
# The method to use for parsing Gherkin text
|
109
114
|
def parsing_method(source_text, filename)
|
110
|
-
messages = Gherkin.from_source(filename,
|
115
|
+
messages = Gherkin.from_source(filename,
|
116
|
+
source_text,
|
117
|
+
{ include_gherkin_document: true })
|
118
|
+
.to_a.map(&:to_hash)
|
111
119
|
|
112
120
|
potential_error_message = messages.find { |message| message[:attachment] }
|
113
121
|
gherkin_ast_message = messages.find { |message| message[:gherkin_document] }
|
114
122
|
|
115
|
-
if potential_error_message
|
116
|
-
raise potential_error_message[:attachment][:text]
|
123
|
+
if potential_error_message && potential_error_message[:attachment][:text] =~ /expected.*got/
|
124
|
+
raise potential_error_message[:attachment][:text]
|
117
125
|
end
|
118
126
|
|
119
127
|
gherkin_ast_message[:gherkin_document]
|
@@ -121,6 +129,7 @@ module CukeModeler
|
|
121
129
|
else
|
122
130
|
raise("Unknown Gherkin version: '#{gherkin_version}'")
|
123
131
|
end
|
132
|
+
# rubocop:enable Lint/DuplicateMethods
|
124
133
|
|
125
134
|
# NOT A PART OF THE PUBLIC API
|
126
135
|
# The adapter to use when converting an AST to a standard internal shape
|
@@ -143,7 +152,8 @@ module CukeModeler
|
|
143
152
|
end
|
144
153
|
|
145
154
|
def dialect_outline_keyword
|
146
|
-
get_word(Parsing.dialects[Parsing.dialect]['scenarioOutline'] ||
|
155
|
+
get_word(Parsing.dialects[Parsing.dialect]['scenarioOutline'] ||
|
156
|
+
Parsing.dialects[Parsing.dialect]['scenario_outline'])
|
147
157
|
end
|
148
158
|
|
149
159
|
def dialect_step_keyword
|
@@ -9,5 +9,13 @@ module CukeModeler
|
|
9
9
|
# The line number where the element began in the source code
|
10
10
|
attr_accessor :source_line
|
11
11
|
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
|
16
|
+
def populate_source_line(model, parsed_model_data)
|
17
|
+
model.source_line = parsed_model_data['line']
|
18
|
+
end
|
19
|
+
|
12
20
|
end
|
13
21
|
end
|
data/lib/cuke_modeler/stepped.rb
CHANGED
@@ -21,5 +21,13 @@ module CukeModeler
|
|
21
21
|
step.to_s.split("\n").collect { |line| " #{line}" }.join("\n")
|
22
22
|
end
|
23
23
|
|
24
|
+
def populate_steps(model, parsed_model_data)
|
25
|
+
return unless parsed_model_data['steps']
|
26
|
+
|
27
|
+
parsed_model_data['steps'].each do |step_data|
|
28
|
+
model.steps << build_child_model(Step, step_data)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
24
32
|
end
|
25
33
|
end
|
@@ -25,7 +25,15 @@ module CukeModeler
|
|
25
25
|
|
26
26
|
|
27
27
|
def tag_output_string
|
28
|
-
tags.
|
28
|
+
tags.map(&:name).join(' ')
|
29
|
+
end
|
30
|
+
|
31
|
+
def populate_tags(model, parsed_model_data)
|
32
|
+
return unless parsed_model_data['tags']
|
33
|
+
|
34
|
+
parsed_model_data['tags'].each do |tag|
|
35
|
+
model.tags << build_child_model(Tag, tag)
|
36
|
+
end
|
29
37
|
end
|
30
38
|
|
31
39
|
end
|
data/lib/cuke_modeler/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cuke_modeler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Kessler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cucumber-gherkin
|
@@ -39,103 +39,123 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: coveralls
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "<"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 1.0.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "<"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 1.0.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: cucumber
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 4.0.0
|
59
62
|
- - "<"
|
60
63
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
64
|
+
version: 6.0.0
|
62
65
|
type: :development
|
63
66
|
prerelease: false
|
64
67
|
version_requirements: !ruby/object:Gem::Requirement
|
65
68
|
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: 4.0.0
|
66
72
|
- - "<"
|
67
73
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
74
|
+
version: 6.0.0
|
69
75
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
76
|
+
name: racatt
|
71
77
|
requirement: !ruby/object:Gem::Requirement
|
72
78
|
requirements:
|
73
79
|
- - "~>"
|
74
80
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
81
|
+
version: '1.0'
|
76
82
|
type: :development
|
77
83
|
prerelease: false
|
78
84
|
version_requirements: !ruby/object:Gem::Requirement
|
79
85
|
requirements:
|
80
86
|
- - "~>"
|
81
87
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
88
|
+
version: '1.0'
|
83
89
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
90
|
+
name: rainbow
|
85
91
|
requirement: !ruby/object:Gem::Requirement
|
86
92
|
requirements:
|
87
|
-
- - "
|
93
|
+
- - "<"
|
88
94
|
- !ruby/object:Gem::Version
|
89
|
-
version: 0.
|
95
|
+
version: 4.0.0
|
90
96
|
type: :development
|
91
97
|
prerelease: false
|
92
98
|
version_requirements: !ruby/object:Gem::Requirement
|
93
99
|
requirements:
|
94
|
-
- - "
|
100
|
+
- - "<"
|
95
101
|
- !ruby/object:Gem::Version
|
96
|
-
version: 0.
|
102
|
+
version: 4.0.0
|
97
103
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
104
|
+
name: rake
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "<"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 14.0.0
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "<"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 14.0.0
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: rspec
|
99
119
|
requirement: !ruby/object:Gem::Requirement
|
100
120
|
requirements:
|
101
121
|
- - "~>"
|
102
122
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
123
|
+
version: '3.0'
|
104
124
|
type: :development
|
105
125
|
prerelease: false
|
106
126
|
version_requirements: !ruby/object:Gem::Requirement
|
107
127
|
requirements:
|
108
128
|
- - "~>"
|
109
129
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
130
|
+
version: '3.0'
|
111
131
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
132
|
+
name: rubocop
|
113
133
|
requirement: !ruby/object:Gem::Requirement
|
114
134
|
requirements:
|
115
135
|
- - "<"
|
116
136
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
137
|
+
version: 0.82.0
|
118
138
|
type: :development
|
119
139
|
prerelease: false
|
120
140
|
version_requirements: !ruby/object:Gem::Requirement
|
121
141
|
requirements:
|
122
142
|
- - "<"
|
123
143
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
144
|
+
version: 0.82.0
|
125
145
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
146
|
+
name: simplecov
|
127
147
|
requirement: !ruby/object:Gem::Requirement
|
128
148
|
requirements:
|
129
|
-
- - "
|
149
|
+
- - "<="
|
130
150
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
151
|
+
version: 0.16.1
|
132
152
|
type: :development
|
133
153
|
prerelease: false
|
134
154
|
version_requirements: !ruby/object:Gem::Requirement
|
135
155
|
requirements:
|
136
|
-
- - "
|
156
|
+
- - "<="
|
137
157
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
158
|
+
version: 0.16.1
|
139
159
|
- !ruby/object:Gem::Dependency
|
140
160
|
name: test-unit
|
141
161
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,13 +170,13 @@ dependencies:
|
|
150
170
|
- - "<"
|
151
171
|
- !ruby/object:Gem::Version
|
152
172
|
version: 4.0.0
|
153
|
-
description: This gem facilitates modeling a test suite that is written in Gherkin
|
154
|
-
(e.g. Cucumber,
|
155
|
-
layer on top of the
|
156
|
-
when parsing features,
|
157
|
-
in order to be able to
|
158
|
-
These models can then
|
159
|
-
AST layer.
|
173
|
+
description: "This gem facilitates modeling a test suite that is written in Gherkin
|
174
|
+
(e.g. Cucumber, \nSpecFlow, Lettuce, etc.). It does this by providing an abstraction
|
175
|
+
layer on top of the \nAbstract Syntax Tree that the 'cucumber-gherkin' gem generates
|
176
|
+
when parsing features, \nas well as providing models for feature files and directories
|
177
|
+
in order to be able to \nhave a fully traversable model tree of a test suite's structure.
|
178
|
+
These models can then \nbe analyzed or manipulated more easily than the underlying
|
179
|
+
AST layer."
|
160
180
|
email:
|
161
181
|
- morrow748@gmail.com
|
162
182
|
executables: []
|