1
0
Fork 0
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:
Vladimir Meremyanin 2013-03-06 15:02:56 +04:00
parent 754e82cfa6
commit 81304b0c54
4 changed files with 51 additions and 28 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)