1
0
Fork 0
mirror of https://github.com/aasm/aasm synced 2023-03-27 23:22:41 -04:00

Merge branch 'master' into aasm4

Conflicts:
	CHANGELOG.md
	lib/aasm/event.rb
	lib/aasm/transition.rb
This commit is contained in:
Thorsten Böttger 2014-11-15 12:24:56 +01:00
commit 7d32335b60
8 changed files with 73 additions and 17 deletions

2
.gitignore vendored
View file

@ -16,4 +16,4 @@ TODO
alto
.rspec
.bundle
tags

View file

@ -20,6 +20,10 @@
* **DSL change**: renamed permissible states and events to permitted states events
* removed deprecated methods (mostly the ones prefixed with `aasm_`)
## 3.5.0 (not yet released)
* support `if` and `unless` guard syntax: (see [issue #179](https://github.com/aasm/aasm/issues/179) and [issue #181](https://github.com/aasm/aasm/issues/181)), thanks to [@bigtunacan](https://github.com/bigtunacan)
## 3.4.0
* allow retrieving the current event (`aasm.current_event`) (see [issue #159](https://github.com/aasm/aasm/issues/159) and [issue #168](https://github.com/aasm/aasm/issues/168))

View file

@ -264,6 +264,20 @@ If you want to provide guards for all transitions within an event, you can use e
end
```
If you prefer a more Ruby-like guard syntax, you can use `if` and `unless` as well:
```ruby
event :clean do
transitions :from => :running, :to => :cleaning, :unless => :cleaning_needed?
end
event :sleep do
transitions :from => :running, :to => :sleeping, :if => :cleaning_needed?
end
end
```
### Transitions
In the event of having multiple transitions for an event, the first transition that successfully completes will stop other transitions in the same event from being processed.

View file

@ -7,7 +7,10 @@ module AASM
def initialize(name, options = {}, &block)
@name = name
@transitions = []
@guards = Array(options[:guard] || options[:guards])
@guards = Array(options[:guard] || options[:guards] || options[:if])
@unless = Array(options[:unless]) #TODO: This could use a better name
# from aasm4
@options = options # QUESTION: .dup ?
add_options_from_dsl(@options, [:after, :before, :error, :success], &block) if block
end
@ -72,8 +75,12 @@ module AASM
def attach_event_guards(definitions)
unless @guards.empty?
given_guards = Array(definitions.delete(:guard) || definitions.delete(:guards))
definitions[:guards] = @guards + given_guards
given_guards = Array(definitions.delete(:guard) || definitions.delete(:guards) || definitions.delete(:if))
definitions[:guards] = @guards + given_guards # from aasm4
end
unless @unless.empty?
given_unless = Array(definitions.delete(:unless))
definitions[:unless] = given_unless + @unless
end
definitions
end
@ -99,7 +106,7 @@ module AASM
transitions.each do |transition|
next if to_state and !Array(transition.to).include?(to_state)
if transition.perform(obj, *args)
if transition.allowed?(obj, *args)
if test
result = true
else

View file

@ -8,19 +8,24 @@ module AASM
def initialize(opts, &block)
add_options_from_dsl(opts, [:on_transition, :guard, :after], &block) if block
@from, @to, @guards = opts[:from], opts[:to], Array(opts[:guard] || opts[:guards])
@from = opts[:from]
@to = opts[:to]
@guards = Array(opts[:guard] || opts[:guards] || opts[:if])
@unless = Array(opts[:unless]) #TODO: This could use a better name
if opts[:on_transition]
warn '[DEPRECATION] :on_transition is deprecated, use :after instead'
opts[:after] = Array(opts[:after]) + Array(opts[:on_transition])
end
@after = Array(opts[:after])
@after = @after[0] if @after.size == 1
@opts = opts
end
# TODO: should be named allowed? or similar
def perform(obj, *args)
invoke_callbacks_compatible_with_guard(@guards, obj, args, :guard => true)
def allowed?(obj, *args)
invoke_callbacks_compatible_with_guard(@guards, obj, args, :guard => true) &&
invoke_callbacks_compatible_with_guard(@unless, obj, args, :unless => true)
end
def execute(obj, *args)
@ -52,9 +57,14 @@ module AASM
# QUESTION : record.instance_exec(*args, &code) ?
code.arity == 0 ? record.instance_exec(&code) : record.instance_exec(*args, &code)
when Array
if options[:guard] # guard callbacks
if options[:guard]
# invoke guard callbacks
code.all? {|a| invoke_callbacks_compatible_with_guard(a, record, args)}
else # after callbacks
elsif options[:unless]
# invoke unless callbacks
code.all? {|a| !invoke_callbacks_compatible_with_guard(a, record, args)}
else
# invoke after callbacks
code.map {|a| invoke_callbacks_compatible_with_guard(a, record, args)}
end
else

View file

@ -4,6 +4,7 @@ class CallbackNewDsl
def initialize(options={})
@fail_event_guard = options[:fail_event_guard]
@fail_transition_guard = options[:fail_transition_guard]
@log = options[:log]
end
aasm do
@ -33,7 +34,7 @@ class CallbackNewDsl
end
def log(text)
# puts text
puts text if @log
end
def before_enter_open; log('before_enter_open'); end

View file

@ -26,7 +26,7 @@ describe 'callbacks for the new DSL' do
end
it "does not run any state callback if the event guard fails" do
callback = CallbackNewDsl.new
callback = CallbackNewDsl.new(:log => false)
callback.aasm.current_state
expect(callback).to receive(:before).once.ordered

View file

@ -124,7 +124,7 @@ describe AASM::Transition, '- when performing guard checks' do
opts = {:from => 'foo', :to => 'bar'}
st = AASM::Transition.new(opts)
expect(st.perform(nil)).to be_true
expect(st.allowed?(nil)).to be_true
end
it 'should call the method on the object if guard is a symbol' do
@ -134,7 +134,17 @@ describe AASM::Transition, '- when performing guard checks' do
obj = double('object')
expect(obj).to receive(:test)
st.perform(obj)
expect(st.allowed?(obj)).to be false
end
it 'should call the method on the object if unless is a symbol' do
opts = {:from => 'foo', :to => 'bar', :unless => :test}
st = AASM::Transition.new(opts)
obj = double('object')
expect(obj).to receive(:test)
expect(st.allowed?(obj)).to be true
end
it 'should call the method on the object if guard is a string' do
@ -144,7 +154,17 @@ describe AASM::Transition, '- when performing guard checks' do
obj = double('object')
expect(obj).to receive(:test)
st.perform(obj)
expect(st.allowed?(obj)).to be false
end
it 'should call the method on the object if unless is a string' do
opts = {:from => 'foo', :to => 'bar', :unless => 'test'}
st = AASM::Transition.new(opts)
obj = double('object')
expect(obj).to receive(:test)
expect(st.allowed?(obj)).to be true
end
it 'should call the proc passing the object if the guard is a proc' do
@ -154,7 +174,7 @@ describe AASM::Transition, '- when performing guard checks' do
obj = double('object')
expect(obj).to receive(:test)
st.perform(obj)
expect(st.allowed?(obj)).to be false
end
end