mirror of
https://github.com/aasm/aasm
synced 2023-03-27 23:22:41 -04:00
Merge pull request #4 from stacksocial/master
Allow transitions without from, which will allow transitioning from ANY state
This commit is contained in:
commit
7bc5180c5d
4 changed files with 45 additions and 27 deletions
|
@ -1,4 +1,4 @@
|
|||
# AASM - Ruby state machines [![Build Status](https://secure.travis-ci.org/aasm/aasm.png)](http://travis-ci.org/aasm/aasm)
|
||||
# AASM - Ruby state machines [![Build Status](https://secure.travis-ci.org/aasm/aasm.png)](http://travis-ci.org/aasm/aasm) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/aasm/aasm)
|
||||
|
||||
This package contains AASM, a library for adding finite state machines to Ruby classes.
|
||||
|
||||
|
@ -101,8 +101,9 @@ This example uses a few of the more complex features available.
|
|||
transitions :to => :intimate, :from => [:dating], :guard => :drunk?
|
||||
end
|
||||
|
||||
# Will allow transitioning from any state if guard allows it
|
||||
event :get_married do
|
||||
transitions :to => :married, :from => [:dating, :intimate], :guard => :willing_to_give_up_manhood?
|
||||
transitions :to => :married, :guard => :willing_to_give_up_manhood?
|
||||
end
|
||||
end
|
||||
aasm_initial_state Proc.new { |relationship| relationship.strictly_for_fun? ? :intimate : :dating }
|
||||
|
|
|
@ -13,34 +13,11 @@ module AASM
|
|||
# executes the transition guards to determine if a transition is even
|
||||
# an option given current conditions.
|
||||
def may_fire?(obj, to_state=nil, *args)
|
||||
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
|
||||
return false if transitions.size == 0
|
||||
|
||||
result = false
|
||||
transitions.each do |transition|
|
||||
next if to_state and !Array(transition.to).include?(to_state)
|
||||
if transition.perform(obj, *args)
|
||||
result = true
|
||||
break
|
||||
end
|
||||
end
|
||||
result
|
||||
_fire(obj, true, to_state, *args) # true indicates test firing
|
||||
end
|
||||
|
||||
def fire(obj, to_state=nil, *args)
|
||||
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
|
||||
return nil if transitions.size == 0
|
||||
|
||||
next_state = nil
|
||||
transitions.each do |transition|
|
||||
next if to_state and !Array(transition.to).include?(to_state)
|
||||
if transition.perform(obj, *args)
|
||||
next_state = to_state || Array(transition.to).first
|
||||
transition.execute(obj, *args)
|
||||
break
|
||||
end
|
||||
end
|
||||
next_state
|
||||
_fire(obj, false, to_state, *args) # false indicates this is not a test (fire!)
|
||||
end
|
||||
|
||||
def transitions_from_state?(state)
|
||||
|
@ -112,6 +89,32 @@ module AASM
|
|||
self
|
||||
end
|
||||
|
||||
# Execute if test? == false, otherwise return true/false depending on whether it would fire
|
||||
def _fire(obj, test, to_state=nil, *args)
|
||||
if @transitions.map(&:from).any?
|
||||
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
|
||||
return nil if transitions.size == 0
|
||||
else
|
||||
transitions = @transitions
|
||||
end
|
||||
|
||||
result = test ? false : nil
|
||||
transitions.each do |transition|
|
||||
next if to_state and !Array(transition.to).include?(to_state)
|
||||
if transition.perform(obj, *args)
|
||||
if test
|
||||
result = true
|
||||
else
|
||||
result = to_state || Array(transition.to).first
|
||||
transition.execute(obj, *args)
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def _fire_callbacks(action, record)
|
||||
case action
|
||||
when Symbol, String
|
||||
|
@ -122,9 +125,12 @@ module AASM
|
|||
end
|
||||
|
||||
def transitions(trans_opts)
|
||||
# Create a separate transition for each from state to the given state
|
||||
Array(trans_opts[:from]).each do |s|
|
||||
@transitions << AASM::SupportingClasses::StateTransition.new(trans_opts.merge({:from => s.to_sym}))
|
||||
end
|
||||
# Create a transition if to is specified without from (transitions from ANY state)
|
||||
@transitions << AASM::SupportingClasses::StateTransition.new(trans_opts) if @transitions.empty? && trans_opts[:to]
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -9,9 +9,14 @@ class Silencer
|
|||
event :cry do
|
||||
transitions :from => :silent, :to => :crying
|
||||
end
|
||||
|
||||
event :smile do
|
||||
transitions :from => :crying, :to => :smiling
|
||||
end
|
||||
|
||||
event :smile_any do
|
||||
transitions :to => :smiling
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -19,6 +19,12 @@ describe 'transitions' do
|
|||
sub.smile!.should be_false
|
||||
sub.should be_silent
|
||||
end
|
||||
|
||||
it 'should not raise an exception when from is nil even if whiny' do
|
||||
silencer = Silencer.new
|
||||
silencer.smile_any!.should be_true
|
||||
silencer.should be_smiling
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue