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
@@ -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
|