state_machine_deuxito 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (310) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +8 -0
  4. data/.yardopts +5 -0
  5. data/Appraisals +12 -0
  6. data/CHANGELOG.md +502 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE +20 -0
  9. data/README.md +8 -0
  10. data/Rakefile +41 -0
  11. data/TODO.md +2 -0
  12. data/examples/AutoShop_state.png +0 -0
  13. data/examples/Car_state.png +0 -0
  14. data/examples/Gemfile +5 -0
  15. data/examples/Gemfile.lock +14 -0
  16. data/examples/TrafficLight_state.png +0 -0
  17. data/examples/Vehicle_state.png +0 -0
  18. data/examples/auto_shop.rb +13 -0
  19. data/examples/car.rb +21 -0
  20. data/examples/doc/AutoShop.html +2856 -0
  21. data/examples/doc/AutoShop_state.png +0 -0
  22. data/examples/doc/Car.html +919 -0
  23. data/examples/doc/Car_state.png +0 -0
  24. data/examples/doc/TrafficLight.html +2230 -0
  25. data/examples/doc/TrafficLight_state.png +0 -0
  26. data/examples/doc/Vehicle.html +7921 -0
  27. data/examples/doc/Vehicle_state.png +0 -0
  28. data/examples/doc/_index.html +136 -0
  29. data/examples/doc/class_list.html +47 -0
  30. data/examples/doc/css/common.css +1 -0
  31. data/examples/doc/css/full_list.css +55 -0
  32. data/examples/doc/css/style.css +322 -0
  33. data/examples/doc/file_list.html +46 -0
  34. data/examples/doc/frames.html +13 -0
  35. data/examples/doc/index.html +136 -0
  36. data/examples/doc/js/app.js +205 -0
  37. data/examples/doc/js/full_list.js +173 -0
  38. data/examples/doc/js/jquery.js +16 -0
  39. data/examples/doc/method_list.html +734 -0
  40. data/examples/doc/top-level-namespace.html +105 -0
  41. data/examples/merb-rest/controller.rb +51 -0
  42. data/examples/merb-rest/model.rb +28 -0
  43. data/examples/merb-rest/view_edit.html.erb +24 -0
  44. data/examples/merb-rest/view_index.html.erb +23 -0
  45. data/examples/merb-rest/view_new.html.erb +13 -0
  46. data/examples/merb-rest/view_show.html.erb +17 -0
  47. data/examples/rails-rest/controller.rb +43 -0
  48. data/examples/rails-rest/migration.rb +7 -0
  49. data/examples/rails-rest/model.rb +23 -0
  50. data/examples/rails-rest/view__form.html.erb +34 -0
  51. data/examples/rails-rest/view_edit.html.erb +6 -0
  52. data/examples/rails-rest/view_index.html.erb +25 -0
  53. data/examples/rails-rest/view_new.html.erb +5 -0
  54. data/examples/rails-rest/view_show.html.erb +19 -0
  55. data/examples/traffic_light.rb +9 -0
  56. data/examples/vehicle.rb +33 -0
  57. data/gemfiles/4.2.11.1.gemfile +9 -0
  58. data/gemfiles/4.2.11.1.gemfile.lock +57 -0
  59. data/gemfiles/active_model_3.0.0.gemfile +7 -0
  60. data/gemfiles/active_model_3.0.0.gemfile.lock +35 -0
  61. data/gemfiles/active_model_3.0.5.gemfile +7 -0
  62. data/gemfiles/active_model_3.0.5.gemfile.lock +35 -0
  63. data/gemfiles/active_model_3.1.1.gemfile +7 -0
  64. data/gemfiles/active_model_3.1.1.gemfile.lock +36 -0
  65. data/gemfiles/active_model_3.2.1.gemfile +7 -0
  66. data/gemfiles/active_model_3.2.12.gemfile +7 -0
  67. data/gemfiles/active_model_3.2.12.gemfile.lock +36 -0
  68. data/gemfiles/active_model_3.2.13.rc1.gemfile +7 -0
  69. data/gemfiles/active_model_3.2.13.rc1.gemfile.lock +36 -0
  70. data/gemfiles/active_model_4.0.0.gemfile +9 -0
  71. data/gemfiles/active_model_4.0.0.gemfile.lock +78 -0
  72. data/gemfiles/active_record_2.0.0.gemfile +9 -0
  73. data/gemfiles/active_record_2.0.0.gemfile.lock +39 -0
  74. data/gemfiles/active_record_2.0.5.gemfile +9 -0
  75. data/gemfiles/active_record_2.0.5.gemfile.lock +39 -0
  76. data/gemfiles/active_record_2.1.0.gemfile +9 -0
  77. data/gemfiles/active_record_2.1.0.gemfile.lock +39 -0
  78. data/gemfiles/active_record_2.1.2.gemfile +9 -0
  79. data/gemfiles/active_record_2.1.2.gemfile.lock +39 -0
  80. data/gemfiles/active_record_2.2.3.gemfile +9 -0
  81. data/gemfiles/active_record_2.2.3.gemfile.lock +39 -0
  82. data/gemfiles/active_record_2.3.12.gemfile +9 -0
  83. data/gemfiles/active_record_2.3.12.gemfile.lock +39 -0
  84. data/gemfiles/active_record_2.3.5.gemfile +9 -0
  85. data/gemfiles/active_record_2.3.5.gemfile.lock +39 -0
  86. data/gemfiles/active_record_3.0.0.gemfile +9 -0
  87. data/gemfiles/active_record_3.0.0.gemfile.lock +51 -0
  88. data/gemfiles/active_record_3.0.5.gemfile +9 -0
  89. data/gemfiles/active_record_3.0.5.gemfile.lock +50 -0
  90. data/gemfiles/active_record_3.1.1.gemfile +9 -0
  91. data/gemfiles/active_record_3.1.1.gemfile.lock +51 -0
  92. data/gemfiles/active_record_3.2.12.gemfile +9 -0
  93. data/gemfiles/active_record_3.2.12.gemfile.lock +51 -0
  94. data/gemfiles/active_record_3.2.13.rc1.gemfile +9 -0
  95. data/gemfiles/active_record_3.2.13.rc1.gemfile.lock +51 -0
  96. data/gemfiles/active_record_4.0.0.gemfile +11 -0
  97. data/gemfiles/active_record_4.0.0.gemfile.lock +83 -0
  98. data/gemfiles/data_mapper_0.10.2.gemfile +13 -0
  99. data/gemfiles/data_mapper_0.10.2.gemfile.lock +56 -0
  100. data/gemfiles/data_mapper_0.9.11.gemfile +13 -0
  101. data/gemfiles/data_mapper_0.9.11.gemfile.lock +71 -0
  102. data/gemfiles/data_mapper_0.9.4.gemfile +12 -0
  103. data/gemfiles/data_mapper_0.9.4.gemfile.lock +70 -0
  104. data/gemfiles/data_mapper_0.9.7.gemfile +13 -0
  105. data/gemfiles/data_mapper_0.9.7.gemfile.lock +67 -0
  106. data/gemfiles/data_mapper_1.0.0.gemfile +12 -0
  107. data/gemfiles/data_mapper_1.0.0.gemfile.lock +63 -0
  108. data/gemfiles/data_mapper_1.0.1.gemfile +12 -0
  109. data/gemfiles/data_mapper_1.0.1.gemfile.lock +63 -0
  110. data/gemfiles/data_mapper_1.0.2.gemfile +12 -0
  111. data/gemfiles/data_mapper_1.0.2.gemfile.lock +63 -0
  112. data/gemfiles/data_mapper_1.1.0.gemfile +12 -0
  113. data/gemfiles/data_mapper_1.1.0.gemfile.lock +61 -0
  114. data/gemfiles/data_mapper_1.2.0.gemfile +12 -0
  115. data/gemfiles/data_mapper_1.2.0.gemfile.lock +61 -0
  116. data/gemfiles/default.gemfile +5 -0
  117. data/gemfiles/default.gemfile.lock +30 -0
  118. data/gemfiles/graphviz_0.9.17.gemfile +7 -0
  119. data/gemfiles/graphviz_0.9.17.gemfile.lock +29 -0
  120. data/gemfiles/graphviz_0.9.21.gemfile +7 -0
  121. data/gemfiles/graphviz_0.9.21.gemfile.lock +29 -0
  122. data/gemfiles/graphviz_1.0.0.gemfile +7 -0
  123. data/gemfiles/graphviz_1.0.0.gemfile.lock +29 -0
  124. data/gemfiles/graphviz_1.0.3.gemfile +7 -0
  125. data/gemfiles/graphviz_1.0.3.gemfile.lock +29 -0
  126. data/gemfiles/graphviz_1.0.8.gemfile +7 -0
  127. data/gemfiles/graphviz_1.0.8.gemfile.lock +29 -0
  128. data/gemfiles/mongo_mapper_0.10.0.gemfile +8 -0
  129. data/gemfiles/mongo_mapper_0.10.0.gemfile.lock +47 -0
  130. data/gemfiles/mongo_mapper_0.11.2.gemfile +9 -0
  131. data/gemfiles/mongo_mapper_0.11.2.gemfile.lock +48 -0
  132. data/gemfiles/mongo_mapper_0.12.0.gemfile +9 -0
  133. data/gemfiles/mongo_mapper_0.12.0.gemfile.lock +48 -0
  134. data/gemfiles/mongo_mapper_0.5.5.gemfile +8 -0
  135. data/gemfiles/mongo_mapper_0.5.5.gemfile.lock +36 -0
  136. data/gemfiles/mongo_mapper_0.5.8.gemfile +8 -0
  137. data/gemfiles/mongo_mapper_0.5.8.gemfile.lock +36 -0
  138. data/gemfiles/mongo_mapper_0.6.0.gemfile +8 -0
  139. data/gemfiles/mongo_mapper_0.6.0.gemfile.lock +36 -0
  140. data/gemfiles/mongo_mapper_0.6.10.gemfile +8 -0
  141. data/gemfiles/mongo_mapper_0.6.10.gemfile.lock +36 -0
  142. data/gemfiles/mongo_mapper_0.7.0.gemfile +8 -0
  143. data/gemfiles/mongo_mapper_0.7.0.gemfile.lock +36 -0
  144. data/gemfiles/mongo_mapper_0.7.5.gemfile +8 -0
  145. data/gemfiles/mongo_mapper_0.7.5.gemfile.lock +39 -0
  146. data/gemfiles/mongo_mapper_0.8.0.gemfile +10 -0
  147. data/gemfiles/mongo_mapper_0.8.0.gemfile.lock +43 -0
  148. data/gemfiles/mongo_mapper_0.8.3.gemfile +10 -0
  149. data/gemfiles/mongo_mapper_0.8.3.gemfile.lock +43 -0
  150. data/gemfiles/mongo_mapper_0.8.4.gemfile +8 -0
  151. data/gemfiles/mongo_mapper_0.8.4.gemfile.lock +42 -0
  152. data/gemfiles/mongo_mapper_0.8.6.gemfile +8 -0
  153. data/gemfiles/mongo_mapper_0.8.6.gemfile.lock +42 -0
  154. data/gemfiles/mongo_mapper_0.9.0.gemfile +7 -0
  155. data/gemfiles/mongo_mapper_0.9.0.gemfile.lock +45 -0
  156. data/gemfiles/mongoid_2.0.0.gemfile +9 -0
  157. data/gemfiles/mongoid_2.0.0.gemfile.lock +49 -0
  158. data/gemfiles/mongoid_2.1.4.gemfile +9 -0
  159. data/gemfiles/mongoid_2.1.4.gemfile.lock +47 -0
  160. data/gemfiles/mongoid_2.2.4.gemfile +9 -0
  161. data/gemfiles/mongoid_2.2.4.gemfile.lock +47 -0
  162. data/gemfiles/mongoid_2.3.3.gemfile +9 -0
  163. data/gemfiles/mongoid_2.3.3.gemfile.lock +47 -0
  164. data/gemfiles/mongoid_2.4.0.gemfile +9 -0
  165. data/gemfiles/mongoid_2.4.0.gemfile.lock +47 -0
  166. data/gemfiles/mongoid_2.4.10.gemfile +9 -0
  167. data/gemfiles/mongoid_2.4.10.gemfile.lock +47 -0
  168. data/gemfiles/mongoid_2.5.2.gemfile +9 -0
  169. data/gemfiles/mongoid_2.5.2.gemfile.lock +47 -0
  170. data/gemfiles/mongoid_2.6.0.gemfile +9 -0
  171. data/gemfiles/mongoid_2.6.0.gemfile.lock +47 -0
  172. data/gemfiles/mongoid_3.0.0.gemfile +8 -0
  173. data/gemfiles/mongoid_3.0.0.gemfile.lock +45 -0
  174. data/gemfiles/mongoid_3.0.22.gemfile +8 -0
  175. data/gemfiles/mongoid_3.0.22.gemfile.lock +45 -0
  176. data/gemfiles/mongoid_3.1.0.gemfile +8 -0
  177. data/gemfiles/mongoid_3.1.0.gemfile.lock +45 -0
  178. data/gemfiles/sequel_2.11.0.gemfile +9 -0
  179. data/gemfiles/sequel_2.11.0.gemfile.lock +33 -0
  180. data/gemfiles/sequel_2.12.0.gemfile +9 -0
  181. data/gemfiles/sequel_2.12.0.gemfile.lock +33 -0
  182. data/gemfiles/sequel_2.8.0.gemfile +9 -0
  183. data/gemfiles/sequel_2.8.0.gemfile.lock +33 -0
  184. data/gemfiles/sequel_3.0.0.gemfile +9 -0
  185. data/gemfiles/sequel_3.0.0.gemfile.lock +33 -0
  186. data/gemfiles/sequel_3.10.0.gemfile +9 -0
  187. data/gemfiles/sequel_3.10.0.gemfile.lock +33 -0
  188. data/gemfiles/sequel_3.13.0.gemfile +9 -0
  189. data/gemfiles/sequel_3.13.0.gemfile.lock +33 -0
  190. data/gemfiles/sequel_3.14.0.gemfile +9 -0
  191. data/gemfiles/sequel_3.14.0.gemfile.lock +33 -0
  192. data/gemfiles/sequel_3.23.0.gemfile +9 -0
  193. data/gemfiles/sequel_3.23.0.gemfile.lock +33 -0
  194. data/gemfiles/sequel_3.24.0.gemfile +9 -0
  195. data/gemfiles/sequel_3.24.0.gemfile.lock +33 -0
  196. data/gemfiles/sequel_3.29.0.gemfile +9 -0
  197. data/gemfiles/sequel_3.29.0.gemfile.lock +33 -0
  198. data/gemfiles/sequel_3.34.0.gemfile +9 -0
  199. data/gemfiles/sequel_3.34.0.gemfile.lock +33 -0
  200. data/gemfiles/sequel_3.35.0.gemfile +9 -0
  201. data/gemfiles/sequel_3.35.0.gemfile.lock +33 -0
  202. data/gemfiles/sequel_3.4.0.gemfile +9 -0
  203. data/gemfiles/sequel_3.4.0.gemfile.lock +33 -0
  204. data/gemfiles/sequel_3.44.0.gemfile +9 -0
  205. data/gemfiles/sequel_3.44.0.gemfile.lock +33 -0
  206. data/init.rb +1 -0
  207. data/lib/state_machine.rb +8 -0
  208. data/lib/state_machine/assertions.rb +36 -0
  209. data/lib/state_machine/branch.rb +225 -0
  210. data/lib/state_machine/callback.rb +236 -0
  211. data/lib/state_machine/core.rb +12 -0
  212. data/lib/state_machine/core_ext.rb +2 -0
  213. data/lib/state_machine/core_ext/class/state_machine.rb +5 -0
  214. data/lib/state_machine/error.rb +13 -0
  215. data/lib/state_machine/eval_helpers.rb +87 -0
  216. data/lib/state_machine/event.rb +257 -0
  217. data/lib/state_machine/event_collection.rb +141 -0
  218. data/lib/state_machine/extensions.rb +149 -0
  219. data/lib/state_machine/graph.rb +92 -0
  220. data/lib/state_machine/helper_module.rb +17 -0
  221. data/lib/state_machine/initializers.rb +4 -0
  222. data/lib/state_machine/initializers/merb.rb +1 -0
  223. data/lib/state_machine/initializers/rails.rb +25 -0
  224. data/lib/state_machine/integrations.rb +121 -0
  225. data/lib/state_machine/integrations/active_model.rb +585 -0
  226. data/lib/state_machine/integrations/active_model/locale.rb +11 -0
  227. data/lib/state_machine/integrations/active_model/observer.rb +33 -0
  228. data/lib/state_machine/integrations/active_model/observer_update.rb +42 -0
  229. data/lib/state_machine/integrations/active_model/versions.rb +31 -0
  230. data/lib/state_machine/integrations/active_record.rb +552 -0
  231. data/lib/state_machine/integrations/active_record/locale.rb +20 -0
  232. data/lib/state_machine/integrations/active_record/versions.rb +123 -0
  233. data/lib/state_machine/integrations/base.rb +100 -0
  234. data/lib/state_machine/integrations/data_mapper.rb +511 -0
  235. data/lib/state_machine/integrations/data_mapper/observer.rb +210 -0
  236. data/lib/state_machine/integrations/data_mapper/versions.rb +85 -0
  237. data/lib/state_machine/integrations/mongo_mapper.rb +389 -0
  238. data/lib/state_machine/integrations/mongo_mapper/locale.rb +4 -0
  239. data/lib/state_machine/integrations/mongo_mapper/versions.rb +89 -0
  240. data/lib/state_machine/integrations/mongoid.rb +465 -0
  241. data/lib/state_machine/integrations/mongoid/locale.rb +4 -0
  242. data/lib/state_machine/integrations/mongoid/versions.rb +81 -0
  243. data/lib/state_machine/integrations/sequel.rb +486 -0
  244. data/lib/state_machine/integrations/sequel/versions.rb +95 -0
  245. data/lib/state_machine/machine.rb +2292 -0
  246. data/lib/state_machine/machine_collection.rb +86 -0
  247. data/lib/state_machine/macro_methods.rb +522 -0
  248. data/lib/state_machine/matcher.rb +123 -0
  249. data/lib/state_machine/matcher_helpers.rb +54 -0
  250. data/lib/state_machine/node_collection.rb +222 -0
  251. data/lib/state_machine/path.rb +120 -0
  252. data/lib/state_machine/path_collection.rb +90 -0
  253. data/lib/state_machine/state.rb +297 -0
  254. data/lib/state_machine/state_collection.rb +112 -0
  255. data/lib/state_machine/state_context.rb +138 -0
  256. data/lib/state_machine/transition.rb +470 -0
  257. data/lib/state_machine/transition_collection.rb +245 -0
  258. data/lib/state_machine/version.rb +3 -0
  259. data/lib/state_machine/yard.rb +8 -0
  260. data/lib/state_machine/yard/handlers.rb +12 -0
  261. data/lib/state_machine/yard/handlers/base.rb +32 -0
  262. data/lib/state_machine/yard/handlers/event.rb +25 -0
  263. data/lib/state_machine/yard/handlers/machine.rb +344 -0
  264. data/lib/state_machine/yard/handlers/state.rb +25 -0
  265. data/lib/state_machine/yard/handlers/transition.rb +47 -0
  266. data/lib/state_machine/yard/templates.rb +3 -0
  267. data/lib/state_machine/yard/templates/default/class/html/setup.rb +30 -0
  268. data/lib/state_machine/yard/templates/default/class/html/state_machines.erb +12 -0
  269. data/lib/tasks/state_machine.rake +1 -0
  270. data/lib/tasks/state_machine.rb +30 -0
  271. data/lib/yard-state_machine.rb +2 -0
  272. data/state_machine.gemspec +21 -0
  273. data/test/files/en.yml +17 -0
  274. data/test/files/switch.rb +15 -0
  275. data/test/functional/state_machine_test.rb +1067 -0
  276. data/test/test_helper.rb +8 -0
  277. data/test/unit/assertions_test.rb +40 -0
  278. data/test/unit/branch_test.rb +969 -0
  279. data/test/unit/callback_test.rb +704 -0
  280. data/test/unit/error_test.rb +43 -0
  281. data/test/unit/eval_helpers_test.rb +270 -0
  282. data/test/unit/event_collection_test.rb +398 -0
  283. data/test/unit/event_test.rb +1196 -0
  284. data/test/unit/graph_test.rb +98 -0
  285. data/test/unit/helper_module_test.rb +17 -0
  286. data/test/unit/integrations/active_model_test.rb +1245 -0
  287. data/test/unit/integrations/active_record_test.rb +2551 -0
  288. data/test/unit/integrations/base_test.rb +104 -0
  289. data/test/unit/integrations/data_mapper_test.rb +2194 -0
  290. data/test/unit/integrations/mongo_mapper_test.rb +2026 -0
  291. data/test/unit/integrations/mongoid_test.rb +2309 -0
  292. data/test/unit/integrations/sequel_test.rb +1896 -0
  293. data/test/unit/integrations_test.rb +83 -0
  294. data/test/unit/invalid_event_test.rb +20 -0
  295. data/test/unit/invalid_parallel_transition_test.rb +18 -0
  296. data/test/unit/invalid_transition_test.rb +115 -0
  297. data/test/unit/machine_collection_test.rb +603 -0
  298. data/test/unit/machine_test.rb +3431 -0
  299. data/test/unit/matcher_helpers_test.rb +37 -0
  300. data/test/unit/matcher_test.rb +155 -0
  301. data/test/unit/node_collection_test.rb +362 -0
  302. data/test/unit/path_collection_test.rb +266 -0
  303. data/test/unit/path_test.rb +485 -0
  304. data/test/unit/state_collection_test.rb +352 -0
  305. data/test/unit/state_context_test.rb +441 -0
  306. data/test/unit/state_machine_test.rb +31 -0
  307. data/test/unit/state_test.rb +1101 -0
  308. data/test/unit/transition_collection_test.rb +2168 -0
  309. data/test/unit/transition_test.rb +1558 -0
  310. metadata +451 -0
