No commit activity in last 3 years
No release in over 3 years
An implementation of the State Design Pattern in Ruby. The State Design Pattern allows an object to alter its behavior when its internal state changes.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 0.7
~> 5.3
~> 10.3
 Project Readme

state_design_pattern

Gem Version Build Status Coverage Status Code Climate

An implementation of the State Design Pattern in Ruby. The State Design Pattern allows an object to alter its behavior when its internal state changes.

Example

Here's an example of the state design pattern in use. A light bulb is modeled. It can be turned on and off. Every time it is turned on it uses 25% of its energy. When it runs out of energy it cannot be turned on again.

class LightBulbContext < Struct.new(:energy, :times_on, :times_off)
end

class LightBulb < StateDesignPattern::StateMachine
  def start_state
    Off
  end

  def initial_context
    LightBulbContext.new(100, 0, 0)
  end
end

class Switch < StateDesignPattern::BaseState
  def_actions :turn_on, :turn_off

  alias_method :light_bulb, :state_machine
end

class On < Switch

  def turn_on
    light_bulb.send_event(:already_turned_on)
  end

  def turn_off
    light_bulb.times_off += 1
    light_bulb.transition_to_state_and_send_event(Off, :turned_off)
  end
end

class Off < Switch

  def turn_on
    if light_bulb.energy >= 25
      light_bulb.energy -= 25
      light_bulb.times_on += 1
      light_bulb.transition_to_state_and_send_event(On, :turned_on)
    else
      light_bulb.send_event(:out_of_energy)
    end
  end

  def turn_off
    light_bulb.send_event(:already_turned_off)
  end
end

class LightBulbObserver

  def initialize
    @events = []
  end

  def last_event
    @events.last
  end

  def update(event)
    @events << event
  end
end

light_bulb = LightBulb.new
light_bulb_observer = LightBulbObserver.new

light_bulb.add_observer(light_bulb_observer)

light_bulb.current_state #=> Off

light_bulb.energy        #=> 100
light_bulb.times_on      #=> 0
light_bulb.times_off     #=> 0

light_bulb.turn_on
light_bulb_observer.last_event[:name] #=> :turned_on

light_bulb.current_state #=> On

light_bulb.energy        #=> 75
light_bulb.times_on      #=> 1
light_bulb.times_off     #=> 0

light_bulb.turn_off
light_bulb.turn_on

light_bulb.turn_off
light_bulb.turn_on

light_bulb.turn_off
light_bulb.turn_on

light_bulb.energy        #=> 0
light_bulb.times_on      #=> 4
light_bulb.times_off     #=> 3

light_bulb.turn_off
light_bulb.turn_on

light_bulb_observer.last_event[:name] #=> :out_of_energy

Testing

You can run:

  • All specs: bundle exec rake, or
  • A specific spec: bundle exec ruby -Ilib -Ispec spec/path_to_spec_file.rb

Contributing

If you'd like to contribute a feature or bugfix: Thanks! To make sure your fix/feature has a high chance of being included, please read the following guidelines:

  1. Post a pull request.
  2. Make sure there are tests! I will not accept any patch that is not tested. It's a rare time when explicit tests aren't needed. If you have questions about writing tests for state_pattern, please open a GitHub issue.

License

state_design_pattern is Copyright © 2014 Dwayne R. Crooks. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.