state_machine 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (240) hide show
  1. data/.gitignore +7 -11
  2. data/.travis.yml +49 -7
  3. data/Appraisals +255 -87
  4. data/CHANGELOG.md +30 -0
  5. data/README.md +142 -21
  6. data/Rakefile +1 -11
  7. data/examples/Gemfile +5 -0
  8. data/examples/Gemfile.lock +14 -0
  9. data/examples/auto_shop.rb +2 -0
  10. data/examples/car.rb +2 -0
  11. data/examples/doc/AutoShop.html +2856 -0
  12. data/examples/doc/AutoShop_state.png +0 -0
  13. data/examples/doc/Car.html +919 -0
  14. data/examples/doc/Car_state.png +0 -0
  15. data/examples/doc/TrafficLight.html +2230 -0
  16. data/examples/doc/TrafficLight_state.png +0 -0
  17. data/examples/doc/Vehicle.html +7921 -0
  18. data/examples/doc/Vehicle_state.png +0 -0
  19. data/examples/doc/_index.html +136 -0
  20. data/examples/doc/class_list.html +47 -0
  21. data/examples/doc/css/common.css +1 -0
  22. data/examples/doc/css/full_list.css +55 -0
  23. data/examples/doc/css/style.css +322 -0
  24. data/examples/doc/file_list.html +46 -0
  25. data/examples/doc/frames.html +13 -0
  26. data/examples/doc/index.html +136 -0
  27. data/examples/doc/js/app.js +205 -0
  28. data/examples/doc/js/full_list.js +173 -0
  29. data/examples/doc/js/jquery.js +16 -0
  30. data/examples/doc/method_list.html +734 -0
  31. data/examples/doc/top-level-namespace.html +105 -0
  32. data/examples/rails-rest/migration.rb +1 -5
  33. data/examples/rails-rest/view__form.html.erb +34 -0
  34. data/examples/rails-rest/view_edit.html.erb +2 -21
  35. data/examples/rails-rest/view_index.html.erb +6 -4
  36. data/examples/rails-rest/view_new.html.erb +2 -11
  37. data/examples/rails-rest/view_show.html.erb +5 -3
  38. data/examples/traffic_light.rb +2 -0
  39. data/examples/vehicle.rb +2 -0
  40. data/gemfiles/active_model-3.0.0.gemfile.lock +9 -6
  41. data/gemfiles/active_model-3.0.5.gemfile.lock +10 -7
  42. data/gemfiles/active_model-3.1.1.gemfile.lock +12 -10
  43. data/gemfiles/{active_model-3.2.0.gemfile → active_model-3.2.1.gemfile} +1 -1
  44. data/gemfiles/{graphviz-0.9.0.gemfile → active_model-3.2.12.gemfile} +1 -1
  45. data/gemfiles/active_model-3.2.12.gemfile.lock +36 -0
  46. data/gemfiles/{active_record-3.2.0.gemfile → active_model-3.2.13.rc1.gemfile} +1 -2
  47. data/gemfiles/active_model-3.2.13.rc1.gemfile.lock +36 -0
  48. data/gemfiles/active_model-4.0.0.gemfile +9 -0
  49. data/gemfiles/active_model-4.0.0.gemfile.lock +78 -0
  50. data/gemfiles/active_record-2.0.0.gemfile +2 -1
  51. data/gemfiles/active_record-2.0.0.gemfile.lock +15 -6
  52. data/gemfiles/active_record-2.0.5.gemfile +2 -1
  53. data/gemfiles/active_record-2.0.5.gemfile.lock +15 -6
  54. data/gemfiles/active_record-2.1.0.gemfile +2 -1
  55. data/gemfiles/active_record-2.1.0.gemfile.lock +15 -6
  56. data/gemfiles/active_record-2.1.2.gemfile +2 -1
  57. data/gemfiles/active_record-2.1.2.gemfile.lock +15 -6
  58. data/gemfiles/active_record-2.2.3.gemfile +2 -1
  59. data/gemfiles/active_record-2.2.3.gemfile.lock +15 -6
  60. data/gemfiles/active_record-2.3.12.gemfile +2 -1
  61. data/gemfiles/active_record-2.3.12.gemfile.lock +15 -6
  62. data/gemfiles/active_record-2.3.5.gemfile +9 -0
  63. data/gemfiles/active_record-2.3.5.gemfile.lock +39 -0
  64. data/gemfiles/active_record-3.0.0.gemfile +2 -1
  65. data/gemfiles/active_record-3.0.0.gemfile.lock +18 -11
  66. data/gemfiles/active_record-3.0.5.gemfile +2 -1
  67. data/gemfiles/active_record-3.0.5.gemfile.lock +19 -12
  68. data/gemfiles/active_record-3.1.1.gemfile +2 -1
  69. data/gemfiles/active_record-3.1.1.gemfile.lock +22 -16
  70. data/gemfiles/active_record-3.2.12.gemfile +9 -0
  71. data/gemfiles/active_record-3.2.12.gemfile.lock +51 -0
  72. data/gemfiles/active_record-3.2.13.rc1.gemfile +9 -0
  73. data/gemfiles/active_record-3.2.13.rc1.gemfile.lock +51 -0
  74. data/gemfiles/active_record-4.0.0.gemfile +11 -0
  75. data/gemfiles/active_record-4.0.0.gemfile.lock +83 -0
  76. data/gemfiles/data_mapper-0.10.2.gemfile +1 -0
  77. data/gemfiles/data_mapper-0.10.2.gemfile.lock +13 -9
  78. data/gemfiles/data_mapper-0.9.11.gemfile +1 -0
  79. data/gemfiles/data_mapper-0.9.11.gemfile.lock +31 -7
  80. data/gemfiles/data_mapper-0.9.4.gemfile.lock +25 -14
  81. data/gemfiles/data_mapper-0.9.7.gemfile +1 -0
  82. data/gemfiles/data_mapper-0.9.7.gemfile.lock +27 -15
  83. data/gemfiles/data_mapper-1.0.0.gemfile.lock +20 -17
  84. data/gemfiles/data_mapper-1.0.1.gemfile.lock +20 -17
  85. data/gemfiles/data_mapper-1.0.2.gemfile.lock +20 -17
  86. data/gemfiles/data_mapper-1.1.0.gemfile.lock +19 -16
  87. data/gemfiles/data_mapper-1.2.0.gemfile.lock +19 -16
  88. data/gemfiles/default.gemfile.lock +8 -5
  89. data/gemfiles/graphviz-0.9.17.gemfile +7 -0
  90. data/gemfiles/graphviz-0.9.17.gemfile.lock +29 -0
  91. data/gemfiles/graphviz-0.9.21.gemfile.lock +7 -4
  92. data/gemfiles/graphviz-1.0.0.gemfile.lock +7 -4
  93. data/gemfiles/graphviz-1.0.3.gemfile +7 -0
  94. data/gemfiles/graphviz-1.0.3.gemfile.lock +29 -0
  95. data/gemfiles/graphviz-1.0.8.gemfile +7 -0
  96. data/gemfiles/graphviz-1.0.8.gemfile.lock +29 -0
  97. data/gemfiles/mongo_mapper-0.10.0.gemfile +1 -0
  98. data/gemfiles/mongo_mapper-0.10.0.gemfile.lock +14 -11
  99. data/gemfiles/mongo_mapper-0.11.1.gemfile +7 -0
  100. data/gemfiles/mongo_mapper-0.11.1.gemfile.lock +44 -0
  101. data/gemfiles/mongo_mapper-0.11.2.gemfile +9 -0
  102. data/gemfiles/mongo_mapper-0.11.2.gemfile.lock +48 -0
  103. data/gemfiles/mongo_mapper-0.12.0.gemfile +9 -0
  104. data/gemfiles/mongo_mapper-0.12.0.gemfile.lock +48 -0
  105. data/gemfiles/mongo_mapper-0.5.5.gemfile.lock +7 -4
  106. data/gemfiles/mongo_mapper-0.5.8.gemfile.lock +7 -4
  107. data/gemfiles/mongo_mapper-0.6.0.gemfile.lock +7 -4
  108. data/gemfiles/mongo_mapper-0.6.10.gemfile.lock +7 -4
  109. data/gemfiles/mongo_mapper-0.7.0.gemfile.lock +7 -4
  110. data/gemfiles/mongo_mapper-0.7.5.gemfile.lock +7 -4
  111. data/gemfiles/mongo_mapper-0.8.0.gemfile.lock +7 -4
  112. data/gemfiles/mongo_mapper-0.8.3.gemfile.lock +7 -4
  113. data/gemfiles/mongo_mapper-0.8.4.gemfile.lock +7 -4
  114. data/gemfiles/mongo_mapper-0.8.6.gemfile.lock +7 -4
  115. data/gemfiles/mongo_mapper-0.9.0.gemfile.lock +7 -4
  116. data/gemfiles/mongoid-2.0.0.gemfile +2 -0
  117. data/gemfiles/mongoid-2.0.0.gemfile.lock +22 -18
  118. data/gemfiles/mongoid-2.1.4.gemfile +2 -0
  119. data/gemfiles/mongoid-2.1.4.gemfile.lock +21 -17
  120. data/gemfiles/mongoid-2.2.4.gemfile +2 -0
  121. data/gemfiles/mongoid-2.2.4.gemfile.lock +21 -17
  122. data/gemfiles/mongoid-2.3.3.gemfile +2 -0
  123. data/gemfiles/mongoid-2.3.3.gemfile.lock +21 -17
  124. data/gemfiles/mongoid-2.4.0.gemfile +9 -0
  125. data/gemfiles/mongoid-2.4.0.gemfile.lock +47 -0
  126. data/gemfiles/mongoid-2.4.10.gemfile +9 -0
  127. data/gemfiles/mongoid-2.4.10.gemfile.lock +47 -0
  128. data/gemfiles/mongoid-2.5.2.gemfile +9 -0
  129. data/gemfiles/mongoid-2.5.2.gemfile.lock +47 -0
  130. data/gemfiles/mongoid-2.6.0.gemfile +9 -0
  131. data/gemfiles/mongoid-2.6.0.gemfile.lock +47 -0
  132. data/gemfiles/mongoid-3.0.0.gemfile +8 -0
  133. data/gemfiles/mongoid-3.0.0.gemfile.lock +45 -0
  134. data/gemfiles/mongoid-3.0.22.gemfile +8 -0
  135. data/gemfiles/mongoid-3.0.22.gemfile.lock +45 -0
  136. data/gemfiles/mongoid-3.1.0.gemfile +8 -0
  137. data/gemfiles/mongoid-3.1.0.gemfile.lock +45 -0
  138. data/gemfiles/sequel-2.11.0.gemfile +2 -1
  139. data/gemfiles/sequel-2.11.0.gemfile.lock +11 -6
  140. data/gemfiles/sequel-2.12.0.gemfile +2 -1
  141. data/gemfiles/sequel-2.12.0.gemfile.lock +11 -6
  142. data/gemfiles/sequel-2.8.0.gemfile +2 -1
  143. data/gemfiles/sequel-2.8.0.gemfile.lock +11 -6
  144. data/gemfiles/sequel-3.0.0.gemfile +2 -1
  145. data/gemfiles/sequel-3.0.0.gemfile.lock +11 -6
  146. data/gemfiles/sequel-3.10.0.gemfile +9 -0
  147. data/gemfiles/sequel-3.10.0.gemfile.lock +33 -0
  148. data/gemfiles/sequel-3.13.0.gemfile +2 -1
  149. data/gemfiles/sequel-3.13.0.gemfile.lock +11 -6
  150. data/gemfiles/sequel-3.14.0.gemfile +2 -1
  151. data/gemfiles/sequel-3.14.0.gemfile.lock +11 -6
  152. data/gemfiles/sequel-3.23.0.gemfile +2 -1
  153. data/gemfiles/sequel-3.23.0.gemfile.lock +11 -6
  154. data/gemfiles/sequel-3.24.0.gemfile +2 -1
  155. data/gemfiles/sequel-3.24.0.gemfile.lock +11 -6
  156. data/gemfiles/sequel-3.29.0.gemfile +2 -1
  157. data/gemfiles/sequel-3.29.0.gemfile.lock +11 -6
  158. data/gemfiles/sequel-3.34.0.gemfile +9 -0
  159. data/gemfiles/sequel-3.34.0.gemfile.lock +33 -0
  160. data/gemfiles/sequel-3.35.0.gemfile +9 -0
  161. data/gemfiles/sequel-3.35.0.gemfile.lock +33 -0
  162. data/gemfiles/sequel-3.4.0.gemfile +9 -0
  163. data/gemfiles/sequel-3.4.0.gemfile.lock +33 -0
  164. data/gemfiles/sequel-3.44.0.gemfile +9 -0
  165. data/gemfiles/sequel-3.44.0.gemfile.lock +33 -0
  166. data/lib/state_machine.rb +6 -0
  167. data/lib/state_machine/branch.rb +9 -8
  168. data/lib/state_machine/callback.rb +2 -2
  169. data/lib/state_machine/core.rb +10 -0
  170. data/lib/state_machine/core_ext.rb +1 -0
  171. data/lib/state_machine/eval_helpers.rb +5 -3
  172. data/lib/state_machine/event.rb +17 -6
  173. data/lib/state_machine/graph.rb +92 -0
  174. data/lib/state_machine/integrations.rb +13 -1
  175. data/lib/state_machine/integrations/active_model.rb +14 -20
  176. data/lib/state_machine/integrations/active_model/observer.rb +3 -3
  177. data/lib/state_machine/integrations/active_model/observer_update.rb +42 -0
  178. data/lib/state_machine/integrations/active_record.rb +52 -25
  179. data/lib/state_machine/integrations/active_record/locale.rb +1 -1
  180. data/lib/state_machine/integrations/active_record/versions.rb +1 -17
  181. data/lib/state_machine/integrations/base.rb +15 -6
  182. data/lib/state_machine/integrations/data_mapper.rb +98 -35
  183. data/lib/state_machine/integrations/data_mapper/versions.rb +46 -8
  184. data/lib/state_machine/integrations/mongo_mapper.rb +39 -12
  185. data/lib/state_machine/integrations/mongo_mapper/locale.rb +1 -1
  186. data/lib/state_machine/integrations/mongo_mapper/versions.rb +3 -20
  187. data/lib/state_machine/integrations/mongoid.rb +52 -14
  188. data/lib/state_machine/integrations/mongoid/locale.rb +1 -1
  189. data/lib/state_machine/integrations/mongoid/versions.rb +52 -26
  190. data/lib/state_machine/integrations/sequel.rb +82 -33
  191. data/lib/state_machine/integrations/sequel/versions.rb +19 -44
  192. data/lib/state_machine/machine.rb +99 -59
  193. data/lib/state_machine/machine_collection.rb +1 -2
  194. data/lib/state_machine/macro_methods.rb +29 -0
  195. data/lib/state_machine/node_collection.rb +1 -1
  196. data/lib/state_machine/state.rb +18 -10
  197. data/lib/state_machine/state_context.rb +2 -2
  198. data/lib/state_machine/transition.rb +8 -1
  199. data/lib/state_machine/transition_collection.rb +2 -1
  200. data/lib/state_machine/version.rb +1 -1
  201. data/lib/state_machine/yard.rb +8 -0
  202. data/lib/state_machine/yard/handlers.rb +12 -0
  203. data/lib/state_machine/yard/handlers/base.rb +32 -0
  204. data/lib/state_machine/yard/handlers/event.rb +25 -0
  205. data/lib/state_machine/yard/handlers/machine.rb +344 -0
  206. data/lib/state_machine/yard/handlers/state.rb +25 -0
  207. data/lib/state_machine/yard/handlers/transition.rb +47 -0
  208. data/lib/state_machine/yard/templates.rb +3 -0
  209. data/lib/state_machine/yard/templates/default/class/html/setup.rb +30 -0
  210. data/lib/state_machine/yard/templates/default/class/html/state_machines.erb +12 -0
  211. data/lib/tasks/state_machine.rb +2 -1
  212. data/lib/yard-state_machine.rb +2 -0
  213. data/state_machine.gemspec +4 -3
  214. data/test/files/switch.rb +4 -0
  215. data/test/test_helper.rb +5 -0
  216. data/test/unit/branch_test.rb +117 -36
  217. data/test/unit/callback_test.rb +5 -2
  218. data/test/unit/eval_helpers_test.rb +49 -1
  219. data/test/unit/event_collection_test.rb +3 -1
  220. data/test/unit/event_test.rb +182 -12
  221. data/test/unit/graph_test.rb +98 -0
  222. data/test/unit/integrations/active_model_test.rb +82 -12
  223. data/test/unit/integrations/active_record_test.rb +393 -37
  224. data/test/unit/integrations/base_test.rb +7 -2
  225. data/test/unit/integrations/data_mapper_test.rb +326 -72
  226. data/test/unit/integrations/mongo_mapper_test.rb +338 -44
  227. data/test/unit/integrations/mongoid_test.rb +606 -98
  228. data/test/unit/integrations/sequel_test.rb +429 -102
  229. data/test/unit/integrations_test.rb +28 -6
  230. data/test/unit/machine_collection_test.rb +6 -2
  231. data/test/unit/machine_test.rb +134 -82
  232. data/test/unit/node_collection_test.rb +2 -2
  233. data/test/unit/path_test.rb +1 -1
  234. data/test/unit/state_test.rb +65 -21
  235. data/test/unit/transition_collection_test.rb +43 -23
  236. data/test/unit/transition_test.rb +8 -2
  237. metadata +303 -221
  238. data/gemfiles/active_model-3.2.0.gemfile.lock +0 -32
  239. data/gemfiles/active_record-3.2.0.gemfile.lock +0 -43
  240. data/gemfiles/graphviz-0.9.0.gemfile.lock +0 -26
