diff --git a/lib/aasm/instance_base.rb b/lib/aasm/instance_base.rb index e5d97fe..63648fe 100644 --- a/lib/aasm/instance_base.rb +++ b/lib/aasm/instance_base.rb @@ -34,19 +34,22 @@ module AASM end def states(options={}) - if options[:permitted] - permitted_events = events(:permitted => true) - + if options.has_key?(:permitted) + selected_events = events(:permitted => options[:permitted]) # 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) } + event_transitions = selected_events.map {|e| e.transitions_from_state(current_state) } - # An array of symbols that are possible :to transition states + # An array of :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) } + # Return the :to state of the first transition that is allowed (or not) or nil + if options[:permitted] + transition = transitions.find { |t| t.allowed?(@instance) } + else + transition = transitions.find { |t| !t.allowed?(@instance) } + end transition ? transition.to : nil end.flatten.compact.uniq @@ -64,10 +67,14 @@ module AASM options[:reject] = Array(options[:reject]) events.reject! { |e| options[:reject].include?(e.name) } - if options[:permitted] + if options.has_key?(:permitted) # filters the results of events_for_current_state so that only those that # are really currently possible (given transition guards) are shown. - events.select! { |e| @instance.send("may_#{e.name}?") } + if options[:permitted] + events.select! { |e| @instance.send("may_#{e.name}?") } + else + events.select! { |e| !@instance.send("may_#{e.name}?") } + end end events diff --git a/spec/unit/inspection_spec.rb b/spec/unit/inspection_spec.rb index d7e5499..254cdc5 100644 --- a/spec/unit/inspection_spec.rb +++ b/spec/unit/inspection_spec.rb @@ -25,10 +25,15 @@ describe 'inspection for common cases' do expect(states).to include(:closed) expect(states).to include(:final) - states = foo.aasm.states(:permitted => true) - expect(states).to include(:closed) - expect(states).not_to include(:open) - expect(states).not_to include(:final) + permitted_states = foo.aasm.states(:permitted => true) + expect(permitted_states).to include(:closed) + expect(permitted_states).not_to include(:open) + expect(permitted_states).not_to include(:final) + + blocked_states = foo.aasm.states(:permitted => false) + expect(blocked_states).to include(:closed) + expect(blocked_states).not_to include(:open) + expect(blocked_states).to include(:final) foo.close expect(foo.aasm.states(:permitted => true)).to be_empty @@ -124,3 +129,16 @@ describe 'permitted events' do expect(foo.aasm.events(:permitted => true, reject: [:close])).not_to include(:close) end end + +describe 'not permitted events' do + let(:foo) {Foo.new} + + it 'work' do + expect(foo.aasm.events(:permitted => false)).to include(:null) + expect(foo.aasm.events(:permitted => false)).not_to include(:close) + end + + it 'should not include events in the reject option' do + expect(foo.aasm.events(:permitted => false, reject: :null)).to eq([]) + end +end