make sure to use parameterised aasm everywhere

This commit is contained in:
Thorsten Böttger 2015-05-13 22:12:59 +12:00
parent b3113ceb9d
commit cf7ac74664
12 changed files with 86 additions and 58 deletions

View File

@ -28,20 +28,20 @@ module AASM
def aasm(*args, &block)
if args[0].is_a?(Symbol) || args[0].is_a?(String)
# using custom name
name = args[0].to_sym
state_machine_name = args[0].to_sym
options = args[1] || {}
else
# using the default name
name = :default
# using the default state_machine_name
state_machine_name = :default
options = args[0] || {}
end
AASM::StateMachine[self][name] ||= AASM::StateMachine.new
AASM::StateMachine[self][state_machine_name] ||= AASM::StateMachine.new(state_machine_name)
@aasm ||= {}
@aasm[name] ||= AASM::Base.new(self, name, AASM::StateMachine[self][name], options)
@aasm[name].instance_eval(&block) if block # new DSL
@aasm[name]
@aasm[state_machine_name] ||= AASM::Base.new(self, state_machine_name, AASM::StateMachine[self][state_machine_name], options)
@aasm[state_machine_name].instance_eval(&block) if block # new DSL
@aasm[state_machine_name]
end
end # ClassMethods
@ -76,7 +76,7 @@ private
event.fire_callbacks(
:before,
self,
*process_args(event, aasm.current_state, *args)
*process_args(event, aasm(state_machine_name).current_state, *args)
)
if may_fire_to = event.may_fire?(self, *args)
@ -146,7 +146,7 @@ private
end
if AASM::StateMachine[self.class][state_machine_name].config.whiny_transitions
raise AASM::InvalidTransition.new(self, event_name)
raise AASM::InvalidTransition.new(self, event_name, state_machine_name)
else
false
end

View File

@ -75,7 +75,7 @@ module AASM
# define an event
def event(name, options={}, &block)
@state_machine.events[name] = AASM::Core::Event.new(name, options, &block)
@state_machine.add_event(name, options, &block)
if @klass.instance_methods.include?("may_#{name}?")
warn "The event name #{name} is already used!"

View File

@ -2,10 +2,11 @@ module AASM::Core
class Event
include DslHelper
attr_reader :name, :options
attr_reader :name, :state_machine, :options
def initialize(name, options = {}, &block)
def initialize(name, state_machine, options = {}, &block)
@name = name
@state_machine = state_machine
@transitions = []
@guards = Array(options[:guard] || options[:guards] || options[:if])
@unless = Array(options[:unless]) #TODO: This could use a better name
@ -61,11 +62,11 @@ module AASM::Core
if definitions # define new transitions
# Create a separate transition for each from-state to the given state
Array(definitions[:from]).each do |s|
@transitions << AASM::Core::Transition.new(attach_event_guards(definitions.merge(:from => s.to_sym)), &block)
@transitions << AASM::Core::Transition.new(self, attach_event_guards(definitions.merge(:from => s.to_sym)), &block)
end
# Create a transition if :to is specified without :from (transitions from ANY state)
if @transitions.empty? && definitions[:to]
@transitions << AASM::Core::Transition.new(attach_event_guards(definitions), &block)
@transitions << AASM::Core::Transition.new(self, attach_event_guards(definitions), &block)
end
end
@transitions
@ -89,7 +90,7 @@ module AASM::Core
def _fire(obj, options={}, to_state=nil, *args)
result = options[:test_only] ? false : nil
if @transitions.map(&:from).any?
transitions = @transitions.select { |t| t.from == obj.aasm.current_state }
transitions = @transitions.select { |t| t.from == obj.aasm(state_machine.name).current_state }
return result if transitions.size == 0
else
transitions = @transitions

View File

@ -1,10 +1,11 @@
module AASM::Core
class State
attr_reader :name, :options
attr_reader :name, :state_machine, :options
def initialize(name, klass, options={})
def initialize(name, klass, state_machine, options={})
@name = name
@klass = klass
@state_machine = state_machine
update(options)
end

View File