@@ -18,8 +18,14 @@ rescue LoadError
18
18
  end
19
19
  end
20
20
 
21
+ require 'active_record/version'
22
+ if ActiveRecord::VERSION::MAJOR >= 4
23
+ require 'rails/observers/activerecord/active_record'
24
+ require 'active_record/mass_assignment_security'
25
+ end
26
+
21
27
  # Establish database connection
22
- ActiveRecord::Base.establish_connection({'adapter' => 'sqlite3', 'database' => ':memory:'})
28
+ ActiveRecord::Base.establish_connection('adapter' => RUBY_PLATFORM == 'java' ? 'jdbcsqlite3' : 'sqlite3', 'database' => ':memory:')
23
29
  ActiveRecord::Base.logger = Logger.new("#{File.dirname(__FILE__)}/../../active_record.log")
24
30
 
25
31
  module ActiveRecordTest
@@ -30,14 +36,15 @@ module ActiveRecordTest
30
36
  protected
31
37
  # Creates a new ActiveRecord model (and the associated table)
32
38
  def new_model(create_table = :foo, &block)
33
- table_name = create_table || :foo
39
+ name = create_table || :foo
40
+ table_name = "#{name}_#{rand(1000000)}"
34
41
 
35
42
  model = Class.new(ActiveRecord::Base) do
