cuke_modeler 0.4.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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