cuke_modeler 2.0.0 → 3.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/CHANGELOG.md +59 -2
- data/README.md +14 -16
- data/cuke_modeler.gemspec +12 -9
- data/lib/cuke_modeler.rb +1 -0
- data/lib/cuke_modeler/adapters/gherkin_10_adapter.rb +12 -0
- data/lib/cuke_modeler/adapters/gherkin_11_adapter.rb +12 -0
- data/lib/cuke_modeler/adapters/gherkin_12_adapter.rb +12 -0
- data/lib/cuke_modeler/adapters/gherkin_13_adapter.rb +12 -0
- data/lib/cuke_modeler/adapters/gherkin_14_adapter.rb +12 -0
- data/lib/cuke_modeler/adapters/gherkin_15_adapter.rb +12 -0
- data/lib/cuke_modeler/adapters/{gherkin_6_adapter.rb → gherkin_9_adapter.rb} +104 -69
- data/lib/cuke_modeler/containing.rb +15 -5
- data/lib/cuke_modeler/models/background.rb +1 -1
- data/lib/cuke_modeler/models/cell.rb +1 -1
- data/lib/cuke_modeler/models/comment.rb +1 -1
- data/lib/cuke_modeler/models/directory.rb +2 -2
- data/lib/cuke_modeler/models/doc_string.rb +1 -1
- data/lib/cuke_modeler/models/example.rb +1 -1
- data/lib/cuke_modeler/models/feature.rb +16 -5
- data/lib/cuke_modeler/models/feature_file.rb +2 -2
- data/lib/cuke_modeler/models/outline.rb +1 -1
- data/lib/cuke_modeler/models/row.rb +1 -1
- data/lib/cuke_modeler/models/rule.rb +99 -0
- data/lib/cuke_modeler/models/scenario.rb +1 -1
- data/lib/cuke_modeler/models/step.rb +1 -1
- data/lib/cuke_modeler/models/table.rb +1 -1
- data/lib/cuke_modeler/models/tag.rb +1 -1
- data/lib/cuke_modeler/parsing.rb +89 -110
- data/lib/cuke_modeler/version.rb +1 -1
- data/testing/cucumber/features/modeling/feature_modeling.feature +28 -7
- data/testing/cucumber/features/modeling/feature_output.feature +45 -23
- data/testing/cucumber/features/modeling/rule_modeling.feature +108 -0
- data/testing/cucumber/features/modeling/rule_output.feature +111 -0
- metadata +39 -140
- data/.gitignore +0 -18
- data/.simplecov +0 -7
- data/.travis.yml +0 -63
- data/Gemfile +0 -37
- data/Rakefile +0 -73
- data/appveyor.yml +0 -61
- data/lib/cuke_modeler/adapters/gherkin_2_adapter.rb +0 -274
- data/lib/cuke_modeler/adapters/gherkin_3_adapter.rb +0 -297
- data/lib/cuke_modeler/adapters/gherkin_4_adapter.rb +0 -309
- data/testing/cucumber/step_definitions/action_steps.rb +0 -13
- data/testing/cucumber/step_definitions/background_steps.rb +0 -1
- data/testing/cucumber/step_definitions/directory_steps.rb +0 -6
- data/testing/cucumber/step_definitions/doc_string_steps.rb +0 -1
- data/testing/cucumber/step_definitions/feature_file_steps.rb +0 -16
- data/testing/cucumber/step_definitions/feature_steps.rb +0 -7
- data/testing/cucumber/step_definitions/modeling_steps.rb +0 -49
- data/testing/cucumber/step_definitions/setup_steps.rb +0 -32
- data/testing/cucumber/step_definitions/step_steps.rb +0 -3
- data/testing/cucumber/step_definitions/table_steps.rb +0 -1
- data/testing/cucumber/step_definitions/tag_steps.rb +0 -3
- data/testing/cucumber/step_definitions/verification_steps.rb +0 -181
- data/testing/cucumber/support/env.rb +0 -30
- data/testing/dialect_helper.rb +0 -48
- data/testing/file_helper.rb +0 -47
- data/testing/gemfiles/gherkin2.gemfile +0 -33
- data/testing/gemfiles/gherkin3.gemfile +0 -26
- data/testing/gemfiles/gherkin4.gemfile +0 -27
- data/testing/gemfiles/gherkin5.gemfile +0 -27
- data/testing/gemfiles/gherkin6.gemfile +0 -10
- data/testing/rspec/spec/integration/adapters/gherkin_2_adapter_spec.rb +0 -166
- data/testing/rspec/spec/integration/adapters/gherkin_3_adapter_spec.rb +0 -166
- data/testing/rspec/spec/integration/adapters/gherkin_4_adapter_spec.rb +0 -165
- data/testing/rspec/spec/integration/adapters/gherkin_6_adapter_spec.rb +0 -166
- data/testing/rspec/spec/integration/models/background_integration_spec.rb +0 -442
- data/testing/rspec/spec/integration/models/cell_integration_spec.rb +0 -335
- data/testing/rspec/spec/integration/models/comment_integration_spec.rb +0 -177
- data/testing/rspec/spec/integration/models/directory_integration_spec.rb +0 -218
- data/testing/rspec/spec/integration/models/doc_string_integration_spec.rb +0 -402
- data/testing/rspec/spec/integration/models/example_integration_spec.rb +0 -741
- data/testing/rspec/spec/integration/models/feature_file_integration_spec.rb +0 -272
- data/testing/rspec/spec/integration/models/feature_integration_spec.rb +0 -650
- data/testing/rspec/spec/integration/models/model_integration_spec.rb +0 -15
- data/testing/rspec/spec/integration/models/outline_integration_spec.rb +0 -624
- data/testing/rspec/spec/integration/models/row_integration_spec.rb +0 -291
- data/testing/rspec/spec/integration/models/scenario_integration_spec.rb +0 -479
- data/testing/rspec/spec/integration/models/step_integration_spec.rb +0 -569
- data/testing/rspec/spec/integration/models/table_integration_spec.rb +0 -337
- data/testing/rspec/spec/integration/models/tag_integration_spec.rb +0 -259
- data/testing/rspec/spec/integration/nested_integration_spec.rb +0 -91
- data/testing/rspec/spec/integration/parsing_integration_spec.rb +0 -122
- data/testing/rspec/spec/integration/shared/models_integration_specs.rb +0 -18
- data/testing/rspec/spec/spec_helper.rb +0 -136
- data/testing/rspec/spec/unit/cuke_modeler_unit_spec.rb +0 -25
- data/testing/rspec/spec/unit/described_unit_spec.rb +0 -23
- data/testing/rspec/spec/unit/models/background_unit_spec.rb +0 -83
- data/testing/rspec/spec/unit/models/cell_unit_spec.rb +0 -68
- data/testing/rspec/spec/unit/models/comment_unit_spec.rb +0 -68
- data/testing/rspec/spec/unit/models/directory_unit_spec.rb +0 -127
- data/testing/rspec/spec/unit/models/doc_string_unit_spec.rb +0 -100
- data/testing/rspec/spec/unit/models/example_unit_spec.rb +0 -133
- data/testing/rspec/spec/unit/models/feature_file_unit_spec.rb +0 -125
- data/testing/rspec/spec/unit/models/feature_unit_spec.rb +0 -157
- data/testing/rspec/spec/unit/models/model_unit_spec.rb +0 -15
- data/testing/rspec/spec/unit/models/outline_unit_spec.rb +0 -117
- data/testing/rspec/spec/unit/models/row_unit_spec.rb +0 -68
- data/testing/rspec/spec/unit/models/scenario_unit_spec.rb +0 -86
- data/testing/rspec/spec/unit/models/step_unit_spec.rb +0 -109
- data/testing/rspec/spec/unit/models/table_unit_spec.rb +0 -77
- data/testing/rspec/spec/unit/models/tag_unit_spec.rb +0 -68
- data/testing/rspec/spec/unit/named_unit_spec.rb +0 -23
- data/testing/rspec/spec/unit/nested_unit_spec.rb +0 -43
- data/testing/rspec/spec/unit/parsed_unit_spec.rb +0 -27
- data/testing/rspec/spec/unit/parsing_unit_spec.rb +0 -54
- data/testing/rspec/spec/unit/shared/bare_bones_models_unit_specs.rb +0 -14
- data/testing/rspec/spec/unit/shared/containing_models_unit_specs.rb +0 -127
- data/testing/rspec/spec/unit/shared/described_models_unit_specs.rb +0 -38
- data/testing/rspec/spec/unit/shared/keyworded_models_unit_specs.rb +0 -58
- data/testing/rspec/spec/unit/shared/models_unit_specs.rb +0 -15
- data/testing/rspec/spec/unit/shared/named_models_unit_specs.rb +0 -39
- data/testing/rspec/spec/unit/shared/nested_models_unit_specs.rb +0 -51
- data/testing/rspec/spec/unit/shared/parsed_models_unit_specs.rb +0 -39
- data/testing/rspec/spec/unit/shared/prepopulated_models_unit_specs.rb +0 -18
- data/testing/rspec/spec/unit/shared/sourced_models_unit_specs.rb +0 -39
- data/testing/rspec/spec/unit/shared/stepped_models_unit_specs.rb +0 -46
- data/testing/rspec/spec/unit/shared/stringifiable_models_unit_specs.rb +0 -18
- data/testing/rspec/spec/unit/shared/tagged_models_unit_specs.rb +0 -72
- data/testing/rspec/spec/unit/sourceable_unit_spec.rb +0 -27
- data/testing/rspec/spec/unit/stepped_unit_spec.rb +0 -23
- data/testing/rspec/spec/unit/taggable_unit_spec.rb +0 -69
- data/testing/test_languages.json +0 -45
- data/todo.txt +0 -25
|
@@ -32,7 +32,6 @@ module CukeModeler
|
|
|
32
32
|
|
|
33
33
|
model.parent_model = self
|
|
34
34
|
|
|
35
|
-
|
|
36
35
|
model
|
|
37
36
|
end
|
|
38
37
|
|
|
@@ -130,6 +129,15 @@ module CukeModeler
|
|
|
130
129
|
populate_children(feature_object, parsed_feature_data)
|
|
131
130
|
end
|
|
132
131
|
|
|
132
|
+
def populate_rule(rule_object, parsed_rule_data)
|
|
133
|
+
populate_parsing_data(rule_object, parsed_rule_data)
|
|
134
|
+
populate_source_line(rule_object, parsed_rule_data)
|
|
135
|
+
populate_keyword(rule_object, parsed_rule_data)
|
|
136
|
+
populate_name(rule_object, parsed_rule_data)
|
|
137
|
+
populate_description(rule_object, parsed_rule_data)
|
|
138
|
+
populate_children(rule_object, parsed_rule_data)
|
|
139
|
+
end
|
|
140
|
+
|
|
133
141
|
def populate_directory(directory_object, processed_directory_data)
|
|
134
142
|
directory_object.path = processed_directory_data['path']
|
|
135
143
|
|
|
@@ -213,18 +221,20 @@ module CukeModeler
|
|
|
213
221
|
end
|
|
214
222
|
end
|
|
215
223
|
|
|
216
|
-
def populate_children(
|
|
224
|
+
def populate_children(model, parsed_feature_data)
|
|
217
225
|
elements = parsed_feature_data['elements']
|
|
218
226
|
|
|
219
227
|
if elements
|
|
220
228
|
elements.each do |element|
|
|
221
229
|
case element['type']
|
|
222
230
|
when 'Scenario', 'scenario'
|
|
223
|
-
|
|
231
|
+
model.tests << build_child_model(Scenario, element)
|
|
224
232
|
when 'ScenarioOutline', 'scenario_outline'
|
|
225
|
-
|
|
233
|
+
model.tests << build_child_model(Outline, element)
|
|
226
234
|
when 'Background', 'background'
|
|
227
|
-
|
|
235
|
+
model.background = build_child_model(Background, element)
|
|
236
|
+
when 'Rule'
|
|
237
|
+
model.rules << build_child_model(Rule, element)
|
|
228
238
|
else
|
|
229
239
|
raise(ArgumentError, "Unknown element type: #{element['type']}")
|
|
230
240
|
end
|
|
@@ -41,7 +41,7 @@ module CukeModeler
|
|
|
41
41
|
|
|
42
42
|
parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_cell.feature')
|
|
43
43
|
|
|
44
|
-
parsed_file
|
|
44
|
+
parsed_file['feature']['elements'].first['steps'].first['table']['rows'].first['cells'].first
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
end
|
|
@@ -82,8 +82,8 @@ module CukeModeler
|
|
|
82
82
|
def process_feature_file(file_path)
|
|
83
83
|
source_text = IO.read(file_path)
|
|
84
84
|
|
|
85
|
-
feature_file_data = Parsing::parse_text(source_text, file_path)
|
|
86
|
-
feature_file_data = feature_file_data.merge({'path' => file_path})
|
|
85
|
+
feature_file_data = Parsing::parse_text(source_text, file_path)
|
|
86
|
+
feature_file_data = feature_file_data.merge({ 'path' => file_path })
|
|
87
87
|
|
|
88
88
|
feature_file_data
|
|
89
89
|
end
|
|
@@ -45,7 +45,7 @@ module CukeModeler
|
|
|
45
45
|
|
|
46
46
|
parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_doc_string.feature')
|
|
47
47
|
|
|
48
|
-
parsed_file
|
|
48
|
+
parsed_file['feature']['elements'].first['steps'].first['doc_string']
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def content_type_output_string
|
|
@@ -124,7 +124,7 @@ module CukeModeler
|
|
|
124
124
|
|
|
125
125
|
parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_example.feature')
|
|
126
126
|
|
|
127
|
-
parsed_file
|
|
127
|
+
parsed_file['feature']['elements'].first['examples'].first
|
|
128
128
|
end
|
|
129
129
|
|
|
130
130
|
def determine_buffer_size(index)
|
|
@@ -17,6 +17,9 @@ module CukeModeler
|
|
|
17
17
|
# The Background object contained by the Feature
|
|
18
18
|
attr_accessor :background
|
|
19
19
|
|
|
20
|
+
# The Rule objects contained by the Feature
|
|
21
|
+
attr_accessor :rules
|
|
22
|
+
|
|
20
23
|
# The Scenario and Outline objects contained by the Feature
|
|
21
24
|
attr_accessor :tests
|
|
22
25
|
|
|
@@ -25,6 +28,7 @@ module CukeModeler
|
|
|
25
28
|
# object.
|
|
26
29
|
def initialize(source_text = nil)
|
|
27
30
|
@tags = []
|
|
31
|
+
@rules = []
|
|
28
32
|
@tests = []
|
|
29
33
|
|
|
30
34
|
super(source_text)
|
|
@@ -50,6 +54,8 @@ module CukeModeler
|
|
|
50
54
|
@tests.select { |test| test.is_a? Outline }
|
|
51
55
|
end
|
|
52
56
|
|
|
57
|
+
# TODO: Remove this method on next major version release
|
|
58
|
+
# DEPRECATED
|
|
53
59
|
# Returns the number of test cases contained in the feature. A test case is a
|
|
54
60
|
# single set of test values, such as an individual scenario or one example row
|
|
55
61
|
# of an outline.
|
|
@@ -63,7 +69,7 @@ module CukeModeler
|
|
|
63
69
|
|
|
64
70
|
# Returns the model objects that belong to this model.
|
|
65
71
|
def children
|
|
66
|
-
models = tests + tags
|
|
72
|
+
models = rules + tests + tags
|
|
67
73
|
models << background if background
|
|
68
74
|
|
|
69
75
|
models
|
|
@@ -79,6 +85,7 @@ module CukeModeler
|
|
|
79
85
|
text << "\n" + description_output_string unless (description.nil? || description.empty?)
|
|
80
86
|
text << "\n\n" + background_output_string if background
|
|
81
87
|
text << "\n\n" + tests_output_string unless tests.empty?
|
|
88
|
+
text << "\n\n" + rules_output_string unless rules.empty?
|
|
82
89
|
|
|
83
90
|
text
|
|
84
91
|
end
|
|
@@ -90,18 +97,22 @@ module CukeModeler
|
|
|
90
97
|
def parse_source(source_text)
|
|
91
98
|
parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_feature.feature')
|
|
92
99
|
|
|
93
|
-
parsed_file
|
|
100
|
+
parsed_file['feature']
|
|
94
101
|
end
|
|
95
102
|
|
|
96
103
|
def background_output_string
|
|
97
|
-
|
|
104
|
+
child_element_output_string(background)
|
|
98
105
|
end
|
|
99
106
|
|
|
100
107
|
def tests_output_string
|
|
101
|
-
tests.collect { |test|
|
|
108
|
+
tests.collect { |test| child_element_output_string(test) }.join("\n\n")
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def rules_output_string
|
|
112
|
+
rules.collect { |rule| child_element_output_string(rule) }.join("\n\n")
|
|
102
113
|
end
|
|
103
114
|
|
|
104
|
-
def
|
|
115
|
+
def child_element_output_string(model)
|
|
105
116
|
model.to_s.split("\n").collect { |line| line.empty? ? '' : " #{line}" }.join("\n")
|
|
106
117
|
end
|
|
107
118
|
|
|
@@ -57,8 +57,8 @@ module CukeModeler
|
|
|
57
57
|
def process_feature_file(file_path)
|
|
58
58
|
source_text = IO.read(file_path)
|
|
59
59
|
|
|
60
|
-
feature_file_data = Parsing::parse_text(source_text, file_path)
|
|
61
|
-
feature_file_data = feature_file_data.merge({'path' => file_path})
|
|
60
|
+
feature_file_data = Parsing::parse_text(source_text, file_path)
|
|
61
|
+
feature_file_data = feature_file_data.merge({ 'path' => file_path })
|
|
62
62
|
|
|
63
63
|
feature_file_data
|
|
64
64
|
end
|
|
@@ -43,7 +43,7 @@ module CukeModeler
|
|
|
43
43
|
|
|
44
44
|
parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_row.feature')
|
|
45
45
|
|
|
46
|
-
parsed_file
|
|
46
|
+
parsed_file['feature']['elements'].first['steps'].first['table']['rows'].first
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module CukeModeler
|
|
2
|
+
|
|
3
|
+
# A class modeling a rule in a Cucumber suite.
|
|
4
|
+
|
|
5
|
+
class Rule < Model
|
|
6
|
+
|
|
7
|
+
include Parsing
|
|
8
|
+
include Parsed
|
|
9
|
+
include Named
|
|
10
|
+
include Described
|
|
11
|
+
include Sourceable
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# The keyword for the rule
|
|
15
|
+
attr_accessor :keyword
|
|
16
|
+
|
|
17
|
+
# The Background object contained by the Rule
|
|
18
|
+
attr_accessor :background
|
|
19
|
+
|
|
20
|
+
# The Scenario and Outline objects contained by the Rule
|
|
21
|
+
attr_accessor :tests
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Creates a new Rule object and, if *source_text* is provided, populates the
|
|
25
|
+
# object.
|
|
26
|
+
def initialize(source_text = nil)
|
|
27
|
+
@tests = []
|
|
28
|
+
|
|
29
|
+
super(source_text)
|
|
30
|
+
|
|
31
|
+
if source_text
|
|
32
|
+
parsed_rule_data = parse_source(source_text)
|
|
33
|
+
populate_rule(self, parsed_rule_data)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Returns *true* if the rule contains a background, *false* otherwise.
|
|
38
|
+
def has_background?
|
|
39
|
+
!@background.nil?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Returns the scenario models contained in the rule.
|
|
43
|
+
def scenarios
|
|
44
|
+
@tests.select { |test| test.is_a? Scenario }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Returns the outline models contained in the rule.
|
|
48
|
+
def outlines
|
|
49
|
+
@tests.select { |test| test.is_a? Outline }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Returns the model objects that belong to this model.
|
|
53
|
+
def children
|
|
54
|
+
models = tests
|
|
55
|
+
models << background if background
|
|
56
|
+
|
|
57
|
+
models
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Returns a string representation of this model. For a rule model,
|
|
61
|
+
# this will be Gherkin text that is equivalent to the rule being modeled.
|
|
62
|
+
def to_s
|
|
63
|
+
text = ''
|
|
64
|
+
|
|
65
|
+
text << "#{@keyword}:#{name_output_string}"
|
|
66
|
+
text << "\n" + description_output_string unless (description.nil? || description.empty?)
|
|
67
|
+
text << "\n\n" + background_output_string if background
|
|
68
|
+
text << "\n\n" + tests_output_string unless tests.empty?
|
|
69
|
+
|
|
70
|
+
text
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def parse_source(source_text)
|
|
78
|
+
base_file_string = "# language: #{Parsing.dialect}\n#{dialect_feature_keyword}: Fake feature to parse\n"
|
|
79
|
+
source_text = base_file_string + source_text
|
|
80
|
+
|
|
81
|
+
parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_rule.feature')
|
|
82
|
+
|
|
83
|
+
parsed_file['feature']['elements'].first
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def background_output_string
|
|
87
|
+
test_output_string(background)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def tests_output_string
|
|
91
|
+
tests.collect { |test| test_output_string(test) }.join("\n\n")
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def test_output_string(model)
|
|
95
|
+
model.to_s.split("\n").collect { |line| line.empty? ? '' : " #{line}" }.join("\n")
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -64,7 +64,7 @@ module CukeModeler
|
|
|
64
64
|
|
|
65
65
|
parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_step.feature')
|
|
66
66
|
|
|
67
|
-
parsed_file
|
|
67
|
+
parsed_file['feature']['elements'].first['steps'].first
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
def text_matches?(other_step)
|
|
@@ -47,7 +47,7 @@ module CukeModeler
|
|
|
47
47
|
|
|
48
48
|
parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_table.feature')
|
|
49
49
|
|
|
50
|
-
parsed_file
|
|
50
|
+
parsed_file['feature']['elements'].first['steps'].first['table']
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def row_output_string(row)
|
data/lib/cuke_modeler/parsing.rb
CHANGED
|
@@ -1,115 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
begin
|
|
12
|
-
require 'gherkin'
|
|
13
|
-
rescue LoadError
|
|
14
|
-
begin
|
|
15
|
-
require 'gherkin/parser'
|
|
16
|
-
rescue LoadError
|
|
17
|
-
# Gherkin 6.x
|
|
18
|
-
require 'gherkin/gherkin'
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# The *gherkin* gem loads differently and has different grammar rules across major versions. Parsing
|
|
24
|
-
# will be done with an 'adapter' appropriate to the version of the *gherkin* gem that has been activated.
|
|
25
|
-
|
|
26
|
-
gherkin_version = Gem.loaded_specs['gherkin'].version.version
|
|
27
|
-
|
|
28
|
-
case gherkin_version
|
|
29
|
-
when /^6\./
|
|
30
|
-
require 'gherkin/gherkin'
|
|
31
|
-
require 'cuke_modeler/adapters/gherkin_6_adapter'
|
|
32
|
-
|
|
33
|
-
# NOT A PART OF THE PUBLIC API
|
|
34
|
-
# The method to use for parsing Gherkin text
|
|
35
|
-
def self.parsing_method(source_text, filename)
|
|
36
|
-
messages = Gherkin::Gherkin.from_source(filename, source_text, {:default_dialect => CukeModeler::Parsing.dialect}).to_a
|
|
37
|
-
|
|
38
|
-
messages.map(&:to_hash).find { |message| message[:gherkinDocument] }[:gherkinDocument]
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# NOT A PART OF THE PUBLIC API
|
|
42
|
-
# The adapter to use when converting an AST to a standard internal shape
|
|
43
|
-
def self.adapter_class
|
|
44
|
-
CukeModeler::Gherkin6Adapter
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
when /^[54]\./
|
|
48
|
-
require 'gherkin/parser'
|
|
49
|
-
require 'cuke_modeler/adapters/gherkin_4_adapter'
|
|
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. The entry points vary across versions,
|
|
3
|
+
# so try them all until one of them works.
|
|
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
|
|
50
11
|
|
|
51
12
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
# The method to use for parsing Gherkin text
|
|
55
|
-
# Filename isn't used by this version of Gherkin but keeping the parameter so that the calling method only has to know one method signature
|
|
56
|
-
def self.parsing_method(source_text, _filename)
|
|
57
|
-
Gherkin::Parser.new.parse(source_text)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# NOT A PART OF THE PUBLIC API
|
|
61
|
-
# The adapter to use when converting an AST to a standard internal shape
|
|
62
|
-
def self.adapter_class
|
|
63
|
-
CukeModeler::Gherkin4Adapter
|
|
64
|
-
end
|
|
13
|
+
# The *cucumber-gherkin* gem loads differently and has different grammar rules across major versions. Parsing
|
|
14
|
+
# will be done with an 'adapter' appropriate to the version of the *cucumber-gherkin* gem that has been activated.
|
|
65
15
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
require 'cuke_modeler/adapters/gherkin_3_adapter'
|
|
16
|
+
gherkin_version = Gem.loaded_specs['cucumber-gherkin'].version.version
|
|
17
|
+
gherkin_major_version = gherkin_version.match(/^(\d+)\./)[1].to_i
|
|
69
18
|
|
|
19
|
+
case gherkin_major_version
|
|
20
|
+
when 9, 10, 11, 12, 13, 14, 15
|
|
21
|
+
# Currently nothing else to load beyond the entry point to the gem
|
|
22
|
+
else
|
|
23
|
+
raise("Unknown Gherkin version: '#{gherkin_version}'")
|
|
24
|
+
end
|
|
70
25
|
|
|
71
|
-
|
|
72
|
-
# The method to use for parsing Gherkin text
|
|
73
|
-
# Filename isn't used by this version of Gherkin but keeping the parameter so that the calling method only has to know one method signature
|
|
74
|
-
def self.parsing_method(source_text, _filename)
|
|
75
|
-
Gherkin::Parser.new.parse(source_text)
|
|
76
|
-
end
|
|
26
|
+
require "cuke_modeler/adapters/gherkin_#{gherkin_major_version}_adapter"
|
|
77
27
|
|
|
78
|
-
# NOT A PART OF THE PUBLIC API
|
|
79
|
-
# The adapter to use when converting an AST to a standard internal shape
|
|
80
|
-
def self.adapter_class
|
|
81
|
-
CukeModeler::Gherkin3Adapter
|
|
82
|
-
end
|
|
83
|
-
when /^2\./
|
|
84
|
-
require 'stringio'
|
|
85
|
-
require 'gherkin/formatter/json_formatter'
|
|
86
|
-
require 'gherkin'
|
|
87
|
-
require 'json'
|
|
88
|
-
require 'multi_json'
|
|
89
|
-
require 'cuke_modeler/adapters/gherkin_2_adapter'
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
# NOT A PART OF THE PUBLIC API
|
|
93
|
-
# The method to use for parsing Gherkin text
|
|
94
|
-
def self.parsing_method(source_text, filename)
|
|
95
|
-
io = StringIO.new
|
|
96
|
-
formatter = Gherkin::Formatter::JSONFormatter.new(io)
|
|
97
|
-
parser = Gherkin::Parser::Parser.new(formatter)
|
|
98
|
-
parser.parse(source_text, filename, 0)
|
|
99
|
-
formatter.done
|
|
100
|
-
MultiJson.load(io.string)
|
|
101
|
-
end
|
|
102
28
|
|
|
103
|
-
|
|
104
|
-
# The adapter to use when converting an AST to a standard internal shape
|
|
105
|
-
def self.adapter_class
|
|
106
|
-
CukeModeler::Gherkin2Adapter
|
|
107
|
-
end
|
|
29
|
+
module CukeModeler
|
|
108
30
|
|
|
109
|
-
|
|
110
|
-
raise("Unknown Gherkin version: '#{gherkin_version}'")
|
|
111
|
-
end
|
|
31
|
+
# A module providing source text parsing functionality.
|
|
112
32
|
|
|
33
|
+
module Parsing
|
|
113
34
|
|
|
114
35
|
class << self
|
|
115
36
|
|
|
@@ -125,28 +46,86 @@ module CukeModeler
|
|
|
125
46
|
# The dialects currently known by the gherkin gem
|
|
126
47
|
def dialects
|
|
127
48
|
unless @dialects
|
|
128
|
-
@dialects =
|
|
49
|
+
@dialects = Gherkin::DIALECTS
|
|
129
50
|
end
|
|
130
51
|
|
|
131
52
|
@dialects
|
|
132
53
|
end
|
|
133
54
|
|
|
134
|
-
# Parses the Cucumber feature given in *source_text* and returns
|
|
135
|
-
#
|
|
55
|
+
# Parses the Cucumber feature given in *source_text* and returns a hash representation of
|
|
56
|
+
# its logical structure. This is a standardized AST that should remain consistent across
|
|
57
|
+
# different versions of `cucumber-gherkin`
|
|
136
58
|
def parse_text(source_text, filename = 'cuke_modeler_fake_file.feature')
|
|
137
59
|
raise(ArgumentError, "Text to parse must be a String but got #{source_text.class}") unless source_text.is_a?(String)
|
|
138
60
|
|
|
139
|
-
|
|
140
61
|
begin
|
|
141
|
-
parsed_result = parsing_method(source_text, filename)
|
|
62
|
+
parsed_result = parsing_method(source_text.encode('UTF-8'), filename)
|
|
142
63
|
rescue => e
|
|
143
64
|
raise(ArgumentError, "Error encountered while parsing '#{filename}'\n#{e.class} - #{e.message}")
|
|
144
65
|
end
|
|
145
66
|
|
|
146
|
-
|
|
67
|
+
adapter_class.new.adapt(parsed_result)
|
|
68
|
+
end
|
|
69
|
+
|
|
147
70
|
|
|
71
|
+
gherkin_version = Gem.loaded_specs['cucumber-gherkin'].version.version
|
|
72
|
+
gherkin_major_version = gherkin_version.match(/^(\d+)\./)[1].to_i
|
|
73
|
+
|
|
74
|
+
case gherkin_major_version
|
|
75
|
+
when 13, 14, 15
|
|
76
|
+
# todo - make these methods private?
|
|
77
|
+
# NOT A PART OF THE PUBLIC API
|
|
78
|
+
# The method to use for parsing Gherkin text
|
|
79
|
+
def parsing_method(source_text, filename)
|
|
80
|
+
messages = Gherkin.from_source(filename, source_text, { :include_gherkin_document => true }).to_a.map(&:to_hash)
|
|
81
|
+
|
|
82
|
+
error_message = messages.find { |message| message[:parse_error] }
|
|
83
|
+
gherkin_ast_message = messages.find { |message| message[:gherkin_document] }
|
|
84
|
+
|
|
85
|
+
raise error_message[:parse_error][:message] if error_message
|
|
86
|
+
|
|
87
|
+
gherkin_ast_message[:gherkin_document]
|
|
88
|
+
end
|
|
89
|
+
when 12
|
|
90
|
+
# todo - make these methods private?
|
|
91
|
+
# NOT A PART OF THE PUBLIC API
|
|
92
|
+
# The method to use for parsing Gherkin text
|
|
93
|
+
def parsing_method(source_text, filename)
|
|
94
|
+
messages = Gherkin.from_source(filename, source_text, { :include_gherkin_document => true }).to_a.map(&:to_hash)
|
|
95
|
+
|
|
96
|
+
potential_error_message = messages.find { |message| message[:attachment] }
|
|
97
|
+
gherkin_ast_message = messages.find { |message| message[:gherkin_document] }
|
|
98
|
+
|
|
99
|
+
if potential_error_message
|
|
100
|
+
raise potential_error_message[:attachment][:body] if potential_error_message[:attachment][:body] =~ /expected.*got/
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
gherkin_ast_message[:gherkin_document]
|
|
104
|
+
end
|
|
105
|
+
when 9, 10, 11
|
|
106
|
+
# todo - make these methods private?
|
|
107
|
+
# NOT A PART OF THE PUBLIC API
|
|
108
|
+
# The method to use for parsing Gherkin text
|
|
109
|
+
def parsing_method(source_text, filename)
|
|
110
|
+
messages = Gherkin.from_source(filename, source_text, { :include_gherkin_document => true }).to_a.map(&:to_hash)
|
|
111
|
+
|
|
112
|
+
potential_error_message = messages.find { |message| message[:attachment] }
|
|
113
|
+
gherkin_ast_message = messages.find { |message| message[:gherkin_document] }
|
|
114
|
+
|
|
115
|
+
if potential_error_message
|
|
116
|
+
raise potential_error_message[:attachment][:text] if potential_error_message[:attachment][:text] =~ /expected.*got/
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
gherkin_ast_message[:gherkin_document]
|
|
120
|
+
end
|
|
121
|
+
else
|
|
122
|
+
raise("Unknown Gherkin version: '#{gherkin_version}'")
|
|
123
|
+
end
|
|
148
124
|
|
|
149
|
-
|
|
125
|
+
# NOT A PART OF THE PUBLIC API
|
|
126
|
+
# The adapter to use when converting an AST to a standard internal shape
|
|
127
|
+
define_method('adapter_class') do
|
|
128
|
+
CukeModeler.const_get("Gherkin#{gherkin_major_version}Adapter")
|
|
150
129
|
end
|
|
151
130
|
|
|
152
131
|
end
|