aasm 3.0.16 → 3.0.17
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.
- data/.gitignore +1 -0
 - data/.travis.yml +2 -1
 - data/API +34 -0
 - data/CHANGELOG.md +7 -0
 - data/Gemfile +1 -1
 - data/HOWTO +12 -0
 - data/README.md +57 -4
 - data/aasm.gemspec +2 -0
 - data/lib/aasm.rb +5 -4
 - data/lib/aasm/aasm.rb +50 -75
 - data/lib/aasm/base.rb +22 -18
 - data/lib/aasm/event.rb +130 -0
 - data/lib/aasm/instance_base.rb +87 -0
 - data/lib/aasm/localizer.rb +54 -0
 - data/lib/aasm/persistence.rb +22 -14
 - data/lib/aasm/persistence/active_record_persistence.rb +38 -69
 - data/lib/aasm/persistence/base.rb +42 -2
 - data/lib/aasm/persistence/mongoid_persistence.rb +33 -64
 - data/lib/aasm/state.rb +78 -0
 - data/lib/aasm/state_machine.rb +2 -2
 - data/lib/aasm/transition.rb +49 -0
 - data/lib/aasm/version.rb +1 -1
 - data/spec/models/active_record/api.rb +75 -0
 - data/spec/models/auth_machine.rb +1 -1
 - data/spec/models/bar.rb +15 -0
 - data/spec/models/foo.rb +34 -0
 - data/spec/models/mongoid/simple_mongoid.rb +10 -0
 - data/spec/models/mongoid/{mongoid_models.rb → simple_new_dsl_mongoid.rb} +1 -12
 - data/spec/models/persistence.rb +2 -1
 - data/spec/models/this_name_better_not_be_in_use.rb +11 -0
 - data/spec/schema.rb +1 -1
 - data/spec/spec_helper.rb +8 -1
 - data/spec/unit/api_spec.rb +72 -0
 - data/spec/unit/callbacks_spec.rb +2 -2
 - data/spec/unit/event_spec.rb +269 -0
 - data/spec/unit/inspection_spec.rb +43 -5
 - data/spec/unit/{supporting_classes/localizer_spec.rb → localizer_spec.rb} +2 -2
 - data/spec/unit/memory_leak_spec.rb +12 -12
 - data/spec/unit/persistence/active_record_persistence_spec.rb +0 -40
 - data/spec/unit/persistence/mongoid_persistance_spec.rb +3 -2
 - data/spec/unit/simple_example_spec.rb +6 -0
 - data/spec/unit/{supporting_classes/state_spec.rb → state_spec.rb} +2 -2
 - data/spec/unit/{supporting_classes/state_transition_spec.rb → transition_spec.rb} +18 -18
 - metadata +127 -38
 - data/lib/aasm/persistence/read_state.rb +0 -40
 - data/lib/aasm/supporting_classes/event.rb +0 -146
 - data/lib/aasm/supporting_classes/localizer.rb +0 -56
 - data/lib/aasm/supporting_classes/state.rb +0 -80
 - data/lib/aasm/supporting_classes/state_transition.rb +0 -51
 - data/spec/spec_helpers/models_spec_helper.rb +0 -64
 - data/spec/unit/supporting_classes/event_spec.rb +0 -203
 
| 
         @@ -2,6 +2,44 @@ module AASM 
     | 
|
| 
       2 
2 
     | 
    
         
             
              module Persistence
         
     | 
| 
       3 
3 
     | 
    
         
             
                module Base
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
      
 5 
     | 
    
         
            +
                  def self.included(base) #:nodoc:
         
     | 
| 
      
 6 
     | 
    
         
            +
                    base.extend ClassMethods
         
     | 
