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:
commit
7d32335b60
8 changed files with 73 additions and 17 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -16,4 +16,4 @@ TODO
|
||||||
alto
|
alto
|
||||||
.rspec
|
.rspec
|
||||||
.bundle
|
.bundle
|
||||||
|
tags
|
||||||
|
|
|
@ -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))
|
||||||
|
|
14
README.md
14
README.md
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue