state_machine 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. data/.gitignore +11 -0
  2. data/.travis.yml +16 -0
  3. data/.yardopts +5 -0
  4. data/Appraisals +260 -0
  5. data/CHANGELOG.rdoc +15 -0
  6. data/Gemfile +3 -0
  7. data/README.rdoc +156 -29
  8. data/Rakefile +31 -57
  9. data/gemfiles/active_model-3.0.0.gemfile +7 -0
  10. data/gemfiles/active_model-3.0.0.gemfile.lock +32 -0
  11. data/gemfiles/active_model-3.0.5.gemfile +7 -0
  12. data/gemfiles/active_model-3.0.5.gemfile.lock +32 -0
  13. data/gemfiles/active_record-2.0.0.gemfile +8 -0
  14. data/gemfiles/active_record-2.0.0.gemfile.lock +30 -0
  15. data/gemfiles/active_record-2.0.5.gemfile +8 -0
  16. data/gemfiles/active_record-2.0.5.gemfile.lock +30 -0
  17. data/gemfiles/active_record-2.1.0.gemfile +8 -0
  18. data/gemfiles/active_record-2.1.0.gemfile.lock +30 -0
  19. data/gemfiles/active_record-2.1.2.gemfile +8 -0
  20. data/gemfiles/active_record-2.1.2.gemfile.lock +30 -0
  21. data/gemfiles/active_record-2.2.3.gemfile +8 -0
  22. data/gemfiles/active_record-2.2.3.gemfile.lock +30 -0
  23. data/gemfiles/active_record-2.3.12.gemfile +8 -0
  24. data/gemfiles/active_record-2.3.12.gemfile.lock +30 -0
  25. data/gemfiles/active_record-3.0.0.gemfile +8 -0
  26. data/gemfiles/active_record-3.0.0.gemfile.lock +44 -0
  27. data/gemfiles/active_record-3.0.5.gemfile +8 -0
  28. data/gemfiles/active_record-3.0.5.gemfile.lock +43 -0
  29. data/gemfiles/data_mapper-0.10.2.gemfile +12 -0
  30. data/gemfiles/data_mapper-0.10.2.gemfile.lock +45 -0
  31. data/gemfiles/data_mapper-0.9.11.gemfile +12 -0
  32. data/gemfiles/data_mapper-0.9.11.gemfile.lock +47 -0
  33. data/gemfiles/data_mapper-0.9.4.gemfile +12 -0
  34. data/gemfiles/data_mapper-0.9.4.gemfile.lock +61 -0
  35. data/gemfiles/data_mapper-0.9.7.gemfile +12 -0
  36. data/gemfiles/data_mapper-0.9.7.gemfile.lock +57 -0
  37. data/gemfiles/data_mapper-1.0.0.gemfile +12 -0
  38. data/gemfiles/data_mapper-1.0.0.gemfile.lock +53 -0
  39. data/gemfiles/data_mapper-1.0.1.gemfile +12 -0
  40. data/gemfiles/data_mapper-1.0.1.gemfile.lock +53 -0
  41. data/gemfiles/data_mapper-1.0.2.gemfile +12 -0
  42. data/gemfiles/data_mapper-1.0.2.gemfile.lock +53 -0
  43. data/gemfiles/data_mapper-1.1.0.gemfile +12 -0
  44. data/gemfiles/data_mapper-1.1.0.gemfile.lock +51 -0
  45. data/gemfiles/default.gemfile +7 -0
  46. data/gemfiles/default.gemfile.lock +24 -0
  47. data/gemfiles/mongo_mapper-0.5.5.gemfile +8 -0
  48. data/gemfiles/mongo_mapper-0.5.5.gemfile.lock +33 -0
  49. data/gemfiles/mongo_mapper-0.5.8.gemfile +8 -0
  50. data/gemfiles/mongo_mapper-0.5.8.gemfile.lock +33 -0
  51. data/gemfiles/mongo_mapper-0.6.0.gemfile +8 -0
  52. data/gemfiles/mongo_mapper-0.6.0.gemfile.lock +33 -0
  53. data/gemfiles/mongo_mapper-0.6.10.gemfile +8 -0
  54. data/gemfiles/mongo_mapper-0.6.10.gemfile.lock +33 -0
  55. data/gemfiles/mongo_mapper-0.7.0.gemfile +8 -0
  56. data/gemfiles/mongo_mapper-0.7.0.gemfile.lock +33 -0
  57. data/gemfiles/mongo_mapper-0.7.5.gemfile +8 -0
  58. data/gemfiles/mongo_mapper-0.7.5.gemfile.lock +36 -0
  59. data/gemfiles/mongo_mapper-0.8.0.gemfile +10 -0
  60. data/gemfiles/mongo_mapper-0.8.0.gemfile.lock +40 -0
  61. data/gemfiles/mongo_mapper-0.8.3.gemfile +10 -0
  62. data/gemfiles/mongo_mapper-0.8.3.gemfile.lock +40 -0
  63. data/gemfiles/mongo_mapper-0.8.4.gemfile +8 -0
  64. data/gemfiles/mongo_mapper-0.8.4.gemfile.lock +38 -0
  65. data/gemfiles/mongo_mapper-0.8.6.gemfile +8 -0
  66. data/gemfiles/mongo_mapper-0.8.6.gemfile.lock +38 -0
  67. data/gemfiles/mongo_mapper-0.9.0.gemfile +7 -0
  68. data/gemfiles/mongo_mapper-0.9.0.gemfile.lock +41 -0
  69. data/gemfiles/mongoid-2.0.0.gemfile +7 -0
  70. data/gemfiles/mongoid-2.0.0.gemfile.lock +42 -0
  71. data/gemfiles/mongoid-2.1.4.gemfile +7 -0
  72. data/gemfiles/mongoid-2.1.4.gemfile.lock +40 -0
  73. data/gemfiles/sequel-2.11.0.gemfile +8 -0
  74. data/gemfiles/sequel-2.11.0.gemfile.lock +28 -0
  75. data/gemfiles/sequel-2.12.0.gemfile +8 -0
  76. data/gemfiles/sequel-2.12.0.gemfile.lock +28 -0
  77. data/gemfiles/sequel-2.8.0.gemfile +8 -0
  78. data/gemfiles/sequel-2.8.0.gemfile.lock +28 -0
  79. data/gemfiles/sequel-3.0.0.gemfile +8 -0
  80. data/gemfiles/sequel-3.0.0.gemfile.lock +28 -0
  81. data/gemfiles/sequel-3.13.0.gemfile +8 -0
  82. data/gemfiles/sequel-3.13.0.gemfile.lock +28 -0
  83. data/gemfiles/sequel-3.14.0.gemfile +8 -0
  84. data/gemfiles/sequel-3.14.0.gemfile.lock +28 -0
  85. data/gemfiles/sequel-3.23.0.gemfile +8 -0
  86. data/gemfiles/sequel-3.23.0.gemfile.lock +28 -0
  87. data/gemfiles/sequel-3.24.0.gemfile +8 -0
  88. data/gemfiles/sequel-3.24.0.gemfile.lock +28 -0
  89. data/lib/state_machine/event.rb +13 -90
  90. data/lib/state_machine/helper_module.rb +17 -0
  91. data/lib/state_machine/integrations/active_model.rb +35 -0
  92. data/lib/state_machine/integrations/active_record.rb +41 -2
  93. data/lib/state_machine/integrations/data_mapper.rb +17 -2
  94. data/lib/state_machine/integrations/mongo_mapper.rb +34 -7
  95. data/lib/state_machine/integrations/mongoid.rb +34 -26
  96. data/lib/state_machine/integrations/mongoid/versions.rb +29 -3
  97. data/lib/state_machine/integrations/sequel.rb +22 -72
  98. data/lib/state_machine/integrations/sequel/versions.rb +87 -6
  99. data/lib/state_machine/machine.rb +279 -19
  100. data/lib/state_machine/state.rb +2 -2
  101. data/lib/state_machine/state_context.rb +133 -0
  102. data/lib/state_machine/version.rb +3 -0
  103. data/state_machine.gemspec +22 -0
  104. data/test/test_helper.rb +1 -3
  105. data/test/unit/branch_test.rb +1 -3
  106. data/test/unit/event_collection_test.rb +3 -3
  107. data/test/unit/event_test.rb +1 -3
  108. data/test/unit/helper_module_test.rb +17 -0
  109. data/test/unit/integrations/active_model_test.rb +0 -4
  110. data/test/unit/integrations/active_record_test.rb +50 -9
  111. data/test/unit/integrations/data_mapper_test.rb +267 -253
  112. data/test/unit/integrations/mongo_mapper_test.rb +47 -15
  113. data/test/unit/integrations/mongoid_test.rb +50 -8
  114. data/test/unit/integrations/sequel_test.rb +10 -6
  115. data/test/unit/machine_test.rb +206 -25
  116. data/test/unit/state_context_test.rb +421 -0
  117. data/test/unit/state_test.rb +20 -3
  118. metadata +303 -128
  119. data/lib/state_machine/condition_proxy.rb +0 -94
  120. data/test/unit/condition_proxy_test.rb +0 -328
