cuke_modeler 2.1.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.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +53 -1
  3. data/README.md +14 -16
  4. data/cuke_modeler.gemspec +33 -21
  5. data/lib/cuke_modeler.rb +2 -1
  6. data/lib/cuke_modeler/adapters/gherkin_10_adapter.rb +13 -0
  7. data/lib/cuke_modeler/adapters/gherkin_11_adapter.rb +13 -0
  8. data/lib/cuke_modeler/adapters/gherkin_12_adapter.rb +13 -0
  9. data/lib/cuke_modeler/adapters/gherkin_13_adapter.rb +13 -0
  10. data/lib/cuke_modeler/adapters/gherkin_14_adapter.rb +13 -0
  11. data/lib/cuke_modeler/adapters/gherkin_15_adapter.rb +13 -0
  12. data/lib/cuke_modeler/adapters/gherkin_9_adapter.rb +356 -4
  13. data/lib/cuke_modeler/containing.rb +41 -89
  14. data/lib/cuke_modeler/described.rb +40 -1
  15. data/lib/cuke_modeler/models/background.rb +12 -12
  16. data/lib/cuke_modeler/models/cell.rb +14 -8
  17. data/lib/cuke_modeler/models/comment.rb +6 -6
  18. data/lib/cuke_modeler/models/directory.rb +14 -18
  19. data/lib/cuke_modeler/models/doc_string.rb +11 -8
  20. data/lib/cuke_modeler/models/example.rb +64 -46
  21. data/lib/cuke_modeler/models/feature.rb +38 -20
  22. data/lib/cuke_modeler/models/feature_file.rb +6 -8
  23. data/lib/cuke_modeler/models/model.rb +2 -1
  24. data/lib/cuke_modeler/models/outline.rb +20 -15
  25. data/lib/cuke_modeler/models/row.rb +11 -8
  26. data/lib/cuke_modeler/models/rule.rb +101 -0
  27. data/lib/cuke_modeler/models/scenario.rb +18 -13
  28. data/lib/cuke_modeler/models/step.rb +41 -19
  29. data/lib/cuke_modeler/models/table.rb +10 -7
  30. data/lib/cuke_modeler/models/tag.rb +10 -6
  31. data/lib/cuke_modeler/named.rb +5 -1
  32. data/lib/cuke_modeler/nested.rb +22 -18
  33. data/lib/cuke_modeler/parsed.rb +8 -0
  34. data/lib/cuke_modeler/parsing.rb +55 -74
  35. data/lib/cuke_modeler/sourceable.rb +8 -0
  36. data/lib/cuke_modeler/stepped.rb +8 -0
  37. data/lib/cuke_modeler/taggable.rb +9 -1
  38. data/lib/cuke_modeler/version.rb +1 -1
  39. data/testing/cucumber/features/modeling/feature_modeling.feature +28 -7
  40. data/testing/cucumber/features/modeling/feature_output.feature +45 -23
  41. data/testing/cucumber/features/modeling/rule_modeling.feature +108 -0
  42. data/testing/cucumber/features/modeling/rule_output.feature +111 -0
  43. metadata +68 -161
  44. data/.gitignore +0 -18
  45. data/.simplecov +0 -7
  46. data/.travis.yml +0 -81
  47. data/Gemfile +0 -44
  48. data/Rakefile +0 -73
  49. data/appveyor.yml +0 -88
  50. data/lib/cuke_modeler/adapters/gherkin_2_adapter.rb +0 -274
  51. data/lib/cuke_modeler/adapters/gherkin_3_adapter.rb +0 -297
  52. data/lib/cuke_modeler/adapters/gherkin_4_adapter.rb +0 -309
  53. data/lib/cuke_modeler/adapters/gherkin_5_adapter.rb +0 -12
  54. data/lib/cuke_modeler/adapters/gherkin_6_adapter.rb +0 -310
  55. data/lib/cuke_modeler/adapters/gherkin_7_adapter.rb +0 -307
  56. data/lib/cuke_modeler/adapters/gherkin_8_adapter.rb +0 -12
  57. data/testing/cucumber/step_definitions/action_steps.rb +0 -13
  58. data/testing/cucumber/step_definitions/background_steps.rb +0 -1
  59. data/testing/cucumber/step_definitions/directory_steps.rb +0 -6
  60. data/testing/cucumber/step_definitions/doc_string_steps.rb +0 -1
  61. data/testing/cucumber/step_definitions/feature_file_steps.rb +0 -16
  62. data/testing/cucumber/step_definitions/feature_steps.rb +0 -7
  63. data/testing/cucumber/step_definitions/modeling_steps.rb +0 -49
  64. data/testing/cucumber/step_definitions/setup_steps.rb +0 -32
  65. data/testing/cucumber/step_definitions/step_steps.rb +0 -3
  66. data/testing/cucumber/step_definitions/table_steps.rb +0 -1
  67. data/testing/cucumber/step_definitions/tag_steps.rb +0 -3
  68. data/testing/cucumber/step_definitions/verification_steps.rb +0 -181
  69. data/testing/cucumber/support/env.rb +0 -30
  70. data/testing/dialect_helper.rb +0 -48
  71. data/testing/file_helper.rb +0 -47
  72. data/testing/gemfiles/gherkin2.gemfile +0 -33
  73. data/testing/gemfiles/gherkin3.gemfile +0 -26
  74. data/testing/gemfiles/gherkin4.gemfile +0 -27
  75. data/testing/gemfiles/gherkin5.gemfile +0 -27
  76. data/testing/gemfiles/gherkin6.gemfile +0 -10
  77. data/testing/gemfiles/gherkin7.gemfile +0 -9
  78. data/testing/gemfiles/gherkin8.gemfile +0 -9
  79. data/testing/gemfiles/gherkin9.gemfile +0 -9
  80. data/testing/helper_methods.rb +0 -23
  81. data/testing/rspec/spec/integration/adapters/gherkin_2_adapter_spec.rb +0 -166
  82. data/testing/rspec/spec/integration/adapters/gherkin_3_adapter_spec.rb +0 -166
  83. data/testing/rspec/spec/integration/adapters/gherkin_4_adapter_spec.rb +0 -165
  84. data/testing/rspec/spec/integration/adapters/gherkin_5_adapter_spec.rb +0 -165
  85. data/testing/rspec/spec/integration/adapters/gherkin_6_adapter_spec.rb +0 -159
  86. data/testing/rspec/spec/integration/adapters/gherkin_7_adapter_spec.rb +0 -162
  87. data/testing/rspec/spec/integration/adapters/gherkin_8_adapter_spec.rb +0 -162
  88. data/testing/rspec/spec/integration/adapters/gherkin_9_adapter_spec.rb +0 -162
  89. data/testing/rspec/spec/integration/models/background_integration_spec.rb +0 -438
  90. data/testing/rspec/spec/integration/models/cell_integration_spec.rb +0 -338
  91. data/testing/rspec/spec/integration/models/comment_integration_spec.rb +0 -180
  92. data/testing/rspec/spec/integration/models/directory_integration_spec.rb +0 -218
  93. data/testing/rspec/spec/integration/models/doc_string_integration_spec.rb +0 -398
  94. data/testing/rspec/spec/integration/models/example_integration_spec.rb +0 -753
  95. data/testing/rspec/spec/integration/models/feature_file_integration_spec.rb +0 -276
  96. data/testing/rspec/spec/integration/models/feature_integration_spec.rb +0 -655
  97. data/testing/rspec/spec/integration/models/model_integration_spec.rb +0 -15
  98. data/testing/rspec/spec/integration/models/outline_integration_spec.rb +0 -619
  99. data/testing/rspec/spec/integration/models/row_integration_spec.rb +0 -303
  100. data/testing/rspec/spec/integration/models/scenario_integration_spec.rb +0 -475
  101. data/testing/rspec/spec/integration/models/step_integration_spec.rb +0 -573
  102. data/testing/rspec/spec/integration/models/table_integration_spec.rb +0 -333
  103. data/testing/rspec/spec/integration/models/tag_integration_spec.rb +0 -271
  104. data/testing/rspec/spec/integration/nested_integration_spec.rb +0 -91
  105. data/testing/rspec/spec/integration/parsing_integration_spec.rb +0 -143
  106. data/testing/rspec/spec/integration/shared/models_integration_specs.rb +0 -18
  107. data/testing/rspec/spec/spec_helper.rb +0 -129
  108. data/testing/rspec/spec/unit/cuke_modeler_unit_spec.rb +0 -25
  109. data/testing/rspec/spec/unit/described_unit_spec.rb +0 -23
  110. data/testing/rspec/spec/unit/models/background_unit_spec.rb +0 -83
  111. data/testing/rspec/spec/unit/models/cell_unit_spec.rb +0 -68
  112. data/testing/rspec/spec/unit/models/comment_unit_spec.rb +0 -68
  113. data/testing/rspec/spec/unit/models/directory_unit_spec.rb +0 -127
  114. data/testing/rspec/spec/unit/models/doc_string_unit_spec.rb +0 -100
  115. data/testing/rspec/spec/unit/models/example_unit_spec.rb +0 -133
  116. data/testing/rspec/spec/unit/models/feature_file_unit_spec.rb +0 -125
  117. data/testing/rspec/spec/unit/models/feature_unit_spec.rb +0 -157
  118. data/testing/rspec/spec/unit/models/model_unit_spec.rb +0 -15
  119. data/testing/rspec/spec/unit/models/outline_unit_spec.rb +0 -117
  120. data/testing/rspec/spec/unit/models/row_unit_spec.rb +0 -68
  121. data/testing/rspec/spec/unit/models/scenario_unit_spec.rb +0 -86
  122. data/testing/rspec/spec/unit/models/step_unit_spec.rb +0 -109
  123. data/testing/rspec/spec/unit/models/table_unit_spec.rb +0 -77
  124. data/testing/rspec/spec/unit/models/tag_unit_spec.rb +0 -68
  125. data/testing/rspec/spec/unit/named_unit_spec.rb +0 -23
  126. data/testing/rspec/spec/unit/nested_unit_spec.rb +0 -43
  127. data/testing/rspec/spec/unit/parsed_unit_spec.rb +0 -27
  128. data/testing/rspec/spec/unit/parsing_unit_spec.rb +0 -54
  129. data/testing/rspec/spec/unit/shared/bare_bones_models_unit_specs.rb +0 -14
  130. data/testing/rspec/spec/unit/shared/containing_models_unit_specs.rb +0 -127
  131. data/testing/rspec/spec/unit/shared/described_models_unit_specs.rb +0 -38
  132. data/testing/rspec/spec/unit/shared/keyworded_models_unit_specs.rb +0 -58
  133. data/testing/rspec/spec/unit/shared/models_unit_specs.rb +0 -15
  134. data/testing/rspec/spec/unit/shared/named_models_unit_specs.rb +0 -39
  135. data/testing/rspec/spec/unit/shared/nested_models_unit_specs.rb +0 -51
  136. data/testing/rspec/spec/unit/shared/parsed_models_unit_specs.rb +0 -39
  137. data/testing/rspec/spec/unit/shared/prepopulated_models_unit_specs.rb +0 -18
  138. data/testing/rspec/spec/unit/shared/sourced_models_unit_specs.rb +0 -39
  139. data/testing/rspec/spec/unit/shared/stepped_models_unit_specs.rb +0 -46
  140. data/testing/rspec/spec/unit/shared/stringifiable_models_unit_specs.rb +0 -18
  141. data/testing/rspec/spec/unit/shared/tagged_models_unit_specs.rb +0 -72
  142. data/testing/rspec/spec/unit/sourceable_unit_spec.rb +0 -27
  143. data/testing/rspec/spec/unit/stepped_unit_spec.rb +0 -23
  144. data/testing/rspec/spec/unit/taggable_unit_spec.rb +0 -69
  145. data/testing/test_languages.json +0 -45
  146. data/todo.txt +0 -25
