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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -1
  3. data/cuke_modeler.gemspec +23 -14
  4. data/lib/cuke_modeler.rb +1 -1
  5. data/lib/cuke_modeler/adapters/gherkin_10_adapter.rb +2 -1
  6. data/lib/cuke_modeler/adapters/gherkin_11_adapter.rb +2 -1
  7. data/lib/cuke_modeler/adapters/gherkin_12_adapter.rb +2 -1
  8. data/lib/cuke_modeler/adapters/gherkin_13_adapter.rb +2 -1
  9. data/lib/cuke_modeler/adapters/gherkin_14_adapter.rb +2 -1
  10. data/lib/cuke_modeler/adapters/gherkin_15_adapter.rb +2 -1
  11. data/lib/cuke_modeler/adapters/gherkin_9_adapter.rb +261 -242
  12. data/lib/cuke_modeler/containing.rb +31 -89
  13. data/lib/cuke_modeler/described.rb +40 -1
  14. data/lib/cuke_modeler/models/background.rb +11 -11
  15. data/lib/cuke_modeler/models/cell.rb +13 -7
  16. data/lib/cuke_modeler/models/comment.rb +5 -5
  17. data/lib/cuke_modeler/models/directory.rb +13 -17
  18. data/lib/cuke_modeler/models/doc_string.rb +10 -7
  19. data/lib/cuke_modeler/models/example.rb +63 -45
  20. data/lib/cuke_modeler/models/feature.rb +23 -16
  21. data/lib/cuke_modeler/models/feature_file.rb +5 -7
  22. data/lib/cuke_modeler/models/model.rb +2 -1
  23. data/lib/cuke_modeler/models/outline.rb +19 -14
  24. data/lib/cuke_modeler/models/row.rb +10 -7
  25. data/lib/cuke_modeler/models/rule.rb +11 -9
  26. data/lib/cuke_modeler/models/scenario.rb +17 -12
  27. data/lib/cuke_modeler/models/step.rb +40 -18
  28. data/lib/cuke_modeler/models/table.rb +9 -6
  29. data/lib/cuke_modeler/models/tag.rb +9 -5
  30. data/lib/cuke_modeler/named.rb +5 -1
  31. data/lib/cuke_modeler/nested.rb +22 -18
  32. data/lib/cuke_modeler/parsed.rb +8 -0
  33. data/lib/cuke_modeler/parsing.rb +36 -26
  34. data/lib/cuke_modeler/sourceable.rb +8 -0
  35. data/lib/cuke_modeler/stepped.rb +8 -0
  36. data/lib/cuke_modeler/taggable.rb +9 -1
  37. data/lib/cuke_modeler/version.rb +1 -1
  38. metadata +53 -33
@@ -33,17 +33,19 @@ module CukeModeler
33
33
 
34
34
  super(source_text)
35
35
 
