mirror of
https://github.com/aasm/aasm
synced 2023-03-27 23:22:41 -04:00
Merge branch 'master' of https://github.com/wickkidd/aasm into wickkidd-master
Conflicts: Rakefile spec/spec_helper.rb
This commit is contained in:
commit
6bc99dcc39
8 changed files with 153 additions and 7 deletions
|
@ -19,6 +19,7 @@ Gem::Specification.new do |s|
|
|||
s.add_development_dependency 'shoulda'
|
||||
s.add_development_dependency 'sqlite3'
|
||||
s.add_development_dependency 'minitest'
|
||||
s.add_development_dependency 'ruby-debug-completion'
|
||||
|
||||
s.files = `git ls-files`.split("\n")
|
||||
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
||||
|
|
|
@ -50,6 +50,13 @@ module AASM
|
|||
sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block)
|
||||
end
|
||||
|
||||
# an addition over standard aasm so that, before firing an event, you can ask
|
||||
# may_event? and get back a boolean that tells you whether the guard method
|
||||
# on the transition will let this happen.
|
||||
define_method("may_#{name.to_s}?") do |*args|
|
||||
aasm_test_event(name, *args)
|
||||
end
|
||||
|
||||
define_method("#{name.to_s}!") do |*args|
|
||||
aasm_fire_event(name, true, *args)
|
||||
end
|
||||
|
@ -104,6 +111,12 @@ module AASM
|
|||
aasm_events_for_state(aasm_current_state)
|
||||
end
|
||||
|
||||
# filters the results of events_for_current_state so that only those that
|
||||
# are really currently possible (given transition guards) are shown.
|
||||
def aasm_permissible_events_for_current_state
|
||||
aasm_events_for_current_state.select{ |e| self.send(("may_" + e.to_s + "?").to_sym) }
|
||||
end
|
||||
|
||||
def aasm_events_for_state(state)
|
||||
events = self.class.aasm_events.values.select {|event| event.transitions_from_state?(state) }
|
||||
events.map {|event| event.name}
|
||||
|
@ -149,6 +162,11 @@ module AASM
|
|||
obj
|
||||
end
|
||||
|
||||
def aasm_test_event(name, *args)
|
||||
event = self.class.aasm_events[name]
|
||||
event.may_fire?(self, *args)
|
||||
end
|
||||
|
||||
def aasm_fire_event(name, persist, *args)
|
||||
event = self.class.aasm_events[name]
|
||||
begin
|
||||
|
|
|
@ -7,6 +7,24 @@ class AASM::SupportingClasses::Event
|
|||
update(options, &block)
|
||||
end
|
||||
|
||||
# a neutered version of fire - it doesn't actually fir the event, it just
|
||||
# executes the transition guards to determine if a transition is even
|
||||
# an option given current conditions.
|
||||
def may_fire?(obj, to_state=nil)
|
||||
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
|
||||
return false if transitions.size == 0
|
||||
|
||||
result = false
|
||||
transitions.each do |transition|
|
||||
next if to_state and !Array(transition.to).include?(to_state)
|
||||
if transition.perform(obj)
|
||||
result = true
|
||||
break
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def fire(obj, to_state=nil, *args)
|
||||
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
|
||||
raise AASM::InvalidTransition, "Event '#{name}' cannot transition from '#{obj.aasm_current_state}'" if transitions.size == 0
|
||||
|
|
|
@ -36,10 +36,10 @@ class AASM::SupportingClasses::StateTransition
|
|||
|
||||
def _execute(obj, on_transition, *args)
|
||||
case on_transition
|
||||
when Symbol, String
|
||||
obj.send(on_transition, *args)
|
||||
when Proc
|
||||
on_transition.call(obj, *args)
|
||||
on_transition.arity == 0 ? on_transition.call : on_transition.call(obj, *args)
|
||||
when Symbol, String
|
||||
obj.send(:method, on_transition.to_sym).arity == 0 ? obj.send(on_transition) : obj.send(on_transition, *args)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ require 'aasm'
|
|||
|
||||
require 'rspec'
|
||||
require 'rspec/autorun'
|
||||
require 'ruby-debug'; Debugger.settings[:autoeval] = true; debugger; rubys_debugger = 'annoying'
|
||||
require 'ruby-debug/completion'
|
||||
|
||||
def load_schema
|
||||
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
||||
|
|
|
@ -82,3 +82,82 @@ describe AASM::SupportingClasses::StateTransition, '- when performing guard chec
|
|||
st.perform(obj)
|
||||
end
|
||||
end
|
||||
|
||||
describe AASM::SupportingClasses::StateTransition, '- when executing the transition with a Proc' do
|
||||
it 'should call a Proc on the object with args' do
|
||||
opts = {:from => 'foo', :to => 'bar', :on_transition => Proc.new {|o| o.test}}
|
||||
st = AASM::SupportingClasses::StateTransition.new(opts)
|
||||
args = {:arg1 => '1', :arg2 => '2'}
|
||||
obj = mock('object')
|
||||
|
||||
opts[:on_transition].should_receive(:call).with(any_args)
|
||||
|
||||
st.execute(obj, args)
|
||||
end
|
||||
|
||||
it 'should call a Proc on the object without args' do
|
||||
opts = {:from => 'foo', :to => 'bar', :on_transition => Proc.new {||}}
|
||||
st = AASM::SupportingClasses::StateTransition.new(opts)
|
||||
args = {:arg1 => '1', :arg2 => '2'}
|
||||
obj = mock('object')
|
||||
|
||||
opts[:on_transition].should_receive(:call).with(no_args)
|
||||
|
||||
st.execute(obj, args)
|
||||
end
|
||||
end
|
||||
|
||||
describe AASM::SupportingClasses::StateTransition, '- when executing the transition with an :on_transtion method call' do
|
||||
it 'should accept a String for the method name' do
|
||||
opts = {:from => 'foo', :to => 'bar', :on_transition => 'test'}
|
||||
st = AASM::SupportingClasses::StateTransition.new(opts)
|
||||
args = {:arg1 => '1', :arg2 => '2'}
|
||||
obj = mock('object')
|
||||
|
||||
obj.should_receive(:test)
|
||||
|
||||
st.execute(obj, args)
|
||||
end
|
||||
|
||||
it 'should accept a Symbol for the method name' do
|
||||
opts = {:from => 'foo', :to => 'bar', :on_transition => :test}
|
||||
st = AASM::SupportingClasses::StateTransition.new(opts)
|
||||
args = {:arg1 => '1', :arg2 => '2'}
|
||||
obj = mock('object')
|
||||
|
||||
obj.should_receive(:test)
|
||||
|
||||
st.execute(obj, args)
|
||||
end
|
||||
|
||||
it 'should pass args if the target method accepts them' do
|
||||
opts = {:from => 'foo', :to => 'bar', :on_transition => :test}
|
||||
st = AASM::SupportingClasses::StateTransition.new(opts)
|
||||
args = {:arg1 => '1', :arg2 => '2'}
|
||||
obj = mock('object')
|
||||
|
||||
obj.class.class_eval do
|
||||
define_method(:test) {|*args| 'success'}
|
||||
end
|
||||
|
||||
return_value = st.execute(obj, args)
|
||||
|
||||
return_value.should == 'success'
|
||||
end
|
||||
|
||||
it 'should NOT pass args if the target method does NOT accept them' do
|
||||
opts = {:from => 'foo', :to => 'bar', :on_transition => :test}
|
||||
st = AASM::SupportingClasses::StateTransition.new(opts)
|
||||
args = {:arg1 => '1', :arg2 => '2'}
|
||||
obj = mock('object')
|
||||
|
||||
obj.class.class_eval do
|
||||
define_method(:test) {|*args| 'success'}
|
||||
end
|
||||
|
||||
return_value = st.execute(obj, args)
|
||||
|
||||
return_value.should == 'success'
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -29,6 +29,11 @@ class AuthMachine
|
|||
transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
|
||||
end
|
||||
|
||||
# a dummy event that can never happen
|
||||
aasm_event :unpassify do
|
||||
transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
|
||||
end
|
||||
|
||||
aasm_event :unsuspend do
|
||||
transitions :from => :suspended, :to => :active, :guard => Proc.new {|u| u.has_activated? }
|
||||
transitions :from => :suspended, :to => :pending, :guard => Proc.new {|u| u.has_activation_code? }
|
||||
|
@ -89,6 +94,29 @@ class AuthMachineTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
context 'when being unsuspended' do
|
||||
|
||||
should 'be able to be unsuspended' do
|
||||
@auth = AuthMachine.new
|
||||
@auth.activate!
|
||||
@auth.suspend!
|
||||
assert @auth.may_unsuspend?
|
||||
end
|
||||
|
||||
should 'not be able to be unsuspended into active' do
|
||||
@auth = AuthMachine.new
|
||||
@auth.suspend!
|
||||
assert_equal false, @auth.may_unsuspend?(:active)
|
||||
end
|
||||
|
||||
should 'not be able to be unpassified' do
|
||||
@auth = AuthMachine.new
|
||||
@auth.activate!
|
||||
@auth.suspend!
|
||||
@auth.unsuspend!
|
||||
|
||||
assert_equal false, @auth.may_unpassify?
|
||||
end
|
||||
|
||||
should 'be active if previously activated' do
|
||||
@auth = AuthMachine.new
|
||||
@auth.activate!
|
||||
|
|
|
@ -33,8 +33,8 @@ class Test::Unit::TestCase
|
|||
end
|
||||
|
||||
begin
|
||||
require 'ruby-debug'
|
||||
Debugger.start
|
||||
require 'ruby-debug'; Debugger.settings[:autoeval] = true; debugger; rubys_debugger = 'annoying'
|
||||
require 'ruby-debug/completion'
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue