cuke_modeler 3.2.0 → 3.7.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/CHANGELOG.md +48 -3
- data/LICENSE.txt +1 -1
- data/README.md +7 -7
- data/cuke_modeler.gemspec +35 -16
- data/lib/cuke_modeler.rb +1 -2
- 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 +13 -0
- data/lib/cuke_modeler/adapters/gherkin_16_adapter.rb +13 -0
- data/lib/cuke_modeler/adapters/gherkin_17_adapter.rb +13 -0
- data/lib/cuke_modeler/adapters/gherkin_9_adapter.rb +261 -243
- data/lib/cuke_modeler/containing.rb +47 -90
- data/lib/cuke_modeler/described.rb +40 -2
- data/lib/cuke_modeler/models/background.rb +11 -12
- data/lib/cuke_modeler/models/cell.rb +13 -8
- data/lib/cuke_modeler/models/comment.rb +5 -6
- data/lib/cuke_modeler/models/directory.rb +13 -18
- data/lib/cuke_modeler/models/doc_string.rb +10 -8
- data/lib/cuke_modeler/models/example.rb +63 -46
- data/lib/cuke_modeler/models/feature.rb +23 -17
- data/lib/cuke_modeler/models/feature_file.rb +5 -8
- data/lib/cuke_modeler/models/model.rb +2 -3
- data/lib/cuke_modeler/models/outline.rb +19 -15
- data/lib/cuke_modeler/models/row.rb +15 -8
- data/lib/cuke_modeler/models/rule.rb +11 -10
- data/lib/cuke_modeler/models/scenario.rb +17 -13
- data/lib/cuke_modeler/models/step.rb +40 -19
- data/lib/cuke_modeler/models/table.rb +9 -7
- data/lib/cuke_modeler/models/tag.rb +9 -6
- data/lib/cuke_modeler/named.rb +5 -2
- data/lib/cuke_modeler/nested.rb +22 -19
- data/lib/cuke_modeler/parsed.rb +8 -1
- data/lib/cuke_modeler/parsing.rb +38 -29
- data/lib/cuke_modeler/sourceable.rb +8 -1
- data/lib/cuke_modeler/stepped.rb +8 -1
- data/lib/cuke_modeler/taggable.rb +9 -2
- data/lib/cuke_modeler/version.rb +1 -1
- metadata +91 -36
@@ -1,7 +1,9 @@
|
|
1
|
+
# I'll take extra class length due to extra helper methods over having fewer but more complex methods
|
2
|
+
# rubocop:disable Metrics/ClassLength
|
3
|
+
|
1
4
|
module CukeModeler
|
2
5
|
|
3
6
|
# A class modeling an example table of an outline.
|
4
|
-
|
5
7
|
class Example < Model
|
6
8
|
|
7
9
|
include Parsing
|
@@ -27,10 +29,10 @@ module CukeModeler
|
|
27
29
|
|
28
30
|
super(source_text)
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
return unless source_text
|
33
|
+
|
34
|
+
parsed_example_data = parse_source(source_text)
|
35
|
+
populate_example(self, parsed_example_data)
|
34
36
|
end
|
35
37
|
|
36
38
|
# Adds a row to the example table. The row can be given as a Hash of
|
@@ -40,42 +42,39 @@ module CukeModeler
|
|
40
42
|
raise('Cannot add a row. No parameters have been set.') if rows.empty?
|
41
43
|
|
42
44
|
# A quick 'deep clone' so that the input isn't modified
|
43
|
-
row = Marshal
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
raise(ArgumentError, "Can only add row from a Hash or an Array but received #{row.class}")
|
58
|
-
end
|
45
|
+
row = Marshal.load(Marshal.dump(row))
|
46
|
+
|
47
|
+
values = if row.is_a?(Array)
|
48
|
+
row
|
49
|
+
elsif row.is_a?(Hash)
|
50
|
+
# There is no guarantee that the user built up their hash with the keys in the same order as
|
51
|
+
# the parameter row and so the values have to be ordered by us. Additionally, the hash needs
|
52
|
+
# to have string keys in order for #order_row_values to work
|
53
|
+
ordered_row_values(stringify_keys(row))
|
54
|
+
else
|
55
|
+
raise(ArgumentError, "Can only add row from a Hash or an Array but received #{row.class}")
|
56
|
+
end
|
57
|
+
|
58
|
+
@rows << Row.new("|#{values.join('|')}|")
|
59
59
|
end
|
60
60
|
|
61
61
|
# Removes a row from the example table. The row can be given as a Hash of
|
62
62
|
# parameters and their corresponding values or as an Array of values
|
63
63
|
# which will be assigned in order.
|
64
64
|
def remove_row(row_removed)
|
65
|
-
return
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
65
|
+
return if argument_rows.empty?
|
66
|
+
|
67
|
+
values = if row_removed.is_a?(Array)
|
68
|
+
row_removed
|
69
|
+
elsif row_removed.is_a?(Hash)
|
70
|
+
# There is no guarantee that the user built up their hash with the keys in the same order as
|
71
|
+
# the parameter row and so the values have to be ordered by us.
|
72
|
+
ordered_row_values(row_removed)
|
73
|
+
else
|
74
|
+
raise(ArgumentError, "Can only remove row from a Hash or an Array but received #{row_removed.class}")
|
75
|
+
end
|
76
|
+
|
77
|
+
location = index_for_values(values.map(&:to_s).map(&:strip))
|
79
78
|
@rows.delete_at(location + 1) if location
|
80
79
|
end
|
81
80
|
|
@@ -91,7 +90,7 @@ module CukeModeler
|
|
91
90
|
|
92
91
|
# Returns the parameters of the example table
|
93
92
|
def parameters
|
94
|
-
parameter_row ? parameter_row.cells.
|
93
|
+
parameter_row ? parameter_row.cells.map(&:value) : []
|
95
94
|
end
|
96
95
|
|
97
96
|
# Returns the model objects that belong to this model.
|
@@ -99,30 +98,38 @@ module CukeModeler
|
|
99
98
|
rows + tags
|
100
99
|
end
|
101
100
|
|
101
|
+
# Building strings just isn't pretty
|
102
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
103
|
+
|
102
104
|
# Returns a string representation of this model. For an example model,
|
103
105
|
# this will be Gherkin text that is equivalent to the example being modeled.
|
104
106
|
def to_s
|
105
107
|
text = ''
|
106
108
|
|
107
|
-
text << tag_output_string
|
109
|
+
text << "#{tag_output_string}\n" unless tags.empty?
|
108
110
|
text << "#{@keyword}:#{name_output_string}"
|
109
|
-
text << "\n"
|
110
|
-
text << "\n" unless
|
111
|
-
text << "\n"
|
112
|
-
text << "\n"
|
111
|
+
text << "\n#{description_output_string}" unless no_description_to_output?
|
112
|
+
text << "\n" unless rows.empty? || no_description_to_output?
|
113
|
+
text << "\n#{parameters_output_string}" if parameter_row
|
114
|
+
text << "\n#{rows_output_string}" unless argument_rows.empty?
|
113
115
|
|
114
116
|
text
|
115
117
|
end
|
116
118
|
|
119
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
120
|
+
|
117
121
|
|
118
122
|
private
|
119
123
|
|
120
124
|
|
121
125
|
def parse_source(source_text)
|
122
|
-
base_file_string = "# language: #{Parsing.dialect}
|
126
|
+
base_file_string = "# language: #{Parsing.dialect}
|
127
|
+
#{dialect_feature_keyword}: Fake feature to parse
|
128
|
+
#{dialect_outline_keyword}:
|
129
|
+
#{dialect_step_keyword} fake step\n"
|
123
130
|
source_text = base_file_string + source_text
|
124
131
|
|
125
|
-
parsed_file = Parsing
|
132
|
+
parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_example.feature')
|
126
133
|
|
127
134
|
parsed_file['feature']['elements'].first['examples'].first
|
128
135
|
end
|
@@ -135,7 +142,7 @@ module CukeModeler
|
|
135
142
|
text = ''
|
136
143
|
|
137
144
|
unless parameter_row.nil?
|
138
|
-
text <<
|
145
|
+
text << ' |'
|
139
146
|
parameter_row.cells.count.times { |index| text << " #{string_for(parameter_row.cells, index)} |" }
|
140
147
|
end
|
141
148
|
|
@@ -148,7 +155,7 @@ module CukeModeler
|
|
148
155
|
unless argument_rows.empty?
|
149
156
|
|
150
157
|
argument_rows.each do |row|
|
151
|
-
text <<
|
158
|
+
text << ' |'
|
152
159
|
row.cells.count.times { |index| text << " #{string_for(row.cells, index)} |" }
|
153
160
|
text << "\n"
|
154
161
|
end
|
@@ -164,8 +171,18 @@ module CukeModeler
|
|
164
171
|
end
|
165
172
|
|
166
173
|
def ordered_row_values(row_hash)
|
167
|
-
parameter_row.cells.
|
174
|
+
parameter_row.cells.map(&:value).collect { |parameter| row_hash[parameter] }
|
175
|
+
end
|
176
|
+
|
177
|
+
def stringify_keys(hash)
|
178
|
+
hash.each_with_object({}) { |(key, value), new_hash| new_hash[key.to_s] = value }
|
179
|
+
end
|
180
|
+
|
181
|
+
def index_for_values(values)
|
182
|
+
argument_rows.index { |row| row.cells.map(&:value) == values }
|
168
183
|
end
|
169
184
|
|
170
185
|
end
|
171
186
|
end
|
187
|
+
|
188
|
+
# rubocop:enable Metrics/ClassLength
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module CukeModeler
|
2
2
|
|
3
3
|
# A class modeling a feature in a Cucumber suite.
|
4
|
-
|
5
4
|
class Feature < Model
|
6
5
|
|
7
6
|
include Parsed
|
@@ -33,17 +32,19 @@ module CukeModeler
|
|
33
32
|
|
34
33
|
super(source_text)
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
return unless source_text
|
36
|
+
|
37
|
+
parsed_feature_data = parse_source(source_text)
|
38
|
+
populate_feature(self, parsed_feature_data)
|
40
39
|
end
|
41
40
|
|
42
41
|
# Returns *true* if the feature contains a background, *false* otherwise.
|
43
|
-
def
|
42
|
+
def background?
|
44
43
|
!@background.nil?
|
45
44
|
end
|
46
45
|
|
46
|
+
alias has_background? background?
|
47
|
+
|
47
48
|
# Returns the scenario models contained in the feature.
|
48
49
|
def scenarios
|
49
50
|
@tests.select { |test| test.is_a? Scenario }
|
@@ -60,11 +61,11 @@ module CukeModeler
|
|
60
61
|
# single set of test values, such as an individual scenario or one example row
|
61
62
|
# of an outline.
|
62
63
|
def test_case_count
|
63
|
-
scenarios.count + outlines.reduce(0)
|
64
|
-
outline_sum
|
65
|
-
example_sum
|
66
|
-
|
67
|
-
|
64
|
+
scenarios.count + outlines.reduce(0) do |outline_sum, outline|
|
65
|
+
outline_sum + outline.examples.reduce(0) do |example_sum, example|
|
66
|
+
example_sum + example.argument_rows.count
|
67
|
+
end
|
68
|
+
end
|
68
69
|
end
|
69
70
|
|
70
71
|
# Returns the model objects that belong to this model.
|
@@ -75,27 +76,32 @@ module CukeModeler
|
|
75
76
|
models
|
76
77
|
end
|
77
78
|
|
79
|
+
# Building strings just isn't pretty
|
80
|
+
# rubocop:disable Metrics/AbcSize
|
81
|
+
|
78
82
|
# Returns a string representation of this model. For a feature model,
|
79
83
|
# this will be Gherkin text that is equivalent to the feature being modeled.
|
80
84
|
def to_s
|
81
85
|
text = ''
|
82
86
|
|
83
|
-
text << tag_output_string
|
87
|
+
text << "#{tag_output_string}\n" unless tags.empty?
|
84
88
|
text << "#{@keyword}:#{name_output_string}"
|
85
|
-
text << "\n"
|
86
|
-
text << "\n\n"
|
87
|
-
text << "\n\n"
|
88
|
-
text << "\n\n"
|
89
|
+
text << "\n#{description_output_string}" unless no_description_to_output?
|
90
|
+
text << "\n\n#{background_output_string}" if background
|
91
|
+
text << "\n\n#{tests_output_string}" unless tests.empty?
|
92
|
+
text << "\n\n#{rules_output_string}" unless rules.empty?
|
89
93
|
|
90
94
|
text
|
91
95
|
end
|
92
96
|
|
97
|
+
# rubocop:enable Metrics/AbcSize
|
98
|
+
|
93
99
|
|
94
100
|
private
|
95
101
|
|
96
102
|
|
97
103
|
def parse_source(source_text)
|
98
|
-
parsed_file = Parsing
|
104
|
+
parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_feature.feature')
|
99
105
|
|
100
106
|
parsed_file['feature']
|
101
107
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module CukeModeler
|
2
2
|
|
3
3
|
# A class modeling a feature file in a Cucumber suite.
|
4
|
-
|
5
4
|
class FeatureFile < Model
|
6
5
|
|
7
6
|
include Parsed
|
@@ -25,13 +24,11 @@ module CukeModeler
|
|
25
24
|
|
26
25
|
super(file_path)
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
processed_feature_file_data = process_feature_file(file_path)
|
32
|
-
populate_featurefile(self, processed_feature_file_data)
|
33
|
-
end
|
27
|
+
return unless file_path
|
28
|
+
raise(ArgumentError, "Unknown file: #{file_path.inspect}") unless File.exist?(file_path)
|
34
29
|
|
30
|
+
processed_feature_file_data = process_feature_file(file_path)
|
31
|
+
populate_featurefile(self, processed_feature_file_data)
|
35
32
|
end
|
36
33
|
|
37
34
|
# Returns the name of the modeled feature file.
|
@@ -57,7 +54,7 @@ module CukeModeler
|
|
57
54
|
def process_feature_file(file_path)
|
58
55
|
source_text = IO.read(file_path)
|
59
56
|
|
60
|
-
feature_file_data = Parsing
|
57
|
+
feature_file_data = Parsing.parse_text(source_text, file_path)
|
61
58
|
feature_file_data = feature_file_data.merge({ 'path' => file_path })
|
62
59
|
|
63
60
|
feature_file_data
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module CukeModeler
|
2
2
|
|
3
3
|
# A class modeling an element of a Cucumber suite.
|
4
|
-
|
5
4
|
class Model
|
6
5
|
|
7
6
|
include Nested
|
@@ -11,7 +10,8 @@ module CukeModeler
|
|
11
10
|
# Creates a new Model object and, if *source_text* is provided,
|
12
11
|
# populates the object.
|
13
12
|
def initialize(source_text = nil)
|
14
|
-
|
13
|
+
error_message = "Can only create models from Strings but was given a #{source_text.class}."
|
14
|
+
raise(ArgumentError, error_message) if source_text && !source_text.is_a?(String)
|
15
15
|
|
16
16
|
# This should be overridden by a child class
|
17
17
|
end
|
@@ -24,7 +24,6 @@ module CukeModeler
|
|
24
24
|
|
25
25
|
# Returns the model objects that belong to this model.
|
26
26
|
def children
|
27
|
-
# This should be overridden by a child class
|
28
27
|
[]
|
29
28
|
end
|
30
29
|
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module CukeModeler
|
2
2
|
|
3
3
|
# A class modeling an individual outline in a Cucumber suite.
|
4
|
-
|
5
4
|
class Outline < Model
|
6
5
|
|
7
6
|
include Parsing
|
@@ -29,17 +28,17 @@ module CukeModeler
|
|
29
28
|
|
30
29
|
super(source_text)
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
return unless source_text
|
32
|
+
|
33
|
+
parsed_outline_data = parse_source(source_text)
|
34
|
+
populate_outline(self, parsed_outline_data)
|
36
35
|
end
|
37
36
|
|
38
37
|
# Returns *true* if the two models have equivalent steps and *false* otherwise.
|
39
|
-
def ==(
|
40
|
-
return false unless
|
38
|
+
def ==(other)
|
39
|
+
return false unless other.respond_to?(:steps)
|
41
40
|
|
42
|
-
steps ==
|
41
|
+
steps == other.steps
|
43
42
|
end
|
44
43
|
|
45
44
|
# Returns the model objects that belong to this model.
|
@@ -47,21 +46,26 @@ module CukeModeler
|
|
47
46
|
examples + steps + tags
|
48
47
|
end
|
49
48
|
|
49
|
+
# Building strings just isn't pretty
|
50
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
51
|
+
|
50
52
|
# Returns a string representation of this model. For an outline model,
|
51
53
|
# this will be Gherkin text that is equivalent to the outline being modeled.
|
52
54
|
def to_s
|
53
55
|
text = ''
|
54
56
|
|
55
|
-
text << tag_output_string
|
57
|
+
text << "#{tag_output_string}\n" unless tags.empty?
|
56
58
|
text << "#{@keyword}:#{name_output_string}"
|
57
|
-
text << "\n"
|
58
|
-
text << "\n" unless
|
59
|
-
text << "\n"
|
60
|
-
text << "\n\n"
|
59
|
+
text << "\n#{description_output_string}" unless no_description_to_output?
|
60
|
+
text << "\n" unless steps.empty? || no_description_to_output?
|
61
|
+
text << "\n#{steps_output_string}" unless steps.empty?
|
62
|
+
text << "\n\n#{examples_output_string}" unless examples.empty?
|
61
63
|
|
62
64
|
text
|
63
65
|
end
|
64
66
|
|
67
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
68
|
+
|
65
69
|
|
66
70
|
private
|
67
71
|
|
@@ -70,13 +74,13 @@ module CukeModeler
|
|
70
74
|
base_file_string = "# language: #{Parsing.dialect}\n#{dialect_feature_keyword}: Fake feature to parse\n"
|
71
75
|
source_text = base_file_string + source_text
|
72
76
|
|
73
|
-
parsed_file = Parsing
|
77
|
+
parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_outline.feature')
|
74
78
|
|
75
79
|
parsed_file['feature']['elements'].first
|
76
80
|
end
|
77
81
|
|
78
82
|
def examples_output_string
|
79
|
-
examples.empty? ? '' : examples.
|
83
|
+
examples.empty? ? '' : examples.join("\n\n")
|
80
84
|
end
|
81
85
|
|
82
86
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module CukeModeler
|
2
2
|
|
3
3
|
# A class modeling a single row of a step table or example table.
|
4
|
-
|
5
4
|
class Row < Model
|
6
5
|
|
7
6
|
include Sourceable
|
@@ -19,16 +18,21 @@ module CukeModeler
|
|
19
18
|
|
20
19
|
super(source_text)
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
return unless source_text
|
22
|
+
|
23
|
+
parsed_row_data = parse_source(source_text)
|
24
|
+
populate_row(self, parsed_row_data)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the model objects that belong to this model.
|
28
|
+
def children
|
29
|
+
@cells
|
26
30
|
end
|
27
31
|
|
28
32
|
# Returns a string representation of this model. For a row model,
|
29
33
|
# this will be Gherkin text that is equivalent to the row being modeled.
|
30
34
|
def to_s
|
31
|
-
text_cells = cells.
|
35
|
+
text_cells = cells.map(&:to_s)
|
32
36
|
|
33
37
|
"| #{text_cells.join(' | ')} |"
|
34
38
|
end
|
@@ -38,10 +42,13 @@ module CukeModeler
|
|
38
42
|
|
39
43
|
|
40
44
|
def parse_source(source_text)
|
41
|
-
base_file_string = "# language: #{Parsing.dialect}
|
45
|
+
base_file_string = "# language: #{Parsing.dialect}
|
46
|
+
#{dialect_feature_keyword}: Fake feature to parse
|
47
|
+
#{dialect_scenario_keyword}:
|
48
|
+
#{dialect_step_keyword} fake step\n"
|
42
49
|
source_text = base_file_string + source_text
|
43
50
|
|
44
|
-
parsed_file = Parsing
|
51
|
+
parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_row.feature')
|
45
52
|
|
46
53
|
parsed_file['feature']['elements'].first['steps'].first['table']['rows'].first
|
47
54
|
end
|