36
- if source_text
37
- parsed_feature_data = parse_source(source_text)
38
- populate_feature(self, parsed_feature_data)
39
- end
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 has_background?
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) { |outline_sum, outline|
64
- outline_sum += outline.examples.reduce(0) { |example_sum, example|
65
- example_sum += example.argument_rows.count
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 + "\n" unless tags.empty?
88
+ text << "#{tag_output_string}\n" unless tags.empty?
84
89
  text << "#{@keyword}:#{name_output_string}"
85
- text << "\n" + description_output_string unless (description.nil? || description.empty?)
86
- text << "\n\n" + background_output_string if background
87
- text << "\n\n" + tests_output_string unless tests.empty?
88
- text << "\n\n" + rules_output_string unless rules.empty?
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::parse_text(source_text, 'cuke_modeler_stand_alone_feature.feature')
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
- if file_path
29
- raise(ArgumentError, "Unknown file: #{file_path.inspect}") unless File.exists?(file_path)
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::parse_text(source_text, file_path)
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
- raise(ArgumentError, "Can only create models from Strings but was given a #{source_text.class}.") if source_text && !source_text.is_a?(String)
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
- if source_text
33
- parsed_outline_data = parse_source(source_text)
34
- populate_outline(self, parsed_outline_data)
35
- end
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 ==(other_model)
40
- return false unless other_model.respond_to?(:steps)
39
+ def ==(other)
40
+ return false unless other.respond_to?(:steps)
41
41
 
42
- steps == other_model.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 + "\n" unless tags.empty?
58
+ text << "#{tag_output_string}\n" unless tags.empty?
56
59
  text << "#{@keyword}:#{name_output_string}"
57
- text << "\n" + description_output_string unless (description.nil? || description.empty?)
58
- text << "\n" unless (steps.empty? || description.nil? || description.empty?)
59
- text << "\n" + steps_output_string unless steps.empty?
60
- text << "\n\n" + examples_output_string unless examples.empty?
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::parse_text(source_text, 'cuke_modeler_stand_alone_outline.feature')
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.collect { |example| example.to_s }.join("\n\n")
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
- if source_text
23
- parsed_row_data = parse_source(source_text)
24
- populate_row(self, parsed_row_data)
25
- end
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.collect { |cell| cell.to_s }
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}\n#{dialect_feature_keyword}: Fake feature to parse\n#{dialect_scenario_keyword}:\n#{dialect_step_keyword} fake step\n"
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::parse_text(source_text, 'cuke_modeler_stand_alone_row.feature')
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
- if source_text
32
- parsed_rule_data = parse_source(source_text)
33
- populate_rule(self, parsed_rule_data)
34
- end
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 has_background?
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" + 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?
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::parse_text(source_text, 'cuke_modeler_stand_alone_rule.feature')
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
- if source_text
29
- parsed_scenario_data = parse_source(source_text)
30
- populate_scenario(self, parsed_scenario_data)
31
- end
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 ==(other_model)
36
- return false unless other_model.respond_to?(:steps)
35
+ def ==(other)
36
+ return false unless other.respond_to?(:steps)
37
37
 
38
- steps == other_model.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 + "\n" unless tags.empty?
54
+ text << "#{tag_output_string}\n" unless tags.empty?
52
55
  text << "#{@keyword}:#{name_output_string}"
53
- text << "\n" + description_output_string unless (description.nil? || description.empty?)
54
- text << "\n" unless (steps.empty? || description.nil? || description.empty?)
55
- text << "\n" + steps_output_string unless steps.empty?
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::parse_text(source_text, 'cuke_modeler_stand_alone_scenario.feature')
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
- if source_text
28
- parsed_step_data = parse_source(source_text)
29
- populate_step(self, parsed_step_data)
30
- end
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 ==(other_step)
36
- return false unless other_step.is_a?(CukeModeler::Step)
35
+ def ==(other)
36
+ return false unless other.is_a?(CukeModeler::Step)
37
37
 
38
- text_matches?(other_step) &&
39
- table_matches?(other_step) &&
40
- doc_string_matches?(other_step)
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" + block.to_s.split("\n").collect { |line| " #{line}" }.join("\n") if block
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}\n#{dialect_feature_keyword}: Fake feature to parse\n#{dialect_scenario_keyword}:\n"
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::parse_text(source_text, 'cuke_modeler_stand_alone_step.feature')
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 (!block.is_a?(CukeModeler::Table) || !other_step.block.is_a?(CukeModeler::Table)) && (block.is_a?(CukeModeler::Table) || other_step.block.is_a?(CukeModeler::Table))
76
- return true unless block.is_a?(CukeModeler::Table) && other_step.block.is_a?(CukeModeler::Table)
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 = block.rows.collect { |table_row| table_row.cells.map(&:value) }
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 (!block.is_a?(CukeModeler::DocString) || !other_step.block.is_a?(CukeModeler::DocString)) && (block.is_a?(CukeModeler::DocString) || other_step.block.is_a?(CukeModeler::DocString))
86
- return true unless block.is_a?(CukeModeler::DocString) && other_step.block.is_a?(CukeModeler::DocString)
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
- (first_content_type == second_content_type)
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
- if source_text
24
- parsed_table_data = parse_source(source_text)
25
- populate_table(self, parsed_table_data)
26
- end
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}\n#{dialect_feature_keyword}:\n#{dialect_scenario_keyword}:\n#{dialect_step_keyword} step\n"
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::parse_text(source_text, 'cuke_modeler_stand_alone_table.feature')
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