| 
      
 7 
     | 
    
         
            +
                  end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  # Returns the value of the aasm_column - called from <tt>aasm.current_state</tt>
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # If it's a new record, and the aasm state column is blank it returns the initial state
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # (example provided here for ActiveRecord, but it's true for Mongoid as well):
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #   class Foo < ActiveRecord::Base
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #     include AASM
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #     aasm :column => :status do
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #       state :opened
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #       state :closed
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #     end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 21 
     | 
    
         
            +
                  #
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #   foo = Foo.new
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #   foo.current_state # => :opened
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #   foo.close
         
     | 
| 
      
 25 
     | 
    
         
            +
                  #   foo.current_state # => :closed
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #
         
     | 
| 
      
 27 
     | 
    
         
            +
                  #   foo = Foo.find(1)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  #   foo.current_state # => :opened
         
     | 
| 
      
 29 
     | 
    
         
            +
                  #   foo.aasm_state = nil
         
     | 
| 
      
 30 
     | 
    
         
            +
                  #   foo.current_state # => nil
         
     | 
| 
      
 31 
     | 
    
         
            +
                  #
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # NOTE: intended to be called from an event
         
     | 
| 
      
 33 
     | 
    
         
            +
                  #
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # This allows for nil aasm states - be sure to add validation to your model
         
     | 
| 
      
 35 
     | 
    
         
            +
                  def aasm_read_state
         
     | 
| 
      
 36 
     | 
    
         
            +
                    if new_record?
         
     | 
| 
      
 37 
     | 
    
         
            +
                      send(self.class.aasm_column).blank? ? aasm.determine_state_name(self.class.aasm_initial_state) : send(self.class.aasm_column).to_sym
         
     | 
| 
      
 38 
     | 
    
         
            +
                    else
         
     | 
| 
      
 39 
     | 
    
         
            +
                      send(self.class.aasm_column).nil? ? nil : send(self.class.aasm_column).to_sym
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
       5 
43 
     | 
    
         
             
                  module ClassMethods
         
     | 
| 
       6 
44 
     | 
    
         
             
                    # Maps to the aasm_column in the database.  Defaults to "aasm_state".  You can write
         
     | 
| 
       7 
45 
     | 
    
         
             
                    # (example provided here for ActiveRecord, but it's true for Mongoid as well):
         
     | 
| 
         @@ -39,18 +77,20 @@ module AASM 
     | 
|
| 
       39 
77 
     | 
    
         
             
                      # @aasm_column
         
     | 
| 
       40 
78 
     | 
    
         
             
                      AASM::StateMachine[self].config.column
         
     | 
| 
       41 
79 
     | 
    
         
             
                    end
         
     | 
| 
       42 
     | 
    
         
            -
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end # ClassMethods
         
     | 
| 
       43 
81 
     | 
    
         | 
| 
       44 
82 
     | 
    
         
             
                end # Base
         
     | 
| 
       45 
83 
     | 
    
         
             
              end # Persistence
         
     | 
| 
       46 
84 
     | 
    
         | 
| 
       47 
85 
     | 
    
         
             
              class Base
         
     | 
| 
      
 86 
     | 
    
         
            +
                # make sure to create a (named) scope for each state
         
     | 
| 
       48 
87 
     | 
    
         
             
                def state_with_scope(name, *args)
         
     | 
| 
       49 
88 
     | 
    
         
             
                  state_without_scope(name, *args)
         
     | 
| 
       50 
89 
     | 
    
         
             
                  unless @clazz.respond_to?(name)
         
     | 
| 
       51 
90 
     | 
    
         
             
                    if @clazz.ancestors.map {|klass| klass.to_s}.include?("ActiveRecord::Base")
         
     | 
| 
       52 
     | 
    
         
            -
                       
     | 
| 
      
 91 
     | 
    
         
            +
                      scope_options_hash = {:conditions => { "#{@clazz.table_name}.#{@clazz.aasm_column}" => name.to_s}}
         
     | 
| 
       53 
92 
     | 
    
         
             
                      scope_method = ActiveRecord::VERSION::MAJOR >= 3 ? :scope : :named_scope
         
     | 
