state_machine 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +0 -2
  3. data/.yardopts +3 -2
  4. data/Appraisals +48 -0
  5. data/{CHANGELOG.rdoc → CHANGELOG.md} +63 -46
  6. data/README.md +1029 -0
  7. data/gemfiles/active_model-3.0.0.gemfile.lock +1 -3
  8. data/gemfiles/active_model-3.0.5.gemfile.lock +1 -3
  9. data/gemfiles/active_model-3.1.1.gemfile +7 -0
  10. data/gemfiles/active_model-3.1.1.gemfile.lock +32 -0
  11. data/gemfiles/active_record-2.0.0.gemfile.lock +1 -3
  12. data/gemfiles/active_record-2.0.5.gemfile.lock +1 -3
  13. data/gemfiles/active_record-2.1.0.gemfile.lock +1 -3
  14. data/gemfiles/active_record-2.1.2.gemfile.lock +1 -3
  15. data/gemfiles/active_record-2.2.3.gemfile.lock +1 -3
  16. data/gemfiles/active_record-2.3.12.gemfile.lock +1 -3
  17. data/gemfiles/active_record-3.0.0.gemfile.lock +1 -3
  18. data/gemfiles/active_record-3.0.5.gemfile.lock +1 -3
  19. data/gemfiles/active_record-3.1.1.gemfile +8 -0
  20. data/gemfiles/active_record-3.1.1.gemfile.lock +43 -0
  21. data/gemfiles/data_mapper-0.10.2.gemfile.lock +1 -3
  22. data/gemfiles/data_mapper-0.9.11.gemfile.lock +1 -3
  23. data/gemfiles/data_mapper-0.9.4.gemfile.lock +1 -3
  24. data/gemfiles/data_mapper-0.9.7.gemfile.lock +1 -3
  25. data/gemfiles/data_mapper-1.0.0.gemfile.lock +1 -3
  26. data/gemfiles/data_mapper-1.0.1.gemfile.lock +1 -3
  27. data/gemfiles/data_mapper-1.0.2.gemfile.lock +1 -3
  28. data/gemfiles/data_mapper-1.1.0.gemfile.lock +1 -3
  29. data/gemfiles/data_mapper-1.2.0.gemfile +12 -0
  30. data/gemfiles/data_mapper-1.2.0.gemfile.lock +49 -0
  31. data/gemfiles/default.gemfile.lock +1 -3
  32. data/gemfiles/graphviz-0.9.0.gemfile +7 -0
  33. data/gemfiles/graphviz-0.9.0.gemfile.lock +24 -0
  34. data/gemfiles/graphviz-0.9.21.gemfile +7 -0
  35. data/gemfiles/graphviz-0.9.21.gemfile.lock +24 -0
  36. data/gemfiles/graphviz-1.0.0.gemfile +7 -0
  37. data/gemfiles/graphviz-1.0.0.gemfile.lock +24 -0
  38. data/gemfiles/mongo_mapper-0.10.0.gemfile +7 -0
  39. data/gemfiles/mongo_mapper-0.10.0.gemfile.lock +41 -0
  40. data/gemfiles/mongo_mapper-0.5.5.gemfile.lock +1 -3
  41. data/gemfiles/mongo_mapper-0.5.8.gemfile.lock +1 -3
  42. data/gemfiles/mongo_mapper-0.6.0.gemfile.lock +1 -3
  43. data/gemfiles/mongo_mapper-0.6.10.gemfile.lock +1 -3
  44. data/gemfiles/mongo_mapper-0.7.0.gemfile.lock +1 -3
  45. data/gemfiles/mongo_mapper-0.7.5.gemfile.lock +1 -3
  46. data/gemfiles/mongo_mapper-0.8.0.gemfile.lock +1 -3
  47. data/gemfiles/mongo_mapper-0.8.3.gemfile.lock +1 -3
  48. data/gemfiles/mongo_mapper-0.8.4.gemfile.lock +1 -3
  49. data/gemfiles/mongo_mapper-0.8.6.gemfile.lock +1 -3
  50. data/gemfiles/mongo_mapper-0.9.0.gemfile.lock +1 -3
  51. data/gemfiles/mongoid-2.0.0.gemfile.lock +1 -3
  52. data/gemfiles/mongoid-2.1.4.gemfile.lock +1 -3
  53. data/gemfiles/mongoid-2.2.4.gemfile +7 -0
  54. data/gemfiles/mongoid-2.2.4.gemfile.lock +40 -0
  55. data/gemfiles/mongoid-2.3.3.gemfile +7 -0
  56. data/gemfiles/mongoid-2.3.3.gemfile.lock +40 -0
  57. data/gemfiles/sequel-2.11.0.gemfile.lock +1 -3
  58. data/gemfiles/sequel-2.12.0.gemfile.lock +1 -3
  59. data/gemfiles/sequel-2.8.0.gemfile.lock +1 -3
  60. data/gemfiles/sequel-3.0.0.gemfile.lock +1 -3
  61. data/gemfiles/sequel-3.13.0.gemfile.lock +1 -3
  62. data/gemfiles/sequel-3.14.0.gemfile.lock +1 -3
  63. data/gemfiles/sequel-3.23.0.gemfile.lock +1 -3
  64. data/gemfiles/sequel-3.24.0.gemfile.lock +1 -3
  65. data/gemfiles/sequel-3.29.0.gemfile +8 -0
  66. data/gemfiles/sequel-3.29.0.gemfile.lock +26 -0
  67. data/lib/state_machine.rb +45 -0
  68. data/lib/state_machine/event.rb +18 -3
  69. data/lib/state_machine/event_collection.rb +1 -1
  70. data/lib/state_machine/integrations/active_model.rb +59 -16
  71. data/lib/state_machine/integrations/active_model/observer.rb +3 -15
  72. data/lib/state_machine/integrations/active_record.rb +46 -9
  73. data/lib/state_machine/integrations/data_mapper.rb +42 -2
  74. data/lib/state_machine/integrations/data_mapper/versions.rb +22 -10
  75. data/lib/state_machine/integrations/mongo_mapper.rb +55 -0
  76. data/lib/state_machine/integrations/mongo_mapper/versions.rb +3 -3
  77. data/lib/state_machine/integrations/mongoid.rb +57 -12
  78. data/lib/state_machine/integrations/mongoid/versions.rb +22 -4
  79. data/lib/state_machine/integrations/sequel.rb +45 -0
  80. data/lib/state_machine/integrations/sequel/versions.rb +3 -0
  81. data/lib/state_machine/machine.rb +148 -34
  82. data/lib/state_machine/node_collection.rb +36 -3
  83. data/lib/state_machine/state.rb +6 -3
  84. data/lib/state_machine/state_collection.rb +1 -1
  85. data/lib/state_machine/version.rb +1 -1
  86. data/lib/tasks/state_machine.rb +11 -9
  87. data/state_machine.gemspec +2 -3
  88. data/test/functional/state_machine_test.rb +54 -1
  89. data/test/unit/event_collection_test.rb +4 -0
  90. data/test/unit/event_test.rb +34 -1
  91. data/test/unit/integrations/active_model_test.rb +80 -0
  92. data/test/unit/integrations/active_record_test.rb +105 -2
  93. data/test/unit/integrations/data_mapper_test.rb +27 -25
  94. data/test/unit/integrations/mongo_mapper_test.rb +80 -25
  95. data/test/unit/integrations/mongoid_test.rb +61 -6
  96. data/test/unit/integrations/sequel_test.rb +8 -2
  97. data/test/unit/machine_test.rb +87 -9
  98. data/test/unit/node_collection_test.rb +129 -12
  99. data/test/unit/state_collection_test.rb +4 -0
  100. data/test/unit/state_test.rb +2 -2
  101. metadata +30 -24
  102. data/README.rdoc +0 -844