@@ -1,3 +1,6 @@
1
+ # It's the module that has functionality for every possible model type. So, yes, it's long.
2
+ # rubocop:disable Metrics/ModuleLength
3
+
1
4
  module CukeModeler
2
5
 
3
6
  # NOT A PART OF THE PUBLIC API
@@ -32,7 +35,6 @@ module CukeModeler
32
35
 
33
36
  model.parent_model = self
34
37
 
35
-
36
38
  model
37
39
  end
38
40
 
@@ -75,14 +77,11 @@ module CukeModeler
75
77
  end
76
78
 
77
79
  def populate_block(step_object, parsed_step_data)
78
- case
79
- when parsed_step_data['table']
80
- step_object.block = build_child_model(Table, parsed_step_data['table'])
81
- when parsed_step_data['doc_string']
82
- step_object.block = build_child_model(DocString, parsed_step_data['doc_string'])
83
- else
84
- step_object.block = nil
85
- end
80
+ step_object.block = if parsed_step_data['table']
81
+ build_child_model(Table, parsed_step_data['table'])
82
+ elsif parsed_step_data['doc_string']
83
+ build_child_model(DocString, parsed_step_data['doc_string'])
84
+ end
86
85
  end
87
86
 
88
87
  def populate_table(table_object, parsed_table_data)