| 
      
 93 
     | 
    
         
            +
                      scope_options = ActiveRecord::VERSION::MAJOR >= 4 ? lambda {  where(scope_options_hash[:conditions])} : scope_options_hash
         
     | 
| 
       54 
94 
     | 
    
         
             
                      @clazz.send(scope_method, name, scope_options)
         
     | 
| 
       55 
95 
     | 
    
         
             
                    elsif @clazz.ancestors.map {|klass| klass.to_s}.include?("Mongoid::Document")
         
     | 
| 
       56 
96 
     | 
    
         
             
                      scope_options = lambda { @clazz.send(:where, {@clazz.aasm_column.to_sym => name.to_s}) }
         
     | 
| 
         @@ -6,11 +6,6 @@ module AASM 
     | 
|
| 
       6 
6 
     | 
    
         
             
                  # * extends the model with ClassMethods
         
     | 
| 
       7 
7 
     | 
    
         
             
                  # * includes InstanceMethods
         
     | 
| 
       8 
8 
     | 
    
         
             
                  #
         
     | 
| 
       9 
     | 
    
         
            -
                  # Unless the corresponding methods are already defined, it includes
         
     | 
| 
       10 
     | 
    
         
            -
                  # * ReadState
         
     | 
| 
       11 
     | 
    
         
            -
                  # * WriteState
         
     | 
| 
       12 
     | 
    
         
            -
                  # * WriteStateWithoutPersistence
         
     | 
| 
       13 
     | 
    
         
            -
                  #
         
     | 
| 
       14 
9 
     | 
    
         
             
                  # Adds
         
     | 
| 
       15 
10 
     | 
    
         
             
                  #
         
     | 
| 
       16 
11 
     | 
    
         
             
                  #   before_validation :aasm_ensure_initial_state
         
     | 
| 
         @@ -34,12 +29,9 @@ module AASM 
     | 
|
| 
       34 
29 
     | 
    
         
             
                  #   end
         
     | 
| 
       35 
30 
     | 
    
         
             
                  #
         
     | 
| 
       36 
31 
     | 
    
         
             
                  def self.included(base)
         
     | 
| 
       37 
     | 
    
         
            -
                    base. 
     | 
| 
      
 32 
     | 
    
         
            +
                    base.send(:include, AASM::Persistence::Base)
         
     | 
| 
       38 
33 
     | 
    
         
             
                    base.extend AASM::Persistence::MongoidPersistence::ClassMethods
         
     | 
| 
       39 
34 
     | 
    
         
             
                    base.send(:include, AASM::Persistence::MongoidPersistence::InstanceMethods)
         
     | 
| 
       40 
     | 
    
         
            -
                    base.send(:include, AASM::Persistence::ReadState) unless base.method_defined?(:aasm_read_state)
         
     | 
| 
       41 
     | 
    
         
            -
                    base.send(:include, AASM::Persistence::MongoidPersistence::WriteState) unless base.method_defined?(:aasm_write_state)
         
     | 
| 
       42 
     | 
    
         
            -
                    base.send(:include, AASM::Persistence::MongoidPersistence::WriteStateWithoutPersistence) unless base.method_defined?(:aasm_write_state_without_persistence)
         
     | 
| 
       43 
35 
     | 
    
         | 
| 
       44 
36 
     | 
    
         
             
                    # Mongoid's Validatable gem dependency goes not have a before_validation_on_xxx hook yet.
         
     | 
| 
       45 
37 
     | 
    
         
             
                    # base.before_validation_on_create :aasm_ensure_initial_state
         
     | 
| 
         @@ -70,48 +62,28 @@ module AASM 
     | 
|
| 
       70 
62 
     | 
    
         | 
| 
       71 
63 
     | 
    
         
             
                  module InstanceMethods
         
     | 
| 
       72 
64 
     | 
    
         | 
| 
       73 
     | 
    
         
            -
                    #  
     | 
| 
       74 
     | 
    
         
            -
                    #  
     | 
| 
       75 
     | 
    
         
            -
                    #
         
     | 