36
- connection.create_table(table_name, :force => true) {|t| t.string(:state)} if create_table
37
43
  self.table_name = table_name.to_s
44
+ connection.create_table(table_name, :force => true) {|t| t.string(:state)} if create_table
38
45
 
39
46
  (class << self; self; end).class_eval do
40
- define_method(:name) { "ActiveRecordTest::#{table_name.to_s.capitalize}" }
47
+ define_method(:name) { "ActiveRecordTest::#{name.to_s.capitalize}" }
41
48
  end
42
49
  end
43
50
  model.class_eval(&block) if block_given?
@@ -86,7 +93,7 @@ module ActiveRecordTest
86
93
  end
87
94
 
88
95
  def test_should_have_defaults
89
- assert_equal e = {:action => :save}, StateMachine::Integrations::ActiveRecord.defaults
96
+ assert_equal({:action => :save}, StateMachine::Integrations::ActiveRecord.defaults)
90
97
  end
91
98
 
92
99
  def test_should_have_a_locale_path
@@ -101,6 +108,10 @@ module ActiveRecordTest
101
108
  def self.connection
102
109
  raise ActiveRecord::ConnectionNotEstablished
103
110
  end
111
+
112
+ def self.connected?
113
+ false
114
+ end
104
115
  end
105
116
  end
