state_machine 1.1.2 → 1.2.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 (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