| 
       76 
     | 
    
         
            -
                    # Internally just calls <tt>aasm_read_state</tt>
         
     | 
| 
      
 65 
     | 
    
         
            +
                    # Writes <tt>state</tt> to the state column and persists it to the database
         
     | 
| 
      
 66 
     | 
    
         
            +
                    # using update_attribute (which bypasses validation)
         
     | 
| 
       77 
67 
     | 
    
         
             
                    #
         
     | 
| 
       78 
68 
     | 
    
         
             
                    #   foo = Foo.find(1)
         
     | 
| 
       79 
     | 
    
         
            -
                    #   foo.aasm_current_state # => :pending
         
     | 
| 
       80 
     | 
    
         
            -
                    #   foo.aasm_state = "opened"
         
     | 
| 
       81 
69 
     | 
    
         
             
                    #   foo.aasm_current_state # => :opened
         
     | 
| 
       82 
     | 
    
         
            -
                    #   foo.close 
     | 
| 
      
 70 
     | 
    
         
            +
                    #   foo.close!
         
     | 
| 
       83 
71 
     | 
    
         
             
                    #   foo.aasm_current_state # => :closed
         
     | 
| 
       84 
     | 
    
         
            -
                    #    
     | 
| 
       85 
     | 
    
         
            -
                    #   foo.aasm_current_state # => :pending
         
     | 
| 
      
 72 
     | 
    
         
            +
                    #   Foo.find(1).aasm_current_state # => :closed
         
     | 
| 
       86 
73 
     | 
    
         
             
                    #
         
     | 
| 
       87 
     | 
    
         
            -
                     
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
      
 74 
     | 
    
         
            +
                    # NOTE: intended to be called from an event
         
     | 
| 
      
 75 
     | 
    
         
            +
                    def aasm_write_state(state)
         
     | 
| 
      
 76 
     | 
    
         
            +
                      old_value = read_attribute(self.class.aasm_column)
         
     | 
| 
      
 77 
     | 
    
         
            +
                      write_attribute(self.class.aasm_column, state.to_s)
         
     | 
| 
       90 
78 
     | 
    
         | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
      
 79 
     | 
    
         
            +
                      unless self.save(:validate => false)
         
     | 
| 
      
 80 
     | 
    
         
            +
                        write_attribute(self.class.aasm_column, old_value)
         
     | 
| 
      
 81 
     | 
    
         
            +
                        return false
         
     | 
| 
      
 82 
     | 
    
         
            +
                      end
         
     | 
| 
       92 
83 
     | 
    
         | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
                    # that the initial state gets populated before validation on create
         
     | 
| 
       95 
     | 
    
         
            -
                    #
         
     | 
| 
       96 
     | 
    
         
            -
                    #   foo = Foo.new
         
     | 
| 
       97 
     | 
    
         
            -
                    #   foo.aasm_state # => nil
         
     | 
| 
       98 
     | 
    
         
            -
                    #   foo.valid?
         
     | 
| 
       99 
     | 
    
         
            -
                    #   foo.aasm_state # => "open" (where :open is the initial state)
         
     | 
| 
       100 
     | 
    
         
            -
                    #
         
     | 
| 
       101 
     | 
    
         
            -
                    #
         
     | 
| 
       102 
     | 
    
         
            -
                    #   foo = Foo.find(:first)
         
     | 
| 
       103 
     | 
    
         
            -
                    #   foo.aasm_state # => 1
         
     | 
| 
       104 
     | 
    
         
            -
                    #   foo.aasm_state = nil
         
     | 
| 
       105 
     | 
    
         
            -
                    #   foo.valid?
         
     | 
| 
       106 
     | 
    
         
            -
                    #   foo.aasm_state # => nil
         
     | 
| 
       107 
     | 
    
         
            -
                    #
         
     | 
| 
       108 
     | 
    
         
            -
                    def aasm_ensure_initial_state
         
     | 
| 
       109 
     | 
    
         
            -
                      send("#{self.class.aasm_column}=", self.aasm_enter_initial_state.to_s) if send(self.class.aasm_column).blank?
         
     | 