@@ -1,19 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
2
 
3
- # Load library
4
- require 'rubygems'
5
-
6
- if ENV['VERSION']
7
- if Gem::Version.new(ENV['VERSION']) >= Gem::Version.new('0.9.0')
8
- gem 'activesupport', '~>3.0'
9
- require 'active_support'
10
- elsif Gem::Version.new(ENV['VERSION']) <= Gem::Version.new('0.7.0') || !Gem.available?('>=0.7.0')
11
- gem 'activesupport', '~>2.3'
12
- require 'active_support'
13
- end
14
- end
15
-
16
- gem 'mongo_mapper', ENV['VERSION'] ? "=#{ENV['VERSION']}" : '>=0.5.5'
17
3
  require 'mongo_mapper'
18
4
 
19
5
  # Establish database connection
@@ -297,6 +283,33 @@ module MongoMapperTest
297
283
  end
298
284
  end
299
285
 
286
+ class MachineWithConflictingStateNameTest < BaseTestCase
287
+ def setup
288
+ require 'stringio'
289
+ @original_stderr, $stderr = $stderr, StringIO.new
290
+
291
+ @model = new_model
292
+ end
293
+
294
+ def test_should_output_warning_with_same_machine_name
295
+ @machine = StateMachine::Machine.new(@model)
296
+ @machine.state :state
297
+
298
+ assert_match /^Instance method "state\?" is already defined in .*, use generic helper instead\.\n$/, $stderr.string
299
+ end
300
+
301
+ def test_should_output_warning_with_same_machine_attribute
302
+ @machine = StateMachine::Machine.new(@model, :public_state, :attribute => :state)
303
+ @machine.state :state
304
+
305
+ assert_match /^Instance method "state\?" is already defined in .*, use generic helper instead\.\n$/, $stderr.string
306
+ end
307
+
308
+ def teardown
309
+ $stderr = @original_stderr
310
+ end
311
+ end
312
+
300
313
  class MachineWithColumnStateAttributeTest < BaseTestCase
