state_machine 0.9.4 → 0.10.0

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 (68) hide show
  1. data/CHANGELOG.rdoc +20 -0
  2. data/LICENSE +1 -1
  3. data/README.rdoc +74 -4
  4. data/Rakefile +3 -3
  5. data/lib/state_machine.rb +51 -24
  6. data/lib/state_machine/{guard.rb → branch.rb} +34 -40
  7. data/lib/state_machine/callback.rb +13 -18
  8. data/lib/state_machine/error.rb +13 -0
  9. data/lib/state_machine/eval_helpers.rb +3 -0
  10. data/lib/state_machine/event.rb +67 -30
  11. data/lib/state_machine/event_collection.rb +20 -3
  12. data/lib/state_machine/extensions.rb +3 -3
  13. data/lib/state_machine/integrations.rb +7 -0
  14. data/lib/state_machine/integrations/active_model.rb +149 -59
  15. data/lib/state_machine/integrations/active_model/versions.rb +30 -0
  16. data/lib/state_machine/integrations/active_record.rb +74 -148
  17. data/lib/state_machine/integrations/active_record/locale.rb +0 -7
  18. data/lib/state_machine/integrations/active_record/versions.rb +149 -0
  19. data/lib/state_machine/integrations/base.rb +64 -0
  20. data/lib/state_machine/integrations/data_mapper.rb +50 -39
  21. data/lib/state_machine/integrations/data_mapper/observer.rb +47 -12
  22. data/lib/state_machine/integrations/data_mapper/versions.rb +62 -0
  23. data/lib/state_machine/integrations/mongo_mapper.rb +37 -64
  24. data/lib/state_machine/integrations/mongo_mapper/locale.rb +4 -0
  25. data/lib/state_machine/integrations/mongo_mapper/versions.rb +102 -0
  26. data/lib/state_machine/integrations/mongoid.rb +297 -0
  27. data/lib/state_machine/integrations/mongoid/locale.rb +4 -0
  28. data/lib/state_machine/integrations/mongoid/versions.rb +18 -0
  29. data/lib/state_machine/integrations/sequel.rb +99 -55
  30. data/lib/state_machine/integrations/sequel/versions.rb +40 -0
  31. data/lib/state_machine/machine.rb +273 -136
  32. data/lib/state_machine/machine_collection.rb +21 -13
  33. data/lib/state_machine/node_collection.rb +6 -1
  34. data/lib/state_machine/path.rb +120 -0
  35. data/lib/state_machine/path_collection.rb +90 -0
  36. data/lib/state_machine/state.rb +28 -9
  37. data/lib/state_machine/state_collection.rb +1 -1
  38. data/lib/state_machine/transition.rb +65 -6
  39. data/lib/state_machine/transition_collection.rb +1 -1
  40. data/test/files/en.yml +8 -0
  41. data/test/functional/state_machine_test.rb +15 -2
  42. data/test/unit/branch_test.rb +890 -0
  43. data/test/unit/callback_test.rb +9 -36
  44. data/test/unit/error_test.rb +43 -0
  45. data/test/unit/event_collection_test.rb +67 -33
  46. data/test/unit/event_test.rb +165 -38
  47. data/test/unit/integrations/active_model_test.rb +103 -3
  48. data/test/unit/integrations/active_record_test.rb +90 -43
  49. data/test/unit/integrations/base_test.rb +87 -0
  50. data/test/unit/integrations/data_mapper_test.rb +105 -44
  51. data/test/unit/integrations/mongo_mapper_test.rb +261 -64
  52. data/test/unit/integrations/mongoid_test.rb +1529 -0
  53. data/test/unit/integrations/sequel_test.rb +33 -49
  54. data/test/unit/integrations_test.rb +4 -0
  55. data/test/unit/invalid_event_test.rb +15 -2
  56. data/test/unit/invalid_parallel_transition_test.rb +18 -0
  57. data/test/unit/invalid_transition_test.rb +72 -2
  58. data/test/unit/machine_collection_test.rb +55 -61
  59. data/test/unit/machine_test.rb +388 -26
  60. data/test/unit/node_collection_test.rb +14 -4
  61. data/test/unit/path_collection_test.rb +266 -0
  62. data/test/unit/path_test.rb +485 -0
  63. data/test/unit/state_collection_test.rb +30 -0
  64. data/test/unit/state_test.rb +82 -35
  65. data/test/unit/transition_collection_test.rb +48 -44
  66. data/test/unit/transition_test.rb +198 -41
  67. metadata +111 -74
  68. data/test/unit/guard_test.rb +0 -909