@@ -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
 
@@ -146,7 +154,9 @@ module CukeModeler
146
154
  populate_parsing_data(feature_file_object, processed_feature_file_data)
147
155
  feature_file_object.path = processed_feature_file_data['path']
148
156
 
149
- feature_file_object.feature = build_child_model(Feature, processed_feature_file_data['feature']) unless processed_feature_file_data['feature'].nil?
157
+ if processed_feature_file_data['feature']
158
+ feature_file_object.feature = build_child_model(Feature, processed_feature_file_data['feature'])
159
+ end
150
160
 
151
161
  processed_feature_file_data['comments'].each do |comment_data|
152
162
  feature_file_object.comments << build_child_model(Comment, comment_data)
@@ -194,7 +204,7 @@ module CukeModeler
194
204
  end
195
205
 
196
206
  def populate_content_type(doc_string_model, parsed_doc_string_data)
197
- doc_string_model.content_type = parsed_doc_string_data['content_type'] == "" ? nil : parsed_doc_string_data['content_type']
207
+ doc_string_model.content_type = parsed_doc_string_data['content_type']
198
208
  end
199
209
 
200
210
  def populate_content(doc_string_model, parsed_doc_string_data)
@@ -213,87 +223,29 @@ module CukeModeler
213
223
  end
214
224
  end
