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 alto
.rspec .rspec
.bundle .bundle
tags

View file

@ -20,6 +20,10 @@
* **DSL change**: renamed permissible states and events to permitted states events * **DSL change**: renamed permissible states and events to permitted states events
* removed deprecated methods (mostly the ones prefixed with `aasm_`) * 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 ## 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)) * 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 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 ### 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. 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) def initialize(name, options = {}, &block)
@name = name @name = name
@transitions = [] @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 ? @options = options # QUESTION: .dup ?
add_options_from_dsl(@options, [:after, :before, :error, :success], &block) if block add_options_from_dsl(@options, [:after, :before, :error, :success], &block) if block
end end
@ -72,8 +75,12 @@ module AASM
def attach_event_guards(definitions) def attach_event_guards(definitions)
unless @guards.empty? unless @guards.empty?
given_guards = Array(definitions.delete(:guard) || definitions.delete(:guards)) given_guards = Array(definitions.delete(:guard) || definitions.delete(:guards) || definitions.delete(:if))
definitions[:guards] = @guards + given_guards definitions[:guards] = @guards + given_guards # from aasm4
end
unless @unless.empty?
given_unless = Array(definitions.delete(:unless))
definitions[:unless] = given_unless + @unless
end end
definitions definitions
end end
@ -99,7 +106,7 @@ module AASM
transitions.each do |transition| transitions.each do |transition|
next if to_state and !Array(transition.to).include?(to_state) next if to_state and !Array(transition.to).include?(to_state)
if transition.perform(obj, *args) if transition.allowed?(obj, *args)
if test if test
result = true result = true
else else

View file

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

View file

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

View file

@ -26,7 +26,7 @@ describe 'callbacks for the new DSL' do
end end
it "does not run any state callback if the event guard fails" do 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 callback.aasm.current_state
expect(callback).to receive(:before).once.ordered 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'} opts = {:from => 'foo', :to => 'bar'}
st = AASM::Transition.new(opts) st = AASM::Transition.new(opts)
expect(st.perform(nil)).to be_true expect(st.allowed?(nil)).to be_true
end end
it 'should call the method on the object if guard is a symbol' do 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') obj = double('object')
expect(obj).to receive(:test) 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 end
it 'should call the method on the object if guard is a string' do 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') obj = double('object')
expect(obj).to receive(:test) 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 end
it 'should call the proc passing the object if the guard is a proc' do 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') obj = double('object')
expect(obj).to receive(:test) expect(obj).to receive(:test)
st.perform(obj) expect(st.allowed?(obj)).to be false
end end
end end