301
314
  def setup
302
315
  @model = new_model
@@ -421,6 +434,25 @@ module MongoMapperTest
421
434
  end
422
435
  end
423
436
 
437
+ class MachineWithCustomAttributeTest < BaseTestCase
438
+ def setup
439
+ require 'stringio'
440
+ @original_stderr, $stderr = $stderr, StringIO.new
441
+
442
+ @model = new_model
443
+ @machine = StateMachine::Machine.new(@model, :public_state, :attribute => :state)
444
+ @record = @model.new
445
+ end
446
+
447
+ def test_should_not_delegate_attribute_predicate_with_different_attribute
448
+ assert_raise(ArgumentError) { @record.public_state? }
449
+ end
450
+
451
+ def teardown
452
+ $stderr = @original_stderr
453
+ end
454
+ end
455
+
424
456
  class MachineWithInitializedStateTest < BaseTestCase
425
457
  def setup
426
458
  @model = new_model
@@ -1606,6 +1638,6 @@ module MongoMapperTest
1606
1638
  end
1607
1639
  end
1608
1640
  else
1609
- $stderr.puts 'Skipping MongoMapper I18n tests. `gem install mongo_mapper` >= v0.9.0 and try again.'
1641
+ $stderr.puts 'Skipping MongoMapper I18n tests.'
1610
1642
  end