215
225
 
216
- def populate_children(feature_model, parsed_feature_data)
217
- elements = parsed_feature_data['elements']
218
-
219
- if elements
220
- elements.each do |element|
221
- case element['type']
222
- when 'Scenario', 'scenario'
223
- feature_model.tests << build_child_model(Scenario, element)
224
- when 'ScenarioOutline', 'scenario_outline'
225
- feature_model.tests << build_child_model(Outline, element)
226
- when 'Background', 'background'
227
- feature_model.background = build_child_model(Background, element)
228
- else
229
- raise(ArgumentError, "Unknown element type: #{element['type']}")
230
- end
231
- end
232
- end
233
- end
234
-
235
- def populate_parsing_data(model, parsed_model_data)
236
- model.parsing_data = parsed_model_data['cuke_modeler_parsing_data']
237
- end
238
-
239
- def populate_source_line(model, parsed_model_data)
240
- model.source_line = parsed_model_data['line']
241
- end
242
-
243
- def populate_name(model, parsed_model_data)
244
- model.name = parsed_model_data['name']
245
- end
246
-
247
- def populate_description(model, parsed_model_data)
248
- model.description = trimmed_description(parsed_model_data['description'])
249
- end
250
-
251
- def trimmed_description(description)
252
- description = description.split("\n")
253
-
254
- trim_leading_blank_lines(description)
255
- trim_trailing_blank_lines(description)
256
- trim_leading_spaces(description)
257
- trim_trailing_spaces(description)
258
-
259
- description.join("\n")
260
- end
261
-
262
- def trim_leading_blank_lines(description)
263
- description.replace(description.drop_while { |line| line !~ /\S/ })
264
- end
265
-
266
- def trim_trailing_blank_lines(description)
267
- # Nothing to do. Already done by the parser but leaving this here in case that changes in future versions.
268
- end
269
-
270
- def trim_leading_spaces(description)
271
- non_blank_lines = description.select { |line| line =~ /\S/ }
272
-
273
- fewest_spaces = non_blank_lines.collect { |line| line[/^\s*/].length }.min || 0
274
-
275
- description.each { |line| line.slice!(0..(fewest_spaces - 1)) } if fewest_spaces > 0
276
- end
277
-
278
- def trim_trailing_spaces(description)
279
- description.map! { |line| line.rstrip }
280
- end
281
-
282
- def populate_tags(model, parsed_model_data)
283
- if parsed_model_data['tags']
284
- parsed_model_data['tags'].each do |tag|
285
- model.tags << build_child_model(Tag, tag)
286
- end
287
- end
288
- end
289
-
290
- def populate_steps(model, parsed_model_data)
291
- if parsed_model_data['steps']
292
- parsed_model_data['steps'].each do |step_data|
293
- model.steps << build_child_model(Step, step_data)
226
+ # It's not getting better any time soon
227
+ # rubocop:disable Metrics/AbcSize
228
+
229
+ def populate_children(model, parsed_feature_data)
230
+ return unless parsed_feature_data['elements']
231
+
232
+ parsed_feature_data['elements'].each do |element|
233
+ case element['type']
234
+ when 'Scenario', 'scenario'
235
+ model.tests << build_child_model(Scenario, element)
236
+ when 'ScenarioOutline', 'scenario_outline'
237
+ model.tests << build_child_model(Outline, element)
238
+ when 'Background', 'background'
239
+ model.background = build_child_model(Background, element)
240
+ when 'Rule'
241
+ model.rules << build_child_model(Rule, element)
242
+ else
243
+ raise(ArgumentError, "Unknown element type: #{element['type']}")
294
244
  end
295
245
  end
296
246
  end
247
+ # rubocop:enable Metrics/AbcSize
297
248
 
298
249
  end
299
250
  end
251
+ # rubocop:enable Metrics/ModuleLength
@@ -19,11 +19,50 @@ module CukeModeler
19
19
  description_lines = description.split("\n")