@ -2,12 +2,13 @@ module AASM::Core
class Transition
include DslHelper
attr_reader :from, :to, :opts
attr_reader :from, :to, :event, :opts
alias_method :options, :opts
def initialize(opts, &block)
def initialize(event, opts, &block)
add_options_from_dsl(opts, [:on_transition, :guard, :after], &block) if block
@event = event
@from = opts[:from]
@to = opts[:to]
@guards = Array(opts[:guards]) + Array(opts[:guard]) + Array(opts[:if])
@ -44,8 +45,8 @@ module AASM::Core
def invoke_callbacks_compatible_with_guard(code, record, args, options={})
if record.respond_to?(:aasm)
record.aasm.from_state = @from if record.aasm.respond_to?(:from_state=)
record.aasm.to_state = @to if record.aasm.respond_to?(:to_state=)
record.aasm(event.state_machine.name).from_state = @from if record.aasm(event.state_machine.name).respond_to?(:from_state=)
record.aasm(event.state_machine.name).to_state = @to if record.aasm(event.state_machine.name).respond_to?(:to_state=)
end
case code

View File

@ -1,13 +1,14 @@
module AASM
class InvalidTransition < RuntimeError
attr_reader :object, :event_name
def initialize(object, event_name)
@object, @event_name = object, event_name
attr_reader :object, :event_name, :state_machine_name
def initialize(object, event_name, state_machine_name)
@object, @event_name, @state_machine_name = object, event_name, state_machine_name
end
def message
"Event '#{event_name}' cannot transition from '#{object.aasm.current_state}'"
"Event '#{event_name}' cannot transition from '#{object.aasm(state_machine_name).current_state}'"
end
end

View File

@ -30,7 +30,7 @@ module AASM
end
def human_state
AASM::Localizer.new.human_state_name(@instance.class, current_state)
AASM::Localizer.new.human_state_name(@instance.class, state_object_for_name(current_state))
end
def states(options={})

View File

@ -21,7 +21,7 @@ module AASM
def item_for(klass, state, ancestor, options={})
separator = options[:old_style] ? '.' : '/'
:"#{i18n_scope(klass)}.attributes.#{i18n_klass(ancestor)}.#{klass.aasm.attribute_name}#{separator}#{state}"
:"#{i18n_scope(klass)}.attributes.#{i18n_klass(ancestor)}.#{klass.aasm(state.state_machine.name).attribute_name}#{separator}#{state}"
end
def translate_queue(checklist)

View File

@ -12,11 +12,12 @@ module AASM
attr_accessor :states, :events, :initial_state, :config, :name
def initialize
def initialize(name)
@initial_state = nil
@states = []
@events = {}
@config = AASM::Configuration.new
@name = name
end
# called internally by Ruby 1.9 after clone()
@ -26,13 +27,17 @@ module AASM
@events = @events.dup
end
def add_state(name, klass, options)
set_initial_state(name, options)
def add_state(state_name, klass, options)
set_initial_state(state_name, options)
# allow reloading, extending or redefining a state
@states.delete(name) if @states.include?(name)
@states.delete(state_name) if @states.include?(state_name)
@states << AASM::Core::State.new(name, klass, options)
@states << AASM::Core::State.new(state_name, klass, self, options)
end
def add_event(name, options, &block)
@events[name] = AASM::Core::Event.new(name, self, options, &block)
end
private

View File

