fcoury-aasm 2.1.3 → 2.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +0 -1
- data/README.rdoc +4 -0
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/lib/aasm.rb +8 -0
- data/lib/aasm/aasm.rb +36 -36
- data/lib/aasm/event.rb +92 -81
- data/lib/aasm/persistence.rb +18 -13
- data/lib/aasm/persistence/active_record_persistence.rb +3 -5
- data/lib/aasm/state.rb +49 -51
- data/lib/aasm/state_machine.rb +25 -29
- data/lib/aasm/state_transition.rb +42 -46
- data/lib/aasm/supporting_classes.rb +6 -0
- data/spec/unit/aasm_spec.rb +31 -1
- data/spec/unit/state_spec.rb +11 -0
- metadata +4 -4
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -66,6 +66,8 @@ Here's a quick example highlighting some of the features.
|
|
66
66
|
class Conversation
|
67
67
|
include AASM
|
68
68
|
|
69
|
+
aasm_column :current_state # defaults to aasm_state
|
70
|
+
|
69
71
|
aasm_initial_state :unread
|
70
72
|
|
71
73
|
aasm_state :unread
|
@@ -88,6 +90,8 @@ This example uses a few of the more complex features available.
|
|
88
90
|
|
89
91
|
class Relationship
|
90
92
|
include AASM
|
93
|
+
|
94
|
+
aasm_column :status
|
91
95
|
|
92
96
|
aasm_initial_state Proc.new { |relationship| relationship.strictly_for_fun? ? :intimate : :dating }
|
93
97
|
|
data/Rakefile
CHANGED
@@ -8,8 +8,8 @@ begin
|
|
8
8
|
gem.summary = %Q{State machine mixin for Ruby objects}
|
9
9
|
gem.description = %Q{AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects.}
|
10
10
|
gem.homepage = "http://rubyist.github.com/aasm/"
|
11
|
-
gem.authors = ["Scott Barron", "Scott Petersen", "Travis Tilley"
|
12
|
-
gem.email = "scott@elitists.net, ttilley@gmail.com
|
11
|
+
gem.authors = ["Scott Barron", "Scott Petersen", "Travis Tilley"]
|
12
|
+
gem.email = "scott@elitists.net, ttilley@gmail.com"
|
13
13
|
gem.add_development_dependency "rspec"
|
14
14
|
gem.add_development_dependency "shoulda"
|
15
15
|
gem.add_development_dependency 'sdoc'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.1.
|
1
|
+
2.1.5
|
data/lib/aasm.rb
CHANGED
@@ -1 +1,9 @@
|
|
1
|
+
module AASM
|
2
|
+
end
|
3
|
+
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
require File.join(File.dirname(__FILE__), 'aasm', 'supporting_classes')
|
7
|
+
require File.join(File.dirname(__FILE__), 'aasm', 'state_machine')
|
8
|
+
require File.join(File.dirname(__FILE__), 'aasm', 'persistence')
|
1
9
|
require File.join(File.dirname(__FILE__), 'aasm', 'aasm')
|
data/lib/aasm/aasm.rb
CHANGED
@@ -1,8 +1,3 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'event')
|
2
|
-
require File.join(File.dirname(__FILE__), 'state')
|
3
|
-
require File.join(File.dirname(__FILE__), 'state_machine')
|
4
|
-
require File.join(File.dirname(__FILE__), 'persistence')
|
5
|
-
|
6
1
|
module AASM
|
7
2
|
class InvalidTransition < RuntimeError
|
8
3
|
end
|
@@ -146,50 +141,55 @@ module AASM
|
|
146
141
|
end
|
147
142
|
|
148
143
|
def aasm_fire_event(name, persist, *args)
|
149
|
-
old_state = aasm_state_object_for_state(aasm_current_state)
|
150
144
|
event = self.class.aasm_events[name]
|
145
|
+
begin
|
146
|
+
old_state = aasm_state_object_for_state(aasm_current_state)
|
151
147
|
|
152
|
-
old_state.call_action(:exit, self)
|
153
148
|
|
154
|
-
|
155
|
-
event.call_action(:before, self)
|
149
|
+
old_state.call_action(:exit, self)
|
156
150
|
|
157
|
-
|
151
|
+
# new event before callback
|
152
|
+
event.call_action(:before, self)
|
158
153
|
|
159
|
-
|
160
|
-
new_state = aasm_state_object_for_state(new_state_name)
|
154
|
+
new_state_name = event.fire(self, *args)
|
161
155
|
|
162
|
-
|
163
|
-
|
164
|
-
new_state.call_action(:before_enter, self)
|
156
|
+
unless new_state_name.nil?
|
157
|
+
new_state = aasm_state_object_for_state(new_state_name)
|
165
158
|
|
166
|
-
|
159
|
+
# new before_ callbacks
|
160
|
+
old_state.call_action(:before_exit, self)
|
161
|
+
new_state.call_action(:before_enter, self)
|
167
162
|
|
168
|
-
|
169
|
-
|
170
|
-
persist_successful =
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
163
|
+
new_state.call_action(:enter, self)
|
164
|
+
|
165
|
+
persist_successful = true
|
166
|
+
if persist
|
167
|
+
persist_successful = set_aasm_current_state_with_persistence(new_state_name)
|
168
|
+
event.execute_success_callback(self) if persist_successful
|
169
|
+
else
|
170
|
+
self.aasm_current_state = new_state_name
|
171
|
+
end
|
175
172
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
173
|
+
if persist_successful
|
174
|
+
old_state.call_action(:after_exit, self)
|
175
|
+
new_state.call_action(:after_enter, self)
|
176
|
+
event.call_action(:after, self)
|
180
177
|
|
181
|
-
|
178
|
+
self.aasm_event_fired(name, old_state.name, self.aasm_current_state) if self.respond_to?(:aasm_event_fired)
|
179
|
+
else
|
180
|
+
self.aasm_event_failed(name, old_state.name) if self.respond_to?(:aasm_event_failed)
|
181
|
+
end
|
182
|
+
|
183
|
+
persist_successful
|
182
184
|
else
|
183
|
-
|
184
|
-
|
185
|
+
if self.respond_to?(:aasm_event_failed)
|
186
|
+
self.aasm_event_failed(name, old_state.name)
|
187
|
+
end
|
185
188
|
|
186
|
-
|
187
|
-
else
|
188
|
-
if self.respond_to?(:aasm_event_failed)
|
189
|
-
self.aasm_event_failed(name, old_state.name)
|
189
|
+
false
|
190
190
|
end
|
191
|
-
|
192
|
-
|
191
|
+
rescue StandardError => e
|
192
|
+
event.execute_error_callback(self, e)
|
193
193
|
end
|
194
194
|
end
|
195
195
|
end
|
data/lib/aasm/event.rb
CHANGED
@@ -1,98 +1,109 @@
|
|
1
|
-
|
1
|
+
class AASM::SupportingClasses::Event
|
2
|
+
attr_reader :name, :success, :options
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
def initialize(name, options = {}, &block)
|
9
|
-
@name = name
|
10
|
-
@transitions = []
|
11
|
-
update(options, &block)
|
12
|
-
end
|
4
|
+
def initialize(name, options = {}, &block)
|
5
|
+
@name = name
|
6
|
+
@transitions = []
|
7
|
+
update(options, &block)
|
8
|
+
end
|
13
9
|
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
def fire(obj, to_state=nil, *args)
|
11
|
+
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
|
12
|
+
raise AASM::InvalidTransition, "Event '#{name}' cannot transition from '#{obj.aasm_current_state}'" if transitions.size == 0
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
26
|
-
end
|
27
|
-
next_state
|
14
|
+
next_state = nil
|
15
|
+
transitions.each do |transition|
|
16
|
+
next if to_state and !Array(transition.to).include?(to_state)
|
17
|
+
if transition.perform(obj)
|
18
|
+
next_state = to_state || Array(transition.to).first
|
19
|
+
transition.execute(obj, *args)
|
20
|
+
break
|
28
21
|
end
|
22
|
+
end
|
23
|
+
next_state
|
24
|
+
end
|
29
25
|
|
30
|
-
|
31
|
-
|
32
|
-
|
26
|
+
def transitions_from_state?(state)
|
27
|
+
@transitions.any? { |t| t.from == state }
|
28
|
+
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
def transitions_from_state(state)
|
31
|
+
@transitions.select { |t| t.from == state }
|
32
|
+
end
|
37
33
|
|
38
|
-
|
39
|
-
|
40
|
-
|
34
|
+
def all_transitions
|
35
|
+
@transitions
|
36
|
+
end
|
41
37
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
38
|
+
def call_action(action, record)
|
39
|
+
action = @options[action]
|
40
|
+
action.is_a?(Array) ?
|
41
|
+
action.each {|a| _call_action(a, record)} :
|
42
|
+
_call_action(action, record)
|
43
|
+
end
|
48
44
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
45
|
+
def ==(event)
|
46
|
+
if event.is_a? Symbol
|
47
|
+
name == event
|
48
|
+
else
|
49
|
+
name == event.name
|
50
|
+
end
|
51
|
+
end
|
56
52
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
53
|
+
def update(options = {}, &block)
|
54
|
+
if options.key?(:success) then
|
55
|
+
@success = options[:success]
|
56
|
+
end
|
57
|
+
if options.key?(:error) then
|
58
|
+
@error = options[:error]
|
59
|
+
end
|
60
|
+
if block then
|
61
|
+
instance_eval(&block)
|
62
|
+
end
|
63
|
+
@options = options
|
64
|
+
self
|
65
|
+
end
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
67
|
+
def execute_success_callback(obj, success = nil)
|
68
|
+
callback = success || @success
|
69
|
+
case(callback)
|
70
|
+
when String, Symbol
|
71
|
+
obj.send(callback)
|
72
|
+
when Proc
|
73
|
+
callback.call(obj)
|
74
|
+
when Array
|
75
|
+
callback.each{|meth|self.execute_success_callback(obj, meth)}
|
76
|
+
end
|
77
|
+
end
|
79
78
|
|
80
|
-
|
79
|
+
def execute_error_callback(obj, error, error_callback=nil)
|
80
|
+
callback = error_callback || @error
|
81
|
+
raise error unless callback
|
82
|
+
case(callback)
|
83
|
+
when String, Symbol
|
84
|
+
raise NoMethodError unless obj.respond_to?(callback.to_sym)
|
85
|
+
obj.send(callback, error)
|
86
|
+
when Proc
|
87
|
+
callback.call(obj, error)
|
88
|
+
when Array
|
89
|
+
callback.each{|meth|self.execute_error_callback(obj, error, meth)}
|
90
|
+
end
|
91
|
+
end
|
81
92
|
|
82
|
-
|
83
|
-
case action
|
84
|
-
when Symbol, String
|
85
|
-
record.send(action)
|
86
|
-
when Proc
|
87
|
-
action.call(record)
|
88
|
-
end
|
89
|
-
end
|
93
|
+
private
|
90
94
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
95
|
+
def _call_action(action, record)
|
96
|
+
case action
|
97
|
+
when Symbol, String
|
98
|
+
record.send(action)
|
99
|
+
when Proc
|
100
|
+
action.call(record)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def transitions(trans_opts)
|
105
|
+
Array(trans_opts[:from]).each do |s|
|
106
|
+
@transitions << AASM::SupportingClasses::StateTransition.new(trans_opts.merge({:from => s.to_sym}))
|
96
107
|
end
|
97
108
|
end
|
98
109
|
end
|
data/lib/aasm/persistence.rb
CHANGED
@@ -1,16 +1,21 @@
|
|
1
|
-
module AASM
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
base.send(:include, AASM::Persistence::ActiveRecordPersistence)
|
13
|
-
end
|
1
|
+
module AASM::Persistence
|
2
|
+
|
3
|
+
# Checks to see this class or any of it's superclasses inherit from
|
4
|
+
# ActiveRecord::Base and if so includes ActiveRecordPersistence
|
5
|
+
def self.set_persistence(base)
|
6
|
+
# Use a fancier auto-loading thingy, perhaps. When there are more persistence engines.
|
7
|
+
hierarchy = base.ancestors.map {|klass| klass.to_s}
|
8
|
+
|
9
|
+
if hierarchy.include?("ActiveRecord::Base") or is_mongo_mapper?(hierarchy)
|
10
|
+
require File.join(File.dirname(__FILE__), 'persistence', 'active_record_persistence')
|
11
|
+
base.send(:include, AASM::Persistence::ActiveRecordPersistence)
|
14
12
|
end
|
15
13
|
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def self.is_mongo_mapper?(hierarchy)
|
18
|
+
hierarchy.include?("MongoMapper::Document") or hierarchy.include?("MongoMapper::EmbeddedDocument")
|
19
|
+
end
|
20
|
+
|
16
21
|
end
|
@@ -13,7 +13,7 @@ module AASM
|
|
13
13
|
#
|
14
14
|
# Adds
|
15
15
|
#
|
16
|
-
#
|
16
|
+
# before_validation :aasm_ensure_initial_state, :on => :create
|
17
17
|
#
|
18
18
|
# As a result, it doesn't matter when you define your methods - the following 2 are equivalent
|
19
19
|
#
|
@@ -50,8 +50,7 @@ module AASM
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
53
|
-
|
54
|
-
base.before_validation_on_create :aasm_ensure_initial_state
|
53
|
+
base.respond_to?(:before_validation_on_create) ? base.before_validation_on_create(:aasm_ensure_initial_state) : base.before_validation(:aasm_ensure_initial_state, :on => :create)
|
55
54
|
end
|
56
55
|
|
57
56
|
module ClassMethods
|
@@ -180,7 +179,6 @@ module AASM
|
|
180
179
|
|
181
180
|
module WriteState
|
182
181
|
# Writes <tt>state</tt> to the state column and persists it to the database
|
183
|
-
# using update_attribute (which bypasses validation)
|
184
182
|
#
|
185
183
|
# foo = Foo.find(1)
|
186
184
|
# foo.aasm_current_state # => :opened
|
@@ -193,7 +191,7 @@ module AASM
|
|
193
191
|
old_value = read_attribute(self.class.aasm_column)
|
194
192
|
write_attribute(self.class.aasm_column, state.to_s)
|
195
193
|
|
196
|
-
unless self.save
|
194
|
+
unless self.save
|
197
195
|
write_attribute(self.class.aasm_column, old_value)
|
198
196
|
return false
|
199
197
|
end
|
data/lib/aasm/state.rb
CHANGED
@@ -1,55 +1,53 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
class State
|
4
|
-
attr_reader :name, :options
|
5
|
-
|
6
|
-
def initialize(name, options={})
|
7
|
-
@name = name
|
8
|
-
update(options)
|
9
|
-
end
|
10
|
-
|
11
|
-
def ==(state)
|
12
|
-
if state.is_a? Symbol
|
13
|
-
name == state
|
14
|
-
else
|
15
|
-
name == state.name
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def call_action(action, record)
|
20
|
-
action = @options[action]
|
21
|
-
action.is_a?(Array) ?
|
22
|
-
action.each {|a| _call_action(a, record)} :
|
23
|
-
_call_action(action, record)
|
24
|
-
end
|
25
|
-
|
26
|
-
def display_name
|
27
|
-
@display_name ||= name.to_s.gsub(/_/, ' ').capitalize
|
28
|
-
end
|
29
|
-
|
30
|
-
def for_select
|
31
|
-
[display_name, name.to_s]
|
32
|
-
end
|
33
|
-
|
34
|
-
def update(options = {})
|
35
|
-
if options.key?(:display) then
|
36
|
-
@display_name = options.delete(:display)
|
37
|
-
end
|
38
|
-
@options = options
|
39
|
-
self
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def _call_action(action, record)
|
45
|
-
case action
|
46
|
-
when Symbol, String
|
47
|
-
record.send(action)
|
48
|
-
when Proc
|
49
|
-
action.call(record)
|
50
|
-
end
|
51
|
-
end
|
1
|
+
class AASM::SupportingClasses::State
|
2
|
+
attr_reader :name, :options
|
52
3
|
|
4
|
+
def initialize(name, options={})
|
5
|
+
@name = name
|
6
|
+
update(options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def ==(state)
|
10
|
+
if state.is_a? Symbol
|
11
|
+
name == state
|
12
|
+
else
|
13
|
+
name == state.name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def call_action(action, record)
|
18
|
+
action = @options[action]
|
19
|
+
catch :halt_aasm_chain do
|
20
|
+
action.is_a?(Array) ?
|
21
|
+
action.each {|a| _call_action(a, record)} :
|
22
|
+
_call_action(action, record)
|
53
23
|
end
|
54
24
|
end
|
25
|
+
|
26
|
+
def display_name
|
27
|
+
@display_name ||= name.to_s.gsub(/_/, ' ').capitalize
|
28
|
+
end
|
29
|
+
|
30
|
+
def for_select
|
31
|
+
[display_name, name.to_s]
|
32
|
+
end
|
33
|
+
|
34
|
+
def update(options = {})
|
35
|
+
if options.key?(:display) then
|
36
|
+
@display_name = options.delete(:display)
|
37
|
+
end
|
38
|
+
@options = options
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def _call_action(action, record)
|
45
|
+
case action
|
46
|
+
when Symbol, String
|
47
|
+
record.send(action)
|
48
|
+
when Proc
|
49
|
+
action.call(record)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
55
53
|
end
|
data/lib/aasm/state_machine.rb
CHANGED
@@ -1,36 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
def self.[](*args)
|
6
|
-
(@machines ||= {})[args]
|
7
|
-
end
|
1
|
+
class AASM::StateMachine
|
2
|
+
def self.[](*args)
|
3
|
+
(@machines ||= {})[args]
|
4
|
+
end
|
8
5
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
def self.[]=(*args)
|
7
|
+
val = args.pop
|
8
|
+
(@machines ||= {})[args] = val
|
9
|
+
end
|
13
10
|
|
14
|
-
|
15
|
-
|
11
|
+
attr_accessor :states, :events, :initial_state, :config
|
12
|
+
attr_reader :name
|
16
13
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
14
|
+
def initialize(name)
|
15
|
+
@name = name
|
16
|
+
@initial_state = nil
|
17
|
+
@states = []
|
18
|
+
@events = {}
|
19
|
+
@config = OpenStruct.new
|
20
|
+
end
|
24
21
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
22
|
+
def clone
|
23
|
+
klone = super
|
24
|
+
klone.states = states.clone
|
25
|
+
klone.events = events.clone
|
26
|
+
klone
|
27
|
+
end
|
31
28
|
|
32
|
-
|
33
|
-
|
34
|
-
end
|
29
|
+
def create_state(name, options)
|
30
|
+
@states << AASM::SupportingClasses::State.new(name, options) unless @states.include?(name)
|
35
31
|
end
|
36
32
|
end
|
@@ -1,50 +1,46 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
attr_reader :from, :to, :opts
|
5
|
-
alias_method :options, :opts
|
6
|
-
|
7
|
-
def initialize(opts)
|
8
|
-
@from, @to, @guard, @on_transition = opts[:from], opts[:to], opts[:guard], opts[:on_transition]
|
9
|
-
@opts = opts
|
10
|
-
end
|
11
|
-
|
12
|
-
def perform(obj)
|
13
|
-
case @guard
|
14
|
-
when Symbol, String
|
15
|
-
obj.send(@guard)
|
16
|
-
when Proc
|
17
|
-
@guard.call(obj)
|
18
|
-
else
|
19
|
-
true
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def execute(obj, *args)
|
24
|
-
@on_transition.is_a?(Array) ?
|
25
|
-
@on_transition.each {|ot| _execute(obj, ot, *args)} :
|
26
|
-
_execute(obj, @on_transition, *args)
|
27
|
-
end
|
28
|
-
|
29
|
-
def ==(obj)
|
30
|
-
@from == obj.from && @to == obj.to
|
31
|
-
end
|
32
|
-
|
33
|
-
def from?(value)
|
34
|
-
@from == value
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def _execute(obj, on_transition, *args)
|
40
|
-
case on_transition
|
41
|
-
when Symbol, String
|
42
|
-
obj.send(on_transition, *args)
|
43
|
-
when Proc
|
44
|
-
on_transition.call(obj, *args)
|
45
|
-
end
|
46
|
-
end
|
1
|
+
class AASM::SupportingClasses::StateTransition
|
2
|
+
attr_reader :from, :to, :opts
|
3
|
+
alias_method :options, :opts
|
47
4
|
|
5
|
+
def initialize(opts)
|
6
|
+
@from, @to, @guard, @on_transition = opts[:from], opts[:to], opts[:guard], opts[:on_transition]
|
7
|
+
@opts = opts
|
8
|
+
end
|
9
|
+
|
10
|
+
def perform(obj)
|
11
|
+
case @guard
|
12
|
+
when Symbol, String
|
13
|
+
obj.send(@guard)
|
14
|
+
when Proc
|
15
|
+
@guard.call(obj)
|
16
|
+
else
|
17
|
+
true
|
48
18
|
end
|
49
19
|
end
|
20
|
+
|
21
|
+
def execute(obj, *args)
|
22
|
+
@on_transition.is_a?(Array) ?
|
23
|
+
@on_transition.each {|ot| _execute(obj, ot, *args)} :
|
24
|
+
_execute(obj, @on_transition, *args)
|
25
|
+
end
|
26
|
+
|
27
|
+
def ==(obj)
|
28
|
+
@from == obj.from && @to == obj.to
|
29
|
+
end
|
30
|
+
|
31
|
+
def from?(value)
|
32
|
+
@from == value
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def _execute(obj, on_transition, *args)
|
38
|
+
case on_transition
|
39
|
+
when Symbol, String
|
40
|
+
obj.send(on_transition, *args)
|
41
|
+
when Proc
|
42
|
+
on_transition.call(obj, *args)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
50
46
|
end
|
data/spec/unit/aasm_spec.rb
CHANGED
@@ -92,7 +92,7 @@ describe AASM, '- subclassing' do
|
|
92
92
|
FooTwo.aasm_states.should include(state)
|
93
93
|
end
|
94
94
|
end
|
95
|
-
|
95
|
+
|
96
96
|
it 'should not add the child states to the parent machine' do
|
97
97
|
Foo.aasm_states.should_not include(:foo)
|
98
98
|
end
|
@@ -270,6 +270,36 @@ describe AASM, '- getting events for a state' do
|
|
270
270
|
end
|
271
271
|
|
272
272
|
describe AASM, '- event callbacks' do
|
273
|
+
describe "with an error callback defined" do
|
274
|
+
before do
|
275
|
+
class Foo
|
276
|
+
aasm_event :safe_close, :success => :success_callback, :error => :error_callback do
|
277
|
+
transitions :to => :closed, :from => [:open]
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
@foo = Foo.new
|
282
|
+
end
|
283
|
+
|
284
|
+
it "should run error_callback if an exception is raised and error_callback defined" do
|
285
|
+
def @foo.error_callback(e)
|
286
|
+
end
|
287
|
+
@foo.stub!(:enter).and_raise(e=StandardError.new)
|
288
|
+
@foo.should_receive(:error_callback).with(e)
|
289
|
+
@foo.safe_close!
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should raise NoMethodError if exceptionis raised and error_callback is declared but not defined" do
|
293
|
+
@foo.stub!(:enter).and_raise(StandardError)
|
294
|
+
lambda{@foo.safe_close!}.should raise_error(NoMethodError)
|
295
|
+
end
|
296
|
+
|
297
|
+
it "should propagate an error if no error callback is declared" do
|
298
|
+
@foo.stub!(:enter).and_raise("Cannot enter safe")
|
299
|
+
lambda{@foo.close!}.should raise_error(StandardError, "Cannot enter safe")
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
273
303
|
describe "with aasm_event_fired defined" do
|
274
304
|
before do
|
275
305
|
@foo = Foo.new
|
data/spec/unit/state_spec.rb
CHANGED
@@ -63,6 +63,17 @@ describe AASM::SupportingClasses::State do
|
|
63
63
|
state.call_action(:entering, record)
|
64
64
|
end
|
65
65
|
|
66
|
+
it "should stop calling actions if one of them raises :halt_aasm_chain" do
|
67
|
+
state = new_state(:entering => [:a, :b, :c])
|
68
|
+
|
69
|
+
record = mock('record')
|
70
|
+
record.should_receive(:a)
|
71
|
+
record.should_receive(:b).and_throw(:halt_aasm_chain)
|
72
|
+
record.should_not_receive(:c)
|
73
|
+
|
74
|
+
state.call_action(:entering, record)
|
75
|
+
end
|
76
|
+
|
66
77
|
it 'should call a proc, passing in the record for an action if the action is present' do
|
67
78
|
state = new_state(:entering => Proc.new {|r| r.foobar})
|
68
79
|
|
metadata
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fcoury-aasm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Barron
|
8
8
|
- Scott Petersen
|
9
9
|
- Travis Tilley
|
10
|
-
- FelipeCoury
|
11
10
|
autorequire:
|
12
11
|
bindir: bin
|
13
12
|
cert_chain: []
|
14
13
|
|
15
|
-
date:
|
14
|
+
date: 2010-02-11 00:00:00 -02:00
|
16
15
|
default_executable:
|
17
16
|
dependencies:
|
18
17
|
- !ruby/object:Gem::Dependency
|
@@ -46,7 +45,7 @@ dependencies:
|
|
46
45
|
version: "0"
|
47
46
|
version:
|
48
47
|
description: AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects.
|
49
|
-
email: scott@elitists.net, ttilley@gmail.com
|
48
|
+
email: scott@elitists.net, ttilley@gmail.com
|
50
49
|
executables: []
|
51
50
|
|
52
51
|
extensions: []
|
@@ -69,6 +68,7 @@ files:
|
|
69
68
|
- lib/aasm/state.rb
|
70
69
|
- lib/aasm/state_machine.rb
|
71
70
|
- lib/aasm/state_transition.rb
|
71
|
+
- lib/aasm/supporting_classes.rb
|
72
72
|
- spec/functional/conversation.rb
|
73
73
|
- spec/functional/conversation_spec.rb
|
74
74
|
- spec/spec_helper.rb
|