106
117
 
@@ -114,7 +125,7 @@ module ActiveRecordTest
114
125
  @model = new_model(false)
115
126
 
116
127
  # Drop the table so that it definitely doesn't exist
117
- @model.connection.drop_table(:foo) if @model.table_exists?
128
+ @model.connection.drop_table(@model.table_name) if @model.table_exists?
118
129
  end
119
130
 
120
131
  def test_should_allow_machine_creation
@@ -159,7 +170,7 @@ module ActiveRecordTest
159
170
 
160
171
  class MachineWithStaticInitialStateTest < BaseTestCase
161
172
  def setup
162
- @model = new_model do
173
+ @model = new_model(:vehicle) do
163
174
  attr_accessor :value
164
175
  end
165
176
  @machine = StateMachine::Machine.new(@model, :initial => :parked)
@@ -191,7 +202,7 @@ module ActiveRecordTest
191
202
 
192
203
  def test_should_set_attributes_prior_to_initialize_block
193
204
  state = nil
194
- record = @model.new do |record|
205
+ @model.new do |record|
195
206
  state = record.state
196
207
  end
197
208
 
@@ -200,7 +211,7 @@ module ActiveRecordTest
200
211
 
201
212
  def test_should_set_attributes_prior_to_after_initialize_hook
202
213
  state = nil
203
- @model.class_eval {define_method(:after_initialize) {}} if ::ActiveRecord::VERSION::MAJOR <= 2
214
+ @model.class_eval {define_method(:after_initialize) {}} if ActiveRecord::VERSION::MAJOR <= 2
204
215
  @model.after_initialize do |record|
205
216
  state = record.state
206
217
  end
@@ -212,6 +223,7 @@ module ActiveRecordTest
212
223
  @model.class_eval do
213
224
  attr_accessor :state_during_setter
214
225
 
226
+ remove_method :value=
215
227
  define_method(:value=) do |value|
216
228
  self.state_during_setter = state
217
229
  end
@@ -230,6 +242,22 @@ module ActiveRecordTest
230
242
  assert_equal 'idling', record.state
231
243
  end
232
244
 
245
+ def test_should_persist_initial_state
246
+ record = @model.new
247
+ record.save
248
+ record.reload
249
+ assert_equal 'parked', record.state
250
+ end
251
+
252
+ unless ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
253
+ def test_should_persist_initial_state_on_dup
254
+ record = @model.create.dup
255
+ record.save
256
+ record.reload
257
+ assert_equal 'parked', record.state
258
+ end
259
+ end
260
+
233
261
  def test_should_use_stored_values_when_loading_from_database
234
262
  @machine.state :idling
235
263
 
@@ -243,6 +271,68 @@ module ActiveRecordTest
243
271
  record = @model.find(@model.create(:state => nil).id)
244
272
  assert_nil record.state
245
273
  end
