state_machines 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
 - data/.ruby-gemset +1 -0
 - data/.ruby-version +1 -0
 - data/.travis.yml +2 -0
 - data/Changelog.md +7 -1
 - data/README.md +11 -9
 - data/lib/state_machines/extensions.rb +1 -1
 - data/lib/state_machines/integrations.rb +1 -5
 - data/lib/state_machines/integrations/base.rb +2 -5
 - data/lib/state_machines/machine.rb +14 -10
 - data/lib/state_machines/path_collection.rb +3 -3
 - data/lib/state_machines/state.rb +21 -16
 - data/lib/state_machines/state_collection.rb +1 -1
 - data/lib/state_machines/transition.rb +1 -1
 - data/lib/state_machines/transition_collection.rb +2 -2
 - data/lib/state_machines/version.rb +1 -1
 - data/state_machines.gemspec +1 -2
 - data/test/files/integrations/vehicle.rb +1 -1
 - data/test/files/models/driver.rb +13 -0
 - data/test/files/models/motorcycle.rb +5 -0
 - data/test/functional/driver_default_nonstandard_test.rb +13 -0
 - data/test/functional/motorcycle_test.rb +6 -0
 - data/test/unit/event/event_with_matching_disabled_transitions_test.rb +1 -1
 - data/test/unit/event/event_with_transition_with_nil_to_state_test.rb +2 -2
 - data/test/unit/integrations/integration_matcher_test.rb +4 -2
 - data/test/unit/machine/machine_with_custom_integration_test.rb +2 -2
 - data/test/unit/transition_collection/transition_collection_empty_with_block_test.rb +1 -1
 - data/test/unit/transition_collection/transition_collection_with_after_callback_halt_test.rb +10 -14
 - data/test/unit/transition_collection/transition_collection_with_before_callback_halt_test.rb +14 -10
 - metadata +9 -426
 - data/test/unit/branch/branch_with_multiple_on_requirements_test.rb +0 -20
 - data/test/unit/machine_collection/machine_collection_fire_attributes_with_validations_test.rb +0 -72
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: '029961fc61666a778298a5b6e5b5b31802b8710f'
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: d9e00ff04cbffbaf522e82b40e76aeb9c9ab3564
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 52f6b57620f17c661585a1bccf2340d46be80366f2a7de609c41033ff46024cc62fc17814279267b26de65974612f149c0a057b47f2396e45f842c249742c9cd
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: b8bbe1923532edffd936139272782d6053b0ab8f1b338eaf61f805fbbc2a3b1c284bd523c35a375fc40fecb6f4948cb4aabcfc72c0fda5ded46959557a20b1cc
         
     | 
    
        data/.ruby-gemset
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            state_machines
         
     | 
    
        data/.ruby-version
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            2.4.1
         
     | 
    
        data/.travis.yml
    CHANGED
    
    
    
        data/Changelog.md
    CHANGED
    
    | 
         @@ -1,4 +1,10 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
      
 1 
     | 
    
         
            +
            ## 0.5.0
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            *   Fix states being evaluated with wrong `owner_class` context
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            *   Fixed state machine false duplication
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            *   Fixed inconsistent use of :use_transactions
         
     | 
| 
       2 
8 
     | 
    
         | 
| 
       3 
9 
     | 
    
         
             
            *   Namespaced integrations are not registered by default anymore
         
     | 
| 
       4 
