diff options
Diffstat (limited to 'activemodel/lib/active_model')
-rw-r--r-- | activemodel/lib/active_model/state_machine.rb | 216 |
1 files changed, 128 insertions, 88 deletions
diff --git a/activemodel/lib/active_model/state_machine.rb b/activemodel/lib/active_model/state_machine.rb index 0399fef1ab..64b91c1659 100644 --- a/activemodel/lib/active_model/state_machine.rb +++ b/activemodel/lib/active_model/state_machine.rb @@ -1,112 +1,152 @@ module ActiveModel - # ==== Examples - # - # class TrafficLight + + # ActiveModel::StateMachine provides methods that turn your object into a + # finite state machine, able to move from one state to another. + # + # A minimal implementation could be: + # + # class EmailMessage # include ActiveModel::StateMachine - # + # # state_machine do - # state :red - # state :green - # state :yellow - # state :blink - # - # event :change_color do - # transitions :to => :red, :from => [:yellow], - # :on_transition => :catch_runners - # transitions :to => :green, :from => [:red] - # transitions :to => :yellow, :from => [:green] - # end - # - # event :defect do - # transitions :to => :blink, :from => [:yellow, :red, :green] - # end - # - # event :repair do - # transitions :to => :red, :from => [:blink] - # end + # state :unread + # state :read # end - # - # def catch_runners - # puts "That'll be $250." + # + # event :open_email do + # transitions :to => :read, :from => :unread # end # end - # - # light = TrafficLight.new - # light.current_state # => :red - # light.change_color # => true - # light.current_state # => :green - # light.green? # => true - # light.change_color! # => true - # light.current_state # => :yellow - # light.red? # => false - # light.change_color # => true - # "That'll be $250." - # - # - # * The initial state for TrafficLight is red which is the first state defined. - # - # # Want to know the initial_state? - # TrafficLight.state_machine.initial_state # => :red - # - # * On a succesful transition to red (from yellow), the local +catch_runners+ - # method is executed - # - # * The object acts differently depending on its current state, for instance, - # the change_color! method has a different action depending on the current - # color of the light - # - # * Get the possible events for a state - # - # TrafficLight.state_machine.events_for(:red) # => [:change_color, :defect] - # TrafficLight.state_machine.events_for(:blink) # => [:repair] - # + # + # === Examples + # + # class TrafficLight + # include ActiveModel::StateMachine + # + # attr_reader :runners_caught + # + # def initialize + # @runners_caught = 0 + # end + # + # state_machine do + # state :red + # state :green + # state :yellow + # state :blink + # + # event :change_color do + # transitions :to => :red, :from => [:yellow], + # :on_transition => :catch_runners + # transitions :to => :green, :from => [:red] + # transitions :to => :yellow, :from => [:green] + # end + # + # event :defect do + # transitions :to => :blink, :from => [:yellow, :red, :green] + # end + # + # event :repair do + # transitions :to => :red, :from => [:blink] + # end + # end + # + # def catch_runners + # @runners_caught += 1 + # end + # end + # + # light = TrafficLight.new + # light.current_state # => :red + # light.change_color! # => true + # light.current_state # => :green + # light.green? # => true + # light.change_color! # => true + # light.current_state # => :yellow + # light.red? # => false + # light.change_color! # => true + # light.runners_caught # => 1 + # + # * The initial state for TrafficLight is red which is the first state defined. + # + # TrafficLight.state_machine.initial_state # => :red + # + # * Call an event to transition a state machine, e.g. <tt>change_color!</tt>. + # You can call the event with or without the exclamation mark, however, the common Ruby + # idiom is to name methods that directly change the state of the receivier with + # an exclamation mark, so <tt>change_color!</tt> is preferred over <tt>change_color</tt>. + # + # light.current_state #=> :green + # light.change_color! #=> true + # light.current_state #=> :yellow + # + # * On a succesful transition to red (from yellow), the local +catch_runners+ + # method is executed + # + # light.current_state #=> :red + # light.change_color! #=> true + # light.runners_caught #=> 1 + # + # * The object acts differently depending on its current state, for instance, + # the change_color! method has a different action depending on the current + # color of the light + # + # light.change_color! #=> true + # light.current_state #=> :red + # light.change_color! #=> true + # light.current_state #=> :green + # + # * Get the possible events for a state + # + # TrafficLight.state_machine.events_for(:red) # => [:change_color, :defect] + # TrafficLight.state_machine.events_for(:blink) # => [:repair] # # The StateMachine also supports the following features : # - # * Success callbacks on event transition + # * Success callbacks on event transition # - # event :sample, :success => :we_win do - # ... - # end - # - # * Enter and exit callbacks par state + # event :sample, :success => :we_win do + # ... + # end # - # state :open, :enter => [:alert_twitter, :send_emails], :exit => :alert_twitter + # * Enter and exit callbacks par state # - # * Guards on transition + # state :open, :enter => [:alert_twitter, :send_emails], :exit => :alert_twitter # - # event :close do - # # You may only close the store if the safe is locked!! - # transitions :to => :closed, :from => :open, :guard => :safe_locked? - # end + # * Guards on transition # - # * Setting the initial state - # - # state_machine :initial => :yellow do - # ... - # end + # event :close do + # # You may only close the store if the safe is locked!! + # transitions :to => :closed, :from => :open, :guard => :safe_locked? + # end # - # * Named the state machine, to have more than one + # * Setting the initial state # - # class Stated - # include ActiveModel::StateMachine + # state_machine :initial => :yellow do + # ... + # end # - # strate_machine :name => :ontest do - # end + # * Named the state machine, to have more than one # - # state_machine do - # end + # class Stated + # include ActiveModel::StateMachine + # + # strate_machine :name => :ontest do # end + # + # state_machine do + # end + # end + # + # # Get the state of the <tt>:ontest</tt> state machine + # stat.current_state(:ontest) + # # Get the initial state + # Stated.state_machine(:ontest).initial_state # - # # Get the state of the <tt>:ontest</tt> state machine - # stat.current_state(:ontest) - # # Get the initial state - # Stated.state_machine(:ontest).initial_state - # - # * Changing the state + # * Changing the state # - # stat.current_state(:default, :astate) # => :astate - # # But you must give the name of the state machine, here <tt>:default</tt> + # stat.current_state(:default, :astate) # => :astate + # # But you must give the name of the state machine, here <tt>:default</tt> # module StateMachine autoload :Event, 'active_model/state_machine/event' |