diff --git a/lib/aasm/base.rb b/lib/aasm/base.rb index 930da8f..67de73f 100644 --- a/lib/aasm/base.rb +++ b/lib/aasm/base.rb @@ -29,6 +29,9 @@ module AASM configure :enum, nil + # Set to true to namespace reader methods and constants + configure :namespace, false + # make sure to raise an error if no_direct_assignment is enabled # and attribute is directly assigned though @klass.class_eval %Q( @@ -66,18 +69,30 @@ module AASM def state(name, options={}) @state_machine.add_state(name, @klass, options) - if @klass.instance_methods.include?("#{name}?") + if namespace? + method_name = "#{namespace}_#{name}" + else + method_name = name + end + + if @klass.instance_methods.include?("#{method_name}?") warn "#{@klass.name}: The state name #{name} is already used!" end @klass.class_eval <<-EORUBY, __FILE__, __LINE__ + 1 - def #{name}? + def #{method_name}? aasm(:#{@name}).current_state == :#{name} end EORUBY - unless @klass.const_defined?("STATE_#{name.upcase}") - @klass.const_set("STATE_#{name.upcase}", name) + if namespace? + const_name = "STATE_#{namespace.upcase}_#{name.upcase}" + else + const_name = "STATE_#{name.upcase}" + end + + unless @klass.const_defined?(const_name) + @klass.const_set(const_name, name) end end @@ -148,5 +163,16 @@ module AASM end end + def namespace? + !!@state_machine.config.namespace + end + + def namespace + if @state_machine.config.namespace == true + @name + else + @state_machine.config.namespace + end + end end end diff --git a/lib/aasm/configuration.rb b/lib/aasm/configuration.rb index eb80865..2f564a6 100644 --- a/lib/aasm/configuration.rb +++ b/lib/aasm/configuration.rb @@ -19,5 +19,8 @@ module AASM attr_accessor :no_direct_assignment attr_accessor :enum + + # namespace reader methods and constants + attr_accessor :namespace end -end \ No newline at end of file +end diff --git a/spec/models/namespaced_multiple_example.rb b/spec/models/namespaced_multiple_example.rb new file mode 100644 index 0000000..ba5237d --- /dev/null +++ b/spec/models/namespaced_multiple_example.rb @@ -0,0 +1,28 @@ +class NamespacedMultipleExample + include AASM + aasm(:status) do + state :unapproved, :initial => true + state :approved + + event :approve do + transitions :from => :unapproved, :to => :approved + end + + event :unapprove do + transitions :from => :approved, :to => :unapproved + end + end + + aasm(:review_status, namespace: :review) do + state :unapproved, :initial => true + state :approved + + event :approve_review do + transitions :from => :unapproved, :to => :approved + end + + event :unapprove_review do + transitions :from => :approved, :to => :unapproved + end + end +end diff --git a/spec/unit/namespaced_multiple_example_spec.rb b/spec/unit/namespaced_multiple_example_spec.rb new file mode 100644 index 0000000..728fb3e --- /dev/null +++ b/spec/unit/namespaced_multiple_example_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +describe 'state machine' do + let(:namespaced) { NamespacedMultipleExample.new } + + it 'starts with an initial state' do + expect(namespaced.aasm(:status).current_state).to eq(:unapproved) + expect(namespaced).to respond_to(:unapproved?) + expect(namespaced).to be_unapproved + + expect(namespaced.aasm(:review_status).current_state).to eq(:unapproved) + expect(namespaced).to respond_to(:review_unapproved?) + expect(namespaced).to be_review_unapproved + end + + it 'allows transitions to other states' do + expect(namespaced).to respond_to(:approve) + expect(namespaced).to respond_to(:approve!) + namespaced.approve! + expect(namespaced).to respond_to(:approved?) + expect(namespaced).to be_approved + + expect(namespaced).to respond_to(:approve_review) + expect(namespaced).to respond_to(:approve_review!) + namespaced.approve_review! + expect(namespaced).to respond_to(:review_approved?) + expect(namespaced).to be_review_approved + end + + it 'denies transitions to other states' do + expect {namespaced.unapprove}.to raise_error(AASM::InvalidTransition) + expect {namespaced.unapprove!}.to raise_error(AASM::InvalidTransition) + namespaced.approve + expect {namespaced.approve}.to raise_error(AASM::InvalidTransition) + expect {namespaced.approve!}.to raise_error(AASM::InvalidTransition) + namespaced.unapprove + + expect {namespaced.unapprove_review}.to raise_error(AASM::InvalidTransition) + expect {namespaced.unapprove_review!}.to raise_error(AASM::InvalidTransition) + namespaced.approve_review + expect {namespaced.approve_review}.to raise_error(AASM::InvalidTransition) + expect {namespaced.approve_review!}.to raise_error(AASM::InvalidTransition) + namespaced.unapprove_review + end + + it 'defines constants for each state name' do + expect(NamespacedMultipleExample::STATE_UNAPPROVED).to eq(:unapproved) + expect(NamespacedMultipleExample::STATE_APPROVED).to eq(:approved) + + expect(NamespacedMultipleExample::STATE_REVIEW_UNAPPROVED).to eq(:unapproved) + expect(NamespacedMultipleExample::STATE_REVIEW_APPROVED).to eq(:approved) + end +end