Skip to content

Commit

Permalink
Added initial state Proc support.
Browse files Browse the repository at this point in the history
Added more complex example to README
  • Loading branch information
nbibler committed Feb 26, 2009
1 parent baceb4b commit f87565f
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 2 deletions.
32 changes: 32 additions & 0 deletions README.rdoc
Expand Up @@ -57,6 +57,38 @@ Here's a quick example highlighting some of the features.
end
end

== A Slightly More Complex Example

This example uses a few of the more complex features available.

class Relationship
include AASM

aasm_initial_state Proc.new { |relationship| relationship.strictly_for_fun? ? :intimate : :dating }

aasm_state :dating, :enter => :make_happy, :exit => :make_depressed
aasm_state :intimate, :enter => :make_very_happy, :exit => :never_speak_again
aasm_state :married, :enter => :give_up_intimacy, :exit => :buy_exotic_car_and_wear_a_combover

aasm_event :get_intimate do
transitions :to => :intimate, :from => [:dating], :guard => :drunk?
end

aasm_event :get_married do
transitions :to => :married, :from => [:dating, :intimate], :guard => :willing_to_give_up_manhood?
end

def strictly_for_fun?; end
def drunk?; end
def willing_to_give_up_manhood?; end
def make_happy; end
def make_depressed; end
def make_very_happy; end
def never_speak_again; end
def give_up_intimacy; end
def buy_exotic_car_and_wear_a_combover; end
end

= Other Stuff

Author:: Scott Barron <scott at elitists dot net>
Expand Down
13 changes: 12 additions & 1 deletion lib/aasm.rb
Expand Up @@ -89,7 +89,7 @@ def aasm_current_state
@aasm_current_state = aasm_read_state
end
return @aasm_current_state if @aasm_current_state
self.class.aasm_initial_state
aasm_determine_state_name(self.class.aasm_initial_state)
end

def aasm_events_for_current_state
Expand Down Expand Up @@ -118,6 +118,17 @@ def aasm_current_state=(state)
end
@aasm_current_state = state
end

def aasm_determine_state_name(state)
case state
when Symbol, String
state
when Proc
state.call(self)
else
raise NotImplementedError, "Unrecognized state-type given. Expected Symbol, String, or Proc."
end
end

def aasm_state_object_for_state(name)
obj = self.class.aasm_states.find {|s| s == name}
Expand Down
2 changes: 1 addition & 1 deletion lib/persistence/active_record_persistence.rb
Expand Up @@ -228,7 +228,7 @@ module ReadState
# This allows for nil aasm states - be sure to add validation to your model
def aasm_read_state
if new_record?
send(self.class.aasm_column).blank? ? self.class.aasm_initial_state : send(self.class.aasm_column).to_sym
send(self.class.aasm_column).blank? ? aasm_determine_state_name(self.class.aasm_initial_state) : send(self.class.aasm_column).to_sym
else
send(self.class.aasm_column).nil? ? nil : send(self.class.aasm_column).to_sym
end
Expand Down
16 changes: 16 additions & 0 deletions spec/unit/aasm_spec.rb
Expand Up @@ -41,6 +41,17 @@ class Bar
class Baz < Bar
end

class Banker
include AASM
aasm_initial_state Proc.new { |banker| banker.rich? ? :retired : :selling_bad_mortgages }
aasm_state :retired
aasm_state :selling_bad_mortgages
RICH = 1_000_000
attr_accessor :balance
def initialize(balance = 0); self.balance = balance; end
def rich?; self.balance >= RICH; end
end


describe AASM, '- class level definitions' do
it 'should define a class level aasm_initial_state() method on its including class' do
Expand Down Expand Up @@ -130,6 +141,11 @@ class Baz < Bar
it 'should use the first state defined if no initial state is given' do
@bar.aasm_current_state.should == :read
end

it 'should determine initial state from the Proc results' do
Banker.new(Banker::RICH - 1).aasm_current_state.should == :selling_bad_mortgages
Banker.new(Banker::RICH + 1).aasm_current_state.should == :retired
end
end

describe AASM, '- event firing with persistence' do
Expand Down
23 changes: 23 additions & 0 deletions spec/unit/active_record_persistence_spec.rb
Expand Up @@ -50,6 +50,14 @@ class June < ActiveRecord::Base

class Beaver < June
end

class Thief < ActiveRecord::Base
include AASM
aasm_initial_state Proc.new { |thief| thief.skilled ? :rich : :jailed }
aasm_state :rich
aasm_state :jailed
attr_accessor :skilled, :aasm_state
end

describe "aasm model", :shared => true do
it "should include AASM::Persistence::ActiveRecordPersistence" do
Expand Down Expand Up @@ -219,6 +227,21 @@ class NamedScopeExample < ActiveRecord::Base
end
end
end

describe 'Thieves' do
before(:each) do
connection = mock(Connection, :columns => [])
Thief.stub!(:connection).and_return(connection)
end

it 'should be rich if they\'re skilled' do
Thief.new(:skilled => true).aasm_current_state.should == :rich
end

it 'should be jailed if they\'re unskilled' do
Thief.new(:skilled => false).aasm_current_state.should == :jailed
end
end

# TODO: figure out how to test ActiveRecord reload! without a database

Expand Down

0 comments on commit f87565f

Please sign in to comment.