rspec 1.0.8 → 1.1.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 (301) hide show
  1. data/CHANGES +122 -2
  2. data/README +10 -9
  3. data/Rakefile +22 -49
  4. data/TODO +2 -0
  5. data/bin/spec +1 -1
  6. data/bin/spec_translator +8 -8
  7. data/examples/{auto_spec_description_example.rb → pure/autogenerated_docstrings_example.rb} +0 -0
  8. data/examples/{before_and_after_example.rb → pure/before_and_after_example.rb} +1 -0
  9. data/examples/{behave_as_example.rb → pure/behave_as_example.rb} +0 -0
  10. data/examples/{custom_expectation_matchers.rb → pure/custom_expectation_matchers.rb} +0 -0
  11. data/examples/{custom_formatter.rb → pure/custom_formatter.rb} +1 -0
  12. data/examples/{dynamic_spec.rb → pure/dynamic_spec.rb} +0 -0
  13. data/examples/{file_accessor.rb → pure/file_accessor.rb} +1 -0
  14. data/examples/{file_accessor_spec.rb → pure/file_accessor_spec.rb} +0 -0
  15. data/examples/{greeter_spec.rb → pure/greeter_spec.rb} +1 -0
  16. data/examples/{helper_method_example.rb → pure/helper_method_example.rb} +0 -0
  17. data/examples/{io_processor.rb → pure/io_processor.rb} +0 -0
  18. data/examples/{io_processor_spec.rb → pure/io_processor_spec.rb} +0 -0
  19. data/examples/{legacy_spec.rb → pure/legacy_spec.rb} +1 -0
  20. data/examples/{mocking_example.rb → pure/mocking_example.rb} +0 -0
  21. data/examples/pure/multi_threaded_behaviour_runner.rb +28 -0
  22. data/examples/pure/nested_classes_example.rb +36 -0
  23. data/examples/{partial_mock_example.rb → pure/partial_mock_example.rb} +0 -0
  24. data/examples/{pending_example.rb → pure/pending_example.rb} +0 -0
  25. data/examples/{predicate_example.rb → pure/predicate_example.rb} +0 -0
  26. data/examples/{priority.txt → pure/priority.txt} +0 -0
  27. data/examples/pure/shared_example_group_example.rb +66 -0
  28. data/examples/pure/shared_stack_examples.rb +38 -0
  29. data/examples/pure/spec_helper.rb +3 -0
  30. data/examples/{stack.rb → pure/stack.rb} +0 -0
  31. data/examples/{stack_spec.rb → pure/stack_spec.rb} +1 -35
  32. data/examples/pure/stack_spec_with_nested_example_groups.rb +67 -0
  33. data/examples/{stubbing_example.rb → pure/stubbing_example.rb} +0 -0
  34. data/examples/stories/adder.rb +13 -0
  35. data/examples/stories/addition +34 -0
  36. data/examples/stories/addition.rb +9 -0
  37. data/examples/stories/calculator.rb +65 -0
  38. data/examples/stories/game-of-life/README.txt +21 -0
  39. data/examples/stories/game-of-life/behaviour/everything.rb +6 -0
  40. data/examples/stories/game-of-life/behaviour/examples/examples.rb +3 -0
  41. data/examples/stories/game-of-life/behaviour/examples/game_behaviour.rb +35 -0
  42. data/examples/stories/game-of-life/behaviour/examples/grid_behaviour.rb +66 -0
  43. data/examples/stories/game-of-life/behaviour/stories/CellsWithLessThanTwoNeighboursDie.story +21 -0
  44. data/examples/stories/game-of-life/behaviour/stories/CellsWithMoreThanThreeNeighboursDie.story +21 -0
  45. data/examples/stories/game-of-life/behaviour/stories/EmptySpacesWithThreeNeighboursCreateACell.story +42 -0
  46. data/examples/stories/game-of-life/behaviour/stories/ICanCreateACell.story +42 -0
  47. data/examples/stories/game-of-life/behaviour/stories/ICanKillACell.story +17 -0
  48. data/examples/stories/game-of-life/behaviour/stories/TheGridWraps.story +53 -0
  49. data/examples/stories/game-of-life/behaviour/stories/create_a_cell.rb +52 -0
  50. data/examples/stories/game-of-life/behaviour/stories/helper.rb +6 -0
  51. data/examples/stories/game-of-life/behaviour/stories/kill_a_cell.rb +26 -0
  52. data/examples/stories/game-of-life/behaviour/stories/steps.rb +5 -0
  53. data/examples/stories/game-of-life/behaviour/stories/stories.rb +3 -0
  54. data/examples/stories/game-of-life/behaviour/stories/stories.txt +22 -0
  55. data/examples/stories/game-of-life/life.rb +3 -0
  56. data/examples/stories/game-of-life/life/game.rb +23 -0
  57. data/examples/stories/game-of-life/life/grid.rb +43 -0
  58. data/examples/stories/helper.rb +9 -0
  59. data/examples/stories/steps/addition_steps.rb +18 -0
  60. data/lib/autotest/rspec.rb +1 -2
  61. data/lib/spec.rb +30 -6
  62. data/lib/spec/example.rb +12 -0
  63. data/lib/spec/{dsl → example}/configuration.rb +48 -39
  64. data/lib/spec/{dsl → example}/errors.rb +2 -2
  65. data/lib/spec/example/example_group.rb +16 -0
  66. data/lib/spec/example/example_group_factory.rb +62 -0
  67. data/lib/spec/example/example_group_methods.rb +412 -0
  68. data/lib/spec/example/example_matcher.rb +42 -0
  69. data/lib/spec/example/example_methods.rb +101 -0
  70. data/lib/spec/example/module_reopening_fix.rb +21 -0
  71. data/lib/spec/example/pending.rb +18 -0
  72. data/lib/spec/example/shared_example_group.rb +58 -0
  73. data/lib/spec/expectations/differs/default.rb +15 -10
  74. data/lib/spec/expectations/errors.rb +7 -1
  75. data/lib/spec/expectations/extensions/object.rb +12 -7
  76. data/lib/spec/expectations/handler.rb +13 -4
  77. data/lib/spec/extensions.rb +2 -0
  78. data/lib/spec/extensions/class.rb +24 -0
  79. data/lib/spec/extensions/main.rb +54 -0
  80. data/lib/spec/extensions/object.rb +5 -1
  81. data/lib/spec/interop/test.rb +10 -0
  82. data/lib/spec/interop/test/unit/autorunner.rb +6 -0
  83. data/lib/spec/interop/test/unit/testcase.rb +61 -0
  84. data/lib/spec/interop/test/unit/testresult.rb +6 -0
  85. data/lib/spec/interop/test/unit/testsuite_adapter.rb +34 -0
  86. data/lib/spec/interop/test/unit/ui/console/testrunner.rb +60 -0
  87. data/lib/spec/matchers.rb +11 -15
  88. data/lib/spec/matchers/be.rb +23 -6
  89. data/lib/spec/matchers/change.rb +25 -1
  90. data/lib/spec/matchers/exist.rb +17 -0
  91. data/lib/spec/matchers/operator_matcher.rb +1 -0
  92. data/lib/spec/matchers/simple_matcher.rb +29 -0
  93. data/lib/spec/matchers/throw_symbol.rb +2 -0
  94. data/lib/spec/mocks.rb +5 -2
  95. data/lib/spec/mocks/argument_expectation.rb +1 -1
  96. data/lib/spec/mocks/message_expectation.rb +62 -44
  97. data/lib/spec/mocks/methods.rb +2 -2
  98. data/lib/spec/mocks/mock.rb +24 -3
  99. data/lib/spec/mocks/proxy.rb +26 -23
  100. data/lib/spec/mocks/space.rb +1 -1
  101. data/lib/spec/mocks/spec_methods.rb +20 -12
  102. data/lib/spec/rake/spectask.rb +19 -1
  103. data/lib/spec/rake/verify_rcov.rb +1 -1
  104. data/lib/spec/runner.rb +33 -10
  105. data/lib/spec/runner/backtrace_tweaker.rb +3 -3
  106. data/lib/spec/runner/class_and_arguments_parser.rb +16 -0
  107. data/lib/spec/runner/command_line.rb +18 -12
  108. data/lib/spec/runner/drb_command_line.rb +4 -5
  109. data/lib/spec/runner/example_group_runner.rb +59 -0
  110. data/lib/spec/runner/formatter/base_formatter.rb +10 -8
  111. data/lib/spec/runner/formatter/base_text_formatter.rb +18 -18
  112. data/lib/spec/runner/formatter/failing_example_groups_formatter.rb +31 -0
  113. data/lib/spec/runner/formatter/failing_examples_formatter.rb +3 -5
  114. data/lib/spec/runner/formatter/html_formatter.rb +37 -27
  115. data/lib/spec/runner/formatter/profile_formatter.rb +47 -0
  116. data/lib/spec/runner/formatter/progress_bar_formatter.rb +3 -4
  117. data/lib/spec/runner/formatter/specdoc_formatter.rb +27 -13
  118. data/lib/spec/runner/formatter/story/html_formatter.rb +124 -0
  119. data/lib/spec/runner/formatter/story/plain_text_formatter.rb +123 -0
  120. data/lib/spec/runner/formatter/text_mate_formatter.rb +16 -0
  121. data/lib/spec/runner/heckle_runner.rb +9 -9
  122. data/lib/spec/runner/option_parser.rb +140 -138
  123. data/lib/spec/runner/options.rb +168 -90
  124. data/lib/spec/runner/reporter.rb +58 -40
  125. data/lib/spec/runner/spec_parser.rb +11 -8
  126. data/lib/spec/story.rb +10 -0
  127. data/lib/spec/story/extensions.rb +1 -0
  128. data/lib/spec/story/extensions/main.rb +86 -0
  129. data/lib/spec/story/given_scenario.rb +14 -0
  130. data/lib/spec/story/runner.rb +58 -0
  131. data/lib/spec/story/runner/plain_text_story_runner.rb +48 -0
  132. data/lib/spec/story/runner/scenario_collector.rb +18 -0
  133. data/lib/spec/story/runner/scenario_runner.rb +46 -0
  134. data/lib/spec/story/runner/story_mediator.rb +123 -0
  135. data/lib/spec/story/runner/story_parser.rb +227 -0
  136. data/lib/spec/story/runner/story_runner.rb +67 -0
  137. data/lib/spec/story/scenario.rb +14 -0
  138. data/lib/spec/story/step.rb +48 -0
  139. data/lib/spec/story/step_group.rb +89 -0
  140. data/lib/spec/story/step_mother.rb +37 -0
  141. data/lib/spec/story/story.rb +42 -0
  142. data/lib/spec/story/world.rb +124 -0
  143. data/lib/spec/version.rb +4 -5
  144. data/plugins/mock_frameworks/rspec.rb +1 -1
  145. data/spec/autotest/rspec_spec.rb +13 -7
  146. data/spec/autotest_helper.rb +4 -3
  147. data/spec/rspec_suite.rb +7 -0
  148. data/spec/ruby_forker.rb +13 -0
  149. data/spec/spec/example/configuration_spec.rb +290 -0
  150. data/spec/spec/example/example_group_class_definition_spec.rb +48 -0
  151. data/spec/spec/example/example_group_factory_spec.rb +129 -0
  152. data/spec/spec/example/example_group_methods_spec.rb +465 -0
  153. data/spec/spec/example/example_group_spec.rb +711 -0
  154. data/spec/spec/{dsl → example}/example_matcher_spec.rb +23 -18
  155. data/spec/spec/example/example_methods_spec.rb +75 -0
  156. data/spec/spec/example/example_runner_spec.rb +194 -0
  157. data/spec/spec/example/example_spec.rb +53 -0
  158. data/spec/spec/example/nested_example_group_spec.rb +59 -0
  159. data/spec/spec/example/pending_module_spec.rb +31 -0
  160. data/spec/spec/{dsl → example}/predicate_matcher_spec.rb +1 -1
  161. data/spec/spec/example/shared_example_group_spec.rb +265 -0
  162. data/spec/spec/example/subclassing_example_group_spec.rb +25 -0
  163. data/spec/spec/expectations/differs/default_spec.rb +5 -3
  164. data/spec/spec/expectations/extensions/object_spec.rb +63 -2
  165. data/spec/spec/extensions/main_spec.rb +50 -0
  166. data/spec/spec/interop/test/unit/test_unit_spec_helper.rb +14 -0
  167. data/spec/spec/interop/test/unit/testcase_spec.rb +10 -0
  168. data/spec/spec/interop/test/unit/testcase_spec_with_test_unit.rb +20 -0
  169. data/spec/spec/interop/test/unit/testsuite_adapter_spec.rb +9 -0
  170. data/spec/spec/interop/test/unit/testsuite_adapter_spec_with_test_unit.rb +34 -0
  171. data/spec/spec/matchers/be_spec.rb +15 -0
  172. data/spec/spec/matchers/change_spec.rb +87 -0
  173. data/spec/spec/matchers/description_generation_spec.rb +31 -37
  174. data/spec/spec/matchers/exist_spec.rb +31 -22
  175. data/spec/spec/matchers/handler_spec.rb +42 -1
  176. data/spec/spec/matchers/have_spec.rb +1 -1
  177. data/spec/spec/matchers/mock_constraint_matchers_spec.rb +1 -1
  178. data/spec/spec/matchers/operator_matcher_spec.rb +1 -1
  179. data/spec/spec/matchers/simple_matcher_spec.rb +31 -0
  180. data/spec/spec/matchers/throw_symbol_spec.rb +4 -1
  181. data/spec/spec/mocks/bug_report_10263.rb +24 -0
  182. data/spec/spec/mocks/bug_report_15719_spec.rb +30 -0
  183. data/spec/spec/mocks/bug_report_8165_spec.rb +2 -2
  184. data/spec/spec/mocks/failing_mock_argument_constraints_spec.rb +1 -0
  185. data/spec/spec/mocks/mock_spec.rb +200 -102
  186. data/spec/spec/mocks/multiple_return_value_spec.rb +1 -1
  187. data/spec/spec/mocks/options_hash_spec.rb +19 -7
  188. data/spec/spec/mocks/partial_mock_spec.rb +31 -9
  189. data/spec/spec/mocks/passing_mock_argument_constraints_spec.rb +6 -0
  190. data/spec/spec/mocks/stub_spec.rb +120 -98
  191. data/spec/spec/package/bin_spec_spec.rb +7 -5
  192. data/spec/spec/runner/class_and_argument_parser_spec.rb +23 -0
  193. data/spec/spec/runner/command_line_spec.rb +140 -27
  194. data/spec/spec/runner/drb_command_line_spec.rb +39 -31
  195. data/spec/spec/runner/formatter/failing_example_groups_formatter_spec.rb +44 -0
  196. data/spec/spec/runner/formatter/failing_examples_formatter_spec.rb +16 -11
  197. data/spec/spec/runner/formatter/html_formatter_spec.rb +60 -50
  198. data/spec/spec/runner/formatter/profile_formatter_spec.rb +65 -0
  199. data/spec/spec/runner/formatter/progress_bar_formatter_spec.rb +29 -13
  200. data/spec/spec/runner/formatter/snippet_extractor_spec.rb +14 -7
  201. data/spec/spec/runner/formatter/spec_mate_formatter_spec.rb +103 -0
  202. data/spec/spec/runner/formatter/specdoc_formatter_spec.rb +103 -39
  203. data/spec/spec/runner/formatter/story/html_formatter_spec.rb +56 -0
  204. data/spec/spec/runner/formatter/story/plain_text_formatter_spec.rb +289 -0
  205. data/spec/spec/runner/heckle_runner_spec.rb +29 -14
  206. data/spec/spec/runner/heckler_spec.rb +4 -5
  207. data/spec/spec/runner/noisy_backtrace_tweaker_spec.rb +5 -5
  208. data/spec/spec/runner/option_parser_spec.rb +86 -58
  209. data/spec/spec/runner/options_spec.rb +239 -120
  210. data/spec/spec/runner/output_one_time_fixture.rb +7 -0
  211. data/spec/spec/runner/output_one_time_fixture_runner.rb +8 -0
  212. data/spec/spec/runner/output_one_time_spec.rb +16 -0
  213. data/spec/spec/runner/quiet_backtrace_tweaker_spec.rb +6 -6
  214. data/spec/spec/runner/reporter_spec.rb +147 -163
  215. data/spec/spec/runner/spec_parser_spec.rb +31 -0
  216. data/spec/spec/runner_spec.rb +11 -0
  217. data/spec/spec/spec_classes.rb +12 -5
  218. data/spec/spec/story/builders.rb +46 -0
  219. data/spec/spec/story/extensions/main_spec.rb +161 -0
  220. data/spec/spec/story/extensions_spec.rb +14 -0
  221. data/spec/spec/story/given_scenario_spec.rb +27 -0
  222. data/spec/spec/story/runner/plain_text_story_runner_spec.rb +92 -0
  223. data/spec/spec/story/runner/scenario_collector_spec.rb +27 -0
  224. data/spec/spec/story/runner/scenario_runner_spec.rb +142 -0
  225. data/spec/spec/story/runner/story_mediator_spec.rb +133 -0
  226. data/spec/spec/story/runner/story_parser_spec.rb +384 -0
  227. data/spec/spec/story/runner/story_runner_spec.rb +219 -0
  228. data/spec/spec/story/runner_spec.rb +106 -0
  229. data/spec/spec/story/scenario_spec.rb +20 -0
  230. data/spec/spec/story/step_group_spec.rb +157 -0
  231. data/spec/spec/story/step_mother_spec.rb +72 -0
  232. data/spec/spec/story/step_spec.rb +147 -0
  233. data/spec/spec/story/story_helper.rb +2 -0
  234. data/spec/spec/story/story_spec.rb +86 -0
  235. data/spec/spec/story/world_spec.rb +416 -0
  236. data/spec/spec/translator_spec.rb +2 -1
  237. data/spec/spec_helper.rb +59 -2
  238. data/stories/all.rb +5 -0
  239. data/stories/example_groups/autogenerated_docstrings +26 -0
  240. data/stories/example_groups/example_group_with_should_methods +17 -0
  241. data/stories/example_groups/nested_groups +17 -0
  242. data/stories/example_groups/output +20 -0
  243. data/stories/example_groups/stories.rb +7 -0
  244. data/stories/helper.rb +6 -0
  245. data/stories/interop/examples_and_tests_together +30 -0
  246. data/stories/interop/stories.rb +7 -0
  247. data/stories/interop/test_case_with_should_methods +17 -0
  248. data/stories/pending_stories/README +3 -0
  249. data/stories/resources/helpers/cmdline.rb +9 -0
  250. data/stories/resources/helpers/story_helper.rb +16 -0
  251. data/stories/resources/matchers/smart_match.rb +37 -0
  252. data/stories/resources/spec/example_group_with_should_methods.rb +12 -0
  253. data/stories/resources/spec/simple_spec.rb +8 -0
  254. data/stories/resources/steps/running_rspec.rb +50 -0
  255. data/stories/resources/test/spec_and_test_together.rb +57 -0
  256. data/stories/resources/test/test_case_with_should_methods.rb +30 -0
  257. metadata +232 -106
  258. data/EXAMPLES.rd +0 -111
  259. data/examples/multi_threaded_behaviour_runner.rb +0 -25
  260. data/examples/shared_behaviours_example.rb +0 -39
  261. data/examples/spec_helper.rb +0 -1
  262. data/examples/test_case_adapter_example.rb +0 -26
  263. data/examples/test_case_spec.rb +0 -65
  264. data/lib/spec/dsl.rb +0 -11
  265. data/lib/spec/dsl/behaviour.rb +0 -220
  266. data/lib/spec/dsl/behaviour_callbacks.rb +0 -82
  267. data/lib/spec/dsl/behaviour_eval.rb +0 -231
  268. data/lib/spec/dsl/behaviour_factory.rb +0 -42
  269. data/lib/spec/dsl/composite_proc_builder.rb +0 -33
  270. data/lib/spec/dsl/description.rb +0 -76
  271. data/lib/spec/dsl/example.rb +0 -135
  272. data/lib/spec/dsl/example_matcher.rb +0 -40
  273. data/lib/spec/dsl/example_should_raise_handler.rb +0 -74
  274. data/lib/spec/runner/behaviour_runner.rb +0 -123
  275. data/lib/spec/runner/extensions/kernel.rb +0 -50
  276. data/lib/spec/runner/extensions/object.rb +0 -32
  277. data/lib/spec/runner/formatter.rb +0 -9
  278. data/lib/spec/runner/formatter/failing_behaviours_formatter.rb +0 -29
  279. data/lib/spec/runner/formatter/rdoc_formatter.rb +0 -24
  280. data/lib/spec/test_case_adapter.rb +0 -10
  281. data/spec/spec/dsl/behaviour_eval_spec.rb +0 -79
  282. data/spec/spec/dsl/behaviour_factory_spec.rb +0 -48
  283. data/spec/spec/dsl/behaviour_spec.rb +0 -661
  284. data/spec/spec/dsl/composite_proc_builder_spec.rb +0 -44
  285. data/spec/spec/dsl/configuration_spec.rb +0 -55
  286. data/spec/spec/dsl/description_spec.rb +0 -89
  287. data/spec/spec/dsl/example_class_spec.rb +0 -24
  288. data/spec/spec/dsl/example_instance_spec.rb +0 -160
  289. data/spec/spec/dsl/example_should_raise_spec.rb +0 -137
  290. data/spec/spec/dsl/shared_behaviour_spec.rb +0 -252
  291. data/spec/spec/runner/behaviour_runner_spec.rb +0 -229
  292. data/spec/spec/runner/context_matching_spec.rb +0 -27
  293. data/spec/spec/runner/extensions/bug_report_10577_spec.rb +0 -35
  294. data/spec/spec/runner/extensions/kernel_spec.rb +0 -36
  295. data/spec/spec/runner/formatter/failing_behaviours_formatter_spec.rb +0 -40
  296. data/spec/spec/runner/formatter/progress_bar_formatter_dry_run_spec.rb +0 -20
  297. data/spec/spec/runner/formatter/progress_bar_formatter_failure_dump_spec.rb +0 -36
  298. data/spec/spec/runner/formatter/rdoc_formatter_dry_run_spec.rb +0 -19
  299. data/spec/spec/runner/formatter/rdoc_formatter_spec.rb +0 -46
  300. data/spec/spec/runner/formatter/specdoc_formatter_dry_run_spec.rb +0 -21
  301. data/spec/spec/runner/object_ext_spec.rb +0 -11