@@ -0,0 +1,25 @@
1
+ module StateMachine
2
+ module YARD
3
+ module Handlers
4
+ # Handles and processes #state
5
+ class State < Base
6
+ handles method_call(:state)
7
+
8
+ def process
9
+ if owner.is_a?(StateMachine::Machine)
10
+ handler = self
11
+ statement = self.statement
12
+ names = extract_node_names(statement.parameters(false))
13
+
14
+ names.each do |name|
15
+ owner.state(name) do
16
+ # Parse the block
17
+ handler.parse_block(statement.last.last, :owner => self)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,47 @@
1
+ module StateMachine
2
+ module YARD
3
+ module Handlers
4
+ # Handles and processes #transition
5
+ class Transition < Base
6
+ handles method_call(:transition)
7
+
8
+ def process
9
+ if [StateMachine::Machine, StateMachine::Event, StateMachine::State].include?(owner.class)
10
+ options = {}
11
+
12
+ # Extract requirements
13
+ ast = statement.parameters.first
14
+ ast.children.each do |assoc|
15
+ # Skip conditionals
16
+ next if %w(if unless).include?(assoc[0].jump(:ident).source)
17
+
18
+ options[extract_requirement(assoc[0])] = extract_requirement(assoc[1])
19
+ end
20
+
21
+ owner.transition(options)
22
+ end
23
+ end
24
+
25
+ private
26
+ # Extracts the statement requirement from the given node
27
+ def extract_requirement(ast)
28
+ case ast.type
29
+ when :symbol_literal, :string_literal, :array
30
+ extract_node_names(ast, false)
31
+ when :binary
32
+ AllMatcher.instance - extract_node_names(ast.children.last)
33
+ when :var_ref, :vcall
34
+ case ast.source
35
+ when 'nil'
36
+ nil
37
+ when 'same'
38
+ LoopbackMatcher.instance
39
+ else
40
+ AllMatcher.instance
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ require 'yard'
2
+
3
+ YARD::Templates::Engine.register_template_path File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
@@ -0,0 +1,30 @@
1
+ require 'tempfile'
2
+
3
+ # Define where state machine descriptions will be rendered
4
+ def init
5
+ super
6
+ sections.place(:state_machine_details).before(:children)
7
+ end
8
+
9
+ # Renders state machine details in the main content of the class's documentation
10
+ def state_machine_details
11
+ erb(:state_machines) if state_machines
12
+ end
13
+
14
+ # Gets a list of state machines prased for this class
15
+ def state_machines
16
+ @state_machines ||= begin
17
+ if state_machines = object['state_machines']
18
+ state_machines.each do |name, machine|
19
+ serializer.serialize(state_machine_image_path(machine), machine[:image]) if machine[:image]
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ # Generates the image path for the given machine's visualization
26
+ def state_machine_image_path(machine)
27
+ base_path = File.dirname(serializer.serialized_path(object))
28
+ image_name = "#{object.name}_#{machine[:name]}"
29
+ "#{File.join(base_path, image_name)}.png"
30
+ end
@@ -0,0 +1,12 @@
1
+ <h2>State Machines</h2>
2
+
3
+ This class contains <%= state_machines.count %> state machine(s).
4
+
5
+ <% state_machines.each do |name, machine| %>
6
+ <h3><%= h(machine[:name]) %></h3>
7
+ <p><%= h(machine[:description]) %></p>
8
+
9
+ <% if machine[:image] %>
10
+ <img alt="State machine diagram for <%= h(machine[:name]) %>" src="<%= url_for(state_machine_image_path(machine)) %>" />
11
+ <% end %>
12
+ <% end %>
@@ -0,0 +1 @@
1
+ require File.join("#{File.dirname(__FILE__)}/state_machine")
@@ -0,0 +1,30 @@
1
+ namespace :state_machine do
2
+ desc 'Draws state machines using GraphViz (options: CLASS=User,Vehicle; FILE=user.rb,vehicle.rb [not required in Rails / Merb]; FONT=Arial; FORMAT=png; ORIENTATION=portrait; HUMAN_NAMES=true'
3
+ task :draw do
4
+ # Build drawing options
5
+ options = {}
6
+ options[:file] = ENV['FILE'] if ENV['FILE']
7
+ options[:path] = ENV['TARGET'] if ENV['TARGET']
8
+ options[:format] = ENV['FORMAT'] if ENV['FORMAT']
9
+ options[:font] = ENV['FONT'] if ENV['FONT']
10
+ options[:orientation] = ENV['ORIENTATION'] if ENV['ORIENTATION']
11
+ options[:human_names] = ENV['HUMAN_NAMES'] == 'true' if ENV['HUMAN_NAMES']
12
+
13
+ if defined?(Rails)
14
+ puts "Files are automatically loaded in Rails; ignoring FILE option" if options.delete(:file)
15
+ Rake::Task['environment'].invoke
16
+ elsif defined?(Merb)
17
+ puts "Files are automatically loaded in Merb; ignoring FILE option" if options.delete(:file)
18
+ Rake::Task['merb_env'].invoke
19
+
20
+ # Fix ruby-graphviz being incompatible with Merb's process title
21
+ $0 = 'rake'
22
+ else
23
+ # Load the library
24
+ $:.unshift(File.dirname(__FILE__) + '/..')
25
+ require 'state_machine'
26
+ end
27
+
28
+ StateMachine::Machine.draw(ENV['CLASS'], options)
29
+ end
30
+ end
@@ -0,0 +1,2 @@
1
+ require 'state_machine/core'
2
+ require 'state_machine/yard'
@@ -0,0 +1,21 @@
1
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
2
+ require 'state_machine/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "state_machine_deuxito"
6
+ s.version = StateMachine::VERSION
7
+ s.authors = ["Cwro Wren"]
8
+ s.description = "Fork of seuros/state_machine for use by DU"
9
+ s.summary = "State machines for attributes"
10
+ s.require_paths = ["lib"]
11
+ ignores = File.read(".gitignore").split.map {|i| i.sub(/\/$/, "/*").sub(/^[^\/]/, "**/\\0")}
12
+ s.files = (Dir[".*"] + Dir["**/*"]).select {|f| File.file?(f) && !ignores.any? {|i| File.fnmatch(i, "/#{f}")}}
13
+ s.test_files = s.files.grep(/^test\//)
14
+ s.rdoc_options = %w(--line-numbers --inline-source --title state_machine --main README.md)
15
+ s.extra_rdoc_files = %w(README.md CHANGELOG.md LICENSE)
16
+
17
+ s.add_development_dependency("rake")
18
+ s.add_development_dependency("simplecov")
19
+ s.add_development_dependency("appraisal")
20
+ s.add_development_dependency("test-unit")
21
+ end
data/test/files/en.yml ADDED
@@ -0,0 +1,17 @@
1
+ en:
2
+ activerecord:
3
+ errors:
4
+ messages:
5
+ invalid_transition: "cannot transition"
6
+ activemodel:
7
+ errors:
8
+ messages:
9
+ invalid_transition: "cannot %{event}"
10
+ mongoid:
11
+ errors:
12
+ messages:
13
+ invalid_transition: "cannot transition"
14
+ mongo_mapper:
15
+ errors:
16
+ messages:
17
+ invalid_transition: "cannot transition"
@@ -0,0 +1,15 @@
1
+ class Switch
2
+ def self.name
3
+ @name ||= "Switch_#{rand(1000000)}"
4
+ end
5
+
6
+ state_machine do
7
+ event :turn_on do
8
+ transition all => :on
9
+ end
10
+
11
+ event :turn_off do
12
+ transition all => :off
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,1067 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+ require 'test/unit'
3
+
4
+ class AutoShop
5
+ attr_accessor :num_customers
6
+
7
+ def initialize
8
+ @num_customers = 0
9
+ super
10
+ end
11
+
12
+ state_machine :initial => :available do
13
+ after_transition :available => any, :do => :increment_customers
14
+ after_transition :busy => any, :do => :decrement_customers
15
+
16
+ event :tow_vehicle do
17
+ transition :available => :busy
18
+ end
19
+
20
+ event :fix_vehicle do
21
+ transition :busy => :available
22
+ end
23
+ end
24
+
25
+ # Increments the number of customers in service
26
+ def increment_customers
27
+ self.num_customers += 1
28
+ end
29
+
30
+ # Decrements the number of customers in service
31
+ def decrement_customers
32
+ self.num_customers -= 1
33
+ end
34
+ end
35
+
36
+ class ModelBase
37
+ def save
38
+ @saved = true
39
+ self
40
+ end
41
+ end
42
+
43
+ class Vehicle < ModelBase
44
+ attr_accessor :auto_shop, :seatbelt_on, :insurance_premium, :force_idle, :callbacks, :saved, :time_elapsed, :last_transition_args
45
+
46
+ def initialize(attributes = {})
47
+ attributes = {
48
+ :auto_shop => AutoShop.new,
49
+ :seatbelt_on => false,
50
+ :insurance_premium => 50,
51
+ :force_idle => false,
52
+ :callbacks => [],
53
+ :saved => false
54
+ }.merge(attributes)
55
+
56
+ attributes.each {|attr, value| send("#{attr}=", value)}
57
+ super()
58
+ end
59
+
60
+ # Defines the state machine for the state of the vehicled
61
+ state_machine :initial => lambda {|vehicle| vehicle.force_idle ? :idling : :parked}, :action => :save do
62
+ before_transition {|vehicle, transition| vehicle.last_transition_args = transition.args}
63
+ before_transition :parked => any, :do => :put_on_seatbelt
64
+ before_transition any => :stalled, :do => :increase_insurance_premium
65
+ after_transition any => :parked, :do => lambda {|vehicle| vehicle.seatbelt_on = false}
66
+ after_transition :on => :crash, :do => :tow
67
+ after_transition :on => :repair, :do => :fix
68
+
69
+ # Callback tracking for initial state callbacks
70
+ after_transition any => :parked, :do => lambda {|vehicle| vehicle.callbacks << 'before_enter_parked'}
71
+ before_transition any => :idling, :do => lambda {|vehicle| vehicle.callbacks << 'before_enter_idling'}
72
+
73
+ around_transition do |vehicle, transition, block|
74
+ time = Time.now
75
+ block.call
76
+ vehicle.time_elapsed = Time.now - time
77
+ end
78
+
79
+ event all do
80
+ transition :locked => :parked
81
+ end
82
+
83
+ event :park do
84
+ transition [:idling, :first_gear] => :parked
85
+ end
86
+
87
+ event :ignite do
88
+ transition :stalled => :stalled
89
+ transition :parked => :idling
90
+ end
91
+
92
+ event :idle do
93
+ transition :first_gear => :idling
94
+ end
95
+
96
+ event :shift_up do
97
+ transition :idling => :first_gear, :first_gear => :second_gear, :second_gear => :third_gear
98
+ end
99
+
100
+ event :shift_down do
101
+ transition :third_gear => :second_gear
102
+ transition :second_gear => :first_gear
103
+ end
104
+
105
+ event :crash do
106
+ transition [:first_gear, :second_gear, :third_gear] => :stalled, :if => lambda {|vehicle| vehicle.auto_shop.available?}
107
+ end
108
+
109
+ event :repair do
110
+ transition :stalled => :parked, :if => :auto_shop_busy?
111
+ end
112
+ end
113
+
114
+ state_machine :insurance_state, :initial => :inactive, :namespace => 'insurance' do
115
+ event :buy do
116
+ transition :inactive => :active
117
+ end
118
+
119
+ event :cancel do
120
+ transition :active => :inactive
121
+ end
122
+ end
123
+
124
+ def save
125
+ super
126
+ end
127
+
128
+ def new_record?
129
+ @saved == false
130
+ end
131
+
132
+ def park
133
+ super
134
+ end
135
+
136
+ # Tows the vehicle to the auto shop
137
+ def tow
138
+ auto_shop.tow_vehicle
139
+ end
140
+
141
+ # Fixes the vehicle; it will no longer be in the auto shop
142
+ def fix
143
+ auto_shop.fix_vehicle
144
+ end
145
+
146
+ def decibels
147
+ 0.0
148
+ end
149
+
150
+ private
151
+ # Safety first! Puts on our seatbelt
152
+ def put_on_seatbelt
153
+ self.seatbelt_on = true
154
+ end
155
+
156
+ # We crashed! Increase the insurance premium on the vehicle
157
+ def increase_insurance_premium
158
+ self.insurance_premium += 100
159
+ end
160
+
161
+ # Is the auto shop currently servicing another customer?
162
+ def auto_shop_busy?
163
+ auto_shop.busy?
164
+ end
165
+ end
166
+
167
+ class Car < Vehicle
168
+ state_machine do
169
+ event :reverse do
170
+ transition [:parked, :idling, :first_gear] => :backing_up
171
+ end
172
+
173
+ event :park do
174
+ transition :backing_up => :parked
175
+ end
176
+
177
+ event :idle do
178
+ transition :backing_up => :idling
179
+ end
180
+
181
+ event :shift_up do
182
+ transition :backing_up => :first_gear
183
+ end
184
+ end
185
+ end
186
+
187
+ class Motorcycle < Vehicle
188
+ state_machine :initial => :idling do
189
+ state :first_gear do
190
+ def decibels
191
+ 1.0
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ class TrafficLight
198
+ state_machine :initial => :stop do
199
+ event :cycle do
200
+ transition :stop => :proceed, :proceed => :caution, :caution => :stop
201
+ end
202
+
203
+ state :stop do
204
+ def color(transform)
205
+ value = 'red'
206
+
207
+ if block_given?
208
+ yield value
209
+ else
210
+ value.send(transform)
211
+ end
212
+
213
+ value
214
+ end
215
+ end
216
+
217
+ state all - :proceed do
218
+ def capture_violations?
219
+ true
220
+ end
221
+ end
222
+
223
+ state :proceed do
224
+ def color(transform)
225
+ 'green'
226
+ end
227
+
228
+ def capture_violations?
229
+ false
230
+ end
231
+ end
232
+
233
+ state :caution do
234
+ def color(transform)
235
+ 'yellow'
236
+ end
237
+ end
238
+ end
239
+
240
+ def color(transform = :to_s)
241
+ super
242
+ end
243
+ end
244
+
245
+ class VehicleTest < Test::Unit::TestCase
246
+ def setup
247
+ @vehicle = Vehicle.new
248
+ end
249
+
250
+ def test_should_not_allow_access_to_subclass_events
251
+ assert !@vehicle.respond_to?(:reverse)
252
+ end
253
+
254
+ def test_should_have_human_state_names
255
+ assert_equal 'parked', Vehicle.human_state_name(:parked)
256
+ end
257
+
258
+ def test_should_have_human_state_event_names
259
+ assert_equal 'park', Vehicle.human_state_event_name(:park)
260
+ end
261
+ end
262
+
263
+ class VehicleUnsavedTest < Test::Unit::TestCase
264
+ def setup
265
+ @vehicle = Vehicle.new
266
+ end
267
+
268
+ def test_should_be_in_parked_state
269
+ assert_equal 'parked', @vehicle.state
270
+ end
271
+
272
+ def test_should_raise_exception_if_checking_invalid_state
273
+ assert_raise(IndexError) { @vehicle.state?(:invalid) }
274
+ end
275
+
276
+ def test_should_raise_exception_if_getting_name_of_invalid_state
277
+ @vehicle.state = 'invalid'
278
+ assert_raise(ArgumentError) { @vehicle.state_name }
279
+ end
280
+
281
+ def test_should_be_parked
282
+ assert @vehicle.parked?
283
+ assert @vehicle.state?(:parked)
284
+ assert_equal :parked, @vehicle.state_name
285
+ assert_equal 'parked', @vehicle.human_state_name
286
+ end
287
+
288
+ def test_should_not_be_idling
289
+ assert !@vehicle.idling?
290
+ end
291
+
292
+ def test_should_not_be_first_gear
293
+ assert !@vehicle.first_gear?
294
+ end
295
+
296
+ def test_should_not_be_second_gear
297
+ assert !@vehicle.second_gear?
298
+ end
299
+
300
+ def test_should_not_be_stalled
301
+ assert !@vehicle.stalled?
302
+ end
303
+
304
+ def test_should_not_be_able_to_park
305
+ assert !@vehicle.can_park?
306
+ end
307
+
308
+ def test_should_not_have_a_transition_for_park
309
+ assert_nil @vehicle.park_transition
310
+ end
311
+
312
+ def test_should_not_allow_park
313
+ assert !@vehicle.park
314
+ end
315
+
316
+ def test_should_be_able_to_ignite
317
+ assert @vehicle.can_ignite?
318
+ end
319
+
320
+ def test_should_have_a_transition_for_ignite
321
+ transition = @vehicle.ignite_transition
322
+ assert_not_nil transition
323
+ assert_equal 'parked', transition.from
324
+ assert_equal 'idling', transition.to
325
+ assert_equal :ignite, transition.event
326
+ assert_equal :state, transition.attribute
327
+ assert_equal @vehicle, transition.object
328
+ end
329
+
330
+ def test_should_have_a_list_of_possible_events
331
+ assert_equal [:ignite], @vehicle.state_events
332
+ end
333
+
334
+ def test_should_have_a_list_of_possible_transitions
335
+ assert_equal [{:object => @vehicle, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}], @vehicle.state_transitions.map {|transition| transition.attributes}
336
+ end
337
+
338
+ def test_should_have_a_list_of_possible_paths
339
+ assert_equal [[
340
+ StateMachine::Transition.new(@vehicle, Vehicle.state_machine, :ignite, :parked, :idling),
341
+ StateMachine::Transition.new(@vehicle, Vehicle.state_machine, :shift_up, :idling, :first_gear)
342
+ ]], @vehicle.state_paths(:to => :first_gear)
343
+ end
344
+
345
+ def test_should_allow_generic_event_to_fire
346
+ assert @vehicle.fire_state_event(:ignite)
347
+ assert_equal 'idling', @vehicle.state
348
+ end
349
+
350
+ def test_should_pass_arguments_through_to_generic_event_runner
351
+ @vehicle.fire_state_event(:ignite, 1, 2, 3)
352
+ assert_equal [1, 2, 3], @vehicle.last_transition_args
353
+ end
354
+
355
+ def test_should_allow_skipping_action_through_generic_event_runner
356
+ @vehicle.fire_state_event(:ignite, false)
357
+ assert_equal false, @vehicle.saved
358
+ end
359
+
360
+ def test_should_raise_error_with_invalid_event_through_generic_event_runer
361
+ assert_raise(IndexError) { @vehicle.fire_state_event(:invalid) }
362
+ end
363
+
364
+ def test_should_allow_ignite
365
+ assert @vehicle.ignite
366
+ assert_equal 'idling', @vehicle.state
367
+ end
368
+
369
+ def test_should_allow_ignite_with_skipped_action
370
+ assert @vehicle.ignite(false)
371
+ assert @vehicle.new_record?
372
+ end
373
+
374
+ def test_should_allow_ignite_bang
375
+ assert @vehicle.ignite!
376
+ end
377
+
378
+ def test_should_allow_ignite_bang_with_skipped_action
379
+ assert @vehicle.ignite!(false)
380
+ assert @vehicle.new_record?
381
+ end
382
+
383
+ def test_should_be_saved_after_successful_event
384
+ @vehicle.ignite
385
+ assert !@vehicle.new_record?
386
+ end
387
+
388
+ def test_should_not_allow_idle
389
+ assert !@vehicle.idle
390
+ end
391
+
392
+ def test_should_not_allow_shift_up
393
+ assert !@vehicle.shift_up
394
+ end
395
+
396
+ def test_should_not_allow_shift_down
397
+ assert !@vehicle.shift_down
398
+ end
399
+
400
+ def test_should_not_allow_crash
401
+ assert !@vehicle.crash
402
+ end
403
+
404
+ def test_should_not_allow_repair
405
+ assert !@vehicle.repair
406
+ end
407
+
408
+ def test_should_be_insurance_inactive
409
+ assert @vehicle.insurance_inactive?
410
+ end
411
+
412
+ def test_should_be_able_to_buy
413
+ assert @vehicle.can_buy_insurance?
414
+ end
415
+
416
+ def test_should_allow_buying_insurance
417
+ assert @vehicle.buy_insurance
418
+ end
419
+
420
+ def test_should_allow_buying_insurance_bang
421
+ assert @vehicle.buy_insurance!
422
+ end
423
+
424
+ def test_should_allow_ignite_buying_insurance_with_skipped_action
425
+ assert @vehicle.buy_insurance!(false)
426
+ assert @vehicle.new_record?
427
+ end
428
+
429
+ def test_should_not_be_insurance_active
430
+ assert !@vehicle.insurance_active?
431
+ end
432
+
433
+ def test_should_not_be_able_to_cancel
434
+ assert !@vehicle.can_cancel_insurance?
435
+ end
436
+
437
+ def test_should_not_allow_cancelling_insurance
438
+ assert !@vehicle.cancel_insurance
439
+ end
440
+ end
441
+
442
+ class VehicleParkedTest < Test::Unit::TestCase
443
+ def setup
444
+ @vehicle = Vehicle.new
445
+ end
446
+
447
+ def test_should_be_in_parked_state
448
+ assert_equal 'parked', @vehicle.state
449
+ end
450
+
451
+ def test_should_not_have_the_seatbelt_on
452
+ assert !@vehicle.seatbelt_on
453
+ end
454
+
455
+ def test_should_not_allow_park
456
+ assert !@vehicle.park
457
+ end
458
+
459
+ def test_should_allow_ignite
460
+ assert @vehicle.ignite
461
+ assert_equal 'idling', @vehicle.state
462
+ end
463
+
464
+ def test_should_not_allow_idle
465
+ assert !@vehicle.idle
466
+ end
467
+
468
+ def test_should_not_allow_shift_up
469
+ assert !@vehicle.shift_up
470
+ end
471
+
472
+ def test_should_not_allow_shift_down
473
+ assert !@vehicle.shift_down
474
+ end
475
+
476
+ def test_should_not_allow_crash
477
+ assert !@vehicle.crash
478
+ end
479
+
480
+ def test_should_not_allow_repair
481
+ assert !@vehicle.repair
482
+ end
483
+
484
+ def test_should_raise_exception_if_repair_not_allowed!
485
+ exception = assert_raise(StateMachine::InvalidTransition) {@vehicle.repair!}
486
+ assert_equal @vehicle, exception.object
487
+ assert_equal Vehicle.state_machine(:state), exception.machine
488
+ assert_equal :repair, exception.event
489
+ assert_equal 'parked', exception.from
490
+ end
491
+ end
492
+
493
+ class VehicleIdlingTest < Test::Unit::TestCase
494
+ def setup
495
+ @vehicle = Vehicle.new
496
+ @vehicle.ignite
497
+ end
498
+
499
+ def test_should_be_in_idling_state
500
+ assert_equal 'idling', @vehicle.state
501
+ end
502
+
503
+ def test_should_be_idling
504
+ assert @vehicle.idling?
505
+ end
506
+
507
+ def test_should_have_seatbelt_on
508
+ assert @vehicle.seatbelt_on
509
+ end
510
+
511
+ def test_should_track_time_elapsed
512
+ assert_not_nil @vehicle.time_elapsed
513
+ end
514
+
515
+ def test_should_allow_park
516
+ assert @vehicle.park
517
+ end
518
+
519
+ def test_should_call_park_with_bang_action
520
+ class << @vehicle
521
+ def park
522
+ super && 1
523
+ end
524
+ end
525
+
526
+ assert_equal 1, @vehicle.park!
527
+ end
528
+
529
+ def test_should_not_allow_idle
530
+ assert !@vehicle.idle
531
+ end
532
+
533
+ def test_should_allow_shift_up
534
+ assert @vehicle.shift_up
535
+ end
536
+
537
+ def test_should_not_allow_shift_down
538
+ assert !@vehicle.shift_down
539
+ end
540
+
541
+ def test_should_not_allow_crash
542
+ assert !@vehicle.crash
543
+ end
544
+
545
+ def test_should_not_allow_repair
546
+ assert !@vehicle.repair
547
+ end
548
+ end
549
+
550
+ class VehicleFirstGearTest < Test::Unit::TestCase
551
+ def setup
552
+ @vehicle = Vehicle.new
553
+ @vehicle.ignite
554
+ @vehicle.shift_up
555
+ end
556
+
557
+ def test_should_be_in_first_gear_state
558
+ assert_equal 'first_gear', @vehicle.state
559
+ end
560
+
561
+ def test_should_be_first_gear
562
+ assert @vehicle.first_gear?
563
+ end
564
+
565
+ def test_should_allow_park
566
+ assert @vehicle.park
567
+ end
568
+
569
+ def test_should_allow_idle
570
+ assert @vehicle.idle
571
+ end
572
+
573
+ def test_should_allow_shift_up
574
+ assert @vehicle.shift_up
575
+ end
576
+
577
+ def test_should_not_allow_shift_down
578
+ assert !@vehicle.shift_down
579
+ end
580
+
581
+ def test_should_allow_crash
582
+ assert @vehicle.crash
583
+ end
584
+
585
+ def test_should_not_allow_repair
586
+ assert !@vehicle.repair
587
+ end
588
+ end
589
+
590
+ class VehicleSecondGearTest < Test::Unit::TestCase
591
+ def setup
592
+ @vehicle = Vehicle.new
593
+ @vehicle.ignite
594
+ 2.times {@vehicle.shift_up}
595
+ end
596
+
597
+ def test_should_be_in_second_gear_state
598
+ assert_equal 'second_gear', @vehicle.state
599
+ end
600
+
601
+ def test_should_be_second_gear
602
+ assert @vehicle.second_gear?
603
+ end
604
+
605
+ def test_should_not_allow_park
606
+ assert !@vehicle.park
607
+ end
608
+
609
+ def test_should_not_allow_idle
610
+ assert !@vehicle.idle
611
+ end
612
+
613
+ def test_should_allow_shift_up
614
+ assert @vehicle.shift_up
615
+ end
616
+
617
+ def test_should_allow_shift_down
618
+ assert @vehicle.shift_down
619
+ end
620
+
621
+ def test_should_allow_crash
622
+ assert @vehicle.crash
623
+ end
624
+
625
+ def test_should_not_allow_repair
626
+ assert !@vehicle.repair
627
+ end
628
+ end
629
+
630
+ class VehicleThirdGearTest < Test::Unit::TestCase
631
+ def setup
632
+ @vehicle = Vehicle.new
633
+ @vehicle.ignite
634
+ 3.times {@vehicle.shift_up}
635
+ end
636
+
637
+ def test_should_be_in_third_gear_state
638
+ assert_equal 'third_gear', @vehicle.state
639
+ end
640
+
641
+ def test_should_be_third_gear
642
+ assert @vehicle.third_gear?
643
+ end
644
+
645
+ def test_should_not_allow_park
646
+ assert !@vehicle.park
647
+ end
648
+
649
+ def test_should_not_allow_idle
650
+ assert !@vehicle.idle
651
+ end
652
+
653
+ def test_should_not_allow_shift_up
654
+ assert !@vehicle.shift_up
655
+ end
656
+
657
+ def test_should_allow_shift_down
658
+ assert @vehicle.shift_down
659
+ end
660
+
661
+ def test_should_allow_crash
662
+ assert @vehicle.crash
663
+ end
664
+
665
+ def test_should_not_allow_repair
666
+ assert !@vehicle.repair
667
+ end
668
+ end
669
+
670
+ class VehicleStalledTest < Test::Unit::TestCase
671
+ def setup
672
+ @vehicle = Vehicle.new
673
+ @vehicle.ignite
674
+ @vehicle.shift_up
675
+ @vehicle.crash
676
+ end
677
+
678
+ def test_should_be_in_stalled_state
679
+ assert_equal 'stalled', @vehicle.state
680
+ end
681
+
682
+ def test_should_be_stalled
683
+ assert @vehicle.stalled?
684
+ end
685
+
686
+ def test_should_be_towed
687
+ assert @vehicle.auto_shop.busy?
688
+ assert_equal 1, @vehicle.auto_shop.num_customers
689
+ end
690
+
691
+ def test_should_have_an_increased_insurance_premium
692
+ assert_equal 150, @vehicle.insurance_premium
693
+ end
694
+
695
+ def test_should_not_allow_park
696
+ assert !@vehicle.park
697
+ end
698
+
699
+ def test_should_allow_ignite
700
+ assert @vehicle.ignite
701
+ end
702
+
703
+ def test_should_not_change_state_when_ignited
704
+ assert_equal 'stalled', @vehicle.state
705
+ end
706
+
707
+ def test_should_not_allow_idle
708
+ assert !@vehicle.idle
709
+ end
710
+
711
+ def test_should_now_allow_shift_up
712
+ assert !@vehicle.shift_up
713
+ end
714
+
715
+ def test_should_not_allow_shift_down
716
+ assert !@vehicle.shift_down
717
+ end
718
+
719
+ def test_should_not_allow_crash
720
+ assert !@vehicle.crash
721
+ end
722
+
723
+ def test_should_allow_repair_if_auto_shop_is_busy
724
+ assert @vehicle.repair
725
+ end
726
+
727
+ def test_should_not_allow_repair_if_auto_shop_is_available
728
+ @vehicle.auto_shop.fix_vehicle
729
+ assert !@vehicle.repair
730
+ end
731
+ end
732
+
733
+ class VehicleRepairedTest < Test::Unit::TestCase
734
+ def setup
735
+ @vehicle = Vehicle.new
736
+ @vehicle.ignite
737
+ @vehicle.shift_up
738
+ @vehicle.crash
739
+ @vehicle.repair
740
+ end
741
+
742
+ def test_should_be_in_parked_state
743
+ assert_equal 'parked', @vehicle.state
744
+ end
745
+
746
+ def test_should_not_have_a_busy_auto_shop
747
+ assert @vehicle.auto_shop.available?
748
+ end
749
+ end
750
+
751
+ class VehicleLockedTest < Test::Unit::TestCase
752
+ def setup
753
+ @vehicle = Vehicle.new
754
+ @vehicle.state = 'locked'
755
+ end
756
+
757
+ def test_should_be_parked_after_park
758
+ @vehicle.park
759
+ assert @vehicle.parked?
760
+ end
761
+
762
+ def test_should_be_parked_after_ignite
763
+ @vehicle.ignite
764
+ assert @vehicle.parked?
765
+ end
766
+
767
+ def test_should_be_parked_after_shift_up
768
+ @vehicle.shift_up
769
+ assert @vehicle.parked?
770
+ end
771
+
772
+ def test_should_be_parked_after_shift_down
773
+ @vehicle.shift_down
774
+ assert @vehicle.parked?
775
+ end
776
+ end
777
+
778
+ class VehicleWithParallelEventsTest < Test::Unit::TestCase
779
+ def setup
780
+ @vehicle = Vehicle.new
781
+ end
782
+
783
+ def test_should_fail_if_any_event_cannot_transition
784
+ assert !@vehicle.fire_events(:ignite, :cancel_insurance)
785
+ end
786
+
787
+ def test_should_be_successful_if_all_events_transition
788
+ assert @vehicle.fire_events(:ignite, :buy_insurance)
789
+ end
790
+
791
+ def test_should_not_save_if_skipping_action
792
+ assert @vehicle.fire_events(:ignite, :buy_insurance, false)
793
+ assert !@vehicle.saved
794
+ end
795
+
796
+ def test_should_raise_exception_if_any_event_cannot_transition_on_bang
797
+ exception = assert_raise(StateMachine::InvalidParallelTransition) { @vehicle.fire_events!(:ignite, :cancel_insurance) }
798
+ assert_equal @vehicle, exception.object
799
+ assert_equal [:ignite, :cancel_insurance], exception.events
800
+ end
801
+
802
+ def test_should_not_raise_exception_if_all_events_transition_on_bang
803
+ assert @vehicle.fire_events!(:ignite, :buy_insurance)
804
+ end
805
+
806
+ def test_should_not_save_if_skipping_action_on_bang
807
+ assert @vehicle.fire_events!(:ignite, :buy_insurance, false)
808
+ assert !@vehicle.saved
809
+ end
810
+ end
811
+
812
+ class VehicleWithEventAttributesTest < Test::Unit::TestCase
813
+ def setup
814
+ @vehicle = Vehicle.new
815
+ @vehicle.state_event = 'ignite'
816
+ end
817
+
818
+ def test_should_fail_if_event_is_invalid
819
+ @vehicle.state_event = 'invalid'
820
+ assert !@vehicle.save
821
+ assert_equal 'parked', @vehicle.state
822
+ end
823
+
824
+ def test_should_fail_if_event_has_no_transition
825
+ @vehicle.state_event = 'park'
826
+ assert !@vehicle.save
827
+ assert_equal 'parked', @vehicle.state
828
+ end
829
+
830
+ def test_should_return_original_action_value_on_success
831
+ assert_equal @vehicle, @vehicle.save
832
+ end
833
+
834
+ def test_should_transition_state_on_success
835
+ @vehicle.save
836
+ assert_equal 'idling', @vehicle.state
837
+ end
838
+ end
839
+
840
+ class MotorcycleTest < Test::Unit::TestCase
841
+ def setup
842
+ @motorcycle = Motorcycle.new
843
+ end
844
+
845
+ def test_should_be_in_idling_state
846
+ assert_equal 'idling', @motorcycle.state
847
+ end
848
+
849
+ def test_should_allow_park
850
+ assert @motorcycle.park
851
+ end
852
+
853
+ def test_should_not_allow_ignite
854
+ assert !@motorcycle.ignite
855
+ end
856
+
857
+ def test_should_allow_shift_up
858
+ assert @motorcycle.shift_up
859
+ end
860
+
861
+ def test_should_not_allow_shift_down
862
+ assert !@motorcycle.shift_down
863
+ end
864
+
865
+ def test_should_not_allow_crash
866
+ assert !@motorcycle.crash
867
+ end
868
+
869
+ def test_should_not_allow_repair
870
+ assert !@motorcycle.repair
871
+ end
872
+
873
+ def test_should_inherit_decibels_from_superclass
874
+ @motorcycle.park
875
+ assert_equal 0.0, @motorcycle.decibels
876
+ end
877
+
878
+ def test_should_use_decibels_defined_in_state
879
+ @motorcycle.shift_up
880
+ assert_equal 1.0, @motorcycle.decibels
881
+ end
882
+ end
883
+
884
+ class CarTest < Test::Unit::TestCase
885
+ def setup
886
+ @car = Car.new
887
+ end
888
+
889
+ def test_should_be_in_parked_state
890
+ assert_equal 'parked', @car.state
891
+ end
892
+
893
+ def test_should_not_have_the_seatbelt_on
894
+ assert !@car.seatbelt_on
895
+ end
896
+
897
+ def test_should_not_allow_park
898
+ assert !@car.park
899
+ end
900
+
901
+ def test_should_allow_ignite
902
+ assert @car.ignite
903
+ assert_equal 'idling', @car.state
904
+ end
905
+
906
+ def test_should_not_allow_idle
907
+ assert !@car.idle
908
+ end
909
+
910
+ def test_should_not_allow_shift_up
911
+ assert !@car.shift_up
912
+ end
913
+
914
+ def test_should_not_allow_shift_down
915
+ assert !@car.shift_down
916
+ end
917
+
918
+ def test_should_not_allow_crash
919
+ assert !@car.crash
920
+ end
921
+
922
+ def test_should_not_allow_repair
923
+ assert !@car.repair
924
+ end
925
+
926
+ def test_should_allow_reverse
927
+ assert @car.reverse
928
+ end
929
+ end
930
+
931
+ class CarBackingUpTest < Test::Unit::TestCase
932
+ def setup
933
+ @car = Car.new
934
+ @car.reverse
935
+ end
936
+
937
+ def test_should_be_in_backing_up_state
938
+ assert_equal 'backing_up', @car.state
939
+ end
940
+
941
+ def test_should_allow_park
942
+ assert @car.park
943
+ end
944
+
945
+ def test_should_not_allow_ignite
946
+ assert !@car.ignite
947
+ end
948
+
949
+ def test_should_allow_idle
950
+ assert @car.idle
951
+ end
952
+
953
+ def test_should_allow_shift_up
954
+ assert @car.shift_up
955
+ end
956
+
957
+ def test_should_not_allow_shift_down
958
+ assert !@car.shift_down
959
+ end
960
+
961
+ def test_should_not_allow_crash
962
+ assert !@car.crash
963
+ end
964
+
965
+ def test_should_not_allow_repair
966
+ assert !@car.repair
967
+ end
968
+
969
+ def test_should_not_allow_reverse
970
+ assert !@car.reverse
971
+ end
972
+ end
973
+
974
+ class AutoShopAvailableTest < Test::Unit::TestCase
975
+ def setup
976
+ @auto_shop = AutoShop.new
977
+ end
978
+
979
+ def test_should_be_in_available_state
980
+ assert_equal 'available', @auto_shop.state
981
+ end
982
+
983
+ def test_should_allow_tow_vehicle
984
+ assert @auto_shop.tow_vehicle
985
+ end
986
+
987
+ def test_should_not_allow_fix_vehicle
988
+ assert !@auto_shop.fix_vehicle
989
+ end
990
+ end
991
+
992
+ class AutoShopBusyTest < Test::Unit::TestCase
993
+ def setup
994
+ @auto_shop = AutoShop.new
995
+ @auto_shop.tow_vehicle
996
+ end
997
+
998
+ def test_should_be_in_busy_state
999
+ assert_equal 'busy', @auto_shop.state
1000
+ end
1001
+
1002
+ def test_should_have_incremented_number_of_customers
1003
+ assert_equal 1, @auto_shop.num_customers
1004
+ end
1005
+
1006
+ def test_should_not_allow_tow_vehicle
1007
+ assert !@auto_shop.tow_vehicle
1008
+ end
1009
+
1010
+ def test_should_allow_fix_vehicle
1011
+ assert @auto_shop.fix_vehicle
1012
+ end
1013
+ end
1014
+
1015
+ class TrafficLightStopTest < Test::Unit::TestCase
1016
+ def setup
1017
+ @light = TrafficLight.new
1018
+ @light.state = 'stop'
1019
+ end
1020
+
1021
+ def test_should_use_stop_color
1022
+ assert_equal 'red', @light.color
1023
+ end
1024
+
1025
+ def test_should_pass_arguments_through
1026
+ assert_equal 'RED', @light.color(:upcase!)
1027
+ end
1028
+
1029
+ def test_should_pass_block_through
1030
+ color = @light.color {|value| value.upcase!}
1031
+ assert_equal 'RED', color
1032
+ end
1033
+
1034
+ def test_should_use_stop_capture_violations
1035
+ assert_equal true, @light.capture_violations?
1036
+ end
1037
+ end
1038
+
1039
+ class TrafficLightProceedTest < Test::Unit::TestCase
1040
+ def setup
1041
+ @light = TrafficLight.new
1042
+ @light.state = 'proceed'
1043
+ end
1044
+
1045
+ def test_should_use_proceed_color
1046
+ assert_equal 'green', @light.color
1047
+ end
1048
+
1049
+ def test_should_use_proceed_capture_violations
1050
+ assert_equal false, @light.capture_violations?
1051
+ end
1052
+ end
1053
+
1054
+ class TrafficLightCautionTest < Test::Unit::TestCase
1055
+ def setup
1056
+ @light = TrafficLight.new
1057
+ @light.state = 'caution'
1058
+ end
1059
+
1060
+ def test_should_use_caution_color
1061
+ assert_equal 'yellow', @light.color
1062
+ end
1063
+
1064
+ def test_should_use_caution_capture_violations
1065
+ assert_equal true, @light.capture_violations?
1066
+ end
1067
+ end