1
0
Fork 0
mirror of https://github.com/aasm/aasm synced 2023-03-27 23:22:41 -04:00

Fixes incorrect permitted states

Permitted states now returns the correct states when an event has more than one transition, and if a transition uses a guard.
This commit is contained in:
Ebrahim Kobeissi 2016-01-13 17:02:49 -05:00
parent bdf7e4c97b
commit 2449fcc165
3 changed files with 56 additions and 5 deletions

View file

@ -35,11 +35,23 @@ module AASM
def states(options={})
if options[:permitted]
# ugliness level 1000
permitted_event_names = events(:permitted => true).map(&:name)
transitions = @instance.class.aasm(@name).state_machine.events.values_at(*permitted_event_names).compact.map {|e| e.transitions_from_state(current_state) }
tos = transitions.map {|t| t[0] ? t[0].to : nil}.flatten.compact.map(&:to_sym).uniq
@instance.class.aasm(@name).states.select {|s| tos.include?(s.name.to_sym)}
permitted_events = events(:permitted => true)
# An array of arrays. Each inner array represents the transitions that
# transition from the current state for an event
event_transitions = permitted_events.map {|e| e.transitions_from_state(current_state) }
# An array of symbols that are possible :to transition states
to_state_names = event_transitions.map do |transitions|
return nil if transitions.empty?
# Return the :to state of the first transition that is allowed or nil
transition = transitions.find { |t| t.allowed?(@instance) }
transition ? transition.to : nil
end.flatten.compact.uniq
# Select states that are in to_state_names
@instance.class.aasm(@name).states.select {|s| to_state_names.include?(s.name)}
else
@instance.class.aasm(@name).states
end

View file

@ -0,0 +1,24 @@
class MultiTransitioner
include AASM
attr_accessor :can_run
def initialize
@can_run = false
end
aasm do
state :sleeping, :initial => true
state :running
state :dancing
event :start do
transitions :from => :sleeping, :to => :running, guard: :runnable?
transitions :from => :sleeping, :to => :dancing
end
end
def runnable?
@can_run
end
end

View file

@ -17,6 +17,7 @@ describe 'inspection for common cases' do
context "instance level inspection" do
let(:foo) { Foo.new }
let(:two) { FooTwo.new }
let(:multi) { MultiTransitioner.new }
it "delivers all states" do
states = foo.aasm.states
@ -37,11 +38,13 @@ describe 'inspection for common cases' do
states = two.aasm.states
expect(states).to include(:open)
expect(states).to include(:closed)
expect(states).to include(:final)
expect(states).to include(:foo)
states = two.aasm.states(:permitted => true)
expect(states).to include(:closed)
expect(states).not_to include(:open)
expect(states).not_to include(:final)
two.close
expect(two.aasm.states(:permitted => true)).to be_empty
@ -54,6 +57,18 @@ describe 'inspection for common cases' do
foo.close
expect(foo.aasm.events).to be_empty
end
it "delivers permitted states when multiple transitions are defined" do
multi.can_run = false
states = multi.aasm.states(:permitted => true)
expect(states).to_not include(:running)
expect(states).to include(:dancing)
multi.can_run = true
states = multi.aasm.states(:permitted => true)
expect(states).to include(:running)
expect(states).to_not include(:dancing)
end
end
it 'should list states in the order they have been defined' do