mirror of
https://github.com/aasm/aasm
synced 2023-03-27 23:22:41 -04:00
fixed consistency: call transitions callbacks in context of record; added dsl declarations support to transitions
This commit is contained in:
parent
754e82cfa6
commit
81304b0c54
4 changed files with 51 additions and 28 deletions
12
README.md
12
README.md
|
@ -81,7 +81,11 @@ class Job
|
|||
state :running
|
||||
|
||||
event :run, :after => :notify_somebody do
|
||||
transitions :from => :sleeping, :to => :running, :on_transition => Proc.new {|obj, *args| obj.set_process(*args) }
|
||||
transitions :from => :sleeping, :to => :running, :on_transition => Proc.new {|*args| set_process(*args) } do
|
||||
on_transition do
|
||||
log('Transitioned')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
event :sleep do
|
||||
|
@ -163,7 +167,11 @@ class Job
|
|||
end
|
||||
|
||||
event :sleep do
|
||||
transitions :from => :running, :to => :sleeping, :guard => :cleaning_needed?
|
||||
transitions :from => :running, :to => :sleeping, :guard => :cleaning_needed? do
|
||||
guard do
|
||||
and_cleaning_possible?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,29 +1,25 @@
|
|||
module AASM
|
||||
class Transition
|
||||
include DslHelper
|
||||
|
||||
attr_reader :from, :to, :opts
|
||||
alias_method :options, :opts
|
||||
|
||||
def initialize(opts)
|
||||
def initialize(opts, &block)
|
||||
@from, @to, @guard, @on_transition = opts[:from], opts[:to], opts[:guard], opts[:on_transition]
|
||||
@opts = opts
|
||||
|
||||
# QUESTION: rename :on_transition to :after?
|
||||
add_options_from_dsl(@opts, [:on_transition, :guard], &block) if block
|
||||
end
|
||||
|
||||
# TODO: should be named allowed? or similar
|
||||
def perform(obj, *args)
|
||||
case @guard
|
||||
when Symbol, String
|
||||
obj.send(@guard, *args)
|
||||
when Proc
|
||||
@guard.call(obj, *args)
|
||||
else
|
||||
true
|
||||
end
|
||||
invoke_callbacks_compatible_with_guard(@guard, obj, args)
|
||||
end
|
||||
|
||||
def execute(obj, *args)
|
||||
@on_transition.is_a?(Array) ?
|
||||
@on_transition.each {|ot| _execute(obj, ot, *args)} :
|
||||
_execute(obj, @on_transition, *args)
|
||||
invoke_callbacks_compatible_with_guard(@on_transition, obj, args)
|
||||
end
|
||||
|
||||
def ==(obj)
|
||||
|
@ -36,14 +32,21 @@ module AASM
|
|||
|
||||
private
|
||||
|
||||
def _execute(obj, on_transition, *args)
|
||||
case on_transition
|
||||
when Proc
|
||||
on_transition.arity == 0 ? on_transition.call : on_transition.call(obj, *args)
|
||||
when Symbol, String
|
||||
obj.send(:method, on_transition.to_sym).arity == 0 ? obj.send(on_transition) : obj.send(on_transition, *args)
|
||||
def invoke_callbacks_compatible_with_guard(code, record, args)
|
||||
case code
|
||||
when Symbol, String
|
||||
# QUESTION : record.send(code, *args) ?
|
||||
arity = record.send(:method, code.to_sym).arity
|
||||
arity == 0 ? record.send(code) : record.send(code, *args)
|
||||
when Proc
|
||||
# QUESTION : record.instance_exec(*args, &code) ?
|
||||
code.arity == 0 ? record.instance_exec(&code) : record.instance_exec(*args, &code)
|
||||
when Array
|
||||
# code.all? {...} fails in on_transition
|
||||
code.map {|a| invoke_callbacks_compatible_with_guard(a, record, args)}.all?
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end # AASM
|
||||
|
|
|
@ -13,7 +13,7 @@ class ParametrisedEvent
|
|||
|
||||
event :dress do
|
||||
transitions :from => :sleeping, :to => :working, :on_transition => :wear_clothes
|
||||
transitions :from => :showering, :to => [:working, :dating], :on_transition => Proc.new { |obj, *args| obj.wear_clothes(*args) }
|
||||
transitions :from => :showering, :to => [:working, :dating], :on_transition => Proc.new { |*args| wear_clothes(*args) }
|
||||
transitions :from => :showering, :to => :prettying_up, :on_transition => [:condition_hair, :fix_hair]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -38,6 +38,17 @@ describe AASM::Transition do
|
|||
st.opts.should == opts
|
||||
end
|
||||
|
||||
it 'should set on_transition and guard from dsl' do
|
||||
opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
|
||||
st = AASM::Transition.new(opts) do
|
||||
guard :gg
|
||||
on_transition :after_callback
|
||||
end
|
||||
|
||||
st.opts[:guard] == ['g', :gg]
|
||||
st.opts[:on_transition] == [:after_callback]
|
||||
end
|
||||
|
||||
it 'should pass equality check if from and to are the same' do
|
||||
opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
|
||||
st = AASM::Transition.new(opts)
|
||||
|
@ -101,7 +112,7 @@ describe AASM::Transition, '- when performing guard checks' do
|
|||
end
|
||||
|
||||
it 'should call the proc passing the object if the guard is a proc' do
|
||||
opts = {:from => 'foo', :to => 'bar', :guard => Proc.new {|o| o.test}}
|
||||
opts = {:from => 'foo', :to => 'bar', :guard => Proc.new { test }}
|
||||
st = AASM::Transition.new(opts)
|
||||
|
||||
obj = mock('object')
|
||||
|
@ -113,29 +124,30 @@ end
|
|||
|
||||
describe AASM::Transition, '- when executing the transition with a Proc' do
|
||||
it 'should call a Proc on the object with args' do
|
||||
opts = {:from => 'foo', :to => 'bar', :on_transition => Proc.new {|o| o.test}}
|
||||
opts = {:from => 'foo', :to => 'bar', :on_transition => Proc.new {|a| test(a) }}
|
||||
st = AASM::Transition.new(opts)
|
||||
args = {:arg1 => '1', :arg2 => '2'}
|
||||
obj = mock('object')
|
||||
|
||||
opts[:on_transition].should_receive(:call).with(any_args)
|
||||
obj.should_receive(:test).with(args)
|
||||
|
||||
st.execute(obj, args)
|
||||
end
|
||||
|
||||
it 'should call a Proc on the object without args' do
|
||||
opts = {:from => 'foo', :to => 'bar', :on_transition => Proc.new {||}}
|
||||
prc = Proc.new {||}
|
||||
opts = {:from => 'foo', :to => 'bar', :on_transition => prc }
|
||||
st = AASM::Transition.new(opts)
|
||||
args = {:arg1 => '1', :arg2 => '2'}
|
||||
obj = mock('object')
|
||||
|
||||
opts[:on_transition].should_receive(:call).with(no_args)
|
||||
obj.should_receive(:instance_exec).with(no_args) # FIXME bad spec
|
||||
|
||||
st.execute(obj, args)
|
||||
end
|
||||
end
|
||||
|
||||
describe AASM::Transition, '- when executing the transition with an :on_transtion method call' do
|
||||
describe AASM::Transition, '- when executing the transition with an :on_transition method call' do
|
||||
it 'should accept a String for the method name' do
|
||||
opts = {:from => 'foo', :to => 'bar', :on_transition => 'test'}
|
||||
st = AASM::Transition.new(opts)
|
||||
|
|
Loading…
Reference in a new issue