@@ -281,14 +281,14 @@ module MongoidTest
281
281
  @machine = StateMachine::Machine.new(@model)
282
282
  @machine.state :state
283
283
 
284
- assert_match /^Instance method "state\?" is already defined in .*, use generic helper instead\.\n$/, $stderr.string
284
+ assert_match /^Instance method "state\?" is already defined in .*, use generic helper instead.*\n$/, $stderr.string
285
285
  end
286
286
 
287
287
  def test_should_output_warning_with_same_machine_attribute
288
288
  @machine = StateMachine::Machine.new(@model, :public_state, :attribute => :state)
289
289
  @machine.state :state
290
290
 
291
- assert_match /^Instance method "state\?" is already defined in .*, use generic helper instead\.\n$/, $stderr.string
291
+ assert_match /^Instance method "state\?" is already defined in .*, use generic helper instead.*\n$/, $stderr.string
292
292
  end
293
293
 
294
294
  def teardown
@@ -474,7 +474,7 @@ module MongoidTest
474
474
 
475
475
  def test_should_allow_different_initial_state_when_dynamic
476
476
  @machine.initial_state = lambda {:parked}
477
- record = @model.new(:state => 'idling')
477
+ record = silence_warnings { @model.new(:state => 'idling') }
478
478
  assert_equal 'idling', record.state