20
20
 
21
21
  text << "\n" if description_lines.first =~ /\S/
22
- text << description_lines.collect { |line| "#{line}" }.join("\n")
22
+ text << description_lines.join("\n")
23
23
  end
24
24
 
25
25
  text
26
26
  end
27
27
 
28
+ def no_description_to_output?
29
+ description.nil? || description.empty?
30
+ end
31
+
32
+ def populate_description(model, parsed_model_data)
33
+ model.description = trimmed_description(parsed_model_data['description'])
34
+ end
35
+
36
+ def trimmed_description(description)
37
+ description = description.split("\n")
38
+
39
+ trim_leading_blank_lines(description)
40
+ trim_trailing_blank_lines(description)
41
+ trim_leading_spaces(description)
42
+ trim_trailing_spaces(description)
43
+
44
+ description.join("\n")
45
+ end
46
+
47
+ def trim_leading_blank_lines(description)
48
+ description.replace(description.drop_while { |line| line !~ /\S/ })
49
+ end
50
+
51
+ def trim_trailing_blank_lines(_description)
52
+ # Nothing to do. Already done by the parser but leaving this here in case that changes in future versions.
53
+ end
54
+
55
+ def trim_leading_spaces(description)
56
+ non_blank_lines = description.select { |line| line =~ /\S/ }
57
+
58
+ fewest_spaces = non_blank_lines.collect { |line| line[/^\s*/].length }.min || 0
59
+
60
+ description.each { |line| line.slice!(0..(fewest_spaces - 1)) } if fewest_spaces.positive?
61
+ end
62
+
63
+ def trim_trailing_spaces(description)
64
+ description.map!(&:rstrip)
65
+ end
66
+
28
67
  end
29
68
  end
@@ -23,17 +23,17 @@ module CukeModeler
23
23
 
24
24
  super(source_text)
25
25
 
26
- if source_text
27
- parsed_background_data = parse_source(source_text)
28
- populate_background(self, parsed_background_data)
29
- end
26
+ return unless source_text
27
+
28
+ parsed_background_data = parse_source(source_text)
29
+ populate_background(self, parsed_background_data)
30
30
  end
31
31
 
32
32
  # Returns *true* if the two models have equivalent steps and *false* otherwise.
33
- def ==(other_model)
34
- return false unless other_model.respond_to?(:steps)
33
+ def ==(other)
34
+ return false unless other.respond_to?(:steps)
35
35
 
36
- steps == other_model.steps
36
+ steps == other.steps
37
37
  end
38
38
 
39
39
  # Returns the model objects that belong to this model.
@@ -47,9 +47,9 @@ module CukeModeler
47
47
  text = ''
48
48
 
49
49
  text << "#{@keyword}:#{name_output_string}"
50
- text << "\n" + description_output_string unless (description.nil? || description.empty?)
51
- text << "\n" unless (steps.empty? || description.nil? || description.empty?)
52
- text << "\n" + steps_output_string unless steps.empty?
50
+ text << "\n#{description_output_string}" unless no_description_to_output?
51
+ text << "\n" unless steps.empty? || no_description_to_output?
52
+ text << "\n#{steps_output_string}" unless steps.empty?
53
53
 
54
54
  text
55
55
  end
@@ -62,9 +62,9 @@ module CukeModeler
62
62
  base_file_string = "# language: #{Parsing.dialect}\n#{dialect_feature_keyword}: Fake feature to parse\n"
63
63
  source_text = base_file_string + source_text
64
64
 
65
- parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_background.feature')
65
+ parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_background.feature')
66
66
 
67
- parsed_file.first['feature']['elements'].first
67
+ parsed_file['feature']['elements'].first
68
68
  end
69
69
 
70
70
  end
@@ -18,10 +18,10 @@ module CukeModeler
18
18
  def initialize(source_text = nil)
19
19
  super(source_text)
20
20
 
21
- if source_text
22
- parsed_cell_data = parse_source(source_text)
23
- populate_cell(self, parsed_cell_data)
24
- end
21
+ return unless source_text
22
+
23
+ parsed_cell_data = parse_source(source_text)
24
+ populate_cell(self, parsed_cell_data)
25
25
  end
26
26
 
27
27
  # Returns a string representation of this model. For a cell model,
@@ -35,14 +35,20 @@ module CukeModeler
35
35
  private
36
36
 
37
37
 
38
+ # It's only considered complex because of how deeply nested cells are in the tree. It's not REALLY complex.
39
+ # rubocop:disable Metrics/AbcSize
38
40
  def parse_source(source_text)
