fire guards only once per transition #184

This commit is contained in:
Thorsten Böttger 2014-11-19 23:34:39 +01:00
parent 8ce7062aa8
commit aac1ece778
6 changed files with 20 additions and 18 deletions

View File

@ -4,6 +4,10 @@
* `aasm_human_event_name` is deprecated, use `aasm.human_event_name` instead
## 4.0.1
* fire guards only once per transition (see [issue #184](https://github.com/aasm/aasm/issues/184) for details)
## 4.0.0
* support `if` and `unless` guard syntax: (see [issue #179](https://github.com/aasm/aasm/issues/179) and [issue #181](https://github.com/aasm/aasm/issues/181)), thanks to [@bigtunacan](https://github.com/bigtunacan)

View File

@ -141,14 +141,12 @@ Here you can see a list of all possible callbacks, together with their order of
```ruby
begin
event before
event guards # test run
transition guards # test run
event guards
transition guards
old_state before_exit
old_state exit
new_state before_enter
new_state enter
event guards
transition guards
...update state...
transition after
event success # if persist successful

View File

@ -86,11 +86,11 @@ private
*process_args(event, aasm.current_state, *args)
)
if event.may_fire?(self, *args)
if may_fire_to = event.may_fire?(self, *args)
old_state.fire_callbacks(:before_exit, self)
old_state.fire_callbacks(:exit, self) # TODO: remove for AASM 4?
if new_state_name = event.fire(self, *args)
if new_state_name = event.fire(self, {:may_fire => may_fire_to}, *args)
aasm_fired(event, old_state, new_state_name, options, *args, &block)
else
aasm_failed(event_name, old_state)

View File

@ -19,11 +19,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)
_fire(obj, true, to_state, *args) # true indicates test firing
_fire(obj, {:test_only => true}, to_state, *args) # true indicates test firing
end
def fire(obj, to_state=nil, *args)
_fire(obj, false, to_state, *args) # false indicates this is not a test (fire!)
def fire(obj, options={}, to_state=nil, *args)
_fire(obj, options, to_state, *args) # false indicates this is not a test (fire!)
end
def transitions_from_state?(state)
@ -86,8 +86,8 @@ module AASM
end
# Execute if test == false, otherwise return true/false depending on whether it would fire
def _fire(obj, test, to_state=nil, *args)
result = test ? false : nil
def _fire(obj, options={}, to_state=nil, *args)
result = options[:test_only] ? false : nil
if @transitions.map(&:from).any?
transitions = @transitions.select { |t| t.from == obj.aasm.current_state }
return result if transitions.size == 0
@ -106,11 +106,11 @@ module AASM
transitions.each do |transition|
next if to_state and !Array(transition.to).include?(to_state)
if transition.allowed?(obj, *args)
if test
result = true
if Array(transition.to).include?(options[:may_fire]) || transition.allowed?(obj, *args)
result = to_state || Array(transition.to).first
if options[:test_only]
# result = true
else
result = to_state || Array(transition.to).first
transition.execute(obj, *args)
end

View File

@ -11,8 +11,8 @@ describe 'callbacks for the new DSL' do
expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
expect(callback).to receive(:before_exit_open).once.ordered # these should be before the state changes
expect(callback).to receive(:exit_open).once.ordered
expect(callback).to receive(:event_guard).once.ordered.and_return(true)
expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
# expect(callback).to receive(:event_guard).once.ordered.and_return(true)
# expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
expect(callback).to receive(:transitioning).once.ordered
expect(callback).to receive(:before_enter_closed).once.ordered
expect(callback).to receive(:enter_closed).once.ordered

View File

@ -101,7 +101,7 @@ describe 'firing an event' do
obj = double('object', :aasm => double('aasm', :current_state => :open))
expect(obj).to receive(:guard_fn).with('arg1', 'arg2').and_return(true)
expect(event.fire(obj, nil, 'arg1', 'arg2')).to eq(:closed)
expect(event.fire(obj, {}, nil, 'arg1', 'arg2')).to eq(:closed)
end
end