1611
1643
  end
@@ -1,9 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
2
 
3
- # Load library
4
- require 'rubygems'
5
-
6
- gem 'mongoid', ENV['VERSION'] ? "=#{ENV['VERSION']}" : '>=2.0.0'
7
3
  require 'mongoid'
8
4
 
9
5
  # Establish database connection
@@ -273,6 +269,33 @@ module MongoidTest
273
269
  end
274
270
  end
275
271
 
272
+ class MachineWithConflictingStateNameTest < BaseTestCase
273
+ def setup
274
+ require 'stringio'
275
+ @original_stderr, $stderr = $stderr, StringIO.new
276
+
277
+ @model = new_model
278
+ end
279
+
280
+ def test_should_output_warning_with_same_machine_name
281
+ @machine = StateMachine::Machine.new(@model)
282
+ @machine.state :state
283
+
284
+ assert_match /^Instance method "state\?" is already defined in .*, use generic helper instead\.\n$/, $stderr.string
285
+ end
286
+
287
+ def test_should_output_warning_with_same_machine_attribute
288
+ @machine = StateMachine::Machine.new(@model, :public_state, :attribute => :state)
289
+ @machine.state :state
290
+
291
+ assert_match /^Instance method "state\?" is already defined in .*, use generic helper instead\.\n$/, $stderr.string
292
+ end
293
+
294
+ def teardown
295
+ $stderr = @original_stderr
296
+ end
297
+ end
298
+
276
299
  class MachineWithColumnStateAttributeTest < BaseTestCase
277
300
  def setup
278
301
  @model = new_model
@@ -403,6 +426,25 @@ module MongoidTest
403
426
  end
404
427
  end
405
428
 
429
+ class MachineWithCustomAttributeTest < BaseTestCase
430
+ def setup
431
+ require 'stringio'
432
+ @original_stderr, $stderr = $stderr, StringIO.new
433
+
434
+ @model = new_model
435
+ @machine = StateMachine::Machine.new(@model, :public_state, :attribute => :state)
436
+ @record = @model.new
437
+ end
438
+
439
+ def test_should_not_delegate_attribute_predicate_with_different_attribute
440
+ assert_raise(ArgumentError) { @record.public_state? }
441
+ end
442
+
443
+ def teardown
444
+ $stderr = @original_stderr
445
+ end
446
+ end
447
+
406
448
  class MachineWithInitializedStateTest < BaseTestCase
407
449
  def setup
408
450
  @model = new_model
@@ -538,7 +580,7 @@ module MongoidTest
538
580
  end
539
581
 
540
582
  def test_should_track_attribute_changes
541
- assert_equal %w(parked parked), @record.changes['state']
583
+ assert_equal %w(parked parked), @record.send(:attribute_change, 'state')
542
584
  end
543
585
  end
544
586
 
@@ -592,7 +634,7 @@ module MongoidTest
592
634
  end
593
635
 
594
636
  def test_should_track_attribute_changes
595
- assert_equal %w(parked parked), @record.changes['status']
637
+ assert_equal %w(parked parked), @record.send(:attribute_change, 'status')
596
638
  end
597
639
  end
598
640
 
@@ -611,12 +653,12 @@ module MongoidTest
611
653
  end
612
654
 
613
655
  def test_should_track_attribute_change
614
- assert_equal %w(parked parked), @record.changes['state']
656
+ assert_equal %w(parked parked), @record.send(:attribute_change, 'state')
615
657
  end
616
658
 
617
659
  def test_should_not_reset_changes_on_multiple_changes
618
660
  @record.state_event = 'ignite'
619
- assert_equal %w(parked parked), @record.changes['state']
661
+ assert_equal %w(parked parked), @record.send(:attribute_change, 'state')
620
662
  end