39
- base_file_string = "# language: #{Parsing.dialect}\n#{dialect_feature_keyword}: Fake feature to parse\n#{dialect_scenario_keyword}:\n#{dialect_step_keyword} fake step\n"
40
- source_text = base_file_string + '|' + source_text + '|'
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"
45
+ source_text = "#{base_file_string}|#{source_text}|"
41
46
 
42
- parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_cell.feature')
47
+ parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_cell.feature')
43
48
 
44
- parsed_file.first['feature']['elements'].first['steps'].first['table']['rows'].first['cells'].first
49
+ parsed_file['feature']['elements'].first['steps'].first['table']['rows'].first['cells'].first
45
50
  end
51
+ # rubocop:enable Metrics/AbcSize
46
52
 
47
53
  end
48
54
 
@@ -18,10 +18,10 @@ module CukeModeler
18
18
  def initialize(source_text = nil)
19
19
  super(source_text)
20
20
 
21
- if source_text
22
- parsed_comment_data = parse_source(source_text)
23
- populate_comment(self, parsed_comment_data)
24
- end
21
+ return unless source_text
22
+
23
+ parsed_comment_data = parse_source(source_text)
24
+ populate_comment(self, parsed_comment_data)
25
25
  end
26
26
 
27
27
  # Returns a string representation of this model. For a comment model,
@@ -38,9 +38,9 @@ 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::parse_text(source_text, 'cuke_modeler_stand_alone_comment.feature')
41
+ parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_comment.feature')
42
42
 
43
- parsed_file.first['comments'].last
43
+ parsed_file['comments'].last
44
44
  end
45
45
 
46
46
  end
@@ -24,12 +24,11 @@ module CukeModeler
24
24
 
25
25
  super(directory_path)
26
26
 
27
- if directory_path
28
- raise(ArgumentError, "Unknown directory: #{directory_path.inspect}") unless File.exists?(directory_path)
27
+ return unless directory_path
28
+ raise(ArgumentError, "Unknown directory: #{directory_path.inspect}") unless File.exist?(directory_path)
29
29
 
30
- processed_directory_data = process_directory(directory_path)
31
- populate_directory(self, processed_directory_data)
32
- end
30
+ processed_directory_data = process_directory(directory_path)
31
+ populate_directory(self, processed_directory_data)
33
32
  end
34
33
 
35
34
  # Returns the name of the modeled directory.
@@ -53,10 +52,9 @@ module CukeModeler
53
52
 
54
53
 
55
54
  def process_directory(directory_path)
56
- directory_data = {'path' => directory_path,
57
- 'directories' => [],
58
- 'feature_files' => []
59
- }
55
+ directory_data = { 'path' => directory_path,
56
+ 'directories' => [],
57
+ 'feature_files' => [] }
60
58
 
61
59
  entries = Dir.entries(directory_path)
62
60
  entries.delete '.'
@@ -65,13 +63,11 @@ module CukeModeler
65
63
  entries.each do |entry|
66
64
  entry = "#{directory_path}/#{entry}"
67
65
 
68
- case
69
- when File.directory?(entry)
70
- directory_data['directories'] << process_directory(entry)
71
- when entry =~ /\.feature$/
72
- directory_data['feature_files'] << process_feature_file(entry)
73
- else
74
- # Ignore anything that isn't a directory or a feature file
66
+ # Ignore anything that isn't a directory or a feature file
67
+ if File.directory?(entry)
68
+ directory_data['directories'] << process_directory(entry)
69
+ elsif entry =~ /\.feature$/
70
+ directory_data['feature_files'] << process_feature_file(entry)
75
71
  end
76
72
  end
77
73
 
@@ -82,8 +78,8 @@ module CukeModeler
82
78
  def process_feature_file(file_path)
83
79
  source_text = IO.read(file_path)
84
80
 
85
- feature_file_data = Parsing::parse_text(source_text, file_path).first
86
- feature_file_data = feature_file_data.merge({'path' => file_path})
81
+ feature_file_data = Parsing.parse_text(source_text, file_path)
82
+ feature_file_data = feature_file_data.merge({ 'path' => file_path })
87
83
 
88
84
  feature_file_data
89
85
  end
@@ -21,10 +21,10 @@ module CukeModeler
21
21
  def initialize(source_text = nil)
22
22
  super(source_text)
23
23
 
24
- if source_text
25
- parsed_doc_string_data = parse_source(source_text)
26
- populate_docstring(self, parsed_doc_string_data)
27
- end
24
+ return unless source_text
25
+
26
+ parsed_doc_string_data = parse_source(source_text)
27
+ populate_docstring(self, parsed_doc_string_data)
28
28
  end
29
29
 