| 
      
 84 
     | 
    
         
            +
                      true
         
     | 
| 
       110 
85 
     | 
    
         
             
                    end
         
     | 
| 
       111 
86 
     | 
    
         | 
| 
       112 
     | 
    
         
            -
                  end
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                  module WriteStateWithoutPersistence
         
     | 
| 
       115 
87 
     | 
    
         
             
                    # Writes <tt>state</tt> to the state column, but does not persist it to the database
         
     | 
| 
       116 
88 
     | 
    
         
             
                    #
         
     | 
| 
       117 
89 
     | 
    
         
             
                    #   foo = Foo.find(1)
         
     | 
| 
         @@ -127,31 +99,28 @@ module AASM 
     | 
|
| 
       127 
99 
     | 
    
         
             
                    def aasm_write_state_without_persistence(state)
         
     | 
| 
       128 
100 
     | 
    
         
             
                      write_attribute(self.class.aasm_column, state.to_s)
         
     | 
| 
       129 
101 
     | 
    
         
             
                    end
         
     | 
| 
       130 
     | 
    
         
            -
                  end
         
     | 
| 
       131 
102 
     | 
    
         | 
| 
       132 
     | 
    
         
            -
                   
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
       134 
     | 
    
         
            -
                    #  
     | 
| 
      
 103 
     | 
    
         
            +
                  private
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                    # Ensures that if the aasm_state column is nil and the record is new
         
     | 
| 
      
 106 
     | 
    
         
            +
                    # that the initial state gets populated before validation on create
         
     | 
| 
       135 
107 
     | 
    
         
             
                    #
         
     | 
| 
       136 
     | 
    
         
            -
                    #   foo = Foo. 
     | 
| 
       137 
     | 
    
         
            -
                    #   foo. 
     | 
| 
       138 
     | 
    
         
            -
                    #   foo. 
     | 
| 
       139 
     | 
    
         
            -
                    #   foo. 
     | 
| 
       140 
     | 
    
         
            -
                    #   Foo.find(1).aasm_current_state # => :closed
         
     | 
| 
      
 108 
     | 
    
         
            +
                    #   foo = Foo.new
         
     | 
| 
      
 109 
     | 
    
         
            +
                    #   foo.aasm_state # => nil
         
     | 
| 
      
 110 
     | 
    
         
            +
                    #   foo.valid?
         
     | 
| 
      
 111 
     | 
    
         
            +
                    #   foo.aasm_state # => "open" (where :open is the initial state)
         
     | 
| 
       141 
112 
     | 
    
         
             
                    #
         
     | 
| 
       142 
     | 
    
         
            -
                    # 
     | 
| 
       143 
     | 
    
         
            -
                     
     | 
| 
       144 
     | 
    
         
            -
             
     | 
| 
       145 
     | 
    
         
            -
             
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
       147 
     | 
    
         
            -
             
     | 
| 
       148 
     | 
    
         
            -
             
     | 
| 
       149 
     | 
    
         
            -
             
     | 
| 
       150 
     | 
    
         
            -
                       
     | 
| 
       151 
     | 
    
         
            -
             
     | 
| 
       152 
     | 
    
         
            -
                      true
         
     | 
| 
      
 113 
     | 
    
         
            +
                    #
         
     | 
| 
      
 114 
     | 
    
         
            +
                    #   foo = Foo.find(:first)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    #   foo.aasm_state # => 1
         
     | 
| 
      
 116 
     | 
    
         
            +
                    #   foo.aasm_state = nil
         
     | 
| 
      
 117 
     | 
    
         
            +
                    #   foo.valid?
         
     | 
| 
      
 118 
     | 
    
         
            +
                    #   foo.aasm_state # => nil
         
     | 
| 
      
 119 
     | 
    
         
            +
                    #
         
     | 
| 
      
 120 
     | 
    
         
            +
                    def aasm_ensure_initial_state
         
     | 