274
+
275
+ def test_should_use_stored_values_when_loading_for_many_association
276
+ @machine.state :idling
277
+
278
+ @model.connection.add_column @model.table_name, :owner_id, :integer
279
+ @model.reset_column_information
280
+ ActiveRecordTest.const_set('Vehicle', @model)
281
+
282
+ owner_model = new_model(:owner) do
283
+ has_many :vehicles, :class_name => 'ActiveRecordTest::Vehicle'
284
+ end
285
+ ActiveRecordTest.const_set('Owner', owner_model)
286
+
287
+ owner = owner_model.create
288
+ record = @model.create(:state => 'idling', :owner_id => owner.id)
289
+ assert_equal 'idling', owner.vehicles[0].state
290
+ end
291
+
292
+ def test_should_use_stored_values_when_loading_for_one_association
293
+ @machine.state :idling
294
+
295
+ @model.connection.add_column @model.table_name, :owner_id, :integer
296
+ @model.reset_column_information
297
+ ActiveRecordTest.const_set('Vehicle', @model)
298
+
299
+ owner_model = new_model(:owner) do
300
+ has_one :vehicle, :class_name => 'ActiveRecordTest::Vehicle'
301
+ end
302
+ ActiveRecordTest.const_set('Owner', owner_model)
303
+
304
+ owner = owner_model.create
305
+ record = @model.create(:state => 'idling', :owner_id => owner.id)
306
+ assert_equal 'idling', owner.vehicle.state
307
+ end
308
+
309
+ def test_should_use_stored_values_when_loading_for_belongs_to_association
310
+ @machine.state :idling
311
+
312
+ ActiveRecordTest.const_set('Vehicle', @model)
313
+
314
+ driver_model = new_model(:driver) do
315
+ connection.add_column table_name, :vehicle_id, :integer
316
+
317
+ belongs_to :vehicle, :class_name => 'ActiveRecordTest::Vehicle'
318
+ end
319
+
320
+ ActiveRecordTest.const_set('Driver', driver_model)
321
+
322
+ record = @model.create(:state => 'idling')
323
+ driver = driver_model.create(:vehicle_id => record.id)
324
+ assert_equal 'idling', driver.vehicle.state
325
+ end
326
+
327
+ def teardown
328
+ ActiveRecordTest.class_eval do
329
+ remove_const('Vehicle') if defined?(ActiveRecordTest::Vehicle)
330
+ remove_const('Owner') if defined?(ActiveRecordTest::Owner)
331
+ remove_const('Driver') if defined?(ActiveRecordTest::Driver)
332
+ end
333
+ ActiveSupport::Dependencies.clear if defined?(ActiveSupport::Dependencies)
334
+ super
335
+ end
246
336
  end
247
337
 
248
338
  class MachineWithDynamicInitialStateTest < BaseTestCase
@@ -275,7 +365,7 @@ module ActiveRecordTest
275
365
 
276
366
  def test_should_set_attributes_prior_to_initialize_block
277
367
  state = nil
278
- record = @model.new do |record|
368
+ @model.new do |record|
279
369
  state = record.state
280
370
  end
281
371
 
@@ -284,7 +374,7 @@ module ActiveRecordTest
284
374
 
285
375
  def test_should_set_attributes_prior_to_after_initialize_hook
286
376
  state = nil
287
- @model.class_eval {define_method(:after_initialize) {}} if ::ActiveRecord::VERSION::MAJOR <= 2
377
+ @model.class_eval {define_method(:after_initialize) {}} if ActiveRecord::VERSION::MAJOR <= 2
288
378
  @model.after_initialize do |record|
289
379
  state = record.state
290
380
  end
@@ -296,6 +386,7 @@ module ActiveRecordTest
296
386
  @model.class_eval do
297
387
  attr_accessor :state_during_setter
298
388
 
389
+ remove_method :value=
299
390
  define_method(:value=) do |value|
300
391
  self.state_during_setter = state || 'nil'
301
392
  end
@@ -314,6 +405,22 @@ module ActiveRecordTest
314
405
  assert_equal 'idling', record.state
315
406
  end
316
407
 
408
+ def test_should_persist_initial_state
409
+ record = @model.new
410
+ record.save
411
+ record.reload
412
+ assert_equal 'parked', record.state
413
+ end
414
+
415
+ unless ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
416
+ def test_should_persist_initial_state_on_dup
417
+ record = @model.create.dup
418
+ record.save
419
+ record.reload
420
+ assert_equal 'parked', record.state
421
+ end
422
+ end
423
+
317
424
  def test_should_use_stored_values_when_loading_from_database
318
425
  @machine.state :idling
319
426
 
@@ -341,10 +448,12 @@ module ActiveRecordTest
341
448
  end
342
449
  end
343
450
 
344
- class MachineWithColumnDefaultTest < BaseTestCase
451
+ class MachineWithSameColumnDefaultTest < BaseTestCase
345
452
  def setup
453
+ @original_stderr, $stderr = $stderr, StringIO.new
454
+
346
455
  @model = new_model do
347
- connection.add_column :foo, :status, :string, :default => 'idling'
456
+ connection.add_column table_name, :status, :string, :default => 'parked'
348
457
  end
349
458
  @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
350
459
  @record = @model.new
@@ -353,6 +462,66 @@ module ActiveRecordTest
353
462
  def test_should_use_machine_default
354
463
  assert_equal 'parked', @record.status
355
464
  end
465
+
466
+ def test_should_not_generate_a_warning
467
+ assert_no_match(/have defined a different default/, $stderr.string)
468
+ end
469
+
470
+ def teardown
471
+ $stderr = @original_stderr
472
+ super
473
+ end
474
+ end
475
+
476
+ class MachineWithDifferentColumnDefaultTest < BaseTestCase
477
+ def setup
478
+ @original_stderr, $stderr = $stderr, StringIO.new
479
+
480
+ @model = new_model do
481
+ connection.add_column table_name, :status, :string, :default => 'idling'
482
+ end
483
+ @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
484
+ @record = @model.new
485
+ end
486
+
487
+ def test_should_use_machine_default
488
+ assert_equal 'parked', @record.status
489
+ end
490
+
491
+ def test_should_generate_a_warning
492
+ assert_match(/Both ActiveRecordTest::Foo and its :status machine have defined a different default for "status". Use only one or the other for defining defaults to avoid unexpected behaviors\./, $stderr.string)
493
+ end
494
+
495
+ def teardown
496
+ $stderr = @original_stderr
497
+ super
498
+ end
499
+ end
500
+
501
+ class MachineWithDifferentIntegerColumnDefaultTest < BaseTestCase
502
+ def setup
503
+ @original_stderr, $stderr = $stderr, StringIO.new
504
+
505
+ @model = new_model do
506
+ connection.add_column table_name, :status, :integer, :default => 0
507
+ end
508
+ @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
509
+ @machine.state :parked, :value => 1
510
+ @record = @model.new
511
+ end
512
+
513
+ def test_should_use_machine_default
514
+ assert_equal 1, @record.status
515
+ end
516
+
517
+ def test_should_generate_a_warning
518
+ assert_match(/Both ActiveRecordTest::Foo and its :status machine have defined a different default for "status". Use only one or the other for defining defaults to avoid unexpected behaviors\./, $stderr.string)
519
+ end
520
+
521
+ def teardown
522
+ $stderr = @original_stderr
523
+ super
524
+ end
356
525
  end