30
30
  # Returns a string representation of this model. For a doc string model,
@@ -40,12 +40,15 @@ module CukeModeler
40
40
 
41
41
 
42
42
  def parse_source(source_text)
43
- base_file_string = "# language: #{Parsing.dialect}\n#{dialect_feature_keyword}:\n#{dialect_scenario_keyword}:\n#{dialect_step_keyword} step\n"
43
+ base_file_string = "# language: #{Parsing.dialect}
44
+ #{dialect_feature_keyword}:
45
+ #{dialect_scenario_keyword}:
46
+ #{dialect_step_keyword} step\n"
44
47
  source_text = base_file_string + source_text
45
48
 
46
- parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_doc_string.feature')
49
+ parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_doc_string.feature')
47
50
 
48
- parsed_file.first['feature']['elements'].first['steps'].first['doc_string']
51
+ parsed_file['feature']['elements'].first['steps'].first['doc_string']
49
52
  end
50
53
 
51
54
  def content_type_output_string
@@ -53,7 +56,7 @@ module CukeModeler
53
56
  end
54
57
 
55
58
  def content_output_string
56
- (content.nil? || content.empty?) ? '' : content.gsub('"""', '\"\"\"') + "\n"
59
+ content.nil? || content.empty? ? '' : content.gsub('"""', '\"\"\"') + "\n"
57
60
  end
58
61
 
59
62
  end
@@ -1,3 +1,6 @@
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.
@@ -27,10 +30,10 @@ module CukeModeler
27
30
 
28
31
  super(source_text)
29
32
 
30
- if source_text
31
- parsed_example_data = parse_source(source_text)
32
- populate_example(self, parsed_example_data)
33
- end
33
+ return unless source_text
34
+
35
+ parsed_example_data = parse_source(source_text)
36
+ populate_example(self, parsed_example_data)
34
37
  end
35
38
 
36
39
  # Adds a row to the example table. The row can be given as a Hash of
@@ -40,42 +43,39 @@ module CukeModeler
40
43
  raise('Cannot add a row. No parameters have been set.') if rows.empty?
41
44
 
42
45
  # A quick 'deep clone' so that the input isn't modified
43
- row = Marshal::load(Marshal.dump(row))
44
-
45
- case
46
- when row.is_a?(Array)
47
- # 'stringify' input
48
- row.collect! { |value| value.to_s }
49
-
50
- @rows << Row.new("|#{row.join('|')}|")
51
- when row.is_a?(Hash)
52
- # 'stringify' input
53
- row = row.inject({}) { |hash, (key, value)| hash[key.to_s] = value.to_s; hash }
54
-
55
- @rows << Row.new("|#{ordered_row_values(row).join('|')}|")
56
- else
57
- raise(ArgumentError, "Can only add row from a Hash or an Array but received #{row.class}")
58
- end
46
+ row = Marshal.load(Marshal.dump(row))
47
+
48
+ values = if row.is_a?(Array)
49
+ row
50
+ elsif row.is_a?(Hash)
51
+ # There is no guarantee that the user built up their hash with the keys in the same order as
52
+ # the parameter row and so the values have to be ordered by us. Additionally, the hash needs
53
+ # to have string keys in order for #order_row_values to work
54
+ ordered_row_values(stringify_keys(row))
55
+ else
56
+ raise(ArgumentError, "Can only add row from a Hash or an Array but received #{row.class}")
57
+ end
58
+
59
+ @rows << Row.new("|#{values.join('|')}|")
59
60
  end
60
61
 
61
62
  # Removes a row from the example table. The row can be given as a Hash of
62
63
  # parameters and their corresponding values or as an Array of values
63
64
  # which will be assigned in order.
64
65
  def remove_row(row_removed)
65
- return unless argument_rows
66
-
67
- case
68
- when row_removed.is_a?(Array)
69
- location = argument_rows.index { |row| row.cells.collect { |cell| cell.value } == row_removed.collect { |value| value.strip } }
70
- when row_removed.is_a?(Hash)
71
- # Note: the hash value order has to be manually calculated because Ruby 1.8.7 does not have ordered
72
- # hash keys. Alternatively, the hash may have simply been built up 'willy nilly' by the user instead
73
- # of being built up in order according to the parameter order.
74
- location = argument_rows.index { |row| row.cells.collect { |cell| cell.value } == ordered_row_values(row_removed.each_value { |value| value.strip! }) }
75
- else
76
- raise(ArgumentError, "Can only remove row from a Hash or an Array but received #{row_removed.class}")
77
- end
78
-
66
+ return if argument_rows.empty?
67
+
68
+ values = if row_removed.is_a?(Array)
69
+ row_removed
70
+ elsif row_removed.is_a?(Hash)
71
+ # There is no guarantee that the user built up their hash with the keys in the same order as
72
+ # the parameter row and so the values have to be ordered by us.
73
+ ordered_row_values(row_removed)
74
+ else
75
+ raise(ArgumentError, "Can only remove row from a Hash or an Array but received #{row_removed.class}")
76
+ end
77
+
78
+ location = index_for_values(values.map(&:to_s).map(&:strip))
79
79
  @rows.delete_at(location + 1) if location