| 
      
 121 
     | 
    
         
            +
                      send("#{self.class.aasm_column}=", aasm.enter_initial_state.to_s) if send(self.class.aasm_column).blank?
         
     | 
| 
       153 
122 
     | 
    
         
             
                    end
         
     | 
| 
       154 
     | 
    
         
            -
                  end
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end # InstanceMethods
         
     | 
| 
       155 
124 
     | 
    
         | 
| 
       156 
125 
     | 
    
         
             
                  module NamedScopeMethods
         
     | 
| 
       157 
126 
     | 
    
         
             
                    def aasm_state_with_named_scope name, options = {}
         
     | 
| 
         @@ -161,4 +130,4 @@ module AASM 
     | 
|
| 
       161 
130 
     | 
    
         
             
                  end
         
     | 
| 
       162 
131 
     | 
    
         
             
                end
         
     | 
| 
       163 
132 
     | 
    
         
             
              end
         
     | 
| 
       164 
     | 
    
         
            -
            end
         
     | 
| 
      
 133 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/aasm/state.rb
    ADDED
    
    | 
         @@ -0,0 +1,78 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module AASM
         
     | 
| 
      
 2 
     | 
    
         
            +
              class State
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_reader :name, :options
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(name, clazz, options={})
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @name = name
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @clazz = clazz
         
     | 
| 
      
 8 
     | 
    
         
            +
                  update(options)
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def ==(state)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  if state.is_a? Symbol
         
     | 
| 
      
 13 
     | 
    
         
            +
                    name == state
         
     | 
| 
      
 14 
     | 
    
         
            +
                  else
         
     | 
| 
      
 15 
     | 
    
         
            +
                    name == state.name
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def <=>(state)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  if state.is_a? Symbol
         
     | 
| 
      
 21 
     | 
    
         
            +
                    name <=> state
         
     | 
| 
      
 22 
     | 
    
         
            +
                  else
         
     | 
| 
      
 23 
     | 
    
         
            +
                    name <=> state.name
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 28 
     | 
    
         
            +
                  name.to_s
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def fire_callbacks(action, record)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  action = @options[action]
         
     | 
| 
      
 33 
     | 
    
         
            +
                  catch :halt_aasm_chain do
         
     | 
| 
      
 34 
     | 
    
         
            +
                    action.is_a?(Array) ?
         
     | 
| 
      
 35 
     | 
    
         
            +
                            action.each {|a| _fire_callbacks(a, record)} :
         
     | 
| 
      
 36 
     | 
    
         
            +
                            _fire_callbacks(action, record)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def display_name
         
     | 
| 
      
 41 
     | 
    
         
            +
                  @display_name ||= begin
         
     | 
| 
      
 42 
     | 
    
         
            +
                    if Module.const_defined?(:I18n)
         
     | 
| 
      
 43 
     | 
    
         
            +
                      localized_name
         
     | 
| 
      
 44 
     | 
    
         
            +
                    else
         
     | 
| 
      
 45 
     | 
    
         
            +
                      name.to_s.gsub(/_/, ' ').capitalize
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def localized_name
         
     | 
| 
      
 51 
     | 
    
         
            +
                  AASM::Localizer.new.human_state_name(@clazz, self)
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                def for_select
         
     | 
| 
      
 55 
     | 
    
         
            +
                  [display_name, name.to_s]
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              private
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                def update(options = {})
         
     | 
| 
      
 61 
     | 
    
         
            +
                  if options.key?(:display) then
         
     | 
| 
      
 62 
     | 
    
         
            +
                    @display_name = options.delete(:display)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                  @options = options
         
     | 
| 
      
 65 
     | 
    
         
            +
                  self
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                def _fire_callbacks(action, record)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  case action
         
     | 
| 
      
 70 
     | 
    
         
            +
                    when Symbol, String
         
     | 
| 
      
 71 
     | 
    
         
            +
                      record.send(action)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    when Proc
         
     | 
