state_machine 0.10.1 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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