state_machine 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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