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