357
526
 
358
527
  class MachineWithConflictingPredicateTest < BaseTestCase
@@ -384,18 +553,19 @@ module ActiveRecordTest
384
553
  @machine = StateMachine::Machine.new(@model)
385
554
  @machine.state :state
386
555
 
387
- assert_match /^Instance method "state\?" is already defined in ActiveRecordTest::Foo, use generic helper instead.*\n$/, $stderr.string
556
+ assert_match(/^Instance method "state\?" is already defined in ActiveRecordTest::Foo, use generic helper instead.*\n$/, $stderr.string)
388
557
  end
389
558
 
390
559
  def test_should_output_warning_with_same_machine_attribute
391
560
  @machine = StateMachine::Machine.new(@model, :public_state, :attribute => :state)
392
561
  @machine.state :state
393
562
 
394
- assert_match /^Instance method "state\?" is already defined in ActiveRecordTest::Foo, use generic helper instead.*\n$/, $stderr.string
563
+ assert_match(/^Instance method "state\?" is already defined in ActiveRecordTest::Foo, use generic helper instead.*\n$/, $stderr.string)
395
564
  end
396
565
 
397
566
  def teardown
398
567
  $stderr = @original_stderr
568
+ super
399
569
  end
400
570
  end
401
571
 
@@ -545,6 +715,7 @@ module ActiveRecordTest
545
715
 
546
716
  def teardown
547
717
  $stderr = @original_stderr
718
+ super
548
719
  end
549
720
  end
550
721
 
@@ -594,7 +765,7 @@ module ActiveRecordTest
594
765
  class MachineMultipleTest < BaseTestCase
595
766
  def setup
596
767
  @model = new_model do
597
- connection.add_column :foo, :status, :string
768
+ connection.add_column table_name, :status, :string
598
769
  end
599
770
  @state_machine = StateMachine::Machine.new(@model, :initial => :parked)
600
771
  @status_machine = StateMachine::Machine.new(@model, :status, :initial => :idling)
@@ -610,7 +781,7 @@ module ActiveRecordTest
610
781
  class MachineWithLoopbackTest < BaseTestCase
611
782
  def setup
612
783
  @model = new_model do
613
- connection.add_column :foo, :updated_at, :datetime
784
+ connection.add_column table_name, :updated_at, :datetime
614
785
  end
615
786
 
616
787
  @machine = StateMachine::Machine.new(@model, :initial => :parked)
@@ -693,7 +864,7 @@ module ActiveRecordTest
693
864
  class MachineWithDirtyAttributesAndCustomAttributeTest < BaseTestCase
694
865
  def setup
695
866
  @model = new_model do
696
- connection.add_column :foo, :status, :string, :default => 'idling'
867
+ connection.add_column table_name, :status, :string
697
868
  end
698
869
  @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
699
870
  @machine.event :ignite
@@ -724,7 +895,7 @@ module ActiveRecordTest
724
895
  class MachineWithDirtyAttributeAndCustomAttributesDuringLoopbackTest < BaseTestCase
725
896
  def setup
726
897
  @model = new_model do
727
- connection.add_column :foo, :status, :string, :default => 'idling'
898
+ connection.add_column table_name, :status, :string
728
899
  end
729
900
  @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
730
901
  @machine.event :park
@@ -910,11 +1081,21 @@ module ActiveRecordTest
910
1081
  def test_should_run_around_callbacks
911
1082
  before_called = false
912
1083
  after_called = false
913
- @machine.around_transition {|block| before_called = true; block.call; after_called = true}
1084
+ ensure_called = 0
1085
+ @machine.around_transition do |block|
1086
+ before_called = true
1087
+ begin
1088
+ block.call
1089
+ ensure
1090
+ ensure_called += 1
1091
+ end
1092
+ after_called = true
1093
+ end
914
1094
 
915
1095
  @transition.perform
916
1096
  assert before_called
917
1097
  assert after_called
1098
+ assert_equal ensure_called, 1
918
1099
  end
919
1100
 
920
1101
  def test_should_include_transition_states_in_known_states
@@ -947,6 +1128,33 @@ module ActiveRecordTest
947
1128
 
948
1129
  assert_equal [1, 2, 3], @record.callback_result
949
1130
  end
1131
+
1132
+ def test_should_run_in_expected_order
1133
+ expected = [
1134
+ :before_transition, :before_validation, :after_validation,
1135
+ :before_save, :before_create, :after_create, :after_save,
1136
+ :after_transition
1137
+ ]
1138
+
1139
+ callbacks = []
1140
+ @model.before_validation { callbacks << :before_validation }
1141
+ @model.after_validation { callbacks << :after_validation }
1142
+ @model.before_save { callbacks << :before_save }
1143
+ @model.before_create { callbacks << :before_create }
1144
+ @model.after_create { callbacks << :after_create }
1145
+ @model.after_save { callbacks << :after_save }
1146
+ if @model.respond_to?(:after_commit)
1147
+ @model.after_commit { callbacks << :after_commit }
1148
+ expected << :after_commit
1149
+ end
1150
+
1151
+ @machine.before_transition { callbacks << :before_transition }
1152
+ @machine.after_transition { callbacks << :after_transition }
1153
+
1154
+ @transition.perform
1155
+
1156
+ assert_equal expected, callbacks
1157
+ end
950
1158
  end
951
1159
 
952
1160
  class MachineWithFailedBeforeCallbacksTest < BaseTestCase
@@ -984,6 +1192,42 @@ module ActiveRecordTest
984
1192
  end
985
1193
  end
986
1194
 
