Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/ejlangev/aasm into ejlang…
Browse files Browse the repository at this point in the history
…ev-master

Conflicts:
	lib/aasm/aasm.rb
  • Loading branch information
alto committed Nov 18, 2013
2 parents 1c6a636 + 83d7d54 commit 3ce4119
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 5 deletions.
30 changes: 26 additions & 4 deletions lib/aasm/aasm.rb
Expand Up @@ -141,17 +141,35 @@ def aasm_human_state

private

# Takes args and a from state and removes the first
# element from args if it is a valid to_state for
# the event given the from_state
def process_args(event, from_state, *args)
# If the first arg doesn't respond to to_sym then
# it isn't a symbol or string so it can't be a state
# name anyway
return args unless args.first.respond_to?(:to_sym)
if event.transitions_from_state(from_state).map(&:to).flatten.include?(args.first)
return args[1..-1]
end
return args
end

def aasm_fire_event(event_name, options, *args, &block)
event = self.class.aasm_events[event_name]
begin
old_state = aasm.state_object_for_name(aasm.current_state)
old_state.fire_callbacks(:exit, self)

# new event before callback
event.fire_callbacks(:before, self)
event.fire_callbacks(
:before,
self,
*process_args(event, aasm.current_state, *args)
)

if new_state_name = event.fire(self, *args)
fired(event, old_state, new_state_name, options, &block)
fired(event, old_state, new_state_name, options, *args, &block)
else
failed(event_name, old_state)
end
Expand All @@ -160,7 +178,7 @@ def aasm_fire_event(event_name, options, *args, &block)
end
end

def fired(event, old_state, new_state_name, options)
def fired(event, old_state, new_state_name, options, *args)
persist = options[:persist]

new_state = aasm.state_object_for_name(new_state_name)
Expand All @@ -186,7 +204,11 @@ def fired(event, old_state, new_state_name, options)
if persist_successful
old_state.fire_callbacks(:after_exit, self)
new_state.fire_callbacks(:after_enter, self)
event.fire_callbacks(:after, self)
event.fire_callbacks(
:after,
self,
*process_args(event, old_state.name, *args)
)

self.aasm_event_fired(event.name, old_state.name, aasm.current_state) if self.respond_to?(:aasm_event_fired)
else
Expand Down
14 changes: 13 additions & 1 deletion lib/aasm/event.rb
Expand Up @@ -43,6 +43,8 @@ def all_transitions
end

def fire_callbacks(callback_name, record, *args)
# strip out the first element in args if it's a valid to_state
# #given where we're coming from, this condition implies args not empty
invoke_callbacks(@options[callback_name], record, args)
end

Expand All @@ -68,12 +70,22 @@ def update(options = {}, &block)
def _fire(obj, test, to_state=nil, *args)
result = test ? false : nil
if @transitions.map(&:from).any?
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
transitions = transitions_from_state(obj.aasm_current_state)
return result if transitions.size == 0
else
transitions = @transitions
end

# If to_state is not nil it either contains a potential
# to_state or an arg
unless to_state == nil
if to_state.respond_to?(:to_sym) &&
!transitions.map(&:to).flatten.include?(to_state.to_sym)
args.unshift(to_state)
to_state = nil
end
end

transitions.each do |transition|
next if to_state and !Array(transition.to).include?(to_state)
if transition.perform(obj, *args)
Expand Down
71 changes: 71 additions & 0 deletions spec/models/callback_new_dsl.rb
Expand Up @@ -41,3 +41,74 @@ def after; end
def enter_closed; end
def exit_open; end
end

class CallbackNewDslArgs
include AASM

aasm do
state :open, :initial => true,
:before_enter => :before_enter_open,
:after_enter => :after_enter_open,
:before_exit => :before_exit_open,
:exit => :exit_open,
:after_exit => :after_exit_open

state :closed,
:before_enter => :before_enter_closed,
:enter => :enter_closed,
:after_enter => :after_enter_closed,
:before_exit => :before_exit_closed,
:after_exit => :after_exit_closed

event :close, :before => :before, :after => :after do
transitions :to => :closed, :from => [:open], :on_transition => :transition_proc
end

event :open, :before => :before, :after => :after do
transitions :to => :open, :from => :closed
end
end

def before_enter_open; end
def before_exit_open; end
def after_enter_open; end
def after_exit_open; end

def before_enter_closed; end
def before_exit_closed; end
def after_enter_closed; end
def after_exit_closed; end

def before(*args); end
def transition_proc(arg1, arg2); end
def after(*args); end

def enter_closed; end
def exit_open; end

end

class CallbackWithStateArg

include AASM

aasm do
state :open, :inital => true
state :closed
state :out_to_lunch

event :close, :before => :before_method, :after => :after_method do
transitions :to => :closed, :from => [:open], :on_transition => :transition_method
transitions :to => :out_to_lunch, :from => [:open], :on_transition => :transition_method2
end
end

def before_method(arg); end

def after_method(arg); end

def transition_method(arg); end

def transition_method2(arg); end

end
32 changes: 32 additions & 0 deletions spec/unit/callbacks_spec.rb
Expand Up @@ -34,6 +34,38 @@

callback.close!
end

it "should properly pass arguments" do
cb = CallbackNewDslArgs.new
cb.should_receive(:exit_open).once.ordered
cb.should_receive(:before).with(:arg1, :arg2).once.ordered
cb.should_receive(:transition_proc).with(:arg1, :arg2).once.ordered
cb.should_receive(:before_exit_open).once.ordered # these should be before the state changes
cb.should_receive(:before_enter_closed).once.ordered
cb.should_receive(:enter_closed).once.ordered
cb.should_receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes
cb.should_receive(:after_exit_open).once.ordered # these should be after the state changes
cb.should_receive(:after_enter_closed).once.ordered
cb.should_receive(:after).with(:arg1, :arg2).once.ordered

cb.close!(:arg1, :arg2)
end

it "should call the proper methods given a to state as the first arg" do
cb = CallbackWithStateArg.new
cb.should_receive(:before_method).with(:arg1).once.ordered
cb.should_receive(:transition_method).with(:arg1).once.ordered
cb.should_receive(:transition_method).never
cb.should_receive(:after_method).with(:arg1).once.ordered
cb.close!(:arg1)

cb = CallbackWithStateArg.new
cb.should_receive(:before_method).with(:arg1).once.ordered
cb.should_receive(:transition_method).never
cb.should_receive(:transition_method2).with(:arg1).once.ordered
cb.should_receive(:after_method).with(:arg1).once.ordered
cb.close!(:out_to_lunch, :arg1)
end
end

describe 'event callbacks' do
Expand Down

0 comments on commit 3ce4119

Please sign in to comment.