enumerated_state

Implement state patterns for your enumerated_attributes

Resources

Install

  • sudo gem enumerated_state

Use

  • require ‘enumerated_state’

Description

This gem belongs to the ASPIUM family of gems – (Another State Pattern Implemented Using Mixology). This ASPIUM adds state pattern support to enumerated attributes (see enumerated_attribute) and allows multiple state variables per object, one for each enumerated attribute.

Usage

Basic implementation

If you are using enumerated_attribute, you may have code looking something like

class Tractor
  def direction
    case
    when tractor.gear_is_first? then 'forwards'
    when tractor.gear_is_reverse? then 'backwards'
    else
      'stopped'
    end
  end
end

We can clean this up a little by using acts_as_enumerated_state like this

class Tractor
  enum_attr :gear, %w(reverse ^neutral first)
  acts_as_enumerated_state :gear

  def direction; nil; end  # called if gear == nil

  module Reverse
    def direction; 'backwards'; end
  end
  module Neutral
    def direction; 'stopped'; end
  end
  module First
    def direction; 'forwards'; end
  end
end

Multi-variable state and enum value conflicts

If your attributes share some enum values with the same name, there will be confusion as to which module belongs to which enumeration. You can clear up the collision by using the :module option like this

class Foobar
  enum_attr :alpha, %w(state1 state2)
  enum_attr :beta, %w(state1 state2 state3)  # names will collide when mapped to modules

  acts_as_enumerated_state :alpha
  acts_as_enumerated_state :beta, :module=>'Beta'

  module State1 ... end
  module State2 ... end

  module Beta
    module State1 ... end
    module State2 ... end
    module State3 ... end
  end
end

Strict versus non-strict

By default, acts_as_enumerated_state assigns one module for each enumeration and fails when it cannot find the module. For example, the following code causes an error

class Tractor
  enum_attr :gear, %w(reverse neutral first)
  acts_as_enumerated_state :gear

  module Reverse ...  end
  # where's the module for :neutral?
  module First ... end
end

Tractor.new.gear = :neutral  #error because there's no module

But sometimes you may not need a module for each enumeration. You may want some enumerations to use a method defined by the object itself. You can back off the strictness by setting the :strict option to false like this

class Tractor
  enum_attr :gear, %w(reverse neutral first)
  acts_as_enumerated_state :gear, :strict=>false

  def motion; 'stopped'; end

  module Reverse
    def motion; 'backwards'; end
  end
  # no neutral module needed
  module First
    def motion; 'forwards'; end
  end
end

t = Tractor.new
t.gear = :neutral
t.motion   # calls motion on the object and returns 'stopped'

Dependencies

  • meta_programming

  • mixology

  • enumerated_attribute