@ -1,8 +1,9 @@
require 'spec_helper'
describe 'adding an event' do
let(:state_machine) { AASM::StateMachine.new(:name) }
let(:event) do
AASM::Core::Event.new(:close_order, {:success => :success_callback}) do
AASM::Core::Event.new(:close_order, state_machine, {:success => :success_callback}) do
before :before_callback
after :after_callback
transitions :to => :closed, :from => [:open, :received]
@ -35,8 +36,9 @@ describe 'adding an event' do
end
describe 'transition inspection' do
let(:state_machine) { AASM::StateMachine.new(:name) }
let(:event) do
AASM::Core::Event.new(:run) do
AASM::Core::Event.new(:run, state_machine) do
transitions :to => :running, :from => :sleeping
end
end
@ -59,8 +61,9 @@ describe 'transition inspection' do
end
describe 'transition inspection without from' do
let(:state_machine) { AASM::StateMachine.new(:name) }
let(:event) do
AASM::Core::Event.new(:run) do
AASM::Core::Event.new(:run, state_machine) do
transitions :to => :running
end
end
@ -76,15 +79,17 @@ describe 'transition inspection without from' do
end
describe 'firing an event' do
let(:state_machine) { AASM::StateMachine.new(:name) }
it 'should return nil if the transitions are empty' do
obj = double('object', :aasm => double('aasm', :current_state => 'open'))
event = AASM::Core::Event.new(:event)
event = AASM::Core::Event.new(:event, state_machine)
expect(event.fire(obj)).to be_nil
end
it 'should return the state of the first matching transition it finds' do
event = AASM::Core::Event.new(:event) do
event = AASM::Core::Event.new(:event, state_machine) do
transitions :to => :closed, :from => [:open, :received]
end
@ -94,7 +99,7 @@ describe 'firing an event' do
end
it 'should call the guard with the params passed in' do
event = AASM::Core::Event.new(:event) do
event = AASM::Core::Event.new(:event, state_machine) do
transitions :to => :closed, :from => [:open, :received], :guard => :guard_fn
end

View File

@ -1,13 +1,15 @@
require 'spec_helper'
describe AASM::Core::State do
let(:state_machine) { AASM::StateMachine.new(:name) }
before(:each) do
@name = :astate
@options = { :crazy_custom_key => 'key' }
end
def new_state(options={})
AASM::Core::State.new(@name, Conversation, @options.merge(options))
AASM::Core::State.new(@name, Conversation, state_machine, @options.merge(options))
end
it 'should set the name' do

View File