@@ -26,12 +26,16 @@ module DataMapperTest
26
26
  def new_resource(create_table = :foo, &block)
27
27
  table_name = create_table || :foo
28
28
 
29
- resource = Class.new
29
+ resource = Class.new do
30
+ (class << self; self; end).class_eval do
31
+ define_method(:name) { "DataMapperTest::#{table_name.to_s.capitalize}" }
32
+ end
33
+ end
34
+
30
35
  resource.class_eval do
31
36
  include DataMapper::Resource
32
37
 
33
38
  storage_names[:default] = table_name.to_s
34
- def self.name; "DataMapperTest::#{storage_names[:default].capitalize}"; end
35
39
 
36
40
  property :id, resource.class_eval('Serial')
37
41
  property :state, String
@@ -516,7 +520,7 @@ module DataMapperTest
516
520
 
517
521
  def test_should_have_changes_when_loaded_from_database
518
522
  record = @resource.get(@record.id)
519
- assert record.dirty_attributes.blank?
523
+ assert record.dirty_attributes.empty?
520
524
  end
521
525
  end
522
526
 
@@ -617,6 +621,50 @@ module DataMapperTest
617
621
  end
618
622
  end
619
623
 
624
+ class MachineWithDirtyAttributeAndStateEventsTest < BaseTestCase
625
+ def setup
626
+ @resource = new_resource
627
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
628
+ @machine.event :ignite
629
+
630
+ @record = @resource.create
631
+ @record.state_event = 'ignite'
632
+ end
633
+
634
+ def test_should_include_state_in_changed_attributes
635
+ assert_equal e = {@resource.properties[:state] => 'parked'}, @record.dirty_attributes
636
+ end
637
+
638
+ def test_should_track_attribute_change
639
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.3')
640
+ assert_equal e = {@resource.properties[:state] => 'parked'}, @record.original_attributes
641
+ elsif Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
642
+ assert_equal e = {@resource.properties[:state] => 'parked-ignored'}, @record.original_attributes
643
+ else
644
+ assert_equal e = {:state => 'parked-ignored'}, @record.original_values
645
+ end
646
+ end
647
+
648
+ def test_should_not_reset_changes_on_multiple_changes
649
+ @record.state_event = 'ignite'
650
+
651
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.3')
652
+ assert_equal e = {@resource.properties[:state] => 'parked'}, @record.original_attributes
653
+ elsif Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
654
+ assert_equal e = {@resource.properties[:state] => 'parked-ignored'}, @record.original_attributes
655
+ else
656
+ assert_equal e = {:state => 'parked-ignored'}, @record.original_values
657
+ end
658
+ end
659
+
660
+ def test_should_not_include_state_in_changed_attributes_if_nil
661
+ @record = @resource.create
662
+ @record.state_event = nil
663
+
664
+ assert_equal e = {}, @record.dirty_attributes
665
+ end
666
+ end
667
+
620
668
  class MachineWithoutTransactionsTest < BaseTestCase
621
669
  def setup
622
670
  @resource = new_resource
@@ -837,13 +885,8 @@ module DataMapperTest
837
885
  callbacks = []
838
886
  @machine.before_transition {callbacks << :before}
839
887
  @machine.after_transition {callbacks << :after}
840
- @machine.after_transition(:include_failures => true) {callbacks << :after_failure}
888
+ @machine.after_failure {callbacks << :after_failure}
841
889
  @machine.around_transition {|block| callbacks << :around_before; block.call; callbacks << :around_after}
842
- @machine.around_transition(:include_failures => true) do |block|
843
- callbacks << :around_before_failure
844
- block.call
845
- callbacks << :around_after_failure
846
- end
847
890
 
848
891
  @record = @resource.new(:state => 'parked')
849
892
  @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
@@ -865,7 +908,7 @@ module DataMapperTest
865
908
  end
866
909
 
867
910
  def test_should_run_before_callbacks_and_after_callbacks_with_failures
868
- assert_equal [:before, :around_before, :around_before_failure, :around_after_failure, :after_failure], @callbacks
911
+ assert_equal [:before, :around_before, :after_failure], @callbacks
869
912
  end
870
913
  end
871
914
 
@@ -1083,7 +1126,7 @@ module DataMapperTest
1083
1126
  assert !ran_callback
1084
1127
  end
1085
1128
 
1086
- def test_should_run_after_callbacks_with_failures_enabled_if_validation_fails
1129
+ def test_should_run_failure_callbacks_if_validation_fails
1087
1130
  @resource.class_eval do
1088
1131
  attr_accessor :seatbelt
1089
1132
  if respond_to?(:validates_presence_of)
@@ -1094,7 +1137,7 @@ module DataMapperTest
1094
1137
  end
1095
1138
 
1096
1139
  ran_callback = false
1097
- @machine.after_transition(:include_failures => true) { ran_callback = true }
1140
+ @machine.after_failure { ran_callback = true }
1098
1141
 
1099
1142
  @record.valid?
1100
1143
  assert ran_callback
@@ -1125,23 +1168,6 @@ module DataMapperTest
1125
1168
  assert !ran_callback[0]
1126
1169
  end
1127
1170
 
1128
- def test_should_run_around_callbacks_after_yield_with_failures_enabled_if_validation_fails
1129
- @resource.class_eval do
1130
- attr_accessor :seatbelt
1131
- if respond_to?(:validates_presence_of)
1132
- validates_presence_of :seatbelt
1133
- else
1134
- validates_present :seatbelt
1135
- end
1136
- end
1137
-
1138
- ran_callback = [false]
1139
- @machine.around_transition(:include_failures => true) {|block| block.call; ran_callback[0] = true }
1140
-
1141
- @record.valid?
1142
- assert ran_callback[0]
1143
- end
1144
-
1145
1171
  def test_should_not_run_before_transitions_within_transaction
1146
1172
  @machine.before_transition { self.class.create; throw :halt }
1147
1173
 
@@ -1232,11 +1258,11 @@ module DataMapperTest
1232
1258
  assert !ran_callback
1233
1259
  end
1234
1260
 
1235
- def test_should_run_after_callbacks_with_failures_enabled_if_fails
1261
+ def test_should_run_failure_callbacks_if_fails
1236
1262
  @resource.before(:create) { throw :halt }
1237
1263
 
1238
1264
  ran_callback = false
1239
- @machine.after_transition(:include_failures => true) { ran_callback = true }
1265
+ @machine.after_failure { ran_callback = true }
1240
1266
 
1241
1267
  @record.save
1242
1268
  assert ran_callback
@@ -1260,16 +1286,6 @@ module DataMapperTest
1260
1286
  assert ran_callback[0]
1261
1287
  end
1262
1288
 
1263
- def test_should_run_around_callbacks_after_yield_with_failures_enabled_if_fails
1264
- @resource.before(:create) { throw :halt }
1265
-
1266
- ran_callback = [false]
1267
- @machine.around_transition(:include_failures => true) {|block| block.call; ran_callback[0] = true }
1268
-
1269
- @record.save
1270
- assert ran_callback[0]
1271
- end
1272
-
1273
1289
  def test_should_not_run_before_transitions_within_transaction
1274
1290
  @machine.before_transition { self.class.create; throw :halt }
1275
1291
 
@@ -1545,7 +1561,7 @@ module DataMapperTest
1545
1561
  assert !called
1546
1562
  end
1547
1563
 
1548
- def test_should_pass_transition_to_after_callbacks
1564
+ def test_should_pass_transition_to_around_callbacks
1549
1565
  callback_args = nil
1550
1566
 
1551
1567
  observer = new_observer(@resource) do
@@ -1560,6 +1576,51 @@ module DataMapperTest
1560
1576
  assert_equal [@transition], callback_args
1561
1577
  end
1562
1578
 