1195
+ class MachineNestedActionTest < BaseTestCase
1196
+ def setup
1197
+ @callbacks = []
1198
+
1199
+ @model = new_model
1200
+ @machine = StateMachine::Machine.new(@model)
1201
+ @machine.event :ignite do
1202
+ transition :parked => :idling
1203
+ end
1204
+
1205
+ @record = @model.new(:state => 'parked')
1206
+ end
1207
+
1208
+ def test_should_allow_transition_prior_to_creation_if_skipping_action
1209
+ record = @record
1210
+ @model.before_create { record.ignite(false) }
1211
+ result = @record.save
1212
+
1213
+ assert_equal true, result
1214
+ assert_equal "idling", @record.state
1215
+ @record.reload
1216
+ assert_equal "idling", @record.state
1217
+ end
1218
+
1219
+ def test_should_allow_transition_after_creation
1220
+ record = @record
1221
+ @model.after_create { record.ignite }
1222
+ result = @record.save
1223
+
1224
+ assert_equal true, result
1225
+ assert_equal "idling", @record.state
1226
+ @record.reload
1227
+ assert_equal "idling", @record.state
1228
+ end
1229
+ end
1230
+
987
1231
  class MachineWithFailedActionTest < BaseTestCase
988
1232
  def setup
989
1233
  @model = new_model do
@@ -1023,7 +1267,7 @@ module ActiveRecordTest
1023
1267
  end
1024
1268
 
1025
1269
  class MachineWithFailedAfterCallbacksTest < BaseTestCase
1026
- def setup
1270
+ def setup
1027
1271
  @callbacks = []
1028
1272
 
1029
1273
  @model = new_model
@@ -1103,10 +1347,7 @@ module ActiveRecordTest
1103
1347
 
1104
1348
  class MachineWithValidationsAndCustomAttributeTest < BaseTestCase
1105
1349
  def setup
1106
- @model = new_model do
1107
- alias_attribute :status, :state
1108
- end
1109
-
1350
+ @model = new_model
1110
1351
  @machine = StateMachine::Machine.new(@model, :status, :attribute => :state)
1111
1352
  @machine.state :parked
1112
1353
 
@@ -1212,7 +1453,11 @@ module ActiveRecordTest
1212
1453
  ran_callback = false
1213
1454
  @machine.around_transition {|block| ran_callback = true; block.call }
1214
1455
 
1215
- @record.valid?
1456
+ begin
1457
+ @record.valid?
1458
+ rescue ArgumentError
1459
+ raise if StateMachine::Transition.pause_supported?
1460
+ end
1216
1461
  assert ran_callback
1217
1462
  end
1218
1463
 
@@ -1259,7 +1504,11 @@ module ActiveRecordTest
1259
1504
  ran_callback = false
1260
1505
  @machine.around_transition {|block| block.call; ran_callback = true }
1261
1506
 
1262
- @record.valid?
1507
+ begin
1508
+ @record.valid?
1509
+ rescue ArgumentError
1510
+ raise if StateMachine::Transition.pause_supported?
1511
+ end
1263
1512
  assert !ran_callback
1264
1513
  end
1265
1514
 
@@ -1426,6 +1675,89 @@ module ActiveRecordTest
1426
1675
 
1427
1676
  assert_equal 0, @model.count
1428
1677
  end
1678
+
1679
+ def test_should_allow_additional_transitions_to_new_state_in_after_transitions
1680
+ @machine.event :park do
1681
+ transition :idling => :parked
1682
+ end
1683
+
1684
+ @machine.after_transition(:on => :ignite) { @record.park }
1685
+
1686
+ @record.save
1687
+ assert_equal 'parked', @record.state
1688
+
1689
+ @record.reload
1690
+ assert_equal 'parked', @record.state
1691
+ end
1692
+
1693
+ def test_should_allow_additional_transitions_to_previous_state_in_after_transitions
1694
+ @machine.event :shift_up do
1695
+ transition :idling => :first_gear
1696
+ end
1697
+
1698
+ @machine.after_transition(:on => :ignite) { @record.shift_up }
1699
+
1700
+ @record.save
1701
+ assert_equal 'first_gear', @record.state
1702
+
1703
+ @record.reload
1704
+ assert_equal 'first_gear', @record.state
1705
+ end
1706
+
1707
+ def test_should_return_nil_on_manual_rollback
1708
+ @machine.before_transition { raise ActiveRecord::Rollback }
1709
+
1710
+ assert_equal nil, @record.save
1711
+ end
1712
+ end
1713
+
1714
+ if ActiveRecord::VERSION::MAJOR >= 3 || ActiveRecord::VERSION::MINOR >= 3
1715
+ class MachineWithEventAttributesOnAutosaveTest < BaseTestCase
1716
+ def setup
1717
+ @vehicle_model = new_model(:vehicle) do
1718
+ connection.add_column table_name, :owner_id, :integer
1719
+ end
1720
+ ActiveRecordTest.const_set('Vehicle', @vehicle_model)
1721
+
1722
+ @owner_model = new_model(:owner)
1723
+ ActiveRecordTest.const_set('Owner', @owner_model)
1724
+
1725
+ machine = StateMachine::Machine.new(@vehicle_model)
1726
+ machine.event :ignite do
1727
+ transition :parked => :idling
1728
+ end
1729
+
1730
+ @owner = @owner_model.create
1731
+ @vehicle = @vehicle_model.create(:state => 'parked', :owner_id => @owner.id)
1732
+ end
1733
+
1734
+ def test_should_persist_has_one_autosave
1735
+ @owner_model.has_one :vehicle, :class_name => 'ActiveRecordTest::Vehicle', :autosave => true
1736
+ @owner.vehicle.state_event = 'ignite'
1737
+ @owner.save
1738
+
1739
+ @vehicle.reload
1740
+ assert_equal 'idling', @vehicle.state
1741
+ end
1742
+
1743
+ def test_should_persist_has_many_autosave
1744
+ @owner_model.has_many :vehicles, :class_name => 'ActiveRecordTest::Vehicle', :autosave => true
1745
+ @owner.vehicles[0].state_event = 'ignite'
1746
+ @owner.save
1747
+
1748
+ @vehicle.reload
1749
+ assert_equal 'idling', @vehicle.state
1750
+ end
1751
+
1752
+ def teardown
1753
+ ActiveRecordTest.class_eval do
1754
+ remove_const('Vehicle')
1755
+ remove_const('Owner')
1756
+ end
1757
+ ActiveSupport::Dependencies.clear if defined?(ActiveSupport::Dependencies)
1758
+ super
1759
+ end
1760
+ end
1429
1761
  end
1430
1762
 
1431
1763
  class MachineWithEventAttributesOnSaveBangTest < BaseTestCase
@@ -1571,7 +1903,6 @@ module ActiveRecordTest
1571
1903
  :before_transition
1572
1904
  ]
1573
1905
 
1574
- notified = false
1575
1906
  observer = new_observer(@model) do
1576
1907
  callbacks.each do |callback|
1577
1908
  define_method(callback) do |*args|
@@ -1586,6 +1917,31 @@ module ActiveRecordTest
1586
1917
  assert_equal callbacks, instance.notifications
1587
1918
  end
1588
1919
 
1920
+ def test_should_call_no_transition_callbacks_when_observers_disabled
1921
+ return unless ActiveRecord::VERSION::MAJOR >= 3 && ActiveRecord::VERSION::MINOR >= 1
1922
+
1923
+ callbacks = [
1924
+ :before_ignite,
1925
+ :before_transition
1926
+ ]
1927
+
1928
+ observer = new_observer(@model) do
1929
+ callbacks.each do |callback|
1930
+ define_method(callback) do |*args|
1931
+ notifications << callback
1932
+ end
1933
+ end
1934
+ end
1935
+
1936
+ instance = observer.instance
1937
+
1938
+ @model.observers.disable(observer) do
1939
+ @transition.perform
1940
+ end
1941
+
1942
+ assert_equal [], instance.notifications
1943
+ end
1944
+
1589
1945
  def test_should_pass_record_and_transition_to_before_callbacks
1590
1946
  observer = new_observer(@model) do
1591
1947
  def before_transition(*args)
@@ -1625,7 +1981,7 @@ module ActiveRecordTest
1625
1981
  def test_should_continue_to_handle_non_state_machine_callbacks
1626
1982
  observer = new_observer(@model) do
1627
1983
  def before_save(object)
1628
- notifications << [:before_save, @object]
1984
+ notifications << [:before_save, object]
1629
1985
  end
1630
1986
 
1631
1987
  def before_ignite(*args)
@@ -1636,7 +1992,7 @@ module ActiveRecordTest
1636
1992
  instance = observer.instance
1637
1993
 
1638
1994
  @transition.perform
1639
- assert_equal [:before_ignite, [:before_save, @object]], instance.notifications
1995
+ assert_equal [:before_ignite, [:before_save, @record]], instance.notifications
1640
1996
  end
1641
1997
 
1642
1998
  def test_should_support_nil_from_states
@@ -1647,7 +2003,6 @@ module ActiveRecordTest
1647
2003
  :before_transition_state_from_nil
1648
2004
  ]
1649
2005
 
1650
- notified = false
1651
2006
  observer = new_observer(@model) do
1652
2007
  callbacks.each do |callback|
1653
2008
  define_method(callback) do |*args|
@@ -1671,7 +2026,6 @@ module ActiveRecordTest
1671
2026
  :before_transition_state_to_nil
1672
2027
  ]
1673
2028
 
1674
- notified = false
1675
2029
  observer = new_observer(@model) do
1676
2030
  callbacks.each do |callback|
1677
2031
  define_method(callback) do |*args|
@@ -1840,7 +2194,7 @@ module ActiveRecordTest
1840
2194
 
1841
2195
  def test_should_only_include_records_with_state_in_singular_with_scope
1842
2196
  parked = @model.create :state => 'parked'
1843
- idling = @model.create :state => 'idling'
2197
+ @model.create :state => 'idling'
1844
2198
 
1845
2199
  assert_equal [parked], @model.with_state(:parked).find(:all)
1846
2200
  end
@@ -1941,7 +2295,7 @@ module ActiveRecordTest
1941
2295
  ActiveRecordTest.const_set('Company', @company)
1942
2296
 
1943
2297
  @vehicle = new_model(:vehicle) do
1944
- connection.add_column :vehicle, :company_id, :integer
2298
+ connection.add_column table_name, :company_id, :integer
1945
2299
  belongs_to :company, :class_name => 'ActiveRecordTest::Company'
1946
2300
  end
1947
2301
  ActiveRecordTest.const_set('Vehicle', @vehicle)
@@ -1955,11 +2309,11 @@ module ActiveRecordTest
1955
2309
  end
1956
2310
 
1957
2311
  def test_should_find_records_in_with_scope
1958
- assert_equal [@mustang], @vehicle.with_states(:parked).find(:all, :include => :company, :conditions => 'company.state = "active"')
2312
+ assert_equal [@mustang], @vehicle.with_states(:parked).find(:all, :joins => :company, :conditions => "#{@company.table_name}.state = \"active\"")
1959
2313
  end
1960
2314
 
1961
2315
  def test_should_find_records_in_without_scope
1962
- assert_equal [@mustang], @vehicle.without_states(:idling).find(:all, :include => :company, :conditions => 'company.state = "active"')
2316
+ assert_equal [@mustang], @vehicle.without_states(:idling).find(:all, :joins => :company, :conditions => "#{@company.table_name}.state = \"active\"")
1963
2317
  end
1964
2318
 
1965
2319
  def teardown
@@ -1967,6 +2321,8 @@ module ActiveRecordTest
1967
2321
  remove_const('Vehicle')
1968
2322
  remove_const('Company')
1969
2323
  end
2324
+ ActiveSupport::Dependencies.clear if defined?(ActiveSupport::Dependencies)
2325
+ super
1970
2326
  end
1971
2327
  end
1972
2328
  else
@@ -1981,7 +2337,7 @@ module ActiveRecordTest
1981
2337
  @machine.state :idling
1982
2338
 
1983
2339
  @model.class_eval do
1984
- default_scope with_state(:parked, :idling)
2340
+ default_scope { with_state(:parked, :idling) }
1985
2341
  end
1986
2342
  end
1987
2343