@ -57,9 +57,12 @@ describe 'blocks' do
end
describe AASM::Core::Transition do
let(:state_machine) { AASM::StateMachine.new(:name) }
let(:event) { AASM::Core::Event.new(:event, state_machine) }
it 'should set from, to, and opts attr readers' do
opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
expect(st.from).to eq(opts[:from])
expect(st.to).to eq(opts[:to])
@ -71,7 +74,7 @@ describe AASM::Core::Transition do
st = AASM::Core::Transition.allocate
expect(st).to receive(:warn).with('[DEPRECATION] :on_transition is deprecated, use :after instead')
st.send :initialize, opts do
st.send :initialize, event, opts do
guard :gg
on_transition :after_callback
end
@ -81,7 +84,7 @@ describe AASM::Core::Transition do
it 'should set after and guard from dsl' do
opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
st = AASM::Core::Transition.new(opts) do
st = AASM::Core::Transition.new(event, opts) do
guard :gg
after :after_callback
end
@ -92,7 +95,7 @@ describe AASM::Core::Transition do
it 'should pass equality check if from and to are the same' do
opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
obj = double('object')
allow(obj).to receive(:from).and_return(opts[:from])
@ -103,7 +106,7 @@ describe AASM::Core::Transition do
it 'should fail equality check if from are not the same' do
opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
obj = double('object')
allow(obj).to receive(:from).and_return('blah')
@ -114,7 +117,7 @@ describe AASM::Core::Transition do
it 'should fail equality check if to are not the same' do
opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
obj = double('object')
allow(obj).to receive(:from).and_return(opts[:from])
@ -125,16 +128,19 @@ describe AASM::Core::Transition do
end
describe AASM::Core::Transition, '- when performing guard checks' do
let(:state_machine) { AASM::StateMachine.new(:name) }
let(:event) { AASM::Core::Event.new(:event, state_machine) }
it 'should return true of there is no guard' do
opts = {:from => 'foo', :to => 'bar'}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
expect(st.allowed?(nil)).to be_truthy
end
it 'should call the method on the object if guard is a symbol' do
opts = {:from => 'foo', :to => 'bar', :guard => :test}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
obj = double('object')
expect(obj).to receive(:test)
@ -144,7 +150,7 @@ describe AASM::Core::Transition, '- when performing guard checks' do
it 'should call the method on the object if unless is a symbol' do
opts = {:from => 'foo', :to => 'bar', :unless => :test}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
obj = double('object')
expect(obj).to receive(:test)
@ -154,7 +160,7 @@ describe AASM::Core::Transition, '- when performing guard checks' do
it 'should call the method on the object if guard is a string' do
opts = {:from => 'foo', :to => 'bar', :guard => 'test'}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
obj = double('object')
expect(obj).to receive(:test)
@ -164,7 +170,7 @@ describe AASM::Core::Transition, '- when performing guard checks' do
it 'should call the method on the object if unless is a string' do
opts = {:from => 'foo', :to => 'bar', :unless => 'test'}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
obj = double('object')
expect(obj).to receive(:test)
@ -174,7 +180,7 @@ describe AASM::Core::Transition, '- when performing guard checks' do
it 'should call the proc passing the object if the guard is a proc' do
opts = {:from => 'foo', :to => 'bar', :guard => Proc.new { test }}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
obj = double('object')
expect(obj).to receive(:test)
@ -184,9 +190,12 @@ describe AASM::Core::Transition, '- when performing guard checks' do
end
describe AASM::Core::Transition, '- when executing the transition with a Proc' do
let(:state_machine) { AASM::StateMachine.new(:name) }
let(:event) { AASM::Core::Event.new(:event, state_machine) }
it 'should call a Proc on the object with args' do
opts = {:from => 'foo', :to => 'bar', :after => Proc.new {|a| test(a) }}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
args = {:arg1 => '1', :arg2 => '2'}
obj = double('object', :aasm => 'aasm')
@ -202,7 +211,7 @@ describe AASM::Core::Transition, '- when executing the transition with a Proc' d
prc = Proc.new { prc_object = self }
opts = {:from => 'foo', :to => 'bar', :after => prc }
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
args = {:arg1 => '1', :arg2 => '2'}
obj = double('object', :aasm => 'aasm')
@ -212,9 +221,12 @@ describe AASM::Core::Transition, '- when executing the transition with a Proc' d
end
describe AASM::Core::Transition, '- when executing the transition with an :after method call' do
let(:state_machine) { AASM::StateMachine.new(:name) }
let(:event) { AASM::Core::Event.new(:event, state_machine) }
it 'should accept a String for the method name' do
opts = {:from => 'foo', :to => 'bar', :after => 'test'}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
args = {:arg1 => '1', :arg2 => '2'}
obj = double('object', :aasm => 'aasm')
@ -225,7 +237,7 @@ describe AASM::Core::Transition, '- when executing the transition with an :after
it 'should accept a Symbol for the method name' do
opts = {:from => 'foo', :to => 'bar', :after => :test}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
args = {:arg1 => '1', :arg2 => '2'}
obj = double('object', :aasm => 'aasm')
@ -236,7 +248,7 @@ describe AASM::Core::Transition, '- when executing the transition with an :after
it 'should pass args if the target method accepts them' do
opts = {:from => 'foo', :to => 'bar', :after => :test}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
args = {:arg1 => '1', :arg2 => '2'}
obj = double('object', :aasm => 'aasm')
@ -251,7 +263,7 @@ describe AASM::Core::Transition, '- when executing the transition with an :after
it 'should NOT pass args if the target method does NOT accept them' do
opts = {:from => 'foo', :to => 'bar', :after => :test}
st = AASM::Core::Transition.new(opts)
st = AASM::Core::Transition.new(event, opts)
args = {:arg1 => '1', :arg2 => '2'}
obj = double('object', :aasm => 'aasm')
@ -266,7 +278,7 @@ describe AASM::Core::Transition, '- when executing the transition with an :after
it 'should allow accessing the from_state and the to_state' do
opts = {:from => 'foo', :to => 'bar', :after => :test}
transition = AASM::Core::Transition.new(opts)
transition = AASM::Core::Transition.new(event, opts)
args = {:arg1 => '1', :arg2 => '2'}
obj = double('object', :aasm => AASM::InstanceBase.new('object'))