diff --git a/CHANGELOG.md b/CHANGELOG.md index a3406ce..d0157b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Unreleased - * supporting instance level inspection for states + * supporting instance level inspection for states (including permissible state, see issue #54) * added autocreation of constants for each state ([@jherdman](https://github.com/jherdman)) ## 3.0.16 diff --git a/README.md b/README.md index 691ff6a..dfe5d08 100644 --- a/README.md +++ b/README.md @@ -304,7 +304,7 @@ class AddJobState < ActiveRecord::Migration end ``` -## Inspection ## +## Inspection AASM supports a couple of methods to find out which states or events are provided or permissible. @@ -316,6 +316,12 @@ job = Job.new job.states => [:sleeping, :running, :cleaning] +job.states(:permissible => true) +=> [:running] +job.run +job.states(:permissible => true) +=> [:cleaning, :sleeping] + job.events => [:run, :clean, :sleep] ``` diff --git a/lib/aasm/instance_base.rb b/lib/aasm/instance_base.rb index 258b689..6f58029 100644 --- a/lib/aasm/instance_base.rb +++ b/lib/aasm/instance_base.rb @@ -30,8 +30,15 @@ module AASM AASM::Localizer.new.human_state_name(@instance.class, current_state) end - def states - @instance.class.aasm.states + def states(options={}) + if options[:permissible] + # ugliness level 1000 + transitions = @instance.class.aasm.events.values.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.states.select {|s| tos.include?(s.name.to_sym)} + else + @instance.class.aasm.states + end end # QUESTION: shouldn't events and permissible_events be the same thing? diff --git a/spec/models/foo.rb b/spec/models/foo.rb index 482b94c..c135e8e 100644 --- a/spec/models/foo.rb +++ b/spec/models/foo.rb @@ -5,11 +5,11 @@ class Foo state :closed, :enter => :enter event :close, :success => :success_callback do - transitions :to => :closed, :from => [:open] + transitions :from => [:open], :to => [:closed] end event :null do - transitions :to => :closed, :from => [:open], :guard => :always_false + transitions :from => [:open], :to => :closed, :guard => :always_false end end diff --git a/spec/unit/inspection_spec.rb b/spec/unit/inspection_spec.rb index e128e91..8d245c2 100644 --- a/spec/unit/inspection_spec.rb +++ b/spec/unit/inspection_spec.rb @@ -28,15 +28,37 @@ describe 'inspection for common cases' do end context "instance level inspection" do + let(:foo) { Foo.new } + let(:two) { FooTwo.new } + it "delivers all states" do - foo = Foo.new states = foo.aasm.states states.should include(:open) states.should include(:closed) + + states = foo.aasm.states(:permissible => true) + states.should include(:closed) + states.should_not include(:open) + + foo.close + foo.aasm.states(:permissible => true).should be_empty + end + + it "delivers all states for subclasses" do + states = two.aasm.states + states.should include(:open) + states.should include(:closed) + states.should include(:foo) + + states = two.aasm.states(:permissible => true) + states.should include(:closed) + states.should_not include(:open) + + two.close + two.aasm.states(:permissible => true).should be_empty end it "delivers all events" do - foo = Foo.new events = foo.aasm.events events.should include(:close) events.should include(:null)