621
663
 
622
664
  def test_should_not_include_state_in_changed_attributes_if_nil
@@ -1,9 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
2
 
3
- # Load library
4
- require 'rubygems'
5
-
6
- gem 'sequel', ENV['VERSION'] ? "=#{ENV['VERSION']}" : '>=2.8.0'
7
3
  require 'sequel'
8
4
  require 'logger'
9
5
 
@@ -19,12 +15,20 @@ module SequelTest
19
15
  # Creates a new Sequel model (and the associated table)
20
16
  def new_model(create_table = :foo, &block)
21
17
  table_name = create_table || :foo
18
+ table_identifier = ::Sequel::SQL::Identifier.new(table_name)
19
+
20
+ if !defined?(Sequel::VERSION) || Gem::Version.new(::Sequel::VERSION) <= Gem::Version.new('3.26.0')
21
+ class << table_identifier
22
+ alias_method :original_to_s, :to_s
23
+ def to_s(*args); args.empty? ? inspect : original_to_s(*args); end
24
+ end
25
+ end
22
26
 
23
- DB.create_table!(::Sequel::SQL::Identifier.new(table_name)) do
27
+ DB.create_table!(table_identifier) do
24
28
  primary_key :id
25
29
  column :state, :string
26
30
  end if create_table
27
- model = Class.new(Sequel::Model(DB[::Sequel::SQL::Identifier.new(table_name)])) do
31
+ model = Class.new(Sequel::Model(DB[table_identifier])) do
28
32
  self.raise_on_save_failure = false
29
33
  (class << self; self; end).class_eval do
30
34
  define_method(:name) { "SequelTest::#{table_name.to_s.capitalize}" }
@@ -1068,7 +1068,7 @@ class MachineWithHelpersTest < Test::Unit::TestCase
1068
1068
  end
1069
1069
 
1070
1070
  def test_should_throw_exception_with_invalid_scope
1071
- assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) { @machine.define_helper(:invalid, :state) {} }
1071
+ assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) { @machine.define_helper(:invalid, :park) {} }
1072
1072
  end
1073
1073
  end
1074
1074
 
@@ -1081,37 +1081,37 @@ class MachineWithInstanceHelpersTest < Test::Unit::TestCase
1081
1081
 
1082
1082
  def test_should_not_redefine_existing_public_methods
1083
1083
  @klass.class_eval do
1084
- def state
1085
- 'parked'
1084
+ def park
1085
+ true
1086
1086
  end
1087
1087
  end
1088
1088
 
1089
- @machine.define_helper(:instance, :state) {}
1090
- assert_equal 'parked', @object.state
1089
+ @machine.define_helper(:instance, :park) {}
1090
+ assert_equal true, @object.park
1091
1091
  end
1092
1092
 
1093
1093
  def test_should_not_redefine_existing_protected_methods
1094
1094
  @klass.class_eval do
1095
1095
  protected
1096
- def state
1097
- 'parked'
1096
+ def park
1097
+ true
1098
1098
  end
1099
1099
  end
1100
1100
 
1101
- @machine.define_helper(:instance, :state) {}
1102
- assert_equal 'parked', @object.send(:state)
1101
+ @machine.define_helper(:instance, :park) {}
1102
+ assert_equal true, @object.send(:park)
1103
1103
  end
1104
1104
 
1105
1105
  def test_should_not_redefine_existing_private_methods
1106
1106
  @klass.class_eval do
1107
1107
  private
1108
- def state
1109
- 'parked'
1108
+ def park
1109
+ true
1110
1110
  end
1111
1111
  end
1112
1112
 
1113
- @machine.define_helper(:instance, :state) {}
1114
- assert_equal 'parked', @object.send(:state)
1113
+ @machine.define_helper(:instance, :park) {}
1114
+ assert_equal true, @object.send(:park)
1115
1115
  end
1116
1116
 
1117
1117
  def test_should_warn_if_defined_in_superclass
@@ -1213,33 +1213,45 @@ class MachineWithInstanceHelpersTest < Test::Unit::TestCase
1213
1213
  end