479
479
  end
480
480
 
@@ -491,7 +491,7 @@ module MongoidTest
491
491
  class MachineMultipleTest < BaseTestCase
492
492
  def setup
493
493
  @model = new_model do
494
- key :status, String, :default => 'idling'
494
+ field :status, :type => String, :default => 'idling'
495
495
  end
496
496
  @state_machine = StateMachine::Machine.new(@model, :initial => :parked)
497
497
  @status_machine = StateMachine::Machine.new(@model, :status, :initial => :idling)
@@ -587,7 +587,7 @@ module MongoidTest
587
587
  class MachineWithDirtyAttributesAndCustomAttributeTest < BaseTestCase
588
588
  def setup
589
589
  @model = new_model do
590
- key :status, String, :default => 'idling'
590
+ field :status, :type => String, :default => 'idling'
591
591
  end
592
592
  @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
593
593
  @machine.event :ignite
@@ -618,7 +618,7 @@ module MongoidTest
618
618
  class MachineWithDirtyAttributeAndCustomAttributesDuringLoopbackTest < BaseTestCase
619
619
  def setup
620
620
  @model = new_model do
621
- key :status, String, :default => 'idling'
621
+ field :status, :type => String, :default => 'idling'
622
622
  end
623
623
  @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
624
624
  @machine.event :park
@@ -744,6 +744,22 @@ module MongoidTest
744
744
  assert_equal self, context
745
745
  end
746
746
 
747
+ def test_should_run_after_callbacks_if_model_callback_added_prior_to_state_machine_definition
748
+ model = new_model do
749
+ after_save { nil }
750
+ end
751
+ machine = StateMachine::Machine.new(model, :initial => :parked)
752
+ machine.other_states :idling
753
+ machine.event :ignite
754
+ after_called = false
755
+ machine.after_transition {after_called = true}
756
+
757
+ record = model.new(:state => 'parked')
758
+ transition = StateMachine::Transition.new(record, machine, :ignite, :parked, :idling)
759
+ transition.perform
760
+ assert_equal true, after_called
761
+ end
762
+
747
763
  def test_should_run_around_callbacks
748
764
  before_called = false
749
765
  after_called = false
@@ -1371,6 +1387,13 @@ module MongoidTest
1371
1387
  assert_equal [parked, idling], @model.with_states(:parked, :idling).to_a
1372
1388
  end
1373
1389
 
1390
+ def test_should_allow_lookup_by_string_name
1391
+ parked = @model.create :state => 'parked'
1392
+ idling = @model.create :state => 'idling'
1393
+
1394
+ assert_equal [parked, idling], @model.with_states('parked', 'idling').to_a
1395
+ end
1396
+
1374
1397
  def test_should_create_singular_without_scope
1375
1398
  assert @model.respond_to?(:without_state)
1376
1399
  end
@@ -1534,6 +1557,17 @@ module MongoidTest
1534
1557
  assert_equal 'shutdown', machine.state(:parked).human_name
1535
1558
  end
1536
1559
 
1560
+ def test_should_allow_customized_state_key_scoped_to_class
1561
+ I18n.backend.store_translations(:en, {
1562
+ :mongoid => {:state_machines => {:'mongoid_test/foo' => {:states => {:parked => 'shutdown'}}}}
1563
+ })
1564
+
1565
+ machine = StateMachine::Machine.new(@model)
1566
+ machine.state :parked
1567
+
1568
+ assert_equal 'shutdown', machine.state(:parked).human_name
1569
+ end
1570
+
1537
1571
  def test_should_allow_customized_state_key_scoped_to_machine