| 
      
 73 
     | 
    
         
            +
                      action.call(record)
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
            end # AASM
         
     | 
    
        data/lib/aasm/state_machine.rb
    CHANGED
    
    | 
         @@ -29,8 +29,8 @@ module AASM 
     | 
|
| 
       29 
29 
     | 
    
         
             
                  @events = @events.dup
         
     | 
| 
       30 
30 
     | 
    
         
             
                end
         
     | 
| 
       31 
31 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
                def  
     | 
| 
       33 
     | 
    
         
            -
                  @states << AASM:: 
     | 
| 
      
 32 
     | 
    
         
            +
                def add_state(name, clazz, options)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @states << AASM::State.new(name, clazz, options) unless @states.include?(name)
         
     | 
| 
       34 
34 
     | 
    
         
             
                end
         
     | 
| 
       35 
35 
     | 
    
         | 
| 
       36 
36 
     | 
    
         
             
              end # StateMachine
         
     | 
| 
         @@ -0,0 +1,49 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module AASM
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Transition
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_reader :from, :to, :opts
         
     | 
| 
      
 4 
     | 
    
         
            +
                alias_method :options, :opts
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def initialize(opts)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @from, @to, @guard, @on_transition = opts[:from], opts[:to], opts[:guard], opts[:on_transition]
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @opts = opts
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                # TODO: should be named allowed? or similar
         
     | 
| 
      
 12 
     | 
    
         
            +
                def perform(obj, *args)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  case @guard
         
     | 
| 
      
 14 
     | 
    
         
            +
                    when Symbol, String
         
     | 
| 
      
 15 
     | 
    
         
            +
                      obj.send(@guard, *args)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    when Proc
         
     | 
| 
      
 17 
     | 
    
         
            +
                      @guard.call(obj, *args)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    else
         
     | 
| 
      
 19 
     | 
    
         
            +
                      true
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def execute(obj, *args)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @on_transition.is_a?(Array) ?
         
     | 
| 
      
 25 
     | 
    
         
            +
                          @on_transition.each {|ot| _execute(obj, ot, *args)} :
         
     | 
| 
      
 26 
     | 
    
         
            +
                          _execute(obj, @on_transition, *args)
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def ==(obj)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @from == obj.from && @to == obj.to
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def from?(value)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @from == value
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                private
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                def _execute(obj, on_transition, *args)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  case on_transition
         
     | 
| 
      
 41 
     | 
    
         
            +
                  when Proc
         
     | 
| 
      
 42 
     | 
    
         
            +
                    on_transition.arity == 0 ? on_transition.call : on_transition.call(obj, *args)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  when Symbol, String
         
     | 
| 
      
 44 
     | 
    
         
            +
                    obj.send(:method, on_transition.to_sym).arity == 0 ? obj.send(on_transition) : obj.send(on_transition, *args)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
            end # AASM
         
     | 
    
        data/lib/aasm/version.rb
    CHANGED
    
    
| 
         @@ -0,0 +1,75 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class DefaultState
         
     | 
| 
      
 2 
     | 
    
         
            +
              attr_accessor :transient_store, :persisted_store
         
     | 
| 
      
 3 
     | 
    
         
            +
              include AASM
         
     | 
| 
      
 4 
     | 
    
         
            +
              aasm do
         
     | 
| 
      
 5 
     | 
    
         
            +
                state :alpha, :initial => true
         
     | 
| 
      
 6 
     | 
    
         
            +
                state :beta
         
     | 
| 
      
 7 
     | 
    
         
            +
                state :gamma
         
     | 
| 
      
 8 
     | 
    
         
            +
                event :release do
         
     | 
| 
      
 9 
     | 
    
         
            +
                  transitions :from => [:alpha, :beta, :gamma], :to => :beta
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            class ProvidedState
         
     | 
| 
      
 15 
     | 
    
         
            +
              attr_accessor :transient_store, :persisted_store
         
     | 
| 
      
 16 
     | 
    
         
            +
              include AASM
         
     | 