1579
+ def test_should_call_failure_callback_if_requirements_match
1580
+ @resource.before(:create) { throw :halt }
1581
+
1582
+ called = false
1583
+
1584
+ observer = new_observer(@resource) do
1585
+ after_transition_failure :on => :ignite do
1586
+ called = true
1587
+ end
1588
+ end
1589
+
1590
+ @transition.perform
1591
+ assert called
1592
+ end
1593
+
1594
+ def test_should_not_call_failure_callback_if_requirements_do_not_match
1595
+ @resource.before(:create) { throw :halt }
1596
+
1597
+ called = false
1598
+
1599
+ observer = new_observer(@resource) do
1600
+ after_transition_failure :on => :park do
1601
+ called = true
1602
+ end
1603
+ end
1604
+
1605
+ @transition.perform
1606
+ assert !called
1607
+ end
1608
+
1609
+ def test_should_pass_transition_to_failure_callbacks
1610
+ @resource.before(:create) { throw :halt }
1611
+
1612
+ callback_args = nil
1613
+
1614
+ observer = new_observer(@resource) do
1615
+ after_transition_failure do |*args|
1616
+ callback_args = args
1617
+ end
1618
+ end
1619
+
1620
+ @transition.perform
1621
+ assert_equal [@transition], callback_args
1622
+ end
1623
+
1563
1624
  def test_should_raise_exception_if_targeting_invalid_machine
1564
1625
  assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) do
1565
1626
  new_observer(@resource) do
@@ -1570,7 +1631,7 @@ module DataMapperTest
1570
1631
  end
1571
1632
 
1572
1633
  def test_should_allow_targeting_specific_machine
1573
- @second_machine = StateMachine::Machine.new(@resource, :status)
1634
+ @second_machine = StateMachine::Machine.new(@resource, :status, :namespace => 'alarm')
1574
1635
  @resource.auto_migrate!
1575
1636
 
1576
1637
  called_state = false
@@ -1593,7 +1654,7 @@ module DataMapperTest
1593
1654
  end
1594
1655
 
1595
1656
  def test_should_allow_targeting_multiple_specific_machines
1596
- @second_machine = StateMachine::Machine.new(@resource, :status)
1657
+ @second_machine = StateMachine::Machine.new(@resource, :status, :namespace => 'alarm')
1597
1658
  @second_machine.state :parked, :idling
1598
1659
  @second_machine.event :ignite
1599
1660
  @resource.auto_migrate!
@@ -3,16 +3,21 @@ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
3
3
  # Load library
4
4
  require 'rubygems'
5
5
 
6
- if ENV['VERSION'] && Gem::Version.new(ENV['VERSION']) <= Gem::Version.new('0.7.0') || !Gem.available?('>=0.7.0')
7
- gem 'activesupport', '~>2.3'
8
- require 'active_support'
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
9
14
  end
10
15
 
11
16
  gem 'mongo_mapper', ENV['VERSION'] ? "=#{ENV['VERSION']}" : '>=0.5.5'
12
17
  require 'mongo_mapper'
13
18
 
14
19
  # Establish database connection
15
- MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017, {:logger => Logger.new("#{File.dirname(__FILE__)}/../../mongo_mapper.log")})
20
+ MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017, {:logger => Logger.new("#{File.dirname(__FILE__)}/../../mongo_mapper.log"), :slave_ok => true})
16
21
  MongoMapper.database = 'test'
17
22
 
18
23
  module MongoMapperTest
@@ -25,12 +30,16 @@ module MongoMapperTest
25
30
  def new_model(table_name = :foo, &block)
26
31
 
27
32
  model = Class.new do
33
+ (class << self; self; end).class_eval do
34
+ define_method(:name) { "MongoMapperTest::#{table_name.to_s.capitalize}" }
35
+ define_method(:to_s) { name }
36
+ end
37
+ end
38
+
39
+ model.class_eval do
28
40
  include MongoMapper::Document
29
41
  set_collection_name(table_name)
30
42
 
31
- def self.name; "MongoMapperTest::#{collection_name}"; end
32
- def self.to_s; "MongoMapperTest::#{collection_name}"; end
33
-
34
43
  key :state, String
35
44
  end
36
45
  model.class_eval(&block) if block_given?
@@ -335,7 +344,7 @@ module MongoMapperTest
335
344
  end
336
345
 
337
346
  def test_should_define_a_new_key_for_the_attribute
338
- assert_not_nil @model.keys[:status]
347
+ assert_not_nil @model.keys['status']
339
348
  end
340
349
 
341
350
  def test_should_define_a_reader_attribute_for_the_attribute
@@ -575,6 +584,37 @@ module MongoMapperTest
575
584
  end
576
585
  end
577
586
 
587
+ class MachineWithDirtyAttributeAndStateEventsTest < BaseTestCase
588
+ def setup
589
+ @model = new_model
590
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
591
+ @machine.event :ignite
592
+
593
+ @record = @model.create
594
+ @record.state_event = 'ignite'
595
+ end
596
+
597
+ def test_should_include_state_in_changed_attributes
598
+ assert_equal %w(state), @record.changed
599
+ end
600
+
601
+ def test_should_track_attribute_change
602
+ assert_equal %w(parked parked), @record.changes['state']
603
+ end
604
+
605
+ def test_should_not_reset_changes_on_multiple_changes
606
+ @record.state_event = 'ignite'
607
+ assert_equal %w(parked parked), @record.changes['state']
608
+ end
609
+
610
+ def test_should_not_include_state_in_changed_attributes_if_nil
611
+ @record = @model.create
612
+ @record.state_event = nil
613
+
614
+ assert_equal [], @record.changed
615
+ end
616
+ end
617
+
578
618
  class MachineWithCallbacksTest < BaseTestCase
579
619
  def setup
580
620
  @model = new_model
@@ -710,27 +750,45 @@ module MongoMapperTest
710
750
  @result = @transition.perform
711
751
  end
712
752
 
713
- def test_should_be_successful
714
- assert @result
715
- end
716
-
717
- def test_should_change_current_state
718
- assert_equal 'idling', @record.state
719
- end
720
-
721
- def test_should_run_action
722
- assert !@record.new_record?
723
- end
724
-
725
- def test_should_run_further_callbacks
726
- assert_equal [:before_1, :before_2, :around_before, :around_after, :after], @callbacks
753
+ if defined?(MongoMapper::Version) && MongoMapper::Version >= '0.9.0'
754
+ def test_should_not_be_successful
755
+ assert !@result
756
+ end
757
+
758
+ def test_should_not_change_current_state
759
+ assert_equal 'parked', @record.state
760
+ end
761
+
762
+ def test_should_not_run_action
763
+ assert @record.new_record?
764
+ end
765
+
766
+ def test_should_not_run_further_callbacks
767
+ assert_equal [:before_1], @callbacks
768
+ end
769
+ else
770
+ def test_should_be_successful
771
+ assert @result
772
+ end
773
+
774
+ def test_should_change_current_state
775
+ assert_equal 'idling', @record.state
776
+ end
777
+
778
+ def test_should_run_action
779
+ assert !@record.new_record?
780
+ end
781
+
782
+ def test_should_run_further_callbacks
783
+ assert_equal [:before_1, :before_2, :around_before, :around_after, :after], @callbacks
784
+ end
727
785
  end
728
786
  end
729
787
 
730
788
  class MachineWithFailedActionTest < BaseTestCase
731
789
  def setup
732
790
  @model = new_model do
733
- validates_inclusion_of :state, :within => %w(first_gear)
791
+ validates_numericality_of :state
734
792
  end
735
793
 
736
794
  @machine = StateMachine::Machine.new(@model)
@@ -740,13 +798,8 @@ module MongoMapperTest
740
798
  @callbacks = []
741
799
  @machine.before_transition {@callbacks << :before}
742
800
  @machine.after_transition {@callbacks << :after}
743
- @machine.after_transition(:include_failures => true) {@callbacks << :after_failure}
801
+ @machine.after_failure {@callbacks << :after_failure}
744
802
  @machine.around_transition {|block| @callbacks << :around_before; block.call; @callbacks << :around_after}
745
- @machine.around_transition(:include_failures => true) do |block|
746
- @callbacks << :around_before_failure
747
- block.call
748
- @callbacks << :around_after_failure
749
- end
750
803
 
751
804
  @record = @model.new(:state => 'parked')
752
805
  @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
@@ -766,7 +819,7 @@ module MongoMapperTest
766
819
  end
767
820
 
768
821
  def test_should_run_before_callbacks_and_after_callbacks_with_failures
769
- assert_equal [:before, :around_before, :around_before_failure, :around_after_failure, :after_failure], @callbacks
822
+ assert_equal [:before, :around_before, :after_failure], @callbacks
770
823
  end
771
824
  end
772
825
 
@@ -799,8 +852,14 @@ module MongoMapperTest
799
852
  assert !@record.new_record?
800
853
  end
801
854
 
802
- def test_should_still_run_further_after_callbacks
803
- assert_equal [:around_before, :around_after, :after_1, :after_2], @callbacks
855
+ if defined?(MongoMapper::Version) && MongoMapper::Version >= '0.9.0'
856
+ def test_should_not_run_further_after_callbacks
857
+ assert_equal [:around_before, :around_after, :after_1], @callbacks
858
+ end
859
+ else
860
+ def test_should_still_run_further_after_callbacks
861
+ assert_equal [:around_before, :around_after, :after_1, :after_2], @callbacks
862
+ end
804
863
  end
805
864
  end
806
865
 
@@ -814,6 +873,7 @@ module MongoMapperTest
814
873
  end
815
874
 
816
875
  def test_should_invalidate_using_errors
876
+ I18n.backend = I18n::Backend::Simple.new if Object.const_defined?(:ActiveModel)
817
877
  @record.state = 'parked'
818
878
 
819
879
  @machine.invalidate(@record, :state, :invalid_transition, [[:event, 'park']])
@@ -995,27 +1055,14 @@ module MongoMapperTest
995
1055
  assert !ran_callback
996
1056
  end
997
1057
 
998
- def test_should_run_around_callbacks_after_yield_with_failures_enabled_if_validation_fails
1058
+ def test_should_run_failure_callbacks_if_validation_fails
999
1059
  @model.class_eval do
1000
1060
  attr_accessor :seatbelt
1001
1061
  validates_presence_of :seatbelt
1002
1062
  end
1003
1063
 
1004
1064
  ran_callback = false
1005
- @machine.around_transition(:include_failures => true) {|block| block.call; ran_callback = true }
1006
-
1007
- @record.valid?
1008
- assert ran_callback
1009
- end
1010
-
1011
- def test_should_run_after_callbacks_with_failures_enabled_if_validation_fails
1012
- @model.class_eval do
1013
- attr_accessor :seatbelt
1014
- validates_presence_of :seatbelt
1015
- end
1016
-
1017
- ran_callback = false
1018
- @machine.after_transition(:include_failures => true) { ran_callback = true }
1065
+ @machine.after_failure { ran_callback = true }
1019
1066
 
1020
1067
  @record.valid?
1021
1068
  assert ran_callback
@@ -1096,7 +1143,7 @@ module MongoMapperTest
1096
1143
 
1097
1144
  def test_should_not_run_after_callbacks_with_failures_disabled_if_fails
1098
1145
  @model.class_eval do
1099
- validates_inclusion_of :state, :within => %w(first_gear)
1146
+ validates_numericality_of :state
1100
1147
  end
1101
1148
 
1102
1149
  ran_callback = false
@@ -1106,13 +1153,13 @@ module MongoMapperTest
1106
1153
  assert !ran_callback
1107
1154
  end
1108
1155
 
1109
- def test_should_run_after_callbacks_with_failures_enabled_if_fails
1156
+ def test_should_run_failure_callbacks__if_fails
1110
1157
  @model.class_eval do
1111
- validates_inclusion_of :state, :within => %w(first_gear)
1158
+ validates_numericality_of :state
1112
1159
  end
1113
1160
 
1114
1161
  ran_callback = false
1115
- @machine.after_transition(:include_failures => true) { ran_callback = true }
1162
+ @machine.after_failure { ran_callback = true }
1116
1163
 
1117
1164
  begin; @record.save; rescue; end
1118
1165
  assert ran_callback
@@ -1120,7 +1167,7 @@ module MongoMapperTest
1120
1167
 
1121
1168
  def test_should_not_run_around_callbacks_with_failures_disabled_if_fails
1122
1169
  @model.class_eval do
