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

support event guards #85

This commit is contained in:
Thorsten Böttger 2014-01-24 12:02:22 +01:00
parent 39f85dbfdf
commit 5f8be13c8c
5 changed files with 80 additions and 16 deletions

View file

@ -6,9 +6,10 @@
## 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))
* allow configuring behavior of nested transactions (see [issue #107](https://github.com/aasm/aasm/issues/107))
* support multiple guards per transition
* support event guards (see [issue #85](https://github.com/aasm/aasm/issues/85))
## 3.0.26

View file

@ -196,11 +196,22 @@ job.sleep # => raises AASM::InvalidTransition
You can even provide a number of guards, which all have to succeed to proceed
```ruby
def walked_the_dog?; ...; end
event :sleep do
transitions :from => :running, :to => :sleeping, :guards => [:cleaning_needed?, :walked_the_dog?]
end
```
If you want to provide guards for all transitions withing an event, you can use event guards
```ruby
event :sleep, :guards => [:walked_the_dog?] do
transitions :from => :running, :to => :sleeping, :guards => [:cleaning_needed?]
transitions :from => :cleaning, :to => :sleeping
end
```
### ActiveRecord
AASM comes with support for ActiveRecord and allows automatical persisting of the object's

View file

@ -6,6 +6,7 @@ module AASM
def initialize(name, options = {}, &block)
@name = name
@transitions = []
@guards = Array(options[:guard] || options[:guards])
update(options, &block)
end
@ -57,18 +58,28 @@ module AASM
## DSL interface
def transitions(definitions=nil)
if definitions # define new transitions
# Create a separate transition for each from state to the given state
# Create a separate transition for each from-state to the given state
Array(definitions[:from]).each do |s|
@transitions << AASM::Transition.new(definitions.merge({:from => s.to_sym}))
@transitions << AASM::Transition.new(attach_event_guards(definitions.merge(:from => s.to_sym)))
end
# Create a transition if :to is specified without :from (transitions from ANY state)
if @transitions.empty? && definitions[:to]
@transitions << AASM::Transition.new(attach_event_guards(definitions))
end
# Create a transition if to is specified without from (transitions from ANY state)
@transitions << AASM::Transition.new(definitions) if @transitions.empty? && definitions[:to]
end
@transitions
end
private
def attach_event_guards(definitions)
unless @guards.empty?
given_guards = Array(definitions.delete(:guard) || definitions.delete(:guards))
definitions[:guards] = given_guards + @guards
end
definitions
end
def update(options = {}, &block)
@options = options
if block then

View file

@ -11,6 +11,7 @@ class Guardian
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
@ -20,18 +21,28 @@ class Guardian
event :use_guards_where_the_second_fails do
transitions :from => :alpha, :to => :beta, :guards => [:fail, :succeed]
end
event :use_event_guards_that_succeed, :guards => [:succeed, :another_succeed] do
transitions :from => :alpha, :to => :beta
end
event :use_event_and_transition_guards_that_succeed, :guards => [:succeed, :another_succeed] do
transitions :from => :alpha, :to => :beta, :guards => [:more_succeed]
end
event :use_event_guards_where_the_first_fails, :guards => [:succeed, :fail] do
transitions :from => :alpha, :to => :beta
end
event :use_event_guards_where_the_second_fails, :guards => [:fail, :succeed] do
transitions :from => :alpha, :to => :beta, :guard => :another_succeed
end
event :use_event_and_transition_guards_where_third_fails, :guards => [:succeed, :another_succeed] do
transitions :from => :alpha, :to => :beta, :guards => [:fail]
end
end
def fail
false
end
def fail; false; end
def succeed
true
end
def another_succeed
true
end
def succeed; true; end
def another_succeed; true; end
def more_succeed; true; end
end

View file

@ -28,3 +28,33 @@ describe "per-transition guards" do
expect(guardian).to be_alpha
end
end
describe "event guards" do
let(:guardian) { Guardian.new }
it "allows the transition if the event guards succeed" do
expect { guardian.use_event_guards_that_succeed! }.to_not raise_error
expect(guardian).to be_beta
end
it "allows the transition if the event and transition guards succeed" do
expect { guardian.use_event_and_transition_guards_that_succeed! }.to_not raise_error
expect(guardian).to be_beta
end
it "stops the transition if the first event guard fails" do
expect { guardian.use_event_guards_where_the_first_fails! }.to raise_error(AASM::InvalidTransition)
expect(guardian).to be_alpha
end
it "stops the transition if the second event guard fails" do
expect { guardian.use_event_guards_where_the_second_fails! }.to raise_error(AASM::InvalidTransition)
expect(guardian).to be_alpha
end
it "stops the transition if the transition guard fails" do
expect { guardian.use_event_and_transition_guards_where_third_fails! }.to raise_error(AASM::InvalidTransition)
expect(guardian).to be_alpha
end
end