cuke_modeler 0.4.1 → 1.0.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 (252) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +17 -17
  3. data/.travis.yml +1 -1
  4. data/Gemfile +4 -0
  5. data/History.rdoc +71 -3
  6. data/LICENSE.txt +22 -22
  7. data/README.md +24 -10
  8. data/Rakefile +2 -12
  9. data/cuke_modeler.gemspec +1 -1
  10. data/features/analysis/test_comparison.feature +37 -122
  11. data/features/modeling/background_modeling.feature +77 -0
  12. data/features/modeling/background_output.feature +42 -0
  13. data/features/modeling/cell_modeling.feature +23 -0
  14. data/features/modeling/cell_output.feature +22 -0
  15. data/features/modeling/directory_modeling.feature +65 -0
  16. data/features/modeling/directory_output.feature +12 -0
  17. data/features/modeling/doc_string_modeling.feature +61 -0
  18. data/features/modeling/doc_string_output.feature +32 -0
  19. data/features/modeling/example_modeling.feature +125 -0
  20. data/features/modeling/example_output.feature +39 -0
  21. data/features/modeling/feature_file_modeling.feature +40 -0
  22. data/features/modeling/feature_file_output.feature +12 -0
  23. data/features/modeling/feature_modeling.feature +109 -0
  24. data/features/modeling/feature_output.feature +104 -0
  25. data/features/modeling/model_output.feature +22 -0
  26. data/features/modeling/model_structure.feature +48 -0
  27. data/features/modeling/outline_modeling.feature +144 -0
  28. data/features/modeling/outline_output.feature +69 -0
  29. data/features/modeling/row_modeling.feature +48 -0
  30. data/features/modeling/row_output.feature +22 -0
  31. data/features/modeling/scenario_modeling.feature +118 -0
  32. data/features/modeling/scenario_output.feature +45 -0
  33. data/features/modeling/step_modeling.feature +84 -0
  34. data/features/modeling/step_output.feature +29 -0
  35. data/features/modeling/table_modeling.feature +50 -0
  36. data/features/modeling/table_output.feature +24 -0
  37. data/features/modeling/tag_modeling.feature +43 -0
  38. data/features/modeling/tag_output.feature +22 -0
  39. data/features/step_definitions/action_steps.rb +11 -1
  40. data/features/step_definitions/background_steps.rb +1 -85
  41. data/features/step_definitions/directory_steps.rb +2 -48
  42. data/features/step_definitions/doc_string_steps.rb +1 -67
  43. data/features/step_definitions/feature_file_steps.rb +2 -37
  44. data/features/step_definitions/feature_steps.rb +4 -100
  45. data/features/step_definitions/modeling_steps.rb +44 -0
  46. data/features/step_definitions/setup_steps.rb +19 -41
  47. data/features/step_definitions/step_steps.rb +2 -166
  48. data/features/step_definitions/table_steps.rb +1 -58
  49. data/features/step_definitions/tag_steps.rb +2 -72
  50. data/features/step_definitions/verification_steps.rb +152 -4
  51. data/features/support/env.rb +4 -6
  52. data/gemfiles/{gherkin.gemfile → gherkin2.gemfile} +4 -0
  53. data/gemfiles/gherkin3.gemfile +4 -0
  54. data/gemfiles/gherkin4.gemfile +4 -0
  55. data/lib/cuke_modeler.rb +24 -22
  56. data/lib/cuke_modeler/adapters/gherkin_2_adapter.rb +103 -31
  57. data/lib/cuke_modeler/adapters/gherkin_3_adapter.rb +103 -40
  58. data/lib/cuke_modeler/adapters/gherkin_4_adapter.rb +111 -50
  59. data/lib/cuke_modeler/containing.rb +255 -4
  60. data/lib/cuke_modeler/described.rb +28 -0
  61. data/lib/cuke_modeler/models/background.rb +66 -0
  62. data/lib/cuke_modeler/models/cell.rb +48 -0
  63. data/lib/cuke_modeler/models/directory.rb +95 -0
  64. data/lib/cuke_modeler/models/doc_string.rb +59 -0
  65. data/lib/cuke_modeler/models/example.rb +167 -0
  66. data/lib/cuke_modeler/models/feature.rb +106 -0
  67. data/lib/cuke_modeler/models/feature_file.rb +64 -0
  68. data/lib/cuke_modeler/models/model.rb +32 -0
  69. data/lib/cuke_modeler/models/outline.rb +79 -0
  70. data/lib/cuke_modeler/models/row.rb +49 -0
  71. data/lib/cuke_modeler/models/scenario.rb +69 -0
  72. data/lib/cuke_modeler/models/step.rb +68 -0
  73. data/lib/cuke_modeler/models/table.rb +67 -0
  74. data/lib/cuke_modeler/models/tag.rb +46 -0
  75. data/lib/cuke_modeler/named.rb +19 -0
  76. data/lib/cuke_modeler/nested.rb +22 -15
  77. data/lib/cuke_modeler/parsed.rb +11 -0
  78. data/lib/cuke_modeler/parsing.rb +66 -83
  79. data/lib/cuke_modeler/sourceable.rb +3 -11
  80. data/lib/cuke_modeler/stepped.rb +24 -0
  81. data/lib/cuke_modeler/taggable.rb +6 -29
  82. data/lib/cuke_modeler/version.rb +2 -1
  83. data/spec/integration/background_integration_spec.rb +332 -7
  84. data/spec/integration/cell_integration_spec.rb +321 -0
  85. data/spec/integration/directory_integration_spec.rb +175 -9
  86. data/spec/integration/doc_string_integration_spec.rb +318 -7
  87. data/spec/integration/example_integration_spec.rb +602 -19
  88. data/spec/integration/feature_file_integration_spec.rb +98 -3
  89. data/spec/integration/feature_integration_spec.rb +445 -27
  90. data/spec/integration/gherkin_2_adapter_spec.rb +122 -0
  91. data/spec/integration/gherkin_3_adapter_spec.rb +125 -0
  92. data/spec/integration/gherkin_4_adapter_spec.rb +123 -0
  93. data/spec/integration/model_integration_spec.rb +15 -0
  94. data/spec/integration/nested_integration_spec.rb +91 -0
  95. data/spec/integration/outline_integration_spec.rb +485 -12
  96. data/spec/integration/parsing_integration_spec.rb +85 -0
  97. data/spec/integration/row_integration_spec.rb +221 -18
  98. data/spec/integration/scenario_integration_spec.rb +368 -14
  99. data/spec/integration/shared/models_integration_specs.rb +18 -0
  100. data/spec/integration/step_integration_spec.rb +328 -77
  101. data/spec/integration/table_integration_spec.rb +242 -20
  102. data/spec/integration/tag_integration_spec.rb +178 -13
  103. data/spec/spec_helper.rb +32 -18
  104. data/spec/unit/background_unit_spec.rb +24 -44
  105. data/spec/unit/cell_unit_spec.rb +73 -0
  106. data/spec/unit/described_unit_spec.rb +23 -0
  107. data/spec/unit/directory_unit_spec.rb +52 -62
  108. data/spec/unit/doc_string_unit_spec.rb +47 -100
  109. data/spec/unit/example_unit_spec.rb +50 -296
  110. data/spec/unit/feature_file_unit_spec.rb +53 -52
  111. data/spec/unit/feature_unit_spec.rb +39 -83
  112. data/spec/unit/model_unit_spec.rb +15 -0
  113. data/spec/unit/named_unit_spec.rb +23 -0
  114. data/spec/unit/nested_unit_spec.rb +24 -21
  115. data/spec/unit/outline_unit_spec.rb +46 -69
  116. data/spec/unit/parsed_unit_spec.rb +27 -0
  117. data/spec/unit/parsing_unit_spec.rb +2 -70
  118. data/spec/unit/row_unit_spec.rb +22 -51
  119. data/spec/unit/scenario_unit_spec.rb +27 -59
  120. data/spec/unit/{bare_bones_unit_specs.rb → shared/bare_bones_models_unit_specs.rb} +2 -2
  121. data/spec/unit/shared/containing_models_unit_specs.rb +18 -0
  122. data/spec/unit/shared/described_models_unit_specs.rb +38 -0
  123. data/spec/unit/shared/models_unit_specs.rb +15 -0
  124. data/spec/unit/shared/named_models_unit_specs.rb +39 -0
  125. data/spec/unit/shared/nested_models_unit_specs.rb +51 -0
  126. data/spec/unit/shared/parsed_models_unit_specs.rb +39 -0
  127. data/spec/unit/shared/prepopulated_models_unit_specs.rb +18 -0
  128. data/spec/unit/shared/sourced_models_unit_specs.rb +39 -0
  129. data/spec/unit/shared/stepped_models_unit_specs.rb +46 -0
  130. data/spec/unit/shared/stringifiable_models_unit_specs.rb +18 -0
  131. data/spec/unit/shared/tagged_models_unit_specs.rb +72 -0
  132. data/spec/unit/sourceable_unit_spec.rb +12 -4
  133. data/spec/unit/step_unit_spec.rb +40 -231
  134. data/spec/unit/stepped_unit_spec.rb +23 -0
  135. data/spec/unit/table_unit_spec.rb +27 -89
  136. data/spec/unit/tag_unit_spec.rb +30 -53
  137. data/spec/unit/taggable_unit_spec.rb +26 -42
  138. data/todo.txt +32 -0
  139. metadata +135 -217
  140. data/features/analysis/test_manipulation.feature +0 -37
  141. data/features/modeling/gherkin/background_modeling.feature +0 -65
  142. data/features/modeling/gherkin/background_output.feature +0 -131
  143. data/features/modeling/gherkin/directory_modeling.feature +0 -110
  144. data/features/modeling/gherkin/directory_output.feature +0 -14
  145. data/features/modeling/gherkin/doc_string_modeling.feature +0 -53
  146. data/features/modeling/gherkin/doc_string_output.feature +0 -72
  147. data/features/modeling/gherkin/example_modeling.feature +0 -101
  148. data/features/modeling/gherkin/example_output.feature +0 -193
  149. data/features/modeling/gherkin/feature_file_modeling.feature +0 -54
  150. data/features/modeling/gherkin/feature_file_output.feature +0 -14
  151. data/features/modeling/gherkin/feature_modeling.feature +0 -154
  152. data/features/modeling/gherkin/feature_output.feature +0 -245
  153. data/features/modeling/gherkin/outline_modeling.feature +0 -90
  154. data/features/modeling/gherkin/outline_output.feature +0 -198
  155. data/features/modeling/gherkin/row_modeling.feature +0 -68
  156. data/features/modeling/gherkin/row_output.feature +0 -28
  157. data/features/modeling/gherkin/scenario_modeling.feature +0 -79
  158. data/features/modeling/gherkin/scenario_output.feature +0 -148
  159. data/features/modeling/gherkin/step_modeling.feature +0 -75
  160. data/features/modeling/gherkin/step_output.feature +0 -53
  161. data/features/modeling/gherkin/table_modeling.feature +0 -42
  162. data/features/modeling/gherkin/table_output.feature +0 -43
  163. data/features/modeling/gherkin/table_row_modeling.feature +0 -57
  164. data/features/modeling/gherkin/table_row_output.feature +0 -28
  165. data/features/modeling/gherkin/tag_modeling.feature +0 -48
  166. data/features/modeling/gherkin/tag_output.feature +0 -17
  167. data/features/modeling/gherkin3/background_modeling.feature +0 -64
  168. data/features/modeling/gherkin3/background_output.feature +0 -131
  169. data/features/modeling/gherkin3/directory_modeling.feature +0 -110
  170. data/features/modeling/gherkin3/directory_output.feature +0 -14
  171. data/features/modeling/gherkin3/doc_string_modeling.feature +0 -53
  172. data/features/modeling/gherkin3/doc_string_output.feature +0 -72
  173. data/features/modeling/gherkin3/example_modeling.feature +0 -100
  174. data/features/modeling/gherkin3/example_output.feature +0 -207
  175. data/features/modeling/gherkin3/feature_file_modeling.feature +0 -54
  176. data/features/modeling/gherkin3/feature_file_output.feature +0 -14
  177. data/features/modeling/gherkin3/feature_modeling.feature +0 -155
  178. data/features/modeling/gherkin3/feature_output.feature +0 -249
  179. data/features/modeling/gherkin3/outline_modeling.feature +0 -89
  180. data/features/modeling/gherkin3/outline_output.feature +0 -255
  181. data/features/modeling/gherkin3/row_modeling.feature +0 -68
  182. data/features/modeling/gherkin3/row_output.feature +0 -28
  183. data/features/modeling/gherkin3/scenario_modeling.feature +0 -78
  184. data/features/modeling/gherkin3/scenario_output.feature +0 -148
  185. data/features/modeling/gherkin3/step_modeling.feature +0 -75
  186. data/features/modeling/gherkin3/step_output.feature +0 -53
  187. data/features/modeling/gherkin3/table_modeling.feature +0 -42
  188. data/features/modeling/gherkin3/table_output.feature +0 -43
  189. data/features/modeling/gherkin3/table_row_modeling.feature +0 -57
  190. data/features/modeling/gherkin3/table_row_output.feature +0 -28
  191. data/features/modeling/gherkin3/tag_modeling.feature +0 -49
  192. data/features/modeling/gherkin3/tag_output.feature +0 -17
  193. data/features/modeling/gherkin4/background_modeling.feature +0 -64
  194. data/features/modeling/gherkin4/background_output.feature +0 -131
  195. data/features/modeling/gherkin4/directory_modeling.feature +0 -110
  196. data/features/modeling/gherkin4/directory_output.feature +0 -14
  197. data/features/modeling/gherkin4/doc_string_modeling.feature +0 -53
  198. data/features/modeling/gherkin4/doc_string_output.feature +0 -72
  199. data/features/modeling/gherkin4/example_modeling.feature +0 -100
  200. data/features/modeling/gherkin4/example_output.feature +0 -193
  201. data/features/modeling/gherkin4/feature_file_modeling.feature +0 -54
  202. data/features/modeling/gherkin4/feature_file_output.feature +0 -14
  203. data/features/modeling/gherkin4/feature_modeling.feature +0 -153
  204. data/features/modeling/gherkin4/feature_output.feature +0 -245
  205. data/features/modeling/gherkin4/outline_modeling.feature +0 -89
  206. data/features/modeling/gherkin4/outline_output.feature +0 -198
  207. data/features/modeling/gherkin4/row_modeling.feature +0 -68
  208. data/features/modeling/gherkin4/row_output.feature +0 -28
  209. data/features/modeling/gherkin4/scenario_modeling.feature +0 -78
  210. data/features/modeling/gherkin4/scenario_output.feature +0 -148
  211. data/features/modeling/gherkin4/step_modeling.feature +0 -75
  212. data/features/modeling/gherkin4/step_output.feature +0 -53
  213. data/features/modeling/gherkin4/table_modeling.feature +0 -42
  214. data/features/modeling/gherkin4/table_output.feature +0 -43
  215. data/features/modeling/gherkin4/table_row_modeling.feature +0 -57
  216. data/features/modeling/gherkin4/table_row_output.feature +0 -28
  217. data/features/modeling/gherkin4/tag_modeling.feature +0 -48
  218. data/features/modeling/gherkin4/tag_output.feature +0 -17
  219. data/features/step_definitions/outline_steps.rb +0 -258
  220. data/features/step_definitions/test_steps.rb +0 -123
  221. data/lib/cuke_modeler/background.rb +0 -38
  222. data/lib/cuke_modeler/directory.rb +0 -83
  223. data/lib/cuke_modeler/doc_string.rb +0 -87
  224. data/lib/cuke_modeler/example.rb +0 -195
  225. data/lib/cuke_modeler/feature.rb +0 -147
  226. data/lib/cuke_modeler/feature_element.rb +0 -73
  227. data/lib/cuke_modeler/feature_file.rb +0 -77
  228. data/lib/cuke_modeler/outline.rb +0 -68
  229. data/lib/cuke_modeler/raw.rb +0 -20
  230. data/lib/cuke_modeler/row.rb +0 -64
  231. data/lib/cuke_modeler/scenario.rb +0 -45
  232. data/lib/cuke_modeler/step.rb +0 -216
  233. data/lib/cuke_modeler/table.rb +0 -90
  234. data/lib/cuke_modeler/table_row.rb +0 -64
  235. data/lib/cuke_modeler/tag.rb +0 -62
  236. data/lib/cuke_modeler/test_element.rb +0 -79
  237. data/lib/cuke_modeler/world.rb +0 -113
  238. data/spec/integration/table_row_integration_spec.rb +0 -76
  239. data/spec/integration/world_integration_spec.rb +0 -14
  240. data/spec/unit/containing_element_unit_specs.rb +0 -18
  241. data/spec/unit/feature_element_unit_spec.rb +0 -19
  242. data/spec/unit/feature_element_unit_specs.rb +0 -52
  243. data/spec/unit/nested_element_unit_specs.rb +0 -39
  244. data/spec/unit/prepopulated_unit_specs.rb +0 -14
  245. data/spec/unit/raw_element_unit_specs.rb +0 -27
  246. data/spec/unit/raw_unit_spec.rb +0 -28
  247. data/spec/unit/sourced_element_unit_specs.rb +0 -18
  248. data/spec/unit/table_row_unit_spec.rb +0 -102
  249. data/spec/unit/tagged_element_unit_specs.rb +0 -67
  250. data/spec/unit/test_element_unit_spec.rb +0 -54
  251. data/spec/unit/test_element_unit_specs.rb +0 -34
  252. data/spec/unit/world_unit_spec.rb +0 -140