@@ -0,0 +1,123 @@
1
+ module Spec
2
+ module Story
3
+ module Runner
4
+
5
+ class StoryMediator
6
+ def initialize(step_group, runner, options={})
7
+ @step_group = step_group
8
+ @stories = []
9
+ @runner = runner
10
+ @options = options
11
+ end
12
+
13
+ def stories
14
+ @stories.collect { |p| p.to_proc }
15
+ end
16
+
17
+ def create_story(title, narrative)
18
+ @stories << Story.new(title, narrative, @step_group, @options)
19
+ end
20
+
21
+ def create_scenario(title)
22
+ current_story.add_scenario Scenario.new(title)
23
+ end
24
+
25
+ def create_given(name)
26
+ current_scenario.add_step Step.new('Given', name)
27
+ end
28
+
29
+ def create_given_scenario(name)
30
+ current_scenario.add_step Step.new('GivenScenario', name)
31
+ end
32
+
33
+ def create_when(name)
34
+ current_scenario.add_step Step.new('When', name)
35
+ end
36
+
37
+ def create_then(name)
38
+ current_scenario.add_step Step.new('Then', name)
39
+ end
40
+
41
+ def run_stories
42
+ stories.each { |story| @runner.instance_eval(&story) }
43
+ end
44
+
45
+ private
46
+ def current_story
47
+ @stories.last
48
+ end
49
+
50
+ def current_scenario
51
+ current_story.current_scenario
52
+ end
53
+
54
+ class Story
55
+ def initialize(title, narrative, step_group, options)
56
+ @title = title
57
+ @narrative = narrative
58
+ @scenarios = []
59
+ @step_group = step_group
60
+ @options = options
61
+ end
62
+
63
+ def to_proc
64
+ title = @title
65
+ narrative = @narrative
66
+ scenarios = @scenarios.collect { |scenario| scenario.to_proc }
67
+ options = @options.merge(:steps => @step_group)
68
+ lambda do
69
+ Story title, narrative, options do
70
+ scenarios.each { |scenario| instance_eval(&scenario) }
71
+ end
72
+ end
73
+ end
74
+
75
+ def add_scenario(scenario)
76
+ @scenarios << scenario
77
+ end
78
+
79
+ def current_scenario
80
+ @scenarios.last
81
+ end
82
+ end
83
+
84
+ class Scenario
85
+ def initialize(name)
86
+ @name = name
87
+ @steps = []
88
+ end
89
+
90
+ def to_proc
91
+ name = @name
92
+ steps = @steps.collect { |step| step.to_proc }
93
+ lambda do
94
+ Scenario name do
95
+ steps.each { |step| instance_eval(&step) }
96
+ end
97
+ end
98
+ end
99
+
100
+ def add_step(step)
101
+ @steps << step
102
+ end
103
+ end
104
+
105
+ class Step
106
+ def initialize(type, name)
107
+ @type = type
108
+ @name = name
109
+ end
110
+
111
+ def to_proc
112
+ type = @type
113
+ name = @name
114
+ lambda do
115
+ send(type, name)
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,227 @@
1
+ module Spec
2
+ module Story
3
+ module Runner
4
+
5
+ class IllegalStepError < StandardError
6
+ def initialize(state, event)
7
+ super("Illegal attempt to create a #{event} after a #{state}")
8
+ end
9
+ end
10
+
11
+ class StoryParser
12
+ def initialize(story_mediator)
13
+ @story_mediator = story_mediator
14
+ @current_story_lines = []
15
+ transition_to(:starting_state)
16
+ end
17
+
18
+ def parse(lines)
19
+ lines.reject! {|line| line == ""}
20
+ until lines.empty?
21
+ process_line(lines.shift)
22
+ end
23
+ @state.eof
24
+ end
25
+
26
+ def process_line(line)
27
+ line.strip!
28
+ case line
29
+ when /^Story: / : @state.story(line)
30
+ when /^Scenario: / : @state.scenario(line)
31
+ when /^Given:? / : @state.given(line)
32
+ when /^GivenScenario:? / : @state.given_scenario(line)
33
+ when /^When:? / : @state.event(line)
34
+ when /^Then:? / : @state.outcome(line)
35
+ when /^And:? / : @state.one_more_of_the_same(line)
36
+ else @state.other(line)
37
+ end
38
+ end
39
+
40
+ def init_story(title)
41
+ @current_story_lines.clear
42
+ add_story_line(title)
43
+ end
44
+
45
+ def add_story_line(line)
46
+ @current_story_lines << line
47
+ end
48
+
49
+ def create_story()
50
+ unless @current_story_lines.empty?
51
+ @story_mediator.create_story(@current_story_lines[0].gsub("Story: ",""), @current_story_lines[1..-1].join("\n"))
52
+ @current_story_lines.clear
53
+ end
54
+ end
55
+
56
+ def create_scenario(title)
57
+ @story_mediator.create_scenario(title.gsub("Scenario: ",""))
58
+ end
59
+
60
+ def create_given(name)
61
+ @story_mediator.create_given(name)
62
+ end
63
+
64
+ def create_given_scenario(name)
65
+ @story_mediator.create_given_scenario(name)
66
+ end
67
+
68
+ def create_when(name)
69
+ @story_mediator.create_when(name)
70
+ end
71
+
72
+ def create_then(name)
73
+ @story_mediator.create_then(name)
74
+ end
75
+
76
+ def transition_to(key)
77
+ @state = states[key]
78
+ end
79
+
80
+ def states
81
+ @states ||= {
82
+ :starting_state => StartingState.new(self),
83
+ :story_state => StoryState.new(self),
84
+ :scenario_state => ScenarioState.new(self),
85
+ :given_state => GivenState.new(self),
86
+ :when_state => WhenState.new(self),
87
+ :then_state => ThenState.new(self)
88
+ }
89
+ end
90
+
91
+ class State
92
+ def initialize(parser)
93
+ @parser = parser
94
+ end
95
+
96
+ def story(line)
97
+ @parser.init_story(line)
98
+ @parser.transition_to(:story_state)
99
+ end
100
+
101
+ def scenario(line)
102
+ @parser.create_scenario(line)
103
+ @parser.transition_to(:scenario_state)
104
+ end
105
+
106
+ def given(line)
107
+ @parser.create_given(remove_tag_from(:given, line))
108
+ @parser.transition_to(:given_state)
109
+ end
110
+
111
+ def given_scenario(line)
112
+ @parser.create_given_scenario(remove_tag_from(:givenscenario, line))
113
+ @parser.transition_to(:given_state)
114
+ end
115
+
116
+ def event(line)
117
+ @parser.create_when(remove_tag_from(:when, line))
118
+ @parser.transition_to(:when_state)
119
+ end
120
+
121
+ def outcome(line)
122
+ @parser.create_then(remove_tag_from(:then, line))
123
+ @parser.transition_to(:then_state)
124
+ end
125
+
126
+ def remove_tag_from(tag, line)
127
+ tokens = line.split
128
+ # validation of tag can go here
129
+ tokens[0].downcase.match(/#{tag.to_s}:?/) ?
130
+ (tokens[1..-1].join(' ')) : line
131
+ end
132
+
133
+ def eof
134
+ end
135
+
136
+ def other(line)
137
+ # no-op - supports header text before the first story in a file
138
+ end
139
+ end
140
+
141
+ class StartingState < State
142
+ def initialize(parser)
143
+ @parser = parser
144
+ end
145
+ end
146
+
147
+ class StoryState < State
148
+ def one_more_of_the_same(line)
149
+ other(line)
150
+ end
151
+
152
+ def story(line)
153
+ @parser.create_story
154
+ @parser.add_story_line(line)
155
+ end
156
+
157
+ def scenario(line)
158
+ @parser.create_story
159
+ @parser.create_scenario(line)
160
+ @parser.transition_to(:scenario_state)
161
+ end
162
+
163
+ def given(line)
164
+ other(line)
165
+ end
166
+
167
+ def event(line)
168
+ other(line)
169
+ end
170
+
171
+ def outcome(line)
172
+ other(line)
173
+ end
174
+
175
+ def other(line)
176
+ @parser.add_story_line(line)
177
+ end
178
+
179
+ def eof
180
+ @parser.create_story
181
+ end
182
+ end
183
+
184
+ class ScenarioState < State
185
+ def one_more_of_the_same(line)
186
+ raise IllegalStepError.new("Scenario", "And")
187
+ end
188
+
189
+ def scenario(line)
190
+ @parser.create_scenario(line)
191
+ end
192
+ end
193
+
194
+ class GivenState < State
195
+ def one_more_of_the_same(line)
196
+ @parser.create_given(remove_tag_from(:and, line))
197
+ end
198
+
199
+ def given(line)
200
+ @parser.create_given(remove_tag_from(:given, line))
201
+ end
202
+ end
203
+
204
+ class WhenState < State
205
+ def one_more_of_the_same(line)
206
+ @parser.create_when(remove_tag_from(:and ,line))
207
+ end
208
+
209
+ def event(line)
210
+ @parser.create_when(remove_tag_from(:when ,line))
211
+ end
212
+ end
213
+
214
+ class ThenState < State
215
+ def one_more_of_the_same(line)
216
+ @parser.create_then(remove_tag_from(:and ,line))
217
+ end
218
+
219
+ def outcome(line)
220
+ @parser.create_then(remove_tag_from(:then ,line))
221
+ end
222
+ end
223
+
224
+ end
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,67 @@
1
+ module Spec
2
+ module Story
3
+ module Runner
4
+ class StoryRunner
5
+ class << self
6
+ attr_accessor :current_story_runner
7
+
8
+ def scenario_from_current_story(scenario_name)
9
+ current_story_runner.scenario_from_current_story(scenario_name)
10
+ end
11
+ end
12
+
13
+ attr_accessor :stories, :scenarios, :current_story
14
+
15
+ def initialize(scenario_runner, world_creator = World)
16
+ StoryRunner.current_story_runner = self
17
+ @scenario_runner = scenario_runner
18
+ @world_creator = world_creator
19
+ @stories = []
20
+ @scenarios_by_story = {}
21
+ @scenarios = []
22
+ @listeners = []
23
+ end
24
+
25
+ def Story(title, narrative, params = {}, &body)
26
+ story = Story.new(title, narrative, params, &body)
27
+ @stories << story
28
+
29
+ # collect scenarios
30
+ collector = ScenarioCollector.new(story)
31
+ story.run_in(collector)
32
+ @scenarios += collector.scenarios
33
+ @scenarios_by_story[story.title] = collector.scenarios
34
+ end
35
+
36
+ def run_stories
37
+ return if @stories.empty?
38
+ @listeners.each { |l| l.run_started(scenarios.size) }
39
+ @stories.each do |story|
40
+ story.assign_steps_to(World)
41
+ @current_story = story
42
+ @listeners.each { |l| l.story_started(story.title, story.narrative) }
43
+ scenarios = @scenarios_by_story[story.title]
44
+ scenarios.each do |scenario|
45
+ type = story[:type] || Object
46
+ args = story[:args] || []
47
+ world = @world_creator.create(type, *args)
48
+ @scenario_runner.run(scenario, world)
49
+ end
50
+ @listeners.each { |l| l.story_ended(story.title, story.narrative) }
51
+ end
52
+ unique_steps = World.step_names.uniq.sort
53
+ @listeners.each { |l| l.collected_steps(unique_steps) }
54
+ @listeners.each { |l| l.run_ended }
55
+ end
56
+
57
+ def add_listener(listener)
58
+ @listeners << listener
59
+ end
60
+
61
+ def scenario_from_current_story(scenario_name)
62
+ @scenarios_by_story[@current_story.title].find {|s| s.name == scenario_name }
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,14 @@
1
+
2
+ module Spec
3
+ module Story
4
+ class Scenario
5
+ attr_accessor :name, :body, :story
6
+
7
+ def initialize(story, name, &body)
8
+ @story = story
9
+ @name = name
10
+ @body = body
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,48 @@
1
+ module Spec
2
+ module Story
3
+ class Step
4
+ PARAM_PATTERN = /(\$\w*)/
5
+
6
+ attr_reader :name
7
+ def initialize(name, &block)
8
+ @name = name
9
+ assign_expression(name)
10
+ init_module(name, &block)
11
+ end
12
+
13
+ def perform(instance, *args)
14
+ instance.extend(@mod)
15
+ instance.__send__(@name, *args)
16
+ end
17
+
18
+ def init_module(name, &block)
19
+ @mod = Module.new do
20
+ define_method(name.to_s, &block)
21
+ end
22
+ end
23
+
24
+ def matches?(name)
25
+ !(matches = name.match(@expression)).nil?
26
+ end
27
+
28
+ def parse_args(name)
29
+ name.match(@expression)[1..-1]
30
+ end
31
+
32
+ private
33
+
34
+ def assign_expression(name)
35
+ expression = name.dup
36
+ if String === expression
37
+ expression.gsub! '(', '\('
38
+ expression.gsub! ')', '\)'
39
+ while expression =~ PARAM_PATTERN
40
+ expression.gsub!($1, "(.*?)")
41
+ end
42
+ end
43
+ @expression = Regexp.new("^#{expression}$")
44
+ end
45
+
46
+ end
47
+ end
48
+ end