cuke_modeler 3.3.0 → 3.4.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 +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
@@ -33,17 +33,19 @@ module CukeModeler
|
|
33
33
|
|
34
34
|
super(source_text)
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
return unless source_text
|
37
|
+
|
38
|
+
parsed_feature_data = parse_source(source_text)
|
39
|
+
populate_feature(self, parsed_feature_data)
|
40
40
|
end
|
41
41
|
|
42
42
|
# Returns *true* if the feature contains a background, *false* otherwise.
|
43
|
-
def
|
43
|
+
def background?
|
44
44
|
!@background.nil?
|
45
45
|
end
|
46
46
|
|
47
|
+
alias has_background? background?
|
48
|
+
|
47
49
|
# Returns the scenario models contained in the feature.
|
48
50
|
def scenarios
|
49
51
|
@tests.select { |test| test.is_a? Scenario }
|
@@ -60,11 +62,11 @@ module CukeModeler
|
|
60
62
|
# single set of test values, such as an individual scenario or one example row
|
61
63
|
# of an outline.
|
62
64
|
def test_case_count
|
63
|
-
scenarios.count + outlines.reduce(0)
|
64
|
-
outline_sum
|
65
|
-
example_sum
|
66
|
-
|
67
|
-
|
65
|
+
scenarios.count + outlines.reduce(0) do |outline_sum, outline|
|
66
|
+
outline_sum + outline.examples.reduce(0) do |example_sum, example|
|
67
|
+
example_sum + example.argument_rows.count
|
68
|
+
end
|
69
|
+
end
|
68
70
|
end
|
69
71
|
|
70
72
|
# Returns the model objects that belong to this model.
|
@@ -75,27 +77,32 @@ module CukeModeler
|
|
75
77
|
models
|
76
78
|
end
|
77
79
|
|
80
|
+
# Building strings just isn't pretty
|
81
|
+
# rubocop:disable Metrics/AbcSize
|
82
|
+
|
78
83
|
# Returns a string representation of this model. For a feature model,
|
79
84
|
# this will be Gherkin text that is equivalent to the feature being modeled.
|
80
85
|
def to_s
|
81
86
|
text = ''
|
82
87
|
|
83
|
-
text << tag_output_string
|
88
|
+
text << "#{tag_output_string}\n" unless tags.empty?
|
84
89
|
text << "#{@keyword}:#{name_output_string}"
|
85
|
-
text << "\n"
|
86
|
-
text << "\n\n"
|
87
|
-
text << "\n\n"
|
88
|
-
text << "\n\n"
|
90
|
+
text << "\n#{description_output_string}" unless no_description_to_output?
|
91
|
+
text << "\n\n#{background_output_string}" if background
|
92
|
+
text << "\n\n#{tests_output_string}" unless tests.empty?
|
93
|
+
text << "\n\n#{rules_output_string}" unless rules.empty?
|
89
94
|
|
90
95
|
text
|
91
96
|
end
|
92
97
|
|
98
|
+
# rubocop:enable Metrics/AbcSize
|
99
|
+
|
93
100
|
|
94
101
|
private
|
95
102
|
|
96
103
|
|
97
104
|
def parse_source(source_text)
|
98
|
-
parsed_file = Parsing
|
105
|
+
parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_feature.feature')
|
99
106
|
|
100
107
|
parsed_file['feature']
|
101
108
|
end
|
@@ -25,13 +25,11 @@ module CukeModeler
|
|
25
25
|
|
26
26
|
super(file_path)
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
processed_feature_file_data = process_feature_file(file_path)
|
32
|
-
populate_featurefile(self, processed_feature_file_data)
|
33
|
-
end
|
28
|
+
return unless file_path
|
29
|
+
raise(ArgumentError, "Unknown file: #{file_path.inspect}") unless File.exist?(file_path)
|
34
30
|
|
31
|
+
processed_feature_file_data = process_feature_file(file_path)
|
32
|
+
populate_featurefile(self, processed_feature_file_data)
|
35
33
|
end
|
36
34
|
|
37
35
|
# Returns the name of the modeled feature file.
|
@@ -57,7 +55,7 @@ module CukeModeler
|
|
57
55
|
def process_feature_file(file_path)
|
58
56
|
source_text = IO.read(file_path)
|
59
57
|
|
60
|
-
feature_file_data = Parsing
|
58
|
+
feature_file_data = Parsing.parse_text(source_text, file_path)
|
61
59
|
feature_file_data = feature_file_data.merge({ 'path' => file_path })
|
62
60
|
|
63
61
|
feature_file_data
|
@@ -11,7 +11,8 @@ module CukeModeler
|
|
11
11
|
# Creates a new Model object and, if *source_text* is provided,
|
12
12
|
# populates the object.
|
13
13
|
def initialize(source_text = nil)
|
14
|
-
|
14
|
+
error_message = "Can only create models from Strings but was given a #{source_text.class}."
|
15
|
+
raise(ArgumentError, error_message) if source_text && !source_text.is_a?(String)
|
15
16
|
|
16
17
|
# This should be overridden by a child class
|
17
18
|
end
|
@@ -29,17 +29,17 @@ module CukeModeler
|
|
29
29
|
|
30
30
|
super(source_text)
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
return unless source_text
|
33
|
+
|
34
|
+
parsed_outline_data = parse_source(source_text)
|
35
|
+
populate_outline(self, parsed_outline_data)
|
36
36
|
end
|
37
37
|
|
38
38
|
# Returns *true* if the two models have equivalent steps and *false* otherwise.
|
39
|
-
def ==(
|
40
|
-
return false unless
|
39
|
+
def ==(other)
|
40
|
+
return false unless other.respond_to?(:steps)
|
41
41
|
|
42
|
-
steps ==
|
42
|
+
steps == other.steps
|
43
43
|
end
|
44
44
|
|
45
45
|
# Returns the model objects that belong to this model.
|
@@ -47,21 +47,26 @@ module CukeModeler
|
|
47
47
|
examples + steps + tags
|
48
48
|
end
|
49
49
|
|
50
|
+
# Building strings just isn't pretty
|
51
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
52
|
+
|
50
53
|
# Returns a string representation of this model. For an outline model,
|
51
54
|
# this will be Gherkin text that is equivalent to the outline being modeled.
|
52
55
|
def to_s
|
53
56
|
text = ''
|
54
57
|
|
55
|
-
text << tag_output_string
|
58
|
+
text << "#{tag_output_string}\n" unless tags.empty?
|
56
59
|
text << "#{@keyword}:#{name_output_string}"
|
57
|
-
text << "\n"
|
58
|
-
text << "\n" unless
|
59
|
-
text << "\n"
|
60
|
-
text << "\n\n"
|
60
|
+
text << "\n#{description_output_string}" unless no_description_to_output?
|
61
|
+
text << "\n" unless steps.empty? || no_description_to_output?
|
62
|
+
text << "\n#{steps_output_string}" unless steps.empty?
|
63
|
+
text << "\n\n#{examples_output_string}" unless examples.empty?
|
61
64
|
|
62
65
|
text
|
63
66
|
end
|
64
67
|
|
68
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
69
|
+
|
65
70
|
|
66
71
|
private
|
67
72
|
|
@@ -70,13 +75,13 @@ module CukeModeler
|
|
70
75
|
base_file_string = "# language: #{Parsing.dialect}\n#{dialect_feature_keyword}: Fake feature to parse\n"
|
71
76
|
source_text = base_file_string + source_text
|
72
77
|
|
73
|
-
parsed_file = Parsing
|
78
|
+
parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_outline.feature')
|
74
79
|
|
75
80
|
parsed_file['feature']['elements'].first
|
76
81
|
end
|
77
82
|
|
78
83
|
def examples_output_string
|
79
|
-
examples.empty? ? '' : examples.
|
84
|
+
examples.empty? ? '' : examples.join("\n\n")
|
80
85
|
end
|
81
86
|
|
82
87
|
end
|
@@ -19,16 +19,16 @@ module CukeModeler
|
|
19
19
|
|
20
20
|
super(source_text)
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
return unless source_text
|
23
|
+
|
24
|
+
parsed_row_data = parse_source(source_text)
|
25
|
+
populate_row(self, parsed_row_data)
|
26
26
|
end
|
27
27
|
|
28
28
|
# Returns a string representation of this model. For a row model,
|
29
29
|
# this will be Gherkin text that is equivalent to the row being modeled.
|
30
30
|
def to_s
|
31
|
-
text_cells = cells.
|
31
|
+
text_cells = cells.map(&:to_s)
|
32
32
|
|
33
33
|
"| #{text_cells.join(' | ')} |"
|
34
34
|
end
|
@@ -38,10 +38,13 @@ module CukeModeler
|
|
38
38
|
|
39
39
|
|
40
40
|
def parse_source(source_text)
|
41
|
-
base_file_string = "# language: #{Parsing.dialect}
|
41
|
+
base_file_string = "# language: #{Parsing.dialect}
|
42
|
+
#{dialect_feature_keyword}: Fake feature to parse
|
43
|
+
#{dialect_scenario_keyword}:
|
44
|
+
#{dialect_step_keyword} fake step\n"
|
42
45
|
source_text = base_file_string + source_text
|
43
46
|
|
44
|
-
parsed_file = Parsing
|
47
|
+
parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_row.feature')
|
45
48
|
|
46
49
|
parsed_file['feature']['elements'].first['steps'].first['table']['rows'].first
|
47
50
|
end
|
@@ -28,17 +28,19 @@ module CukeModeler
|
|
28
28
|
|
29
29
|
super(source_text)
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
return unless source_text
|
32
|
+
|
33
|
+
parsed_rule_data = parse_source(source_text)
|
34
|
+
populate_rule(self, parsed_rule_data)
|
35
35
|
end
|
36
36
|
|
37
37
|
# Returns *true* if the rule contains a background, *false* otherwise.
|
38
|
-
def
|
38
|
+
def background?
|
39
39
|
!@background.nil?
|
40
40
|
end
|
41
41
|
|
42
|
+
alias has_background? background?
|
43
|
+
|
42
44
|
# Returns the scenario models contained in the rule.
|
43
45
|
def scenarios
|
44
46
|
@tests.select { |test| test.is_a? Scenario }
|
@@ -63,9 +65,9 @@ module CukeModeler
|
|
63
65
|
text = ''
|
64
66
|
|
65
67
|
text << "#{@keyword}:#{name_output_string}"
|
66
|
-
text << "\n"
|
67
|
-
text << "\n\n"
|
68
|
-
text << "\n\n"
|
68
|
+
text << "\n#{description_output_string}" unless no_description_to_output?
|
69
|
+
text << "\n\n#{background_output_string}" if background
|
70
|
+
text << "\n\n#{tests_output_string}" unless tests.empty?
|
69
71
|
|
70
72
|
text
|
71
73
|
end
|
@@ -78,7 +80,7 @@ module CukeModeler
|
|
78
80
|
base_file_string = "# language: #{Parsing.dialect}\n#{dialect_feature_keyword}: Fake feature to parse\n"
|
79
81
|
source_text = base_file_string + source_text
|
80
82
|
|
81
|
-
parsed_file = Parsing
|
83
|
+
parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_rule.feature')
|
82
84
|
|
83
85
|
parsed_file['feature']['elements'].first
|
84
86
|
end
|
@@ -25,17 +25,17 @@ module CukeModeler
|
|
25
25
|
|
26
26
|
super(source_text)
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
return unless source_text
|
29
|
+
|
30
|
+
parsed_scenario_data = parse_source(source_text)
|
31
|
+
populate_scenario(self, parsed_scenario_data)
|
32
32
|
end
|
33
33
|
|
34
34
|
# Returns *true* if the two models have equivalent steps and *false* otherwise.
|
35
|
-
def ==(
|
36
|
-
return false unless
|
35
|
+
def ==(other)
|
36
|
+
return false unless other.respond_to?(:steps)
|
37
37
|
|
38
|
-
steps ==
|
38
|
+
steps == other.steps
|
39
39
|
end
|
40
40
|
|
41
41
|
# Returns the model objects that belong to this model.
|
@@ -43,20 +43,25 @@ module CukeModeler
|
|
43
43
|
steps + tags
|
44
44
|
end
|
45
45
|
|
46
|
+
# Building strings just isn't pretty
|
47
|
+
# rubocop:disable Metrics/AbcSize
|
48
|
+
|
46
49
|
# Returns a string representation of this model. For a scenario model,
|
47
50
|
# this will be Gherkin text that is equivalent to the scenario being modeled.
|
48
51
|
def to_s
|
49
52
|
text = ''
|
50
53
|
|
51
|
-
text << tag_output_string
|
54
|
+
text << "#{tag_output_string}\n" unless tags.empty?
|
52
55
|
text << "#{@keyword}:#{name_output_string}"
|
53
|
-
text << "\n"
|
54
|
-
text << "\n" unless
|
55
|
-
text << "\n"
|
56
|
+
text << "\n#{description_output_string}" unless no_description_to_output?
|
57
|
+
text << "\n" unless steps.empty? || no_description_to_output?
|
58
|
+
text << "\n#{steps_output_string}" unless steps.empty?
|
56
59
|
|
57
60
|
text
|
58
61
|
end
|
59
62
|
|
63
|
+
# rubocop:enable Metrics/AbcSize
|
64
|
+
|
60
65
|
|
61
66
|
private
|
62
67
|
|
@@ -65,7 +70,7 @@ module CukeModeler
|
|
65
70
|
base_file_string = "# language: #{Parsing.dialect}\n#{dialect_feature_keyword}: Fake feature to parse\n"
|
66
71
|
source_text = base_file_string + source_text
|
67
72
|
|
68
|
-
parsed_file = Parsing
|
73
|
+
parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_scenario.feature')
|
69
74
|
|
70
75
|
parsed_file['feature']['elements'].first
|
71
76
|
end
|
@@ -24,20 +24,20 @@ module CukeModeler
|
|
24
24
|
def initialize(source_text = nil)
|
25
25
|
super(source_text)
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
return unless source_text
|
28
|
+
|
29
|
+
parsed_step_data = parse_source(source_text)
|
30
|
+
populate_step(self, parsed_step_data)
|
31
31
|
end
|
32
32
|
|
33
33
|
# Returns *true* if the two steps have the same base text (i.e. minus any keyword,
|
34
34
|
# table, or doc string and *false* otherwise.
|
35
|
-
def ==(
|
36
|
-
return false unless
|
35
|
+
def ==(other)
|
36
|
+
return false unless other.is_a?(CukeModeler::Step)
|
37
37
|
|
38
|
-
text_matches?(
|
39
|
-
|
40
|
-
|
38
|
+
text_matches?(other) &&
|
39
|
+
table_matches?(other) &&
|
40
|
+
doc_string_matches?(other)
|
41
41
|
end
|
42
42
|
|
43
43
|
# Returns the model objects that belong to this model.
|
@@ -49,7 +49,7 @@ module CukeModeler
|
|
49
49
|
# this will be Gherkin text that is equivalent to the step being modeled.
|
50
50
|
def to_s
|
51
51
|
text = "#{keyword} #{self.text}"
|
52
|
-
text << "\n
|
52
|
+
text << "\n#{block.to_s.split("\n").collect { |line| " #{line}" }.join("\n")}" if block
|
53
53
|
|
54
54
|
text
|
55
55
|
end
|
@@ -59,10 +59,12 @@ module CukeModeler
|
|
59
59
|
|
60
60
|
|
61
61
|
def parse_source(source_text)
|
62
|
-
base_file_string = "# language: #{Parsing.dialect}
|
62
|
+
base_file_string = "# language: #{Parsing.dialect}
|
63
|
+
#{dialect_feature_keyword}: Fake feature to parse
|
64
|
+
#{dialect_scenario_keyword}:\n"
|
63
65
|
source_text = base_file_string + source_text
|
64
66
|
|
65
|
-
parsed_file = Parsing
|
67
|
+
parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_step.feature')
|
66
68
|
|
67
69
|
parsed_file['feature']['elements'].first['steps'].first
|
68
70
|
end
|
@@ -72,18 +74,18 @@ module CukeModeler
|
|
72
74
|
end
|
73
75
|
|
74
76
|
def table_matches?(other_step)
|
75
|
-
return false if
|
76
|
-
return true
|
77
|
+
return false if only_one_step_has_table?(other_step)
|
78
|
+
return true if neither_step_has_table?(other_step)
|
77
79
|
|
78
|
-
first_step_values
|
80
|
+
first_step_values = block.rows.collect { |table_row| table_row.cells.map(&:value) }
|
79
81
|
second_step_values = other_step.block.rows.collect { |table_row| table_row.cells.map(&:value) }
|
80
82
|
|
81
83
|
first_step_values == second_step_values
|
82
84
|
end
|
83
85
|
|
84
86
|
def doc_string_matches?(other_step)
|
85
|
-
return false if
|
86
|
-
return true
|
87
|
+
return false if only_one_step_has_doc_string?(other_step)
|
88
|
+
return true if neither_step_has_doc_string?(other_step)
|
87
89
|
|
88
90
|
first_content = block.content
|
89
91
|
first_content_type = block.content_type
|
@@ -91,7 +93,27 @@ module CukeModeler
|
|
91
93
|
second_content_type = other_step.block.content_type
|
92
94
|
|
93
95
|
(first_content == second_content) &&
|
94
|
-
|
96
|
+
(first_content_type == second_content_type)
|
97
|
+
end
|
98
|
+
|
99
|
+
def only_one_step_has_table?(other_step)
|
100
|
+
(!block.is_a?(CukeModeler::Table) || !other_step.block.is_a?(CukeModeler::Table)) &&
|
101
|
+
(block.is_a?(CukeModeler::Table) || other_step.block.is_a?(CukeModeler::Table))
|
102
|
+
end
|
103
|
+
|
104
|
+
def neither_step_has_table?(other_step)
|
105
|
+
!block.is_a?(CukeModeler::Table) &&
|
106
|
+
!other_step.block.is_a?(CukeModeler::Table)
|
107
|
+
end
|
108
|
+
|
109
|
+
def only_one_step_has_doc_string?(other_step)
|
110
|
+
(!block.is_a?(CukeModeler::DocString) || !other_step.block.is_a?(CukeModeler::DocString)) &&
|
111
|
+
(block.is_a?(CukeModeler::DocString) || other_step.block.is_a?(CukeModeler::DocString))
|
112
|
+
end
|
113
|
+
|
114
|
+
def neither_step_has_doc_string?(other_step)
|
115
|
+
!block.is_a?(CukeModeler::DocString) &&
|
116
|
+
!other_step.block.is_a?(CukeModeler::DocString)
|
95
117
|
end
|
96
118
|
|
97
119
|
end
|
@@ -20,10 +20,10 @@ module CukeModeler
|
|
20
20
|
|
21
21
|
super(source_text)
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
return unless source_text
|
24
|
+
|
25
|
+
parsed_table_data = parse_source(source_text)
|
26
|
+
populate_table(self, parsed_table_data)
|
27
27
|
end
|
28
28
|
|
29
29
|
# Returns the model objects that belong to this model.
|
@@ -42,10 +42,13 @@ module CukeModeler
|
|
42
42
|
|
43
43
|
|
44
44
|
def parse_source(source_text)
|
45
|
-
base_file_string = "# language: #{Parsing.dialect}
|
45
|
+
base_file_string = "# language: #{Parsing.dialect}
|
46
|
+
#{dialect_feature_keyword}:
|
47
|
+
#{dialect_scenario_keyword}:
|
48
|
+
#{dialect_step_keyword} step\n"
|
46
49
|
source_text = base_file_string + source_text
|
47
50
|
|
48
|
-
parsed_file = Parsing
|
51
|
+
parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_table.feature')
|
49
52
|
|
50
53
|
parsed_file['feature']['elements'].first['steps'].first['table']
|
51
54
|
end
|