10 
     | 
    
         | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,9 +1,11 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            [](https://travis-ci.org/state-machines/state_machines)
         
     | 
| 
       2 
     | 
    
         
            -
            [](https://codeclimate.com/github/state-machines/state_machines)
         
     | 
| 
       3 
3 
     | 
    
         
             
            # State Machines
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            State Machines adds support for creating state machines for attributes on any Ruby class.
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
      
 7 
     | 
    
         
            +
            *Please note that multiple integrations are available for [Active Model](https://github.com/state-machines/state_machines-activemodel), [Active Record](https://github.com/state-machines/state_machines-activerecord), [Mongoid](https://github.com/state-machines/state_machines-mongoid) and more in the [State Machines organisation](https://github.com/state-machines).*  If you want to save state in your database, **you need one of these additional integrations**.
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
       7 
9 
     | 
    
         
             
            ## Installation
         
     | 
| 
       8 
10 
     | 
    
         | 
| 
       9 
11 
     | 
    
         
             
            Add this line to your application's Gemfile:
         
     | 
| 
         @@ -40,10 +42,10 @@ class Vehicle 
     | 
|
| 
       40 
42 
     | 
    
         
             
              attr_accessor :seatbelt_on, :time_used, :auto_shop_busy
         
     | 
| 
       41 
43 
     | 
    
         | 
| 
       42 
44 
     | 
    
         
             
              state_machine :state, initial: :parked do
         
     | 
| 
       43 
     | 
    
         
            -
                before_transition parked:  
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
      
 45 
     | 
    
         
            +
                before_transition parked: any - :parked, do: :put_on_seatbelt
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
       45 
47 
     | 
    
         
             
                after_transition on: :crash, do: :tow
         
     | 
| 
       46 
     | 
    
         
            -
                after_transition on: :repair,  
     | 
| 
      
 48 
     | 
    
         
            +
                after_transition on: :repair, do: :fix
         
     | 
| 
       47 
49 
     | 
    
         
             
                after_transition any => :parked do |vehicle, transition|
         
     | 
| 
       48 
50 
     | 
    
         
             
                  vehicle.seatbelt_on = false
         
     | 
| 
       49 
51 
     | 
    
         
             
                end
         
     | 
| 
         @@ -83,7 +85,7 @@ class Vehicle 
     | 
|
| 
       83 
85 
     | 
    
         
             
                event :repair do
         
     | 
| 
       84 
86 
     | 
    
         
             
                  # The first transition that matches the state and passes its conditions
         
     | 
| 
       85 
87 
     | 
    
         
             
                  # will be used
         
     | 
| 
       86 
     | 
    
         
            -
                  transition stalled: parked, unless: :auto_shop_busy
         
     | 
| 
      
 88 
     | 
    
         
            +
                  transition stalled: :parked, unless: :auto_shop_busy
         
     | 
| 
       87 
89 
     | 
    
         
             
                  transition stalled: same
         
     | 
| 
       88 
90 
     | 
    
         
             
                end
         
     | 
| 
       89 
91 
     | 
    
         | 
| 
         @@ -217,7 +219,7 @@ vehicle.fire_events(:shift_down, :enable_alarm) # => true 
     | 
|
| 
       217 
219 
     | 
    
         
             
            vehicle.state_name                              # => :first_gear
         
     | 
| 
       218 
220 
     | 
    
         
             
            vehicle.alarm_state_name                        # => :active
         
     | 
| 
       219 
221 
     | 
    
         | 
| 
       220 
     | 
    
         
            -
            vehicle.fire_events!(:ignite, :enable_alarm)    # => StateMachines: 
     | 
| 
      
 222 
     | 
    
         
            +
            vehicle.fire_events!(:ignite, :enable_alarm)    # => StateMachines:InvalidParallelTransition: Cannot run events in parallel: ignite, enable_alarm
         
     | 
| 
       221 
223 
     | 
    
         | 
| 
       222 
224 
     | 
    
         
             
            # Human-friendly names can be accessed for states/events
         
     | 
| 
       223 
225 
     | 
    
         
             
            Vehicle.human_state_name(:first_gear)               # => "first gear"
         
     | 
| 
         @@ -400,8 +402,8 @@ For example, transitions and callbacks can be defined like so: 
     | 
|
| 
       400 
402 
     | 
    
         
             
            class Vehicle
         
     | 
| 
       401 
403 
     | 
    
         
             
              state_machine initial: :parked do
         
     | 
| 
       402 
404 
     | 
    
         
             
                before_transition from: :parked, except_to: :parked, do: :put_on_seatbelt
         
     | 
| 
       403 
     | 
    
         
            -
                after_transition to: :parked do |transition|
         
     | 
| 
       404 
     | 
    
         
            -
                   
     | 
| 
      
 405 
     | 
    
         
            +
                after_transition to: :parked do |vehicle, transition|
         
     | 
| 
      
 406 
     | 
    
         
            +
                  vehicle.seatbelt = 'off'
         
     | 
| 
       405 
407 
     | 
    
         
             
                end
         
     | 
| 
       406 
408 
     | 
    
         | 
| 
       407 
409 
     | 
    
         
             
                event :ignite do
         
     | 
| 
         @@ -425,7 +427,7 @@ class Vehicle 
     | 
|
| 
       425 
427 
     | 
    
         
             
                ...
         
     | 
| 
       426 
428 
     | 
    
         | 
| 
       427 
429 
     | 
    
         
             
                state :parked do
         
     | 
| 
       428 
     | 
    
         
            -
                  transition to 
     | 
| 
      
 430 
     | 
    
         
            +
                  transition to: :idling, :on => [:ignite, :shift_up], if: :seatbelt_on?
         
     | 
| 
       429 
431 
     | 
    
         | 
| 
       430 
432 
     | 
    
         
             
                  def speed
         
     | 
| 
       431 
433 
     | 
    
         
             
                    0
         
     | 
| 
         @@ -133,7 +133,7 @@ module StateMachines 
     | 
|
| 
       133 
133 
     | 
    
         
             
                #   vehicle = Vehicle.new                         # => #<Vehicle:0xb7c02850 @state="parked", @alarm_state="active">
         
     | 
| 
       134 
134 
     | 
    
         
             
                #   vehicle.fire_events(:ignite, :disable_alarm)  # => true
         
     | 
| 
       135 
135 
     | 
    
         
             
                #
         
     | 
| 
       136 
     | 
    
         
            -
                #   vehicle.fire_events!(:ignite, :disable_alarm) # => StateMachines:: 
     | 
| 
      
 136 
     | 
    
         
            +
                #   vehicle.fire_events!(:ignite, :disable_alarm) # => StateMachines::InvalidParallelTransition: Cannot run events in parallel: ignite, disable_alarm
         
     | 
| 
       137 
137 
     | 
    
         
             
                def fire_events!(*events)
         
     | 
| 
       138 
138 
     | 
    
         
             
                  run_action = [true, false].include?(events.last) ? events.pop : true
         
     | 
| 
       139 
139 
     | 
    
         
             
                  fire_events(*(events + [run_action])) || fail(StateMachines::InvalidParallelTransition.new(self, events))
         
     | 
| 
         @@ -1,5 +1,3 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'set'
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module StateMachines
         
     | 
| 
       4 
2 
     | 
    
         
             
              # Integrations allow state machines to take advantage of features within the
         
     | 
| 
       5 
3 
     | 
    
         
             
              # context of a particular library.  This is currently most useful with
         
     | 
| 
         @@ -54,7 +52,6 @@ module StateMachines 
     | 
|
| 
       54 
52 
     | 
    
         | 
| 
       55 
53 
     | 
    
         
             
                  alias_method :list, :integrations
         
     | 
| 
       56 
54 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
55 
     | 
    
         
             
                  # Attempts to find an integration that matches the given class.  This will
         
     | 
| 
       59 
56 
     | 
    
         
             
                  # look through all of the built-in integrations under the StateMachines::Integrations
         
     | 
| 
       60 
57 
     | 
    
         
             
                  # namespace and find one that successfully matches the class.
         
     | 
| 
         @@ -86,7 +83,7 @@ module StateMachines 
     | 
|
| 
       86 
83 
     | 
    
         
             
                  # == Examples
         
     | 
| 
       87 
84 
     | 
    
         
             
                  #
         
     | 
| 
       88 
85 
     | 
    
         
             
                  #   StateMachines::Integrations.match_ancestors([])                    # => nil
         
     | 
| 
       89 
     | 
    
         
            -
                  #   StateMachines::Integrations.match_ancestors([ 
     | 
| 
      
 86 
     | 
    
         
            +
                  #   StateMachines::Integrations.match_ancestors([ActiveRecord::Base]) # => StateMachines::Integrations::ActiveModel
         
     | 
| 
       90 
87 
     | 
    
         
             
                  def match_ancestors(ancestors)
         
     | 
| 
       91 
88 
     | 
    
         
             
                    integrations.detect { |integration| integration.matches_ancestors?(ancestors) }
         
     | 
| 
       92 
89 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -103,7 +100,6 @@ module StateMachines 
     | 
|
| 
       103 
100 
     | 
    
         
             
                    integrations.detect { |integration| integration.integration_name == name } || raise(IntegrationNotFound.new(name))
         
     | 
| 
       104 
101 
     | 
    
         
             
                  end
         
     | 
| 
       105 
102 
     | 
    
         | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
103 
     | 
    
         
             
                  private
         
     | 
| 
       108 
104 
     | 
    
         | 
| 
       109 
105 
     | 
    
         
             
                  def add(integration)
         
     | 
| 
         @@ -24,20 +24,17 @@ module StateMachines 
     | 
|
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                    # Whether the integration should be used for the given class.
         
     | 
| 
       26 
26 
     | 
    
         
             
                    def matches?(klass)
         
     | 
| 
       27 
     | 
    
         
            -
                       
     | 
| 
      
 27 
     | 
    
         
            +
                      matching_ancestors.any? { |ancestor| klass <= ancestor }
         
     | 
| 
       28 
28 
     | 
    
         
             
                    end
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                    # Whether the integration should be used for the given list of ancestors.
         
     | 
| 
       31 
31 
     | 
    
         
             
                    def matches_ancestors?(ancestors)
         
     | 
| 
       32 
32 
     | 
    
         
             
                      (ancestors & matching_ancestors).any?
         
     | 
| 
       33 
33 
     | 
    
         
             
                    end
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
34 
     | 
    
         
             
                  end
         
     | 
| 
       36 
35 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
                  extend ClassMethods
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
36 
     | 
    
         
             
                  def self.included(base) #:nodoc:
         
     | 
| 
       40 
     | 
    
         
            -
                    base. 
     | 
| 
      
 37 
     | 
    
         
            +
                    base.extend ClassMethods
         
     | 
| 
       41 
38 
     | 
    
         
             
                  end
         
     | 
| 
       42 
39 
     | 
    
         
             
                end
         
     | 
| 
       43 
40 
     | 
    
         
             
              end
         
     | 
| 
         @@ -419,7 +419,11 @@ module StateMachines 
     | 
|
| 
       419 
419 
     | 
    
         
             
                    name = args.first || :state
         
     | 
| 
       420 
420 
     | 
    
         | 
| 
       421 
421 
     | 
    
         
             
                    # Find an existing machine
         
     | 
| 
       422 
     | 
    
         
            -
                     
     | 
| 
      
 422 
     | 
    
         
            +
                    machine = owner_class.respond_to?(:state_machines) &&
         
     | 
| 
      
 423 
     | 
    
         
            +
                      (args.first && owner_class.state_machines[name] || !args.first &&
         
     | 
| 
      
 424 
     | 
    
         
            +
                      owner_class.state_machines.values.first) || nil
         
     | 
| 
      
 425 
     | 
    
         
            +
             
     | 
| 
      
 426 
     | 
    
         
            +
                    if machine
         
     | 
| 
       423 
427 
     | 
    
         
             
                      # Only create a new copy if changes are being made to the machine in
         
     | 
| 
       424 
428 
     | 
    
         
             
                      # a subclass
         
     | 
| 
       425 
429 
     | 
    
         
             
                      if machine.owner_class != owner_class && (options.any? || block_given?)
         
     | 
| 
         @@ -2046,14 +2050,12 @@ module StateMachines 
     | 
|
| 
       2046 
2050 
     | 
    
         
             
                # the method and is further along in the ancestor chain than this
         
     | 
| 
       2047 
2051 
     | 
    
         
             
                # machine's helper module.
         
     | 
| 
       2048 
2052 
     | 
    
         
             
                def owner_class_ancestor_has_method?(scope, method)
         
     | 
| 
      
 2053 
     | 
    
         
            +
                  return false unless owner_class_has_method?(scope, method)
         
     | 
| 
      
 2054 
     | 
    
         
            +
             
     | 
| 
       2049 
2055 
     | 
    
         
             
                  superclasses = owner_class.ancestors[1..-1].select { |ancestor| ancestor.is_a?(Class) }
         
     | 
| 
       2050 
2056 
     | 
    
         | 
| 
       2051 
2057 
     | 
    
         
             
                  if scope == :class
         
     | 
| 
       2052 
     | 
    
         
            -
                     
     | 
| 
       2053 
     | 
    
         
            -
                    current = (
         
     | 
| 
       2054 
     | 
    
         
            -
                    class << owner_class;
         
     | 
| 
       2055 
     | 
    
         
            -
                      self;
         
     | 
| 
       2056 
     | 
    
         
            -
                    end)
         
     | 
| 
      
 2058 
     | 
    
         
            +
                    current = owner_class.singleton_class
         
     | 
| 
       2057 
2059 
     | 
    
         
             
                    superclass = superclasses.first
         
     | 
| 
       2058 
2060 
     | 
    
         
             
                  else
         
     | 
| 
       2059 
2061 
     | 
    
         
             
                    current = owner_class
         
     | 
| 
         @@ -2068,14 +2070,16 @@ module StateMachines 
     | 
|
| 
       2068 
2070 
     | 
    
         | 
| 
       2069 
2071 
     | 
    
         
             
                  # Search for for the first ancestor that defined this method
         
     | 
| 
       2070 
2072 
     | 
    
         
             
                  ancestors.detect do |ancestor|
         
     | 
| 
       2071 
     | 
    
         
            -
                    ancestor = (
         
     | 
| 
       2072 
     | 
    
         
            -
                    class << ancestor;
         
     | 
| 
       2073 
     | 
    
         
            -
                      self;
         
     | 
| 
       2074 
     | 
    
         
            -
                    end) if scope == :class && ancestor.is_a?(Class)
         
     | 
| 
      
 2073 
     | 
    
         
            +
                    ancestor = ancestor.singleton_class if scope == :class && ancestor.is_a?(Class)
         
     | 
| 
       2075 
2074 
     | 
    
         
             
                    ancestor.method_defined?(method) || ancestor.private_method_defined?(method)
         
     | 
| 
       2076 
2075 
     | 
    
         
             
                  end
         
     | 
| 
       2077 
2076 
     | 
    
         
             
                end
         
     | 
| 
       2078 
2077 
     | 
    
         | 
| 
      
 2078 
     | 
    
         
            +
                def owner_class_has_method?(scope, method)
         
     | 
| 
      
 2079 
     | 
    
         
            +
                  target = scope == :class ? owner_class.singleton_class : owner_class
         
     | 
| 
      
 2080 
     | 
    
         
            +
                  target.method_defined?(method) || target.private_method_defined?(method)
         
     | 
| 
      
 2081 
     | 
    
         
            +
                end
         
     | 
| 
      
 2082 
     | 
    
         
            +
             
     | 
| 
       2079 
2083 
     | 
    
         
             
                # Adds helper methods for accessing naming information about states and
         
     | 
| 
       2080 
2084 
     | 
    
         
             
                # events on the owner class
         
     | 
| 
       2081 
2085 
     | 
    
         
             
                def define_name_helpers
         
     | 
| 
         @@ -45,7 +45,7 @@ module StateMachines 
     | 
|
| 
       45 
45 
     | 
    
         
             
                # 
         
     | 
| 
       46 
46 
     | 
    
         
             
                #   paths.from_states # => [:parked, :idling, :first_gear, ...]
         
     | 
| 
       47 
47 
     | 
    
         
             
                def from_states
         
     | 
| 
       48 
     | 
    
         
            -
                   
     | 
| 
      
 48 
     | 
    
         
            +
                  flat_map(&:from_states).uniq
         
     | 
| 
       49 
49 
     | 
    
         
             
                end
         
     | 
| 
       50 
50 
     | 
    
         | 
| 
       51 
51 
     | 
    
         
             
                # Lists all of the states that can be transitioned to through the paths in
         
     | 
| 
         @@ -55,7 +55,7 @@ module StateMachines 
     | 
|
| 
       55 
55 
     | 
    
         
             
                # 
         
     | 
| 
       56 
56 
     | 
    
         
             
                #   paths.to_states # => [:idling, :first_gear, :second_gear, ...]
         
     | 
| 
       57 
57 
     | 
    
         
             
                def to_states
         
     | 
| 
       58 
     | 
    
         
            -
                   
     | 
| 
      
 58 
     | 
    
         
            +
                  flat_map(&:to_states).uniq
         
     | 
| 
       59 
59 
     | 
    
         
             
                end
         
     | 
| 
       60 
60 
     | 
    
         | 
| 
       61 
61 
     | 
    
         
             
                # Lists all of the events that can be fired through the paths in this
         
     | 
| 
         @@ -65,7 +65,7 @@ module StateMachines 
     | 
|
| 
       65 
65 
     | 
    
         
             
                # 
         
     | 
| 
       66 
66 
     | 
    
         
             
                #   paths.events  # => [:park, :ignite, :shift_up, ...]
         
     | 
| 
       67 
67 
     | 
    
         
             
                def events
         
     | 
| 
       68 
     | 
    
         
            -
                   
     | 
| 
      
 68 
     | 
    
         
            +
                  flat_map(&:events).uniq
         
     | 
| 
       69 
69 
     | 
    
         
             
                end
         
     | 
| 
       70 
70 
     | 
    
         | 
| 
       71 
71 
     | 
    
         
             
                private
         
     | 
    
        data/lib/state_machines/state.rb
    CHANGED
    
    | 
         @@ -2,7 +2,7 @@ module StateMachines 
     | 
|
| 
       2 
2 
     | 
    
         
             
              # A state defines a value that an attribute can be in after being transitioned
         
     | 
| 
       3 
3 
     | 
    
         
             
              # 0 or more times.  States can represent a value of any type in Ruby, though
         
     | 
| 
       4 
4 
     | 
    
         
             
              # the most common (and default) type is String.
         
     | 
| 
       5 
     | 
    
         
            -
              # 
     | 
| 
      
 5 
     | 
    
         
            +
              #
         
     | 
| 
       6 
6 
     | 
    
         
             
              # In addition to defining the machine's value, a state can also define a
         
     | 
| 
       7 
7 
     | 
    
         
             
              # behavioral context for an object when that object is in the state.  See
         
     | 
| 
       8 
8 
     | 
    
         
             
              # StateMachines::Machine#state for more information about how state-driven
         
     | 
| 
         @@ -10,7 +10,7 @@ module StateMachines 
     | 
|
| 
       10 
10 
     | 
    
         
             
              class State
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                # The state machine for which this state is defined
         
     | 
| 
       13 
     | 
    
         
            -
                 
     | 
| 
      
 13 
     | 
    
         
            +
                attr_reader :machine
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
15 
     | 
    
         
             
                # The unique identifier for the state used in event and callback definitions
         
     | 
| 
       16 
16 
     | 
    
         
             
                attr_reader :name
         
     | 
| 
         @@ -38,7 +38,7 @@ module StateMachines 
     | 
|
| 
       38 
38 
     | 
    
         
             
                attr_accessor :matcher
         
     | 
| 
       39 
39 
     | 
    
         | 
| 
       40 
40 
     | 
    
         
             
                # Creates a new state within the context of the given machine.
         
     | 
| 
       41 
     | 
    
         
            -
                # 
     | 
| 
      
 41 
     | 
    
         
            +
                #
         
     | 
| 
       42 
42 
     | 
    
         
             
                # Configuration options:
         
     | 
| 
       43 
43 
     | 
    
         
             
                # * <tt>:initial</tt> - Whether this state is the beginning state for the
         
     | 
| 
       44 
44 
     | 
    
         
             
                #   machine. Default is false.
         
     | 
| 
         @@ -86,6 +86,11 @@ module StateMachines 
     | 
|
| 
       86 
86 
     | 
    
         
             
                  @context = StateContext.new(self)
         
     | 
| 
       87 
87 
     | 
    
         
             
                end
         
     | 
| 
       88 
88 
     | 
    
         | 
| 
      
 89 
     | 
    
         
            +
                def machine=(machine)
         
     | 
| 
      
 90 
     | 
    
         
            +
                  @machine = machine
         
     | 
| 
      
 91 
     | 
    
         
            +
                  @context = StateContext.new(self)
         
     | 
| 
      
 92 
     | 
    
         
            +
                end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
       89 
94 
     | 
    
         
             
                # Determines whether there are any states that can be transitioned to from
         
     | 
| 
       90 
95 
     | 
    
         
             
                # this state.  If there are none, then this state is considered *final*.
         
     | 
| 
       91 
96 
     | 
    
         
             
                # Any objects in a final state will remain so forever given the current
         
     | 
| 
         @@ -107,15 +112,15 @@ module StateMachines 
     | 
|
| 
       107 
112 
     | 
    
         
             
                end
         
     | 
| 
       108 
113 
     | 
    
         | 
| 
       109 
114 
     | 
    
         
             
                # Generates a human-readable description of this state's name / value:
         
     | 
| 
       110 
     | 
    
         
            -
                # 
     | 
| 
      
 115 
     | 
    
         
            +
                #
         
     | 
| 
       111 
116 
     | 
    
         
             
                # For example,
         
     | 
| 
       112 
     | 
    
         
            -
                # 
     | 
| 
      
 117 
     | 
    
         
            +
                #
         
     | 
| 
       113 
118 
     | 
    
         
             
                #   State.new(machine, :parked).description                               # => "parked"
         
     | 
| 
       114 
119 
     | 
    
         
             
                #   State.new(machine, :parked, :value => :parked).description            # => "parked"
         
     | 
| 
       115 
120 
     | 
    
         
             
                #   State.new(machine, :parked, :value => nil).description                # => "parked (nil)"
         
     | 
| 
       116 
121 
     | 
    
         
             
                #   State.new(machine, :parked, :value => 1).description                  # => "parked (1)"
         
     | 
| 
       117 
122 
     | 
    
         
             
                #   State.new(machine, :parked, :value => lambda {Time.now}).description  # => "parked (*)
         
     | 
| 
       118 
     | 
    
         
            -
                # 
     | 
| 
      
 123 
     | 
    
         
            +
                #
         
     | 
| 
       119 
124 
     | 
    
         
             
                # Configuration options:
         
     | 
| 
       120 
125 
     | 
    
         
             
                # * <tt>:human_name</tt> - Whether to use this state's human name in the
         
     | 
| 
       121 
126 
     | 
    
         
             
                #   description or just the internal name
         
     | 
| 
         @@ -129,9 +134,9 @@ module StateMachines 
     | 
|
| 
       129 
134 
     | 
    
         
             
                # The value that represents this state.  This will optionally evaluate the
         
     | 
| 
       130 
135 
     | 
    
         
             
                # original block if it's a lambda block.  Otherwise, the static value is
         
     | 
| 
       131 
136 
     | 
    
         
             
                # returned.
         
     | 
| 
       132 
     | 
    
         
            -
                # 
     | 
| 
      
 137 
     | 
    
         
            +
                #
         
     | 
| 
       133 
138 
     | 
    
         
             
                # For example,
         
     | 
| 
       134 
     | 
    
         
            -
                # 
     | 
| 
      
 139 
     | 
    
         
            +
                #
         
     | 
| 
       135 
140 
     | 
    
         
             
                #   State.new(machine, :parked, :value => 1).value                        # => 1
         
     | 
| 
       136 
141 
     | 
    
         
             
                #   State.new(machine, :parked, :value => lambda {Time.now}).value        # => Tue Jan 01 00:00:00 UTC 2008
         
     | 
| 
       137 
142 
     | 
    
         
             
                #   State.new(machine, :parked, :value => lambda {Time.now}).value(false) # => <Proc:0xb6ea7ca0@...>
         
     | 
| 
         @@ -152,14 +157,14 @@ module StateMachines 
     | 
|
| 
       152 
157 
     | 
    
         
             
                # Determines whether this state matches the given value.  If no matcher is
         
     | 
| 
       153 
158 
     | 
    
         
             
                # configured, then this will check whether the values are equivalent.
         
     | 
| 
       154 
159 
     | 
    
         
             
                # Otherwise, the matcher will determine the result.
         
     | 
| 
       155 
     | 
    
         
            -
                # 
     | 
| 
      
 160 
     | 
    
         
            +
                #
         
     | 
| 
       156 
161 
     | 
    
         
             
                # For example,
         
     | 
| 
       157 
     | 
    
         
            -
                # 
     | 
| 
      
 162 
     | 
    
         
            +
                #
         
     | 
| 
       158 
163 
     | 
    
         
             
                #   # Without a matcher
         
     | 
| 
       159 
164 
     | 
    
         
             
                #   state = State.new(machine, :parked, :value => 1)
         
     | 
| 
       160 
165 
     | 
    
         
             
                #   state.matches?(1)           # => true
         
     | 
| 
       161 
166 
     | 
    
         
             
                #   state.matches?(2)           # => false
         
     | 
| 
       162 
     | 
    
         
            -
                # 
     | 
| 
      
 167 
     | 
    
         
            +
                #
         
     | 
| 
       163 
168 
     | 
    
         
             
                #   # With a matcher
         
     | 
| 
       164 
169 
     | 
    
         
             
                #   state = State.new(machine, :parked, :value => lambda {Time.now}, :if => lambda {|value| !value.nil?})
         
     | 
| 
       165 
170 
     | 
    
         
             
                #   state.matches?(nil)         # => false
         
     | 
| 
         @@ -170,7 +175,7 @@ module StateMachines 
     | 
|
| 
       170 
175 
     | 
    
         | 
| 
       171 
176 
     | 
    
         
             
                # Defines a context for the state which will be enabled on instances of
         
     | 
| 
       172 
177 
     | 
    
         
             
                # the owner class when the machine is in this state.
         
     | 
| 
       173 
     | 
    
         
            -
                # 
     | 
| 
      
 178 
     | 
    
         
            +
                #
         
     | 
| 
       174 
179 
     | 
    
         
             
                # This can be called multiple times.  Each time a new context is created,
         
     | 
| 
       175 
180 
     | 
    
         
             
                # a new module will be included in the owner class.
         
     | 
| 
       176 
181 
     | 
    
         
             
                def context(&block)
         
     | 
| 
         @@ -184,7 +189,7 @@ module StateMachines 
     | 
|
| 
       184 
189 
     | 
    
         
             
                  new_methods = context_methods.to_a.select { |(name, method)| old_methods[name] != method }
         
     | 
| 
       185 
190 
     | 
    
         | 
| 
       186 
191 
     | 
    
         
             
                  # Alias new methods so that the only execute when the object is in this state
         
     | 
| 
       187 
     | 
    
         
            -
                  new_methods.each do |(method_name,  
     | 
| 
      
 192 
     | 
    
         
            +
                  new_methods.each do |(method_name, _method)|
         
     | 
| 
       188 
193 
     | 
    
         
             
                    context_name = context_name_for(method_name)
         
     | 
| 
       189 
194 
     | 
    
         
             
                    context.class_eval <<-end_eval, __FILE__, __LINE__ + 1
         
     | 
| 
       190 
195 
     | 
    
         
             
                      alias_method :"#{context_name}", :#{method_name}
         
     | 
| 
         @@ -208,7 +213,7 @@ module StateMachines 
     | 
|
| 
       208 
213 
     | 
    
         | 
| 
       209 
214 
     | 
    
         
             
                # Calls a method defined in this state's context on the given object.  All
         
     | 
| 
       210 
215 
     | 
    
         
             
                # arguments and any block will be passed into the method defined.
         
     | 
| 
       211 
     | 
    
         
            -
                # 
     | 
| 
      
 216 
     | 
    
         
            +
                #
         
     | 
| 
       212 
217 
     | 
    
         
             
                # If the method has never been defined for this state, then a NoMethodError
         
     | 
| 
       213 
218 
     | 
    
         
             
                # will be raised.
         
     | 
| 
       214 
219 
     | 
    
         
             
                def call(object, method, *args, &block)
         
     | 
| 
         @@ -239,9 +244,9 @@ module StateMachines 
     | 
|
| 
       239 
244 
     | 
    
         
             
                end
         
     | 
| 
       240 
245 
     | 
    
         | 
| 
       241 
246 
     | 
    
         
             
                # Generates a nicely formatted description of this state's contents.
         
     | 
| 
       242 
     | 
    
         
            -
                # 
     | 
| 
      
 247 
     | 
    
         
            +
                #
         
     | 
| 
       243 
248 
     | 
    
         
             
                # For example,
         
     | 
| 
       244 
     | 
    
         
            -
                # 
     | 
| 
      
 249 
     | 
    
         
            +
                #
         
     | 
| 
       245 
250 
     | 
    
         
             
                #   state = StateMachines::State.new(machine, :parked, :value => 1, :initial => true)
         
     | 
| 
       246 
251 
     | 
    
         
             
                #   state   # => #<StateMachines::State name=:parked value=1 initial=true context=[]>
         
     | 
| 
       247 
252 
     | 
    
         
             
                def inspect
         
     | 
| 
         @@ -93,7 +93,7 @@ module StateMachines 
     | 
|
| 
       93 
93 
     | 
    
         | 
| 
       94 
94 
     | 
    
         
             
                  machine.events.each { |event| order += event.known_states }
         
     | 
| 
       95 
95 
     | 
    
         
             
                  order += select { |state| state.context_methods.any? }.map { |state| state.name }
         
     | 
| 
       96 
     | 
    
         
            -
                  order += keys(:name) - machine.callbacks.values.flatten. 
     | 
| 
      
 96 
     | 
    
         
            +
                  order += keys(:name) - machine.callbacks.values.flatten.flat_map(&:known_states)
         
     | 
| 
       97 
97 
     | 
    
         
             
                  order += keys(:name)
         
     | 
| 
       98 
98 
     | 
    
         | 
| 
       99 
99 
     | 
    
         
             
                  order.uniq!
         
     | 
| 
         @@ -168,7 +168,7 @@ module StateMachines 
     | 
|
| 
       168 
168 
     | 
    
         
             
                  def catch_exceptions
         
     | 
| 
       169 
169 
     | 
    
         
             
                    begin
         
     | 
| 
       170 
170 
     | 
    
         
             
                      yield
         
     | 
| 
       171 
     | 
    
         
            -
                    rescue 
     | 
| 
      
 171 
     | 
    
         
            +
                    rescue
         
     | 
| 
       172 
172 
     | 
    
         
             
                      rollback
         
     | 
| 
       173 
173 
     | 
    
         
             
                      raise
         
     | 
| 
       174 
174 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -210,7 +210,7 @@ module StateMachines 
     | 
|
| 
       210 
210 
     | 
    
         
             
                      # Rollback only if exceptions occur during before callbacks
         
     | 
| 
       211 
211 
     | 
    
         
             
                      begin
         
     | 
| 
       212 
212 
     | 
    
         
             
                        super
         
     | 
| 
       213 
     | 
    
         
            -
                      rescue 
     | 
| 
      
 213 
     | 
    
         
            +
                      rescue
         
     | 
| 
       214 
214 
     | 
    
         
             
                        rollback unless @before_run
         
     | 
| 
       215 
215 
     | 
    
         
             
                        @success = nil  # mimics ActiveRecord.save behavior on rollback
         
     | 
| 
       216 
216 
     | 
    
         
             
                        raise
         
     | 
    
        data/state_machines.gemspec
    CHANGED
    
    | 
         @@ -12,9 +12,8 @@ Gem::Specification.new do |spec| 
     | 
|
| 
       12 
12 
     | 
    
         
             
              spec.homepage      = 'https://github.com/state-machines/state_machines'
         
     | 
| 
       13 
13 
     | 
    
         
             
              spec.license       = 'MIT'
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
              spec.required_ruby_version     = '>=  
     | 
| 
      
 15 
     | 
    
         
            +
              spec.required_ruby_version     = '>= 2.0.0'
         
     | 
| 
       16 
16 
     | 
    
         
             
              spec.files         = `git ls-files -z`.split("\x0")
         
     | 
| 
       17 
     | 
    
         
            -
              spec.test_files    = spec.files.grep(/^test\//)
         
     | 
| 
       18 
17 
     | 
    
         
             
              spec.require_paths = ['lib']
         
     | 
| 
       19 
18 
     | 
    
         | 
| 
       20 
19 
     | 
    
         
             
              spec.add_development_dependency 'bundler', '>= 1.7.6'
         
     |