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.
@@ -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 = {:static => true, :dynamic => true}.merge(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
@@ -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(IndexError) { @record.state? }
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 test_should_should_use_initialized_state_when_static
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 test_should_should_not_use_initialized_state_when_dynamic
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
- assert_equal 'parked', record.state
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(:attributes => attrs) do
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 test_should_not_define_a_reader_attribute_for_the_attribute
409
- assert !@record.respond_to?(:status)
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 test_should_not_define_a_writer_attribute_for_the_attribute
413
- assert !@record.respond_to?(:status=)
412
+ def test_should_define_a_reader_attribute_for_the_attribute
413
+ assert @record.respond_to?(:status)
414
414
  end
415
415
 
416
- def test_should_define_an_attribute_predicate
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 test_should_raise_exception_on_predicate_without_parameters
421
- old_verbose, $VERBOSE = $VERBOSE, nil
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
- attr_accessor :status
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 nil, :idling
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(IndexError) { @record.state? }
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 nil, :idling
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 nil, :idling
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.rc.7'
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 test_should_not_have_any_before_callbacks
67
- assert_equal 0, @machine.callbacks[:before].size
66
+ def test_should_create_notifier_before_callback
67
+ assert_equal 1, @machine.callbacks[:before].size
68
68
  end
69
69
 
70
- def test_should_not_have_any_after_callbacks
71
- assert_equal 0, @machine.callbacks[:after].size
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
- attr_accessor :status
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 nil, :idling
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(IndexError) { @record.state? }
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
- def initialize
368
- # Skip attribute initialization
369
- @initialized_state_machines = true
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 nil, :idling
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
@@ -264,13 +264,7 @@ end
264
264
 
265
265
  class MachineWithStaticInitialStateTest < Test::Unit::TestCase
266
266
  def setup
267
- @klass = Class.new do
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 test_should_set_initial_state_if_existing_is_nil
297
- object = @klass.new(:state => nil)
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 test_should_set_initial_state_if_existing_is_empty
302
- object = @klass.new(:state => '')
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 3, helper_args.length
1083
- assert_equal [@machine, @object], helper_args[0..1]
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 6, helper_args.length
1091
- assert_equal [@machine, @object], helper_args[0..1]
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 test_should_allow_super_calls
1096
- @klass = Class.new
1097
- @klass.class_eval do
1098
- include(Module.new {
1099
- def state
1100
- 'original'
1101
- end
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 3, helper_args.length
1191
- assert_equal [@machine, @klass], helper_args[0..1]
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 6, helper_args.length
1199
- assert_equal [@machine, @klass], helper_args[0..1]
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 test_should_allow_super_calls
1204
- @klass = Class.new
1205
- @klass.class_eval do
1206
- extend(Module.new {
1207
- def states
1208
- 'original'
1209
- end
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 test_should_initialize_based_on_first_available_initial_state
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