@@ -0,0 +1,28 @@
1
+ module CukeModeler
2
+
3
+ # A mix-in module containing methods used by models that represent an element that has a description.
4
+
5
+ module Described
6
+
7
+ # The description of the element
8
+ attr_accessor :description
9
+
10
+
11
+ private
12
+
13
+
14
+ def description_output_string
15
+ text = ''
16
+
17
+ unless description.empty?
18
+ description_lines = description.split("\n")
19
+
20
+ text << "\n" if description_lines.first =~ /\S/
21
+ text << description_lines.collect { |line| "#{line}" }.join("\n")
22
+ end
23
+
24
+ text
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,66 @@
1
+ module CukeModeler
2
+
3
+ # A class modeling a feature's background.
4
+
5
+ class Background < Model
6
+
7
+ include Parsed
8
+ include Named
9
+ include Described
10
+ include Stepped
11
+ include Sourceable
12
+
13
+
14
+ # Creates a new Background object and, if *source_text* is provided, populates
15
+ # the object.
16
+ def initialize(source_text = nil)
17
+ @steps = []
18
+
19
+ super(source_text)
20
+
21
+ if source_text
22
+ parsed_background_data = parse_source(source_text)
23
+ populate_background(self, parsed_background_data)
24
+ end
25
+ end
26
+
27
+ # Returns *true* if the two models have equivalent steps and *false* otherwise.
28
+ def ==(other_model)
29
+ return false unless other_model.respond_to?(:steps)
30
+
31
+ steps == other_model.steps
32
+ end
33
+
34
+ # Returns the model objects that belong to this model.
35
+ def children
36
+ steps
37
+ end
38
+
39
+ # Returns a string representation of this model. For a background model,
40
+ # this will be Gherkin text that is equivalent to the background being modeled.
41
+ def to_s
42
+ text = ''
43
+
44
+ text << "Background:#{name_output_string}"
45
+ text << "\n" + description_output_string unless (description.nil? || description.empty?)
46
+ text << "\n" unless (steps.empty? || description.nil? || description.empty?)
47
+ text << "\n" + steps_output_string unless steps.empty?
48
+
49
+ text
50
+ end
51
+
52
+
53
+ private
54
+
55
+
56
+ def parse_source(source_text)
57
+ base_file_string = "Feature: Fake feature to parse\n"
58
+ source_text = base_file_string + source_text
59
+
60
+ parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_background.feature')
61
+
62
+ parsed_file.first['elements'].first
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,48 @@
1
+ module CukeModeler
2
+
3
+ # A class modeling a single cell of a row.
4
+
5
+ class Cell < Model
6
+
7
+ include Sourceable
8
+ include Parsed
9
+
10
+
11
+ # The value of the cell
12
+ attr_accessor :value
13
+
14
+
15
+ # Creates a new Cell object and, if *source_text* is provided, populates
16
+ # the object.
17
+ def initialize(source_text = nil)
18
+ super(source_text)
19
+
20
+ if source_text
21
+ parsed_cell_data = parse_source(source_text)
22
+ populate_cell(self, parsed_cell_data)
23
+ end
24
+ end
25
+
26
+ # Returns a string representation of this model. For a cell model,
27
+ # this will be Gherkin text that is equivalent to the cell being modeled.
28
+ def to_s
29
+ # Vertical bars and backslashes are special characters that need to be escaped
30
+ @value ? @value.gsub('\\', '\\\\\\').gsub('|', '\|') : ''
31
+ end
32
+
33
+
34
+ private
35
+
36
+
37
+ def parse_source(source_text)
38
+ base_file_string = "Feature: Fake feature to parse\nScenario:\n* fake step\n"
39
+ source_text = base_file_string + '|' + source_text + '|'
40
+
41
+ parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_cell.feature')
42
+
43
+ parsed_file.first['elements'].first['steps'].first['table']['rows'].first['cells'].first
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,95 @@
1
+ module CukeModeler
2
+
3
+ # A class modeling a directory in a Cucumber suite.
4
+
5
+ class Directory < Model
6
+
7
+
8
+ # The feature file models contained by the modeled directory
9
+ attr_accessor :feature_files
10
+
11
+ # The directory models contained by the modeled directory
12
+ attr_accessor :directories
13
+
14
+ # The file path of the modeled directory
15
+ attr_accessor :path
16
+
17
+
18
+ # Creates a new Directory object and, if *directory_path* is provided,
19
+ # populates the object.
20
+ def initialize(directory_path = nil)
21
+ @path = directory_path
22
+ @feature_files = []
23
+ @directories = []
24
+
25
+ super(directory_path)
26
+
27
+ if directory_path
28
+ raise(ArgumentError, "Unknown directory: #{directory_path.inspect}") unless File.exists?(directory_path)
29
+
30
+ processed_directory_data = process_directory(directory_path)
31
+ populate_directory(self, processed_directory_data)
32
+ end
33
+ end
34
+
35
+ # Returns the name of the modeled directory.
36
+ def name
37
+ File.basename(@path.gsub('\\', '/')) if @path
38
+ end
39
+
40
+ # Returns the model objects that belong to this model.
41
+ def children
42
+ @feature_files + @directories
43
+ end
44
+
45
+ # Returns a string representation of this model. For a directory
46
+ # model, this will be the path of the modeled directory.
47
+ def to_s
48
+ path.to_s
49
+ end
50
+
51
+
52
+ private
53
+
54
+
55
+ def process_directory(directory_path)
56
+ directory_data = {'path' => directory_path,
57
+ 'directories' => [],
58
+ 'feature_files' => []
59
+ }
60
+
61
+ entries = Dir.entries(directory_path)
62
+ entries.delete '.'
63
+ entries.delete '..'
64
+
65
+ entries.each do |entry|
66
+ entry = "#{directory_path}/#{entry}"
67
+
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
75
+ end
76
+ end
77
+
78
+
79
+ directory_data
80
+ end
81
+
82
+ def process_feature_file(file_path)
83
+ feature_file_data = {'path' => file_path}
84
+
85
+ source_text = IO.read(file_path)
86
+ feature = Parsing::parse_text(source_text, file_path).first
87
+
88
+ feature_file_data['feature'] = feature
89
+
90
+
91
+ feature_file_data
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,59 @@
1
+ module CukeModeler
2
+
3
+ # A class modeling a step's doc string.
4
+
5
+ class DocString < Model
6
+
7
+ include Parsed
8
+ include Sourceable
9
+
10
+
11
+ # The content type associated with the doc string
12
+ attr_accessor :content_type
13
+
14
+ # The content of the doc string
15
+ attr_accessor :content
16
+
17
+
18
+ # Creates a new DocString object and, if *source_text* is provided, populates
19
+ # the object.
20
+ def initialize(source_text = nil)
21
+ super(source_text)
22
+
23
+ if source_text
24
+ parsed_doc_string_data = parse_source(source_text)
25
+ populate_docstring(self, parsed_doc_string_data)
26
+ end
27
+ end
28
+
29
+ # Returns a string representation of this model. For a doc string model,
30
+ # this will be Gherkin text that is equivalent to the doc string being modeled.
31
+ def to_s
32
+ text = "\"\"\"#{content_type_output_string}\n"
33
+ text << content_output_string
34
+ text << '"""'
35
+ end
36
+
37
+
38
+ private
39
+
40
+
41
+ def parse_source(source_text)
42
+ base_file_string = "Feature:\nScenario:\n* step\n"
43
+ source_text = base_file_string + source_text
44
+
45
+ parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_doc_string.feature')
46
+
47
+ parsed_file.first['elements'].first['steps'].first['doc_string']
48
+ end
49
+
50
+ def content_type_output_string
51
+ content_type ? " #{content_type}" : ''
52
+ end
53
+
54
+ def content_output_string
55
+ (content.nil? || content.empty?) ? '' : content.gsub('"""', '\"\"\"') + "\n"
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,167 @@
1
+ module CukeModeler
2
+
3
+ # A class modeling an example table of an outline.
4
+
5
+ class Example < Model
6
+
7
+ include Parsed
8
+ include Named
9
+ include Described
10
+ include Sourceable
11
+ include Taggable
12
+
13
+
14
+ # The row models in the example table
15
+ attr_accessor :rows
16
+
17
+
18
+ # Creates a new Example object and, if *source_text* is provided,
19
+ # populates the object.
20
+ def initialize(source_text = nil)
21
+ @tags = []
22
+ @rows = []
23
+
24
+ super(source_text)
25
+
26
+ if source_text
27
+ parsed_example_data = parse_source(source_text)
28
+ populate_example(self, parsed_example_data)
29
+ end
30
+ end
31
+
32
+ # Adds a row to the example table. The row can be given as a Hash of
33
+ # parameters and their corresponding values or as an Array of values which
34
+ # will be assigned in order.
35
+ def add_row(row)
36
+ raise('Cannot add a row. No parameters have been set.') if rows.empty?
37
+
38
+ # A quick 'deep clone' so that the input isn't modified
39
+ row = Marshal::load(Marshal.dump(row))
40
+
41
+ case
42
+ when row.is_a?(Array)
43
+ # 'stringify' input
44
+ row.collect! { |value| value.to_s }
45
+
46
+ @rows << Row.new("|#{row.join('|')}|")
47
+ when row.is_a?(Hash)
48
+ # 'stringify' input
49
+ row = row.inject({}) { |hash, (key, value)| hash[key.to_s] = value.to_s; hash }
50
+
51
+ @rows << Row.new("|#{ordered_row_values(row).join('|')}|")
52
+ else
53
+ raise(ArgumentError, "Can only add row from a Hash or an Array but received #{row.class}")
54
+ end
55
+ end
56
+
57
+ # Removes a row from the example table. The row can be given as a Hash of
58
+ # parameters and their corresponding values or as an Array of values
59
+ # which will be assigned in order.
60
+ def remove_row(row_removed)
61
+ return unless argument_rows
62
+
63
+ case
64
+ when row_removed.is_a?(Array)
65
+ location = argument_rows.index { |row| row.cells.collect { |cell| cell.value } == row_removed.collect { |value| value.strip } }
66
+ when row_removed.is_a?(Hash)
67
+ # Note: the hash value order has to be manually calculated because Ruby 1.8.7 does not have ordered
68
+ # hash keys. Alternatively, the hash may have simply been built up 'willy nilly' by the user instead
69
+ # of being built up in order according to the parameter order.
70
+ location = argument_rows.index { |row| row.cells.collect { |cell| cell.value } == ordered_row_values(row_removed.each_value { |value| value.strip! }) }
71
+ else
72
+ raise(ArgumentError, "Can only remove row from a Hash or an Array but received #{row_removed.class}")
73
+ end
74
+
75
+ @rows.delete_at(location + 1) if location
76
+ end
77
+
78
+ # The argument rows in the example table
79
+ def argument_rows
80
+ rows[1..rows.count] || []
81
+ end
82
+
83
+ # The parameter row for the example table
84
+ def parameter_row
85
+ rows.first
86
+ end
87
+
88
+ # Returns the parameters of the example table
89
+ def parameters
90
+ parameter_row ? parameter_row.cells.collect { |cell| cell.value } : []
91
+ end
92
+
93
+ # Returns the model objects that belong to this model.
94
+ def children
95
+ rows + tags
96
+ end
97
+
98
+ # Returns a string representation of this model. For an example model,
99
+ # this will be Gherkin text that is equivalent to the example being modeled.
100
+ def to_s
101
+ text = ''
102
+
103
+ text << tag_output_string + "\n" unless tags.empty?
104
+ text << "Examples:#{name_output_string}"
105
+ text << "\n" + description_output_string unless (description.nil? || description.empty?)
106
+ text << "\n" unless (description.nil? || description.empty?)
107
+ text << "\n" + parameters_output_string
108
+ text << "\n" + rows_output_string unless argument_rows.empty?
109
+
110
+ text
111
+ end
112
+
113
+
114
+ private
115
+
116
+
117
+ def parse_source(source_text)
118
+ base_file_string = "Feature: Fake feature to parse\nScenario Outline:\n* fake step\n"
119
+ source_text = base_file_string + source_text
120
+
121
+ parsed_file = Parsing::parse_text(source_text, 'cuke_modeler_stand_alone_example.feature')
122
+
123
+ parsed_file.first['elements'].first['examples'].first
124
+ end
125
+
126
+ def determine_buffer_size(index)
127
+ rows.collect { |row| row.cells[index].to_s.length }.max || 0
128
+ end
129
+
130
+ def parameters_output_string
131
+ text = ''
132
+
133
+ unless parameter_row.nil?
134
+ text << " |"
135
+ parameter_row.cells.count.times { |index| text << " #{string_for(parameter_row.cells, index)} |" }
136
+ end
137
+
138
+ text
139
+ end
140
+
141
+ def rows_output_string
142
+ text = ''
143
+
144
+ unless argument_rows.empty?
145
+
146
+ argument_rows.each do |row|
147
+ text << " |"
148
+ row.cells.count.times { |index| text << " #{string_for(row.cells, index)} |" }
149
+ text << "\n"
150
+ end
151
+
152
+ text.chomp!
153
+ end
154
+
155
+ text
156
+ end
157
+
158
+ def string_for(cells, index)
159
+ cells[index] ? cells[index].to_s.ljust(determine_buffer_size(index)) : ''
160
+ end
161
+
162
+ def ordered_row_values(row_hash)
163
+ parameter_row.cells.collect { |cell| cell.value }.collect { |parameter| row_hash[parameter] }
164
+ end
165
+
166
+ end
167
+ end