1214
1214
 
1215
1215
  def test_should_define_nonexistent_methods
1216
- @machine.define_helper(:instance, :state) {'parked'}
1217
- assert_equal 'parked', @object.state
1216
+ @machine.define_helper(:instance, :park) {false}
1217
+ assert_equal false, @object.park
1218
+ end
1219
+
1220
+ def test_should_warn_if_defined_multiple_times
1221
+ require 'stringio'
1222
+ @original_stderr, $stderr = $stderr, StringIO.new
1223
+
1224
+ @machine.define_helper(:instance, :park) {}
1225
+ @machine.define_helper(:instance, :park) {}
1226
+
1227
+ assert_equal "Instance method \"park\" is already defined in #{@klass} :state instance helpers, use generic helper instead.\n", $stderr.string
1228
+ ensure
1229
+ $stderr = @original_stderr
1218
1230
  end
1219
1231
 
1220
1232
  def test_should_pass_context_as_arguments
1221
1233
  helper_args = nil
1222
- @machine.define_helper(:instance, :state) {|*args| helper_args = args}
1223
- @object.state
1234
+ @machine.define_helper(:instance, :park) {|*args| helper_args = args}
1235
+ @object.park
1224
1236
  assert_equal 2, helper_args.length
1225
1237
  assert_equal [@machine, @object], helper_args
1226
1238
  end
1227
1239
 
1228
1240
  def test_should_pass_method_arguments_through
1229
1241
  helper_args = nil
1230
- @machine.define_helper(:instance, :state) {|*args| helper_args = args}
1231
- @object.state(1, 2, 3)
1242
+ @machine.define_helper(:instance, :park) {|*args| helper_args = args}
1243
+ @object.park(1, 2, 3)
1232
1244
  assert_equal 5, helper_args.length
1233
1245
  assert_equal [@machine, @object, 1, 2, 3], helper_args
1234
1246
  end
1235
1247
 
1236
1248
  def test_should_allow_string_evaluation
1237
1249
  @machine.define_helper :instance, <<-end_eval, __FILE__, __LINE__ + 1
1238
- def state
1239
- 'parked'
1250
+ def park
1251
+ false
1240
1252
  end
1241
1253
  end_eval
1242
- assert_equal 'parked', @object.state
1254
+ assert_equal false, @object.park
1243
1255
  end
1244
1256
  end
1245
1257
 
@@ -1387,6 +1399,18 @@ class MachineWithClassHelpersTest < Test::Unit::TestCase
1387
1399
  assert_equal [], @klass.states
1388
1400
  end
1389
1401
 
1402
+ def test_should_warn_if_defined_multiple_times
1403
+ require 'stringio'
1404
+ @original_stderr, $stderr = $stderr, StringIO.new
1405
+
1406
+ @machine.define_helper(:class, :states) {}
1407
+ @machine.define_helper(:class, :states) {}
1408
+
1409
+ assert_equal "Class method \"states\" is already defined in #{@klass} :state class helpers, use generic helper instead.\n", $stderr.string
1410
+ ensure
1411
+ $stderr = @original_stderr
1412
+ end
1413
+
1390
1414
  def test_should_pass_context_as_arguments
1391
1415
  helper_args = nil
1392
1416
  @machine.define_helper(:class, :states) {|*args| helper_args = args}
@@ -1808,6 +1832,40 @@ class MachineWithConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase
1808
1832
  end
1809
1833
  end
1810
1834
 
1835
+ class MachineWithSuperclassConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase
1836
+ def setup
1837
+ require 'stringio'
1838
+ @original_stderr, $stderr = $stderr, StringIO.new
1839
+
1840
+ @superclass = Class.new
1841
+ @klass = Class.new(@superclass)
1842
+
1843
+ @machine = StateMachine::Machine.new(@klass)
1844
+ @machine.state :parked, :idling
1845
+ @machine.event :ignite
1846
+
1847
+ @superclass.class_eval do
1848
+ def state?
1849
+ true
1850
+ end
1851
+ end
1852
+
1853
+ @object = @klass.new
1854
+ end
1855
+
1856
+ def test_should_call_superclass_attribute_predicate_without_arguments
1857
+ assert @object.state?
1858
+ end
1859
+
1860
+ def test_should_define_attribute_predicate_with_arguments
1861
+ assert !@object.state?(:parked)
1862
+ end
1863
+
1864
+ def teardown
1865
+ $stderr = @original_stderr
1866
+ end
1867
+ end
1868
+
1811
1869
  class MachineWithoutInitializeTest < Test::Unit::TestCase
