mirror of
https://github.com/aasm/aasm
synced 2023-03-27 23:22:41 -04:00
Add ability to set up transitions without specifying from - these will allow transitioning from ANY state
This commit is contained in:
parent
6357675b6b
commit
afa65d8603
3 changed files with 42 additions and 25 deletions
|
@ -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