80
80
  end
81
81
 
@@ -91,7 +91,7 @@ module CukeModeler
91
91
 
92
92
  # Returns the parameters of the example table
93
93
  def parameters
94
- parameter_row ? parameter_row.cells.collect { |cell| cell.value } : []
94
+ parameter_row ? parameter_row.cells.map(&:value) : []
95
95
  end
96
96
 
97
97
  # Returns the model objects that belong to this model.
@@ -99,32 +99,40 @@ module CukeModeler
99
99
  rows + tags
100
100
  end
101
101
 
102
+ # Building strings just isn't pretty
103
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
104
+
102
105
  # Returns a string representation of this model. For an example model,
103
106
  # this will be Gherkin text that is equivalent to the example being modeled.
104
107
  def to_s
105
108
  text = ''
106
109
 
107
- text << tag_output_string + "\n" unless tags.empty?
110
+ text << "#{tag_output_string}\n" unless tags.empty?
108
111
  text << "#{@keyword}:#{name_output_string}"
109
- text << "\n" + description_output_string unless (description.nil? || description.empty?)
110
- text << "\n" unless (rows.empty? || description.nil? || description.empty?)
111
- text << "\n" + parameters_output_string if parameter_row
112
- text << "\n" + rows_output_string unless argument_rows.empty?
112
+ text << "\n#{description_output_string}" unless no_description_to_output?
113
+ text << "\n" unless rows.empty? || no_description_to_output?
114
+ text << "\n#{parameters_output_string}" if parameter_row
115
+ text << "\n#{rows_output_string}" unless argument_rows.empty?
113
116
 
114
117
  text
115
118
  end
116
119
 
120
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
121
+
117
122
 
118
123
  private
119
124
 
120
125
 
121
126
  def parse_source(source_text)
122
- base_file_string = "# language: #{Parsing.dialect}\n#{dialect_feature_keyword}: Fake feature to parse\n#{dialect_outline_keyword}:\n#{dialect_step_keyword} fake step\n"
127
+ base_file_string = "# language: #{Parsing.dialect}
128
+ #{dialect_feature_keyword}: Fake feature to parse
129
+ #{dialect_outline_keyword}:
130
+ #{dialect_step_keyword} fake step\n"
123
131
  source_text = base_file_string + source_text
124
132
 
125
- parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_example.feature')
133
+ parsed_file = Parsing.parse_text(source_text, 'cuke_modeler_stand_alone_example.feature')
126
134
 
127
- parsed_file.first['feature']['elements'].first['examples'].first
135
+ parsed_file['feature']['elements'].first['examples'].first
128
136
  end
129
137
 
130
138
  def determine_buffer_size(index)
@@ -135,7 +143,7 @@ module CukeModeler
135
143
  text = ''
136
144
 
137
145
  unless parameter_row.nil?
138
- text << " |"
146
+ text << ' |'
139
147
  parameter_row.cells.count.times { |index| text << " #{string_for(parameter_row.cells, index)} |" }
140
148
  end
141
149
 
@@ -148,7 +156,7 @@ module CukeModeler
148
156
  unless argument_rows.empty?
149
157
 
150
158
  argument_rows.each do |row|
151
- text << " |"
159
+ text << ' |'
152
160
  row.cells.count.times { |index| text << " #{string_for(row.cells, index)} |" }
153
161
  text << "\n"
154
162
  end
@@ -164,8 +172,18 @@ module CukeModeler
164
172
  end
165
173
 
166
174
  def ordered_row_values(row_hash)
167
- parameter_row.cells.collect { |cell| cell.value }.collect { |parameter| row_hash[parameter] }
175
+ parameter_row.cells.map(&:value).collect { |parameter| row_hash[parameter] }
176
+ end
177
+
178
+ def stringify_keys(hash)
179
+ hash.each_with_object({}) { |(key, value), new_hash| new_hash[key.to_s] = value }
180
+ end
181
+
182
+ def index_for_values(values)
183
+ argument_rows.index { |row| row.cells.map(&:value) == values }
168
184
  end
169
185
 
170
186
  end
171
187
  end
188
+
189
+ # rubocop:enable Metrics/ClassLength