1812
1870
  def setup
1813
1871
  @klass = Class.new
@@ -2288,6 +2346,86 @@ class MachineWithMultipleEventsTest < Test::Unit::TestCase
2288
2346
  end
2289
2347
  end
2290
2348
 
2349
+ class MachineWithTransitionsTest < Test::Unit::TestCase
2350
+ def setup
2351
+ @klass = Class.new
2352
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
2353
+ end
2354
+
2355
+ def test_should_require_on_event
2356
+ exception = assert_raise(ArgumentError) { @machine.transition(:parked => :idling) }
2357
+ assert_equal 'Must specify :on event', exception.message
2358
+ end
2359
+
2360
+ def test_should_not_allow_except_to_option
2361
+ exception = assert_raise(ArgumentError) {@machine.transition(:except_to => :parked, :on => :ignite)}
2362
+ assert_equal 'Invalid key(s): except_to', exception.message
2363
+ end
2364
+
2365
+ def test_should_not_allow_except_on_option
2366
+ exception = assert_raise(ArgumentError) {@machine.transition(:except_on => :ignite, :on => :ignite)}
2367
+ assert_equal 'Invalid key(s): except_on', exception.message
2368
+ end
2369
+
2370
+ def test_should_allow_transitioning_without_a_to_state
2371
+ assert_nothing_raised {@machine.transition(:from => :parked, :on => :ignite)}
2372
+ end
2373
+
2374
+ def test_should_allow_transitioning_without_a_from_state
2375
+ assert_nothing_raised {@machine.transition(:to => :idling, :on => :ignite)}
2376
+ end
2377
+
2378
+ def test_should_allow_except_from_option
2379
+ assert_nothing_raised {@machine.transition(:except_from => :idling, :on => :ignite)}
2380
+ end
2381
+
2382
+ def test_should_allow_implicit_options
2383
+ branch = @machine.transition(:first_gear => :second_gear, :on => :shift_up)
2384
+ assert_instance_of StateMachine::Branch, branch
2385
+
2386
+ state_requirements = branch.state_requirements
2387
+ assert_equal 1, state_requirements.length
2388
+
2389
+ assert_instance_of StateMachine::WhitelistMatcher, state_requirements[0][:from]
2390
+ assert_equal [:first_gear], state_requirements[0][:from].values
2391
+ assert_instance_of StateMachine::WhitelistMatcher, state_requirements[0][:to]
2392
+ assert_equal [:second_gear], state_requirements[0][:to].values
2393
+ assert_instance_of StateMachine::WhitelistMatcher, branch.event_requirement
2394
+ assert_equal [:shift_up], branch.event_requirement.values
2395
+ end
2396
+
2397
+ def test_should_allow_multiple_implicit_options
2398
+ branch = @machine.transition(:first_gear => :second_gear, :second_gear => :third_gear, :on => :shift_up)
2399
+
2400
+ state_requirements = branch.state_requirements
2401
+ assert_equal 2, state_requirements.length
2402
+ end
2403
+
2404
+ def test_should_allow_verbose_options
2405
+ branch = @machine.transition(:from => :parked, :to => :idling, :on => :ignite)
2406
+ assert_instance_of StateMachine::Branch, branch
2407
+ end
2408
+
2409
+ def test_should_include_all_transition_states_in_machine_states
2410
+ @machine.transition(:parked => :idling, :on => :ignite)
2411
+
2412
+ assert_equal [:parked, :idling], @machine.states.map {|state| state.name}
2413
+ end
2414
+
2415
+ def test_should_include_all_transition_events_in_machine_events
2416
+ @machine.transition(:parked => :idling, :on => :ignite)
2417
+
2418
+ assert_equal [:ignite], @machine.events.map {|event| event.name}
2419
+ end
2420
+
2421
+ def test_should_allow_multiple_events
2422
+ branches = @machine.transition(:parked => :ignite, :on => [:ignite, :shift_up])
2423
+
2424
+ assert_equal 2, branches.length
2425
+ assert_equal [:ignite, :shift_up], @machine.events.map {|event| event.name}
2426
+ end
2427
+ end
2428
+
2291
2429
  class MachineWithTransitionCallbacksTest < Test::Unit::TestCase
2292
2430
  def setup
2293
2431
  @klass = Class.new do
@@ -2588,6 +2726,51 @@ class MachineWithExistingMachinesWithSameAttributesOnOwnerClassTest < Test::Unit
2588
2726
  @object.park
2589
2727
  assert_equal 'parked', @object.state
2590
2728
  end
2729
+
2730
+ def test_should_copy_new_states_to_sibling_machines
2731
+ @first_gear = @machine.state :first_gear
2732
+ assert_equal @first_gear, @second_machine.state(:first_gear)
2733
+
2734
+ @second_gear = @second_machine.state :second_gear
2735
+ assert_equal @second_gear, @machine.state(:second_gear)
2736
+ end
2737
+
2738
+ def test_should_copy_all_existing_states_to_new_machines
2739
+ third_machine = StateMachine::Machine.new(@klass, :protected_state, :attribute => :state)
2740
+
2741
+ assert_equal @machine.state(:parked), third_machine.state(:parked)
2742
+ assert_equal @machine.state(:idling), third_machine.state(:idling)
2743
+ end
2744
+ end
2745
+
2746
+ class MachineWithExistingMachinesWithSameAttributesOnOwnerSubclassTest < Test::Unit::TestCase
2747
+ def setup
2748
+ @klass = Class.new
2749
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
2750
+ @second_machine = StateMachine::Machine.new(@klass, :public_state, :initial => :idling, :attribute => :state)
2751
+
2752
+ @subclass = Class.new(@klass)
2753
+ @object = @subclass.new
2754
+ end
2755
+
2756
+ def test_should_not_copy_sibling_machines_to_subclass_after_initialization
2757
+ @subclass.state_machine(:state) {}
2758
+ assert_equal @klass.state_machine(:public_state), @subclass.state_machine(:public_state)
2759
+ end
2760
+
2761
+ def test_should_copy_sibling_machines_to_subclass_after_new_state
2762
+ subclass_machine = @subclass.state_machine(:state) {}
2763
+ subclass_machine.state :first_gear
2764
+ assert_not_equal @klass.state_machine(:public_state), @subclass.state_machine(:public_state)
2765
+ end
2766
+
2767
+ def test_should_copy_new_states_to_sibling_machines
2768
+ subclass_machine = @subclass.state_machine(:state) {}
2769
+ @first_gear = subclass_machine.state :first_gear
2770
+
2771
+ second_subclass_machine = @subclass.state_machine(:public_state)
2772
+ assert_equal @first_gear, second_subclass_machine.state(:first_gear)
2773
+ end
2591
2774
  end
2592
2775
 
2593
2776
  class MachineWithNamespaceTest < Test::Unit::TestCase
@@ -2869,8 +3052,6 @@ end
2869
3052
 
2870
3053
  begin
2871
3054
  # Load library
2872
- require 'rubygems'
2873
- gem 'ruby-graphviz', '>=0.9.0'
2874
3055
  require 'graphviz'
2875
3056
 
2876
3057
  class MachineDrawingTest < Test::Unit::TestCase
@@ -3040,4 +3221,4 @@ begin
3040
3221
  end
3041
3222
  rescue LoadError
3042
3223
  $stderr.puts 'Skipping GraphViz StateMachine::Machine tests. `gem install ruby-graphviz` >= v0.9.0 and try again.'
3043
- end
3224
+ end unless ENV['TRAVIS']