1123
- validates_inclusion_of :state, :within => %w(first_gear)
1170
+ validates_numericality_of :state
1124
1171
  end
1125
1172
 
1126
1173
  ran_callback = false
@@ -1137,18 +1184,6 @@ module MongoMapperTest
1137
1184
  @record.save
1138
1185
  assert ran_callback
1139
1186
  end
1140
-
1141
- def test_should_run_around_callbacks_after_yield_with_failures_enabled_if_fails
1142
- @model.class_eval do
1143
- validates_inclusion_of :state, :within => %w(first_gear)
1144
- end
1145
-
1146
- ran_callback = false
1147
- @machine.around_transition(:include_failures => true) {|block| block.call; ran_callback = true }
1148
-
1149
- begin; @record.save; rescue; end
1150
- assert ran_callback
1151
- end
1152
1187
  end
1153
1188
 
1154
1189
  class MachineWithEventAttributesOnSaveBangTest < BaseTestCase
@@ -1379,4 +1414,166 @@ module MongoMapperTest
1379
1414
  assert @model.respond_to?(:with_statuses)
1380
1415
  end
1381
1416
  end
1417
+
1418
+ if defined?(ActiveModel)
1419
+ class MachineWithInternationalizationTest < BaseTestCase
1420
+ def setup
1421
+ I18n.backend = I18n::Backend::Simple.new
1422
+
1423
+ # Initialize the backend
1424
+ StateMachine::Machine.new(new_model)
1425
+ I18n.backend.translate(:en, 'mongo_mapper.errors.messages.invalid_transition', :event => 'ignite', :value => 'idling')
1426
+
1427
+ @model = new_model
1428
+ end
1429
+
1430
+ def test_should_use_defaults
1431
+ I18n.backend.store_translations(:en, {
1432
+ :mongo_mapper => {:errors => {:messages => {:invalid_transition => 'cannot %{event}'}}}
1433
+ })
1434
+
1435
+ machine = StateMachine::Machine.new(@model)
1436
+ machine.state :parked, :idling
1437
+ machine.event :ignite
1438
+
1439
+ record = @model.new(:state => 'idling')
1440
+
1441
+ machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
1442
+ assert_equal ['State cannot ignite'], record.errors.full_messages
1443
+ end
1444
+
1445
+ def test_should_allow_customized_error_key
1446
+ I18n.backend.store_translations(:en, {
1447
+ :mongo_mapper => {:errors => {:messages => {:bad_transition => 'cannot %{event}'}}}
1448
+ })
1449
+
1450
+ machine = StateMachine::Machine.new(@model, :messages => {:invalid_transition => :bad_transition})
1451
+ machine.state :parked, :idling
1452
+
1453
+ record = @model.new(:state => 'idling')
1454
+
1455
+ machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
1456
+ assert_equal ['State cannot ignite'], record.errors.full_messages
1457
+ end
1458
+
1459
+ def test_should_allow_customized_error_string
1460
+ machine = StateMachine::Machine.new(@model, :messages => {:invalid_transition => 'cannot %{event}'})
1461
+ machine.state :parked, :idling
1462
+
1463
+ record = @model.new(:state => 'idling')
1464
+
1465
+ machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
1466
+ assert_equal ['State cannot ignite'], record.errors.full_messages
1467
+ end
1468
+
1469
+ def test_should_allow_customized_state_key_scoped_to_class_and_machine
1470
+ I18n.backend.store_translations(:en, {
1471
+ :mongo_mapper => {:state_machines => {:'mongo_mapper_test/foo' => {:state => {:states => {:parked => 'shutdown'}}}}}
1472
+ })
1473
+
1474
+ machine = StateMachine::Machine.new(@model)
1475
+ machine.state :parked
1476
+
1477
+ assert_equal 'shutdown', machine.state(:parked).human_name
1478
+ end
1479
+
1480
+ def test_should_allow_customized_state_key_scoped_to_machine
1481
+ I18n.backend.store_translations(:en, {
1482
+ :mongo_mapper => {:state_machines => {:state => {:states => {:parked => 'shutdown'}}}}
1483
+ })
1484
+
1485
+ machine = StateMachine::Machine.new(@model)
1486
+ machine.state :parked
1487
+
1488
+ assert_equal 'shutdown', machine.state(:parked).human_name
1489
+ end
1490
+
1491
+ def test_should_allow_customized_state_key_unscoped
1492
+ I18n.backend.store_translations(:en, {
1493
+ :mongo_mapper => {:state_machines => {:states => {:parked => 'shutdown'}}}
1494
+ })
1495
+
1496
+ machine = StateMachine::Machine.new(@model)
1497
+ machine.state :parked
1498
+
1499
+ assert_equal 'shutdown', machine.state(:parked).human_name
1500
+ end
1501
+
1502
+ def test_should_allow_customized_event_key_scoped_to_class_and_machine
1503
+ I18n.backend.store_translations(:en, {
1504
+ :mongo_mapper => {:state_machines => {:'mongo_mapper_test/foo' => {:state => {:events => {:park => 'stop'}}}}}
1505
+ })
1506
+
1507
+ machine = StateMachine::Machine.new(@model)
1508
+ machine.event :park
1509
+
1510
+ assert_equal 'stop', machine.event(:park).human_name
1511
+ end
1512
+
1513
+ def test_should_allow_customized_event_key_scoped_to_machine
1514
+ I18n.backend.store_translations(:en, {
1515
+ :mongo_mapper => {:state_machines => {:state => {:events => {:park => 'stop'}}}}
1516
+ })
1517
+
1518
+ machine = StateMachine::Machine.new(@model)
1519
+ machine.event :park
1520
+
1521
+ assert_equal 'stop', machine.event(:park).human_name
1522
+ end
1523
+
1524
+ def test_should_allow_customized_event_key_unscoped
1525
+ I18n.backend.store_translations(:en, {
1526
+ :mongo_mapper => {:state_machines => {:events => {:park => 'stop'}}}
1527
+ })
1528
+
1529
+ machine = StateMachine::Machine.new(@model)
1530
+ machine.event :park
1531
+
1532
+ assert_equal 'stop', machine.event(:park).human_name
1533
+ end
1534
+
1535
+ def test_should_only_add_locale_once_in_load_path
1536
+ assert_equal 1, I18n.load_path.select {|path| path =~ %r{mongo_mapper/locale\.rb$}}.length
1537
+
1538
+ # Create another MongoMapper model that will triger the i18n feature
1539
+ new_model
1540
+
1541
+ assert_equal 1, I18n.load_path.select {|path| path =~ %r{mongo_mapper/locale\.rb$}}.length
1542
+ end
1543
+
1544
+ def test_should_add_locale_to_beginning_of_load_path
1545
+ @original_load_path = I18n.load_path
1546
+ I18n.backend = I18n::Backend::Simple.new
1547
+
1548
+ app_locale = File.dirname(__FILE__) + '/../../files/en.yml'
1549
+ default_locale = File.dirname(__FILE__) + '/../../../lib/state_machine/integrations/mongo_mapper/locale.rb'
1550
+ I18n.load_path = [app_locale]
1551
+
1552
+ StateMachine::Machine.new(@model)
1553
+
1554
+ assert_equal [default_locale, app_locale].map {|path| File.expand_path(path)}, I18n.load_path.map {|path| File.expand_path(path)}
1555
+ ensure
1556
+ I18n.load_path = @original_load_path
1557
+ end
1558
+
1559
+ def test_should_prefer_other_locales_first
1560
+ @original_load_path = I18n.load_path
1561
+ I18n.backend = I18n::Backend::Simple.new
1562
+ I18n.load_path = [File.dirname(__FILE__) + '/../../files/en.yml']
1563
+
1564
+ machine = StateMachine::Machine.new(@model)
1565
+ machine.state :parked, :idling
1566
+ machine.event :ignite
1567
+
1568
+ record = @model.new(:state => 'idling')
1569
+
1570
+ machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
1571
+ assert_equal ['State cannot transition'], record.errors.full_messages
1572
+ ensure
1573
+ I18n.load_path = @original_load_path
1574
+ end
1575
+ end
1576
+ else
1577
+ $stderr.puts 'Skipping MongoMapper I18n tests. `gem install mongo_mapper` >= v0.9.0 and try again.'
1578
+ end
1382
1579
  end