state_machine 0.10.1 → 0.10.2
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.
- data/CHANGELOG.rdoc +9 -0
- data/Rakefile +1 -1
- data/lib/state_machine/event.rb +4 -4
- data/lib/state_machine/integrations/active_model.rb +4 -32
- data/lib/state_machine/integrations/active_model/versions.rb +5 -4
- data/lib/state_machine/integrations/active_record.rb +15 -30
- data/lib/state_machine/integrations/active_record/versions.rb +5 -2
- data/lib/state_machine/integrations/data_mapper.rb +10 -14
- data/lib/state_machine/integrations/mongo_mapper.rb +5 -16
- data/lib/state_machine/integrations/mongo_mapper/versions.rb +20 -12
- data/lib/state_machine/integrations/mongoid.rb +71 -14
- data/lib/state_machine/integrations/sequel.rb +45 -52
- data/lib/state_machine/integrations/sequel/versions.rb +2 -10
- data/lib/state_machine/machine.rb +105 -78
- data/lib/state_machine/machine_collection.rb +18 -3
- data/lib/state_machine/state.rb +1 -1
- data/test/unit/integrations/active_model_test.rb +21 -9
- data/test/unit/integrations/active_record_test.rb +20 -13
- data/test/unit/integrations/data_mapper_test.rb +7 -2
- data/test/unit/integrations/mongo_mapper_test.rb +5 -1
- data/test/unit/integrations/mongoid_test.rb +25 -8
- data/test/unit/integrations/sequel_test.rb +10 -6
- data/test/unit/machine_collection_test.rb +40 -0
- data/test/unit/machine_test.rb +91 -154
- metadata +4 -4
@@ -1,6 +1,10 @@
|
|
1
|
+
require 'state_machine/assertions'
|
2
|
+
|
1
3
|
module StateMachine
|
2
4
|
# Represents a collection of state machines for a class
|
3
5
|
class MachineCollection < Hash
|
6
|
+
include Assertions
|
7
|
+
|
4
8
|
# Initializes the state of each machine in the given object. This can allow
|
5
9
|
# states to be initialized in two groups: static and dynamic. For example:
|
6
10
|
#
|
@@ -9,17 +13,28 @@ module StateMachine
|
|
9
13
|
# end
|
10
14
|
#
|
11
15
|
# If no block is provided, then all states will still be initialized.
|
16
|
+
#
|
17
|
+
# Valid configuration options:
|
18
|
+
# * <tt>:static</tt> - Whether to initialize static states. If set to
|
19
|
+
# :force, the state will be initialized regardless of its current value.
|
20
|
+
# Default is :force.
|
21
|
+
# * <tt>:dynamic</tt> - Whether to initialize dynamic states. If set to
|
22
|
+
# :force, the state will be initialized regardless of its current value.
|
23
|
+
# Default is true.
|
24
|
+
# * <tt>:to</tt> - A hash to write the initialized state to instead of
|
25
|
+
# writing to the object. Default is to write directly to the object.
|
12
26
|
def initialize_states(object, options = {})
|
13
|
-
options
|
27
|
+
assert_valid_keys(options, :static, :dynamic, :to)
|
28
|
+
options = {:static => :force, :dynamic => true}.merge(options)
|
14
29
|
|
15
30
|
each_value do |machine|
|
16
|
-
machine.initialize_state(object, options) unless machine.dynamic_initial_state?
|
31
|
+
machine.initialize_state(object, :force => options[:static] == :force, :to => options[:to]) unless machine.dynamic_initial_state?
|
17
32
|
end if options[:static]
|
18
33
|
|
19
34
|
result = yield if block_given?
|
20
35
|
|
21
36
|
each_value do |machine|
|
22
|
-
machine.initialize_state(object, options) if machine.dynamic_initial_state?
|
37
|
+
machine.initialize_state(object, :force => options[:dynamic] == :force, :to => options[:to]) if machine.dynamic_initial_state?
|
23
38
|
end if options[:dynamic]
|
24
39
|
|
25
40
|
result
|
data/lib/state_machine/state.rb
CHANGED
@@ -190,7 +190,7 @@ module StateMachine
|
|
190
190
|
methods[method.to_sym] = context.instance_method(method)
|
191
191
|
|
192
192
|
# Calls the method defined by the current state of the machine
|
193
|
-
context.class_eval <<-end_eval, __FILE__, __LINE__
|
193
|
+
context.class_eval <<-end_eval, __FILE__, __LINE__ + 1
|
194
194
|
def #{method}(*args, &block)
|
195
195
|
self.class.state_machine(#{machine_name.inspect}).states.match!(self).call(self, #{method.inspect}, lambda {super}, *args, &block)
|
196
196
|
end
|
@@ -79,10 +79,6 @@ module ActiveModelTest
|
|
79
79
|
assert StateMachine::Integrations::ActiveModel.matches?(new_model { include ActiveModel::Dirty })
|
80
80
|
end
|
81
81
|
|
82
|
-
def test_should_match_if_class_includes_mass_assignment_security_feature
|
83
|
-
assert StateMachine::Integrations::ActiveModel.matches?(new_model { include ActiveModel::MassAssignmentSecurity })
|
84
|
-
end
|
85
|
-
|
86
82
|
def test_should_match_if_class_includes_observing_feature
|
87
83
|
assert StateMachine::Integrations::ActiveModel.matches?(new_model { include ActiveModel::Observing })
|
88
84
|
end
|
@@ -186,7 +182,8 @@ module ActiveModelTest
|
|
186
182
|
end
|
187
183
|
|
188
184
|
def test_should_raise_exception_for_predicate_without_parameters
|
189
|
-
assert_raise(
|
185
|
+
exception = assert_raise(ArgumentError) { @record.state? }
|
186
|
+
assert_equal 'wrong number of arguments (1 for 2)', exception.message
|
190
187
|
end
|
191
188
|
|
192
189
|
def test_should_return_false_for_predicate_if_does_not_match_current_value
|
@@ -234,15 +231,30 @@ module ActiveModelTest
|
|
234
231
|
@machine.state nil, :idling
|
235
232
|
end
|
236
233
|
|
237
|
-
def
|
234
|
+
def test_should_allow_nil_initial_state_when_static
|
235
|
+
@machine.state nil
|
236
|
+
|
238
237
|
record = @model.new(:state => nil)
|
239
238
|
assert_nil record.state
|
240
239
|
end
|
241
240
|
|
242
|
-
def
|
241
|
+
def test_should_allow_nil_initial_state_when_dynamic
|
242
|
+
@machine.state nil
|
243
|
+
|
243
244
|
@machine.initial_state = lambda {:parked}
|
244
245
|
record = @model.new(:state => nil)
|
245
|
-
|
246
|
+
assert_nil record.state
|
247
|
+
end
|
248
|
+
|
249
|
+
def test_should_allow_different_initial_state_when_static
|
250
|
+
record = @model.new(:state => 'idling')
|
251
|
+
assert_equal 'idling', record.state
|
252
|
+
end
|
253
|
+
|
254
|
+
def test_should_allow_different_initial_state_when_dynamic
|
255
|
+
@machine.initial_state = lambda {:parked}
|
256
|
+
record = @model.new(:state => 'idling')
|
257
|
+
assert_equal 'idling', record.state
|
246
258
|
end
|
247
259
|
|
248
260
|
def test_should_use_default_state_if_protected
|
@@ -251,7 +263,7 @@ module ActiveModelTest
|
|
251
263
|
attr_protected :state
|
252
264
|
|
253
265
|
def initialize(attrs = {})
|
254
|
-
initialize_state_machines
|
266
|
+
initialize_state_machines do
|
255
267
|
sanitize_for_mass_assignment(attrs).each {|attr, value| send("#{attr}=", value)} if attrs
|
256
268
|
@changed_attributes = {}
|
257
269
|
end
|
@@ -405,30 +405,33 @@ module ActiveRecordTest
|
|
405
405
|
@record = @model.new
|
406
406
|
end
|
407
407
|
|
408
|
-
def
|
409
|
-
|
408
|
+
def test_should_not_define_a_column_for_the_attribute
|
409
|
+
assert_nil @model.columns_hash['status']
|
410
410
|
end
|
411
411
|
|
412
|
-
def
|
413
|
-
assert
|
412
|
+
def test_should_define_a_reader_attribute_for_the_attribute
|
413
|
+
assert @record.respond_to?(:status)
|
414
414
|
end
|
415
415
|
|
416
|
-
def
|
417
|
-
assert @record.respond_to?(:status
|
416
|
+
def test_should_define_a_writer_attribute_for_the_attribute
|
417
|
+
assert @record.respond_to?(:status=)
|
418
418
|
end
|
419
419
|
|
420
|
-
def
|
421
|
-
|
422
|
-
assert_raise(NoMethodError) { @record.status? }
|
423
|
-
ensure
|
424
|
-
$VERBOSE = old_verbose
|
420
|
+
def test_should_define_an_attribute_predicate
|
421
|
+
assert @record.respond_to?(:status?)
|
425
422
|
end
|
426
423
|
end
|
427
424
|
|
428
425
|
class MachineWithNonColumnStateAttributeDefinedTest < BaseTestCase
|
429
426
|
def setup
|
430
427
|
@model = new_model do
|
431
|
-
|
428
|
+
def status=(value)
|
429
|
+
self['status'] = value
|
430
|
+
end
|
431
|
+
|
432
|
+
def status
|
433
|
+
self['status']
|
434
|
+
end
|
432
435
|
end
|
433
436
|
|
434
437
|
@machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
|
@@ -478,15 +481,19 @@ module ActiveRecordTest
|
|
478
481
|
def setup
|
479
482
|
@model = new_model
|
480
483
|
@machine = StateMachine::Machine.new(@model, :initial => :parked)
|
481
|
-
@machine.state
|
484
|
+
@machine.state :idling
|
482
485
|
end
|
483
486
|
|
484
487
|
def test_should_allow_nil_initial_state_when_static
|
488
|
+
@machine.state nil
|
489
|
+
|
485
490
|
record = @model.new(:state => nil)
|
486
491
|
assert_nil record.state
|
487
492
|
end
|
488
493
|
|
489
494
|
def test_should_allow_nil_initial_state_when_dynamic
|
495
|
+
@machine.state nil
|
496
|
+
|
490
497
|
@machine.initial_state = lambda {:parked}
|
491
498
|
record = @model.new(:state => nil)
|
492
499
|
assert_nil record.state
|
@@ -339,7 +339,8 @@ module DataMapperTest
|
|
339
339
|
end
|
340
340
|
|
341
341
|
def test_should_raise_exception_for_predicate_without_parameters
|
342
|
-
assert_raise(
|
342
|
+
exception = assert_raise(ArgumentError) { @record.state? }
|
343
|
+
assert_equal 'wrong number of arguments (1 for 2)', exception.message
|
343
344
|
end
|
344
345
|
|
345
346
|
def test_should_return_false_for_predicate_if_does_not_match_current_value
|
@@ -418,15 +419,19 @@ module DataMapperTest
|
|
418
419
|
def setup
|
419
420
|
@resource = new_resource
|
420
421
|
@machine = StateMachine::Machine.new(@resource, :initial => :parked)
|
421
|
-
@machine.state
|
422
|
+
@machine.state :idling
|
422
423
|
end
|
423
424
|
|
424
425
|
def test_should_allow_nil_initial_state_when_static
|
426
|
+
@machine.state nil
|
427
|
+
|
425
428
|
record = @resource.new(:state => nil)
|
426
429
|
assert_nil record.state
|
427
430
|
end
|
428
431
|
|
429
432
|
def test_should_allow_nil_initial_state_when_dynamic
|
433
|
+
@machine.state nil
|
434
|
+
|
430
435
|
@machine.initial_state = lambda {:parked}
|
431
436
|
record = @resource.new(:state => nil)
|
432
437
|
assert_nil record.state
|
@@ -413,15 +413,19 @@ module MongoMapperTest
|
|
413
413
|
def setup
|
414
414
|
@model = new_model
|
415
415
|
@machine = StateMachine::Machine.new(@model, :initial => :parked)
|
416
|
-
@machine.state
|
416
|
+
@machine.state :idling
|
417
417
|
end
|
418
418
|
|
419
419
|
def test_should_allow_nil_initial_state_when_static
|
420
|
+
@machine.state nil
|
421
|
+
|
420
422
|
record = @model.new(:state => nil)
|
421
423
|
assert_nil record.state
|
422
424
|
end
|
423
425
|
|
424
426
|
def test_should_allow_nil_initial_state_when_dynamic
|
427
|
+
@machine.state nil
|
428
|
+
|
425
429
|
@machine.initial_state = lambda {:parked}
|
426
430
|
record = @model.new(:state => nil)
|
427
431
|
assert_nil record.state
|
@@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
|
|
3
3
|
# Load library
|
4
4
|
require 'rubygems'
|
5
5
|
|
6
|
-
gem 'mongoid', ENV['VERSION'] ? "=#{ENV['VERSION']}" : '>=2.0.0
|
6
|
+
gem 'mongoid', ENV['VERSION'] ? "=#{ENV['VERSION']}" : '>=2.0.0'
|
7
7
|
require 'mongoid'
|
8
8
|
|
9
9
|
# Establish database connection
|
@@ -63,12 +63,12 @@ module MongoidTest
|
|
63
63
|
assert_equal :save, @machine.action
|
64
64
|
end
|
65
65
|
|
66
|
-
def
|
67
|
-
assert_equal
|
66
|
+
def test_should_create_notifier_before_callback
|
67
|
+
assert_equal 1, @machine.callbacks[:before].size
|
68
68
|
end
|
69
69
|
|
70
|
-
def
|
71
|
-
assert_equal
|
70
|
+
def test_should_create_notifier_after_callback
|
71
|
+
assert_equal 1, @machine.callbacks[:after].size
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
@@ -339,7 +339,13 @@ module MongoidTest
|
|
339
339
|
class MachineWithNonColumnStateAttributeDefinedTest < BaseTestCase
|
340
340
|
def setup
|
341
341
|
@model = new_model do
|
342
|
-
|
342
|
+
def status
|
343
|
+
self['status']
|
344
|
+
end
|
345
|
+
|
346
|
+
def status=(value)
|
347
|
+
self['status'] = value
|
348
|
+
end
|
343
349
|
end
|
344
350
|
|
345
351
|
@machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
|
@@ -389,15 +395,19 @@ module MongoidTest
|
|
389
395
|
def setup
|
390
396
|
@model = new_model
|
391
397
|
@machine = StateMachine::Machine.new(@model, :initial => :parked)
|
392
|
-
@machine.state
|
398
|
+
@machine.state :idling
|
393
399
|
end
|
394
400
|
|
395
401
|
def test_should_allow_nil_initial_state_when_static
|
402
|
+
@machine.state nil
|
403
|
+
|
396
404
|
record = @model.new(:state => nil)
|
397
405
|
assert_nil record.state
|
398
406
|
end
|
399
407
|
|
400
408
|
def test_should_allow_nil_initial_state_when_dynamic
|
409
|
+
@machine.state nil
|
410
|
+
|
401
411
|
@machine.initial_state = lambda {:parked}
|
402
412
|
record = @model.new(:state => nil)
|
403
413
|
assert_nil record.state
|
@@ -1345,9 +1355,15 @@ module MongoidTest
|
|
1345
1355
|
|
1346
1356
|
MongoidTest.const_set('Foo', @model)
|
1347
1357
|
|
1348
|
-
@subclass = Class.new(@model)
|
1358
|
+
@subclass = Class.new(@model) do
|
1359
|
+
def self.name
|
1360
|
+
'MongoidTest::SubFoo'
|
1361
|
+
end
|
1362
|
+
end
|
1349
1363
|
@subclass_machine = @subclass.state_machine(:state) {}
|
1350
1364
|
@subclass_machine.state :parked, :idling, :first_gear
|
1365
|
+
|
1366
|
+
MongoidTest.const_set('SubFoo', @subclass)
|
1351
1367
|
end
|
1352
1368
|
|
1353
1369
|
def test_should_only_include_records_with_subclass_states_in_with_scope
|
@@ -1366,6 +1382,7 @@ module MongoidTest
|
|
1366
1382
|
end
|
1367
1383
|
|
1368
1384
|
def teardown
|
1385
|
+
MongoidTest.send(:remove_const, 'SubFoo')
|
1369
1386
|
MongoidTest.send(:remove_const, 'Foo')
|
1370
1387
|
end
|
1371
1388
|
end
|
@@ -345,7 +345,8 @@ module SequelTest
|
|
345
345
|
end
|
346
346
|
|
347
347
|
def test_should_raise_exception_for_predicate_without_parameters
|
348
|
-
assert_raise(
|
348
|
+
exception = assert_raise(ArgumentError) { @record.state? }
|
349
|
+
assert_equal 'wrong number of arguments (1 for 2)', exception.message
|
349
350
|
end
|
350
351
|
|
351
352
|
def test_should_return_false_for_predicate_if_does_not_match_current_value
|
@@ -364,10 +365,9 @@ module SequelTest
|
|
364
365
|
class MachineWithNonColumnStateAttributeUndefinedTest < BaseTestCase
|
365
366
|
def setup
|
366
367
|
@model = new_model do
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
super
|
368
|
+
# Prevent attempts to access the status field
|
369
|
+
def method_missing(method, *args)
|
370
|
+
super unless %w(status status=).include?(method.to_s)
|
371
371
|
end
|
372
372
|
end
|
373
373
|
|
@@ -417,15 +417,19 @@ module SequelTest
|
|
417
417
|
def setup
|
418
418
|
@model = new_model
|
419
419
|
@machine = StateMachine::Machine.new(@model, :initial => :parked)
|
420
|
-
@machine.state
|
420
|
+
@machine.state :idling
|
421
421
|
end
|
422
422
|
|
423
423
|
def test_should_allow_nil_initial_state_when_static
|
424
|
+
@machine.state nil
|
425
|
+
|
424
426
|
record = @model.new(:state => nil)
|
425
427
|
assert_nil record.state
|
426
428
|
end
|
427
429
|
|
428
430
|
def test_should_allow_nil_initial_state_when_dynamic
|
431
|
+
@machine.state nil
|
432
|
+
|
429
433
|
@machine.initial_state = lambda {:parked}
|
430
434
|
record = @model.new(:state => nil)
|
431
435
|
assert_nil record.state
|
@@ -31,6 +31,10 @@ class MachineCollectionStateInitializationTest < Test::Unit::TestCase
|
|
31
31
|
@object.alarm_state = nil
|
32
32
|
end
|
33
33
|
|
34
|
+
def test_should_raise_exception_if_invalid_option_specified
|
35
|
+
assert_raise(ArgumentError) {@machines.initialize_states(@object, :invalid => true)}
|
36
|
+
end
|
37
|
+
|
34
38
|
def test_should_only_initialize_static_states_prior_to_block
|
35
39
|
@machines.initialize_states(@object) do
|
36
40
|
@state_in_block = @object.state
|
@@ -63,11 +67,47 @@ class MachineCollectionStateInitializationTest < Test::Unit::TestCase
|
|
63
67
|
assert_equal 'active', @object.alarm_state
|
64
68
|
end
|
65
69
|
|
70
|
+
def test_should_initialize_existing_static_states_by_default
|
71
|
+
@object.state = 'idling'
|
72
|
+
@machines.initialize_states(@object)
|
73
|
+
assert_equal 'parked', @object.state
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_should_initialize_existing_static_states_if_forced
|
77
|
+
@object.state = 'idling'
|
78
|
+
@machines.initialize_states(@object, :static => :force)
|
79
|
+
assert_equal 'parked', @object.state
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_should_not_initialize_existing_static_states_if_not_forced
|
83
|
+
@object.state = 'idling'
|
84
|
+
@machines.initialize_states(@object, :static => true)
|
85
|
+
assert_equal 'idling', @object.state
|
86
|
+
end
|
87
|
+
|
66
88
|
def test_should_skip_dynamic_states_if_disabled
|
67
89
|
@machines.initialize_states(@object, :dynamic => false)
|
68
90
|
assert_equal 'parked', @object.state
|
69
91
|
assert_nil @object.alarm_state
|
70
92
|
end
|
93
|
+
|
94
|
+
def test_should_not_initialize_existing_dynamic_states_by_default
|
95
|
+
@object.alarm_state = 'inactive'
|
96
|
+
@machines.initialize_states(@object)
|
97
|
+
assert_equal 'inactive', @object.alarm_state
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_should_initialize_existing_dynamic_states_if_forced
|
101
|
+
@object.alarm_state = 'inactive'
|
102
|
+
@machines.initialize_states(@object, :dynamic => :force)
|
103
|
+
assert_equal 'active', @object.alarm_state
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_should_not_initialize_existing_dynamic_states_if_not_forced
|
107
|
+
@object.alarm_state = 'inactive'
|
108
|
+
@machines.initialize_states(@object, :dynamic => true)
|
109
|
+
assert_equal 'inactive', @object.alarm_state
|
110
|
+
end
|
71
111
|
end
|
72
112
|
|
73
113
|
class MachineCollectionFireTest < Test::Unit::TestCase
|
data/test/unit/machine_test.rb
CHANGED
@@ -264,13 +264,7 @@ end
|
|
264
264
|
|
265
265
|
class MachineWithStaticInitialStateTest < Test::Unit::TestCase
|
266
266
|
def setup
|
267
|
-
@klass = Class.new
|
268
|
-
def initialize(attributes = {})
|
269
|
-
attributes.each {|attr, value| send("#{attr}=", value)}
|
270
|
-
super()
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
267
|
+
@klass = Class.new
|
274
268
|
@machine = StateMachine::Machine.new(@klass, :initial => :parked)
|
275
269
|
end
|
276
270
|
|
@@ -293,21 +287,21 @@ class MachineWithStaticInitialStateTest < Test::Unit::TestCase
|
|
293
287
|
assert @machine.state(:parked).initial
|
294
288
|
end
|
295
289
|
|
296
|
-
def
|
297
|
-
|
298
|
-
assert_equal 'parked', object.state
|
290
|
+
def test_should_set_initial_state_on_created_object
|
291
|
+
assert_equal 'parked', @klass.new.state
|
299
292
|
end
|
300
293
|
|
301
|
-
def
|
302
|
-
|
294
|
+
def test_should_still_set_initial_state_even_if_not_empty
|
295
|
+
@klass.class_eval do
|
296
|
+
def initialize(attributes = {})
|
297
|
+
self.state = 'idling'
|
298
|
+
super()
|
299
|
+
end
|
300
|
+
end
|
301
|
+
object = @klass.new
|
303
302
|
assert_equal 'parked', object.state
|
304
303
|
end
|
305
304
|
|
306
|
-
def test_should_not_set_initial_state_if_existing_is_not_empty
|
307
|
-
object = @klass.new(:state => 'idling')
|
308
|
-
assert_equal 'idling', object.state
|
309
|
-
end
|
310
|
-
|
311
305
|
def test_should_set_initial_state_prior_to_initialization
|
312
306
|
base = Class.new do
|
313
307
|
attr_accessor :state_on_init
|
@@ -360,6 +354,17 @@ class MachineWithDynamicInitialStateTest < Test::Unit::TestCase
|
|
360
354
|
assert_equal 'default', @object.state
|
361
355
|
end
|
362
356
|
|
357
|
+
def test_should_not_set_initial_state_even_if_not_empty
|
358
|
+
@klass.class_eval do
|
359
|
+
def initialize(attributes = {})
|
360
|
+
self.state = 'parked'
|
361
|
+
super()
|
362
|
+
end
|
363
|
+
end
|
364
|
+
object = @klass.new
|
365
|
+
assert_equal 'parked', object.state
|
366
|
+
end
|
367
|
+
|
363
368
|
def test_should_set_initial_state_after_initialization
|
364
369
|
base = Class.new do
|
365
370
|
attr_accessor :state_on_init
|
@@ -383,13 +388,7 @@ end
|
|
383
388
|
class MachineStateInitializationTest < Test::Unit::TestCase
|
384
389
|
def setup
|
385
390
|
@klass = Class.new
|
386
|
-
@machine = StateMachine::Machine.new(@klass, :state, :initial => :parked)
|
387
|
-
|
388
|
-
# Prevent the auto-initialization hook from firing
|
389
|
-
@klass.class_eval do
|
390
|
-
def initialize
|
391
|
-
end
|
392
|
-
end
|
391
|
+
@machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :initialize => false)
|
393
392
|
|
394
393
|
@object = @klass.new
|
395
394
|
@object.state = nil
|
@@ -414,6 +413,30 @@ class MachineStateInitializationTest < Test::Unit::TestCase
|
|
414
413
|
|
415
414
|
assert_equal 'idling', @object.state
|
416
415
|
end
|
416
|
+
|
417
|
+
def test_should_set_states_if_not_empty_and_forced
|
418
|
+
@object.state = 'idling'
|
419
|
+
@machine.initialize_state(@object, :force => true)
|
420
|
+
|
421
|
+
assert_equal 'parked', @object.state
|
422
|
+
end
|
423
|
+
|
424
|
+
def test_should_not_set_state_if_nil_and_nil_is_valid_state
|
425
|
+
@machine.state :initial, :value => nil
|
426
|
+
@machine.initialize_state(@object)
|
427
|
+
|
428
|
+
assert_nil @object.state
|
429
|
+
end
|
430
|
+
|
431
|
+
def test_should_write_to_hash_if_specified
|
432
|
+
@machine.initialize_state(@object, :to => hash = {})
|
433
|
+
assert_equal expected = {'state' => 'parked'}, hash
|
434
|
+
end
|
435
|
+
|
436
|
+
def test_should_not_write_to_object_if_writing_to_hash
|
437
|
+
@machine.initialize_state(@object, :to => {})
|
438
|
+
assert_nil @object.state
|
439
|
+
end
|
417
440
|
end
|
418
441
|
|
419
442
|
class MachineWithCustomActionTest < Test::Unit::TestCase
|
@@ -1021,11 +1044,6 @@ class MachineWithHelpersTest < Test::Unit::TestCase
|
|
1021
1044
|
def test_should_throw_exception_with_invalid_scope
|
1022
1045
|
assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) { @machine.define_helper(:invalid, :state) {} }
|
1023
1046
|
end
|
1024
|
-
|
1025
|
-
def test_should_throw_exception_if_calling_helper_directly_with_invalid_scope
|
1026
|
-
@machine.define_helper(:instance, :state) {}
|
1027
|
-
assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) { @machine.call_helper(:invalid, :state, lambda {}, @object) }
|
1028
|
-
end
|
1029
1047
|
end
|
1030
1048
|
|
1031
1049
|
class MachineWithInstanceHelpersTest < Test::Unit::TestCase
|
@@ -1079,61 +1097,25 @@ class MachineWithInstanceHelpersTest < Test::Unit::TestCase
|
|
1079
1097
|
helper_args = nil
|
1080
1098
|
@machine.define_helper(:instance, :state) {|*args| helper_args = args}
|
1081
1099
|
@object.state
|
1082
|
-
assert_equal
|
1083
|
-
assert_equal [@machine, @object], helper_args
|
1100
|
+
assert_equal 2, helper_args.length
|
1101
|
+
assert_equal [@machine, @object], helper_args
|
1084
1102
|
end
|
1085
1103
|
|
1086
1104
|
def test_should_pass_method_arguments_through
|
1087
1105
|
helper_args = nil
|
1088
1106
|
@machine.define_helper(:instance, :state) {|*args| helper_args = args}
|
1089
1107
|
@object.state(1, 2, 3)
|
1090
|
-
assert_equal
|
1091
|
-
assert_equal [@machine, @object], helper_args
|
1092
|
-
assert_equal [1, 2, 3], helper_args[3..5]
|
1108
|
+
assert_equal 5, helper_args.length
|
1109
|
+
assert_equal [@machine, @object, 1, 2, 3], helper_args
|
1093
1110
|
end
|
1094
1111
|
|
1095
|
-
def
|
1096
|
-
@
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
})
|
1103
|
-
end
|
1104
|
-
@machine = StateMachine::Machine.new(@klass)
|
1105
|
-
@object = @klass.new
|
1106
|
-
|
1107
|
-
@machine.define_helper(:instance, :state) {|machine, object, _super| _super.call}
|
1108
|
-
assert_equal 'original', @object.state
|
1109
|
-
end
|
1110
|
-
|
1111
|
-
def test_should_allow_rewrite_of_super_args
|
1112
|
-
@klass = Class.new
|
1113
|
-
@klass.class_eval do
|
1114
|
-
include(Module.new {
|
1115
|
-
def state(value)
|
1116
|
-
value
|
1117
|
-
end
|
1118
|
-
})
|
1119
|
-
end
|
1120
|
-
@machine = StateMachine::Machine.new(@klass)
|
1121
|
-
@object = @klass.new
|
1122
|
-
|
1123
|
-
@machine.define_helper(:instance, :state) {|machine, object, _super, *args| _super.call('override')}
|
1124
|
-
assert_equal 'override', @object.state(1)
|
1125
|
-
end
|
1126
|
-
|
1127
|
-
def test_should_throw_exception_if_calling_helper_directly_with_invalid_method
|
1128
|
-
assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) { @machine.call_helper(:instance, :invalid, @object, lambda {}) }
|
1129
|
-
end
|
1130
|
-
|
1131
|
-
def test_should_be_able_to_call_helper_directly
|
1132
|
-
helper_args = nil
|
1133
|
-
@machine.define_helper(:instance, :state) {|*args| helper_args = args}
|
1134
|
-
|
1135
|
-
@machine.call_helper(:instance, :state, @object, _super = lambda {}, 1, 2, 3)
|
1136
|
-
assert_equal [@machine, @object, _super, 1, 2, 3], helper_args
|
1112
|
+
def test_should_allow_string_evaluation
|
1113
|
+
@machine.define_helper :instance, <<-end_eval, __FILE__, __LINE__ + 1
|
1114
|
+
def state
|
1115
|
+
'parked'
|
1116
|
+
end
|
1117
|
+
end_eval
|
1118
|
+
assert_equal 'parked', @object.state
|
1137
1119
|
end
|
1138
1120
|
end
|
1139
1121
|
|
@@ -1187,59 +1169,25 @@ class MachineWithClassHelpersTest < Test::Unit::TestCase
|
|
1187
1169
|
helper_args = nil
|
1188
1170
|
@machine.define_helper(:class, :states) {|*args| helper_args = args}
|
1189
1171
|
@klass.states
|
1190
|
-
assert_equal
|
1191
|
-
assert_equal [@machine, @klass], helper_args
|
1172
|
+
assert_equal 2, helper_args.length
|
1173
|
+
assert_equal [@machine, @klass], helper_args
|
1192
1174
|
end
|
1193
1175
|
|
1194
1176
|
def test_should_pass_method_arguments_through
|
1195
1177
|
helper_args = nil
|
1196
1178
|
@machine.define_helper(:class, :states) {|*args| helper_args = args}
|
1197
1179
|
@klass.states(1, 2, 3)
|
1198
|
-
assert_equal
|
1199
|
-
assert_equal [@machine, @klass], helper_args
|
1200
|
-
assert_equal [1, 2, 3], helper_args[3..5]
|
1180
|
+
assert_equal 5, helper_args.length
|
1181
|
+
assert_equal [@machine, @klass, 1, 2, 3], helper_args
|
1201
1182
|
end
|
1202
1183
|
|
1203
|
-
def
|
1204
|
-
@
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
})
|
1211
|
-
end
|
1212
|
-
@machine = StateMachine::Machine.new(@klass)
|
1213
|
-
|
1214
|
-
@machine.define_helper(:class, :states) {|machine, klass, _super| _super.call}
|
1215
|
-
assert_equal 'original', @klass.states
|
1216
|
-
end
|
1217
|
-
|
1218
|
-
def test_should_allow_rewrite_of_super_args
|
1219
|
-
@klass = Class.new
|
1220
|
-
@klass.class_eval do
|
1221
|
-
extend(Module.new {
|
1222
|
-
def states(value)
|
1223
|
-
value
|
1224
|
-
end
|
1225
|
-
})
|
1226
|
-
end
|
1227
|
-
@machine = StateMachine::Machine.new(@klass)
|
1228
|
-
|
1229
|
-
@machine.define_helper(:class, :states) {|machine, klass, _super, *args| _super.call('override')}
|
1230
|
-
assert_equal 'override', @klass.states(1)
|
1231
|
-
end
|
1232
|
-
|
1233
|
-
def test_should_throw_exception_if_calling_helper_directly_with_invalid_method
|
1234
|
-
assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) { @machine.call_helper(:class, :invalid, @klass, lambda {}) }
|
1235
|
-
end
|
1236
|
-
|
1237
|
-
def test_should_be_able_to_call_helper_directly
|
1238
|
-
helper_args = nil
|
1239
|
-
@machine.define_helper(:class, :states) {|*args| helper_args = args}
|
1240
|
-
|
1241
|
-
@machine.call_helper(:class, :states, @klass, _super = lambda {}, 1, 2, 3)
|
1242
|
-
assert_equal [@machine, @klass, _super, 1, 2, 3], helper_args
|
1184
|
+
def test_should_allow_string_evaluation
|
1185
|
+
@machine.define_helper :class, <<-end_eval, __FILE__, __LINE__ + 1
|
1186
|
+
def states
|
1187
|
+
[]
|
1188
|
+
end
|
1189
|
+
end_eval
|
1190
|
+
assert_equal [], @klass.states
|
1243
1191
|
end
|
1244
1192
|
end
|
1245
1193
|
|
@@ -2174,37 +2122,6 @@ class MachineWithOwnerSubclassTest < Test::Unit::TestCase
|
|
2174
2122
|
end
|
2175
2123
|
end
|
2176
2124
|
|
2177
|
-
class MachineWithOwnerSubclassHelpersTest < Test::Unit::TestCase
|
2178
|
-
def setup
|
2179
|
-
@base = Class.new
|
2180
|
-
@base_machine = StateMachine::Machine.new(@base)
|
2181
|
-
@base_machine.define_helper(:instance, :transition) { :base }
|
2182
|
-
|
2183
|
-
@subclass = Class.new(@base)
|
2184
|
-
@subclass_machine = @subclass.state_machine {}
|
2185
|
-
@subclass_machine.define_helper(:instance, :run) { :subclass }
|
2186
|
-
|
2187
|
-
@base_object = @base.new
|
2188
|
-
@subclass_object = @subclass.new
|
2189
|
-
end
|
2190
|
-
|
2191
|
-
def test_should_be_able_to_call_base_helper_on_base
|
2192
|
-
assert_equal :base, @base_machine.call_helper(:instance, :transition, @base_object, lambda {})
|
2193
|
-
end
|
2194
|
-
|
2195
|
-
def test_should_be_able_to_call_base_helper_on_subclass
|
2196
|
-
assert_equal :base, @subclass_machine.call_helper(:instance, :transition, @subclass_object, lambda {})
|
2197
|
-
end
|
2198
|
-
|
2199
|
-
def test_should_not_be_able_to_call_subclass_helper_on_base
|
2200
|
-
assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) { @base_machine.call_helper(:instance, :run, @base_object, lambda {}) }
|
2201
|
-
end
|
2202
|
-
|
2203
|
-
def test_should_be_able_to_call_subclass_helper_on_base
|
2204
|
-
assert_equal :subclass, @subclass_machine.call_helper(:instance, :run, @subclass_object, lambda {})
|
2205
|
-
end
|
2206
|
-
end
|
2207
|
-
|
2208
2125
|
class MachineWithExistingMachinesOnOwnerClassTest < Test::Unit::TestCase
|
2209
2126
|
def setup
|
2210
2127
|
@klass = Class.new
|
@@ -2228,7 +2145,7 @@ class MachineWithExistingMachinesWithSameAttributesOnOwnerClassTest < Test::Unit
|
|
2228
2145
|
def setup
|
2229
2146
|
@klass = Class.new
|
2230
2147
|
@machine = StateMachine::Machine.new(@klass, :initial => :parked)
|
2231
|
-
@second_machine = StateMachine::Machine.new(@klass, :public_state, :attribute => :state)
|
2148
|
+
@second_machine = StateMachine::Machine.new(@klass, :public_state, :initial => :idling, :attribute => :state)
|
2232
2149
|
@object = @klass.new
|
2233
2150
|
end
|
2234
2151
|
|
@@ -2237,10 +2154,30 @@ class MachineWithExistingMachinesWithSameAttributesOnOwnerClassTest < Test::Unit
|
|
2237
2154
|
assert_equal expected, @klass.state_machines
|
2238
2155
|
end
|
2239
2156
|
|
2240
|
-
def
|
2157
|
+
def test_should_write_to_state_only_once
|
2158
|
+
@klass.class_eval do
|
2159
|
+
attr_reader :write_count
|
2160
|
+
|
2161
|
+
def state=(value)
|
2162
|
+
@write_count ||= 0
|
2163
|
+
@write_count += 1
|
2164
|
+
end
|
2165
|
+
end
|
2166
|
+
object = @klass.new
|
2167
|
+
|
2168
|
+
assert_equal 1, object.write_count
|
2169
|
+
end
|
2170
|
+
|
2171
|
+
def test_should_initialize_based_on_first_machine
|
2241
2172
|
assert_equal 'parked', @object.state
|
2242
2173
|
end
|
2243
2174
|
|
2175
|
+
def test_should_not_allow_second_machine_to_initialize_state
|
2176
|
+
@object.state = nil
|
2177
|
+
@second_machine.initialize_state(@object)
|
2178
|
+
assert_nil @object.state
|
2179
|
+
end
|
2180
|
+
|
2244
2181
|
def test_should_allow_transitions_on_both_machines
|
2245
2182
|
@machine.event :ignite do
|
2246
2183
|
transition :parked => :idling
|