1538
1572
  I18n.backend.store_translations(:en, {
1539
1573
  :mongoid => {:state_machines => {:state => {:states => {:parked => 'shutdown'}}}}
@@ -1556,6 +1590,16 @@ module MongoidTest
1556
1590
  assert_equal 'shutdown', machine.state(:parked).human_name
1557
1591
  end
1558
1592
 
1593
+ def test_should_support_nil_state_key
1594
+ I18n.backend.store_translations(:en, {
1595
+ :mongoid => {:state_machines => {:states => {:nil => 'empty'}}}
1596
+ })
1597
+
1598
+ machine = StateMachine::Machine.new(@model)
1599
+
1600
+ assert_equal 'empty', machine.state(nil).human_name
1601
+ end
1602
+
1559
1603
  def test_should_allow_customized_event_key_scoped_to_class_and_machine
1560
1604
  I18n.backend.store_translations(:en, {
1561
1605
  :mongoid => {:state_machines => {:'mongoid_test/foo' => {:state => {:events => {:park => 'stop'}}}}}
@@ -1567,6 +1611,17 @@ module MongoidTest
1567
1611
  assert_equal 'stop', machine.event(:park).human_name
1568
1612
  end
1569
1613
 
1614
+ def test_should_allow_customized_event_key_scoped_to_class
1615
+ I18n.backend.store_translations(:en, {
1616
+ :mongoid => {:state_machines => {:'mongoid_test/foo' => {:events => {:park => 'stop'}}}}
1617
+ })
1618
+
1619
+ machine = StateMachine::Machine.new(@model)
1620
+ machine.event :park
1621
+
1622
+ assert_equal 'stop', machine.event(:park).human_name
1623
+ end
1624
+
1570
1625
  def test_should_allow_customized_event_key_scoped_to_machine
1571
1626
  I18n.backend.store_translations(:en, {
1572
1627
  :mongoid => {:state_machines => {:state => {:events => {:park => 'stop'}}}}
@@ -34,8 +34,6 @@ module SequelTest
34
34
  define_method(:name) { "SequelTest::#{table_name.to_s.capitalize}" }
35
35
  end
36
36
  end
37
- model.plugin(:validation_class_methods) if model.respond_to?(:plugin)
38
- model.plugin(:hook_class_methods) if model.respond_to?(:plugin)
39
37
  model.class_eval(&block) if block_given?
40
38
  model
41
39
  end
@@ -856,6 +854,7 @@ module SequelTest
856
854
  class MachineWithFailedActionTest < BaseTestCase
857
855
  def setup
858
856
  @model = new_model do
857
+ plugin(:validation_class_methods) if respond_to?(:plugin)
859
858
  validates_each :state do |object, attribute, value|
860
859
  object.errors[attribute] << 'is invalid' unless %w(first_gear).include?(value)
861
860
  end
@@ -1403,6 +1402,13 @@ module SequelTest
1403
1402
  assert_equal [parked, idling], @model.with_states(:parked, :idling).all
1404
1403
  end
1405
1404
 
1405
+ def test_should_allow_lookup_by_string_name
1406
+ parked = @model.create :state => 'parked'
1407
+ idling = @model.create :state => 'idling'
1408
+
1409
+ assert_equal [parked, idling], @model.with_states('parked', 'idling').all
1410
+ end
1411
+
1406
1412
  def test_should_create_singular_without_scope
1407
1413
  assert @model.respond_to?(:without_state)
1408
1414
  end
@@ -1126,7 +1126,7 @@ class MachineWithInstanceHelpersTest < Test::Unit::TestCase
1126
1126
  machine = StateMachine::Machine.new(klass)
1127
1127
 
1128
1128
  machine.define_helper(:instance, :park) {}
1129
- assert_equal "Instance method \"park\" is already defined in #{superclass.to_s}, use generic helper instead.\n", $stderr.string
1129
+ assert_equal "Instance method \"park\" is already defined in #{superclass.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1130
1130
  ensure
1131
1131
  $stderr = @original_stderr
1132
1132
  end
@@ -1147,7 +1147,7 @@ class MachineWithInstanceHelpersTest < Test::Unit::TestCase
1147
1147
  machine = StateMachine::Machine.new(klass)
1148
1148
 
1149
1149
  machine.define_helper(:instance, :park) {}
1150
- assert_equal "Instance method \"park\" is already defined in #{superclass1.to_s}, use generic helper instead.\n", $stderr.string
1150
+ assert_equal "Instance method \"park\" is already defined in #{superclass1.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1151
1151
  ensure
1152
1152
  $stderr = @original_stderr
1153
1153
  end
@@ -1166,7 +1166,7 @@ class MachineWithInstanceHelpersTest < Test::Unit::TestCase
1166
1166
  machine = StateMachine::Machine.new(klass)
1167
1167
 
1168
1168
  machine.define_helper(:instance, :park) {}
1169
- assert_equal "Instance method \"park\" is already defined in #{mod.to_s}, use generic helper instead.\n", $stderr.string
1169
+ assert_equal "Instance method \"park\" is already defined in #{mod.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1170
1170
  ensure
1171
1171
  $stderr = @original_stderr
1172
1172
  end
@@ -1224,7 +1224,7 @@ class MachineWithInstanceHelpersTest < Test::Unit::TestCase
1224
1224
  @machine.define_helper(:instance, :park) {}
1225
1225
  @machine.define_helper(:instance, :park) {}
1226
1226
 
1227
- assert_equal "Instance method \"park\" is already defined in #{@klass} :state instance helpers, use generic helper instead.\n", $stderr.string
1227
+ assert_equal "Instance method \"park\" is already defined in #{@klass} :state instance helpers, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1228
1228
  ensure
1229
1229
  $stderr = @original_stderr
1230
1230
  end
@@ -1308,7 +1308,7 @@ class MachineWithClassHelpersTest < Test::Unit::TestCase
1308
1308
  machine = StateMachine::Machine.new(klass)
1309
1309
 
1310
1310
  machine.define_helper(:class, :park) {}
1311
- assert_equal "Class method \"park\" is already defined in #{superclass.to_s}, use generic helper instead.\n", $stderr.string
1311
+ assert_equal "Class method \"park\" is already defined in #{superclass.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1312
1312
  ensure
1313
1313
  $stderr = @original_stderr
1314
1314
  end
@@ -1329,7 +1329,7 @@ class MachineWithClassHelpersTest < Test::Unit::TestCase
1329
1329
  machine = StateMachine::Machine.new(klass)
1330
1330
 
1331
1331
  machine.define_helper(:class, :park) {}
1332
- assert_equal "Class method \"park\" is already defined in #{superclass1.to_s}, use generic helper instead.\n", $stderr.string
1332
+ assert_equal "Class method \"park\" is already defined in #{superclass1.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1333
1333
  ensure
1334
1334
  $stderr = @original_stderr
1335
1335
  end
@@ -1348,7 +1348,7 @@ class MachineWithClassHelpersTest < Test::Unit::TestCase
1348
1348
  machine = StateMachine::Machine.new(klass)
1349
1349
 
1350
1350
  machine.define_helper(:class, :park) {}
1351
- assert_equal "Class method \"park\" is already defined in #{mod.to_s}, use generic helper instead.\n", $stderr.string
1351
+ assert_equal "Class method \"park\" is already defined in #{mod.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1352
1352
  ensure
1353
1353
  $stderr = @original_stderr
1354
1354
  end
@@ -1406,7 +1406,7 @@ class MachineWithClassHelpersTest < Test::Unit::TestCase
1406
1406
  @machine.define_helper(:class, :states) {}
1407
1407
  @machine.define_helper(:class, :states) {}
1408
1408
 
1409
- assert_equal "Class method \"states\" is already defined in #{@klass} :state class helpers, use generic helper instead.\n", $stderr.string
1409
+ assert_equal "Class method \"states\" is already defined in #{@klass} :state class helpers, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1410
1410
  ensure
1411
1411
  $stderr = @original_stderr
1412
1412
  end
@@ -1591,7 +1591,7 @@ class MachineWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase
1591
1591
  'Class method "without_state"',
1592
1592
  'Class method "with_states"',
1593
1593
  'Class method "without_states"'
1594
- ].map {|method| "#{method} is already defined in #{@superclass.to_s}, use generic helper instead.\n"}.join
1594
+ ].map {|method| "#{method} is already defined in #{@superclass.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n"}.join
1595
1595
 
1596
1596
  assert_equal expected, $stderr.string
1597
1597
  end
@@ -2184,6 +2184,45 @@ class MachineWithExistingStateTest < Test::Unit::TestCase
2184
2184
  end
2185
2185
  end
2186
2186
 
2187
+ class MachineWithStateMatchersTest < Test::Unit::TestCase
2188
+ def setup
2189
+ @klass = Class.new
2190
+ @machine = StateMachine::Machine.new(@klass)
2191
+ end
2192
+
2193
+ def test_should_empty_array_for_all_matcher
2194
+ assert_equal [], @machine.state(StateMachine::AllMatcher.instance)
2195
+ end
2196
+
2197
+ def test_should_return_referenced_states_for_blacklist_matcher
2198
+ assert_instance_of StateMachine::State, @machine.state(StateMachine::BlacklistMatcher.new([:parked]))
2199
+ end
2200
+
2201
+ def test_should_not_allow_configurations
2202
+ exception = assert_raise(ArgumentError) { @machine.state(StateMachine::BlacklistMatcher.new([:parked]), :human_name => 'Parked') }
2203
+ assert_equal 'Cannot configure states when using matchers (using {:human_name=>"Parked"})', exception.message
2204
+ end
2205
+
2206
+ def test_should_track_referenced_states
2207
+ @machine.state(StateMachine::BlacklistMatcher.new([:parked]))
2208
+ assert_equal [nil, :parked], @machine.states.map {|state| state.name}
2209
+ end
2210
+
2211
+ def test_should_eval_context_for_matching_states
2212
+ contexts_run = []
2213
+ @machine.event(StateMachine::BlacklistMatcher.new([:parked])) { contexts_run << self.name }
2214
+
2215
+ @machine.event :parked
2216
+ assert_equal [], contexts_run
2217
+
2218
+ @machine.event :idling
2219
+ assert_equal [:idling], contexts_run
2220
+
2221
+ @machine.event :first_gear, :second_gear
2222
+ assert_equal [:idling, :first_gear, :second_gear], contexts_run
2223
+ end
2224
+ end
2225
+
2187
2226
  class MachineWithOtherStates < Test::Unit::TestCase
2188
2227
  def setup
2189
2228
  @klass = Class.new
@@ -2281,6 +2320,45 @@ class MachineWithEventsWithCustomHumanNamesTest < Test::Unit::TestCase
2281
2320
  end
2282
2321
  end
2283
2322
 
2323
+ class MachineWithEventMatchersTest < Test::Unit::TestCase
2324
+ def setup
2325
+ @klass = Class.new
2326
+ @machine = StateMachine::Machine.new(@klass)
2327
+ end
2328
+
2329
+ def test_should_empty_array_for_all_matcher
2330
+ assert_equal [], @machine.event(StateMachine::AllMatcher.instance)
2331
+ end
2332
+
2333
+ def test_should_return_referenced_events_for_blacklist_matcher
2334
+ assert_instance_of StateMachine::Event, @machine.event(StateMachine::BlacklistMatcher.new([:park]))
2335
+ end
2336
+
2337
+ def test_should_not_allow_configurations
2338
+ exception = assert_raise(ArgumentError) { @machine.event(StateMachine::BlacklistMatcher.new([:park]), :human_name => 'Park') }
2339
+ assert_equal 'Cannot configure events when using matchers (using {:human_name=>"Park"})', exception.message
2340
+ end
2341
+
2342
+ def test_should_track_referenced_events
2343
+ event = @machine.event(StateMachine::BlacklistMatcher.new([:park]))
2344
+ assert_equal [:park], @machine.events.map {|event| event.name}
2345
+ end
2346
+
2347
+ def test_should_eval_context_for_matching_events
2348
+ contexts_run = []
2349
+ @machine.event(StateMachine::BlacklistMatcher.new([:park])) { contexts_run << self.name }
2350
+
2351
+ @machine.event :park
2352
+ assert_equal [], contexts_run
2353
+
2354
+ @machine.event :ignite
2355
+ assert_equal [:ignite], contexts_run
2356
+
2357
+ @machine.event :shift_up, :shift_down
2358
+ assert_equal [:ignite, :shift_up, :shift_down], contexts_run
2359
+ end
2360
+ end
2361
+
2284
2362
  class MachineWithEventsWithTransitionsTest < Test::Unit::TestCase
2285
2363
  def setup
2286
2364
  @klass = Class.new
@@ -1,5 +1,15 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
2
 
3
+ class Node < Struct.new(:name, :value, :machine)
4
+ def name_to_s
5
+ name.to_s
6
+ end
7
+
8
+ def context
9
+ yield
10
+ end
11
+ end
12
+
3
13
  class NodeCollectionByDefaultTest < Test::Unit::TestCase
4
14
  def setup
5
15
  @machine = StateMachine::Machine.new(Class.new)
@@ -15,7 +25,7 @@ class NodeCollectionByDefaultTest < Test::Unit::TestCase
15
25
  end
16
26
 
17
27
  def test_should_index_by_name
18
- @collection << object = Struct.new(:name).new(:parked)
28
+ @collection << object = Node.new(:parked)
19
29
  assert_equal object, @collection[:parked]
20
30
  end
21
31
  end
@@ -46,10 +56,15 @@ class NodeCollectionAfterBeingCopiedTest < Test::Unit::TestCase
46
56
  def setup
47
57
  machine = StateMachine::Machine.new(Class.new)
48
58
  @collection = StateMachine::NodeCollection.new(machine)
49
- @collection << @parked = Struct.new(:name).new(:parked)
59
+ @collection << @parked = Node.new(:parked)
60
+
61
+ @contexts_run = contexts_run = []
62
+ @collection.context([:parked]) {contexts_run << :parked}
63
+ @contexts_run.clear
50
64
 
51
65
  @copied_collection = @collection.dup
52
- @copied_collection << @idling = Struct.new(:name).new(:idling)
66
+ @copied_collection << @idling = Node.new(:idling)
67
+ @copied_collection.context([:first_gear]) {contexts_run << :first_gear}
53
68
  end
54
69
 
55
70
  def test_should_not_modify_the_original_list
@@ -65,6 +80,20 @@ class NodeCollectionAfterBeingCopiedTest < Test::Unit::TestCase
65
80
  def test_should_copy_each_node
66
81
  assert_not_same @parked, @copied_collection[:parked]
67
82
  end
83
+
84
+ def test_should_not_run_contexts
85
+ assert_equal [], @contexts_run
86
+ end
87
+
88
+ def test_should_not_modify_contexts
89
+ @collection << Node.new(:first_gear)
90
+ assert_equal [], @contexts_run
91
+ end
92
+
93
+ def test_should_copy_contexts
94
+ @copied_collection << Node.new(:parked)
95
+ assert !@contexts_run.empty?
96
+ end
68
97
  end
69
98
 
70
99
  class NodeCollectionWithoutIndicesTest < Test::Unit::TestCase
@@ -101,7 +130,7 @@ class NodeCollectionWithIndicesTest < Test::Unit::TestCase
101
130
  machine = StateMachine::Machine.new(Class.new)
102
131
  @collection = StateMachine::NodeCollection.new(machine, :index => [:name, :value])
103
132
 
104
- @object = Struct.new(:name, :value).new(:parked, 1)
133
+ @object = Node.new(:parked, 1)
105
134
  @collection << @object
106
135
  end
107
136
 
@@ -141,9 +170,8 @@ class NodeCollectionWithNodesTest < Test::Unit::TestCase
141
170
  @machine = StateMachine::Machine.new(Class.new)
142
171
  @collection = StateMachine::NodeCollection.new(@machine)
143
172
 
144
- @klass = Struct.new(:name, :machine)
145
- @parked = @klass.new(:parked, @machine)
146
- @idling = @klass.new(:idling, @machine)
173
+ @parked = Node.new(:parked, nil, @machine)
174
+ @idling = Node.new(:idling, nil, @machine)
147
175
 
148
176
  @collection << @parked
149
177
  @collection << @idling
@@ -157,8 +185,8 @@ class NodeCollectionWithNodesTest < Test::Unit::TestCase
157
185
  end
158
186
 
159
187
  def test_should_be_able_to_concatenate_multiple_nodes
160
- @first_gear = @klass.new(:first_gear, @machine)
161
- @second_gear = @klass.new(:second_gear, @machine)
188
+ @first_gear = Node.new(:first_gear, nil, @machine)
189
+ @second_gear = Node.new(:second_gear, nil, @machine)
162
190
  @collection.concat([@first_gear, @second_gear])
163
191
 
164
192
  order = []
@@ -186,9 +214,8 @@ class NodeCollectionAfterUpdateTest < Test::Unit::TestCase
186
214
  machine = StateMachine::Machine.new(Class.new)
187
215
  @collection = StateMachine::NodeCollection.new(machine, :index => [:name, :value])
188
216
 
189
- @klass = Struct.new(:name, :value)
190
- @parked = @klass.new(:parked, 1)
191
- @idling = @klass.new(:idling, 2)
217
+ @parked = Node.new(:parked, 1)
218
+ @idling = Node.new(:idling, 2)
192
219
 
193
220
  @collection << @parked << @idling
194
221
 
@@ -215,3 +242,93 @@ class NodeCollectionAfterUpdateTest < Test::Unit::TestCase
215
242
  assert_nil @collection[1, :value]
216
243
  end
217
244
  end
245
+
246
+ class NodeCollectionWithStringIndexTest < Test::Unit::TestCase
247
+ def setup
248
+ machine = StateMachine::Machine.new(Class.new)
249
+ @collection = StateMachine::NodeCollection.new(machine, :index => [:name, :name_to_s, :value])
250
+
251
+ @parked = Node.new(:parked, 1)
252
+ @collection << @parked
253
+ end
254
+
255
+ def test_should_index_by_name
256
+ assert_equal @parked, @collection[:parked]
257
+ end
258
+
259
+ def test_should_index_by_string_name
260
+ assert_equal @parked, @collection['parked', :name_to_s]
261
+ end
262
+
263
+ def test_should_fallback_to_string_index
264
+ assert_equal @parked, @collection['parked']
265
+ end
266
+
267
+ def test_should_not_fallback_to_string_index_if_not_available
268
+ assert_nil @collection['1', :value]
269
+ end
270
+ end
271
+
272
+ class NodeCollectionWithPredefinedContextsTest < Test::Unit::TestCase
273
+ def setup
274
+ machine = StateMachine::Machine.new(Class.new)
275
+ @collection = StateMachine::NodeCollection.new(machine)
276
+
277
+ @contexts_run = contexts_run = []
278
+ @collection.context([:parked]) { contexts_run << :parked }
279
+ @collection.context([:parked]) { contexts_run << :second_parked }
280
+ end
281
+
282
+ def test_should_run_contexts_in_the_order_defined
283
+ @collection << Node.new(:parked)
284
+ assert_equal [:parked, :second_parked], @contexts_run
285
+ end
286
+
287
+ def test_should_not_run_contexts_if_not_matched
288
+ @collection << Node.new(:idling)
289
+ assert_equal [], @contexts_run
290
+ end
291
+ end
292
+
293
+ class NodeCollectionWithPostdefinedContextsTest < Test::Unit::TestCase
294
+ def setup
295
+ machine = StateMachine::Machine.new(Class.new)
296
+ @collection = StateMachine::NodeCollection.new(machine)
297
+ @collection << Node.new(:parked)
298
+ end
299
+
300
+ def test_should_run_context_if_matched
301
+ contexts_run = []
302
+ @collection.context([:parked]) { contexts_run << :parked }
303
+ assert_equal [:parked], contexts_run
304
+ end
305
+
306
+ def test_should_not_run_contexts_if_not_matched
307
+ contexts_run = []
308
+ @collection.context([:idling]) { contexts_run << :idling }
309
+ assert_equal [], contexts_run
310
+ end
311
+ end
312
+
313
+ class NodeCollectionWithMatcherContextsTest < Test::Unit::TestCase
314
+ def setup
315
+ machine = StateMachine::Machine.new(Class.new)
316
+ @collection = StateMachine::NodeCollection.new(machine)
317
+ @collection << Node.new(:parked)
318
+ end
319
+
320
+ def test_should_always_run_all_matcher_context
321
+ contexts_run = []
322
+ @collection.context([StateMachine::AllMatcher.instance]) { contexts_run << :all }
323
+ assert_equal [:all], contexts_run
324
+ end
325
+
326
+ def test_should_only_run_blacklist_matcher_if_not_matched
327
+ contexts_run = []
328
+ @collection.context([StateMachine::BlacklistMatcher.new([:parked])]) { contexts_run << :blacklist }
329
+ assert_equal [], contexts_run
330
+
331
+ @collection << Node.new(:idling)
332
+ assert_equal [:blacklist], contexts_run
333
+ end
334
+ end