| 
      
 17 
     | 
    
         
            +
              aasm do
         
     | 
| 
      
 18 
     | 
    
         
            +
                state :alpha, :initial => true
         
     | 
| 
      
 19 
     | 
    
         
            +
                state :beta
         
     | 
| 
      
 20 
     | 
    
         
            +
                state :gamma
         
     | 
| 
      
 21 
     | 
    
         
            +
                event :release do
         
     | 
| 
      
 22 
     | 
    
         
            +
                  transitions :from => [:alpha, :beta, :gamma], :to => :beta
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              def aasm_read_state
         
     | 
| 
      
 27 
     | 
    
         
            +
                :beta
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              def aasm_write_state(new_state)
         
     | 
| 
      
 31 
     | 
    
         
            +
                @persisted_store = new_state
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              def aasm_write_state_without_persistence(new_state)
         
     | 
| 
      
 35 
     | 
    
         
            +
                @transient_store = new_state
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            class PersistedState < ActiveRecord::Base
         
     | 
| 
      
 40 
     | 
    
         
            +
              attr_accessor :transient_store, :persisted_store
         
     | 
| 
      
 41 
     | 
    
         
            +
              include AASM
         
     | 
| 
      
 42 
     | 
    
         
            +
              aasm do
         
     | 
| 
      
 43 
     | 
    
         
            +
                state :alpha, :initial => true
         
     | 
| 
      
 44 
     | 
    
         
            +
                state :beta
         
     | 
| 
      
 45 
     | 
    
         
            +
                state :gamma
         
     | 
| 
      
 46 
     | 
    
         
            +
                event :release do
         
     | 
| 
      
 47 
     | 
    
         
            +
                  transitions :from => [:alpha, :beta, :gamma], :to => :beta
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            class ProvidedAndPersistedState < ActiveRecord::Base
         
     | 
| 
      
 53 
     | 
    
         
            +
              attr_accessor :transient_store, :persisted_store
         
     | 
| 
      
 54 
     | 
    
         
            +
              include AASM
         
     | 
| 
      
 55 
     | 
    
         
            +
              aasm do
         
     | 
| 
      
 56 
     | 
    
         
            +
                state :alpha, :initial => true
         
     | 
| 
      
 57 
     | 
    
         
            +
                state :beta
         
     | 
| 
      
 58 
     | 
    
         
            +
                state :gamma
         
     | 
| 
      
 59 
     | 
    
         
            +
                event :release do
         
     | 
| 
      
 60 
     | 
    
         
            +
                  transitions :from => [:alpha, :beta, :gamma], :to => :beta
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
              def aasm_read_state
         
     | 
| 
      
 65 
     | 
    
         
            +
                :gamma
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
              def aasm_write_state(new_state)
         
     | 
| 
      
 69 
     | 
    
         
            +
                @persisted_store = new_state
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
              def aasm_write_state_without_persistence(new_state)
         
     | 
| 
      
 73 
     | 
    
         
            +
                @transient_store = new_state
         
     | 
| 
      
 74 
     | 
    
         
            +
              end
         
     | 
| 
      
 75 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/models/auth_machine.rb
    CHANGED
    
    | 
         @@ -46,7 +46,7 @@ class AuthMachine 
     | 
|
| 
       46 
46 
     | 
    
         
             
              def initialize
         
     | 
| 
       47 
47 
     | 
    
         
             
                # the AR backend uses a before_validate_on_create :aasm_ensure_initial_state
         
     | 
| 
       48 
48 
     | 
    
         
             
                # lets do something similar here for testing purposes.
         
     | 
| 
       49 
     | 
    
         
            -
                 
     | 
| 
      
 49 
     | 
    
         
            +
                aasm.enter_initial_state
         
     | 
| 
       50 
50 
     | 
    
         
             
              end
         
     | 
| 
       51 
51 
     | 
    
         | 
| 
       52 
52 
     | 
    
         
             
              def make_activation_code
         
     |