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

support multiple guards per transition

This commit is contained in:
Thorsten Böttger 2014-01-24 11:12:43 +01:00
parent cc19ab60fd
commit 39f85dbfdf
5 changed files with 85 additions and 6 deletions

View file

@ -6,6 +6,7 @@
## 3.1.0 (not yet released)
* support multiple guards per transition
* allow configuring behavior of nested transactions (see [issue #107](https://github.com/aasm/aasm/issues/107))
* validating the current state (see [issue #95](https://github.com/aasm/aasm/issues/95), thanks to [@ivantsepp](https://github.com/ivantsepp))

View file

@ -193,6 +193,13 @@ job.may_sleep? # => false
job.sleep # => raises AASM::InvalidTransition
```
You can even provide a number of guards, which all have to succeed to proceed
```ruby
event :sleep do
transitions :from => :running, :to => :sleeping, :guards => [:cleaning_needed?, :walked_the_dog?]
end
```
### ActiveRecord

View file

@ -4,20 +4,24 @@ module AASM
alias_method :options, :opts
def initialize(opts)
@from, @to, @guard, @on_transition = opts[:from], opts[:to], opts[:guard], opts[:on_transition]
@from = opts[:from]
@to = opts[:to]
@guards = Array(opts[:guard] || opts[:guards])
@on_transition = opts[:on_transition]
@opts = opts
end
# TODO: should be named allowed? or similar
def perform(obj, *args)
case @guard
@guards.each do |guard|
case guard
when Symbol, String
obj.send(@guard, *args)
return false unless obj.send(guard, *args)
when Proc
@guard.call(obj, *args)
else
true
return false unless guard.call(obj, *args)
end
end
true
end
def execute(obj, *args)

37
spec/models/guardian.rb Normal file
View file

@ -0,0 +1,37 @@
class Guardian
include AASM
aasm do
state :alpha, :initial => true
state :beta
event :use_one_guard_that_succeeds do
transitions :from => :alpha, :to => :beta, :guard => :succeed
end
event :use_one_guard_that_fails do
transitions :from => :alpha, :to => :beta, :guard => :fail
end
event :use_guards_that_succeed do
transitions :from => :alpha, :to => :beta, :guards => [:succeed, :another_succeed]
end
event :use_guards_where_the_first_fails do
transitions :from => :alpha, :to => :beta, :guards => [:succeed, :fail]
end
event :use_guards_where_the_second_fails do
transitions :from => :alpha, :to => :beta, :guards => [:fail, :succeed]
end
end
def fail
false
end
def succeed
true
end
def another_succeed
true
end
end

30
spec/unit/guard_spec.rb Normal file
View file

@ -0,0 +1,30 @@
require 'spec_helper'
describe "per-transition guards" do
let(:guardian) { Guardian.new }
it "allows the transition if the guard succeeds" do
expect { guardian.use_one_guard_that_succeeds! }.to_not raise_error
expect(guardian).to be_beta
end
it "stops the transition if the guard fails" do
expect { guardian.use_one_guard_that_fails! }.to raise_error(AASM::InvalidTransition)
expect(guardian).to be_alpha
end
it "allows the transition if all guards succeeds" do
expect { guardian.use_guards_that_succeed! }.to_not raise_error
expect(guardian).to be_beta
end
it "stops the transition if the first guard fails" do
expect { guardian.use_guards_where_the_first_fails! }.to raise_error(AASM::InvalidTransition)
expect(guardian).to be_alpha
end
it "stops the transition if the second guard fails" do
expect { guardian.use_guards_where_the_second_fails! }.to raise_error(AASM::InvalidTransition)
expect(guardian).to be_alpha
end
end