aasm 2.4.0 → 3.0.0
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/CHANGELOG.md +6 -0
- data/README.md +33 -35
- data/lib/aasm.rb +10 -5
- data/lib/aasm/aasm.rb +41 -41
- data/lib/aasm/base.rb +9 -3
- data/lib/aasm/deprecated/aasm.rb +15 -0
- data/lib/aasm/errors.rb +4 -0
- data/lib/aasm/persistence.rb +12 -11
- data/lib/aasm/state_machine.rb +27 -25
- data/lib/aasm/supporting_classes/event.rb +132 -0
- data/lib/aasm/supporting_classes/localizer.rb +40 -0
- data/lib/aasm/supporting_classes/state.rb +57 -0
- data/lib/aasm/supporting_classes/state_transition.rb +50 -0
- data/lib/aasm/version.rb +1 -1
- data/spec/models/conversation.rb +21 -21
- data/spec/models/silencer.rb +17 -0
- data/spec/spec_helpers/models_spec_helper.rb +83 -72
- data/spec/unit/aasm_spec.rb +4 -18
- data/spec/unit/active_record_persistence_spec.rb +6 -4
- data/spec/unit/event_spec.rb +2 -2
- data/spec/unit/localizer_spec.rb +7 -7
- data/spec/unit/state_spec.rb +5 -5
- data/spec/unit/state_transition_spec.rb +22 -6
- metadata +12 -9
- data/lib/aasm/event.rb +0 -127
- data/lib/aasm/localizer.rb +0 -36
- data/lib/aasm/state.rb +0 -53
- data/lib/aasm/state_transition.rb +0 -46
- data/lib/aasm/supporting_classes.rb +0 -7
data/spec/unit/aasm_spec.rb
CHANGED
@@ -104,13 +104,6 @@ describe AASM, '- initial states' do
|
|
104
104
|
end
|
105
105
|
|
106
106
|
describe AASM, '- event firing with persistence' do
|
107
|
-
it 'should fire the Event' do
|
108
|
-
foo = Foo.new
|
109
|
-
|
110
|
-
Foo.aasm_events[:close].should_receive(:fire).with(foo)
|
111
|
-
foo.close!
|
112
|
-
end
|
113
|
-
|
114
107
|
it 'should update the current state' do
|
115
108
|
foo = Foo.new
|
116
109
|
foo.close!
|
@@ -172,13 +165,6 @@ describe AASM, '- event firing with persistence' do
|
|
172
165
|
end
|
173
166
|
|
174
167
|
describe AASM, '- event firing without persistence' do
|
175
|
-
it 'should fire the Event' do
|
176
|
-
foo = Foo.new
|
177
|
-
|
178
|
-
Foo.aasm_events[:close].should_receive(:fire).with(foo)
|
179
|
-
foo.close
|
180
|
-
end
|
181
|
-
|
182
168
|
it 'should update the current state' do
|
183
169
|
foo = Foo.new
|
184
170
|
foo.close
|
@@ -274,7 +260,7 @@ describe AASM, '- event callbacks' do
|
|
274
260
|
end
|
275
261
|
|
276
262
|
it 'should not call it for failing bang fire' do
|
277
|
-
@foo.stub!(:
|
263
|
+
@foo.stub!(:aasm_set_current_state_with_persistence).and_return(false)
|
278
264
|
@foo.should_not_receive(:aasm_event_fired)
|
279
265
|
@foo.close!
|
280
266
|
end
|
@@ -289,16 +275,16 @@ describe AASM, '- event callbacks' do
|
|
289
275
|
|
290
276
|
it 'should call it when transition failed for bang fire' do
|
291
277
|
@foo.should_receive(:aasm_event_failed).with(:null, :open)
|
292
|
-
@foo.null!
|
278
|
+
lambda {@foo.null!}.should raise_error(AASM::InvalidTransition)
|
293
279
|
end
|
294
280
|
|
295
281
|
it 'should call it when transition failed for non-bang fire' do
|
296
282
|
@foo.should_receive(:aasm_event_failed).with(:null, :open)
|
297
|
-
@foo.null
|
283
|
+
lambda {@foo.null}.should raise_error(AASM::InvalidTransition)
|
298
284
|
end
|
299
285
|
|
300
286
|
it 'should not call it if persist fails for bang fire' do
|
301
|
-
@foo.stub!(:
|
287
|
+
@foo.stub!(:aasm_set_current_state_with_persistence).and_return(false)
|
302
288
|
@foo.should_receive(:aasm_event_failed)
|
303
289
|
@foo.close!
|
304
290
|
end
|
@@ -12,11 +12,13 @@ class Gate < ActiveRecord::Base
|
|
12
12
|
# Fake this column for testing purposes
|
13
13
|
attr_accessor :aasm_state
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
aasm do
|
16
|
+
state :opened
|
17
|
+
state :closed
|
17
18
|
|
18
|
-
|
19
|
-
|
19
|
+
event :view do
|
20
|
+
transitions :to => :read, :from => [:needs_attention]
|
21
|
+
end
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
data/spec/unit/event_spec.rb
CHANGED
@@ -30,12 +30,12 @@ describe AASM::SupportingClasses::Event do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
describe AASM::SupportingClasses::Event, 'when firing an event' do
|
33
|
-
it 'should
|
33
|
+
it 'should return nil if the transitions are empty' do
|
34
34
|
obj = mock('object')
|
35
35
|
obj.stub!(:aasm_current_state)
|
36
36
|
|
37
37
|
event = AASM::SupportingClasses::Event.new(:event)
|
38
|
-
|
38
|
+
event.fire(obj).should be_nil
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'should return the state of the first matching transition it finds' do
|
data/spec/unit/localizer_spec.rb
CHANGED
@@ -18,7 +18,7 @@ class LocalizerTestModel < ActiveRecord::Base
|
|
18
18
|
aasm_event :open
|
19
19
|
end
|
20
20
|
|
21
|
-
describe AASM::Localizer do
|
21
|
+
describe AASM::SupportingClasses::Localizer do
|
22
22
|
before(:all) do
|
23
23
|
I18n.load_path << 'spec/en.yml'
|
24
24
|
I18n.default_locale = :en
|
@@ -29,23 +29,23 @@ describe AASM::Localizer do
|
|
29
29
|
let (:foo_opened) { LocalizerTestModel.new }
|
30
30
|
let (:foo_closed) { LocalizerTestModel.new.tap { |x| x.aasm_state = :closed } }
|
31
31
|
|
32
|
-
context '
|
32
|
+
context 'aasm_human_state' do
|
33
33
|
it 'should return translated state value' do
|
34
|
-
foo_opened.
|
34
|
+
foo_opened.aasm_human_state.should == "It's opened now!"
|
35
35
|
end
|
36
36
|
|
37
37
|
it 'should return humanized value if not localized' do
|
38
|
-
foo_closed.
|
38
|
+
foo_closed.aasm_human_state.should == "Closed"
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
context '
|
42
|
+
context 'aasm_human_event_name' do
|
43
43
|
it 'should return translated event name' do
|
44
|
-
LocalizerTestModel.
|
44
|
+
LocalizerTestModel.aasm_human_event_name(:close).should == "Let's close it!"
|
45
45
|
end
|
46
46
|
|
47
47
|
it 'should return humanized event name' do
|
48
|
-
LocalizerTestModel.
|
48
|
+
LocalizerTestModel.aasm_human_event_name(:open).should == "Open"
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
data/spec/unit/state_spec.rb
CHANGED
@@ -41,7 +41,7 @@ describe AASM::SupportingClasses::State do
|
|
41
41
|
record = mock('record')
|
42
42
|
record.should_receive(:foo)
|
43
43
|
|
44
|
-
state.
|
44
|
+
state.fire_callbacks(:entering, record)
|
45
45
|
end
|
46
46
|
|
47
47
|
it 'should send a message to the record for an action if the action is present as a string' do
|
@@ -50,7 +50,7 @@ describe AASM::SupportingClasses::State do
|
|
50
50
|
record = mock('record')
|
51
51
|
record.should_receive(:foo)
|
52
52
|
|
53
|
-
state.
|
53
|
+
state.fire_callbacks(:entering, record)
|
54
54
|
end
|
55
55
|
|
56
56
|
it 'should send a message to the record for each action' do
|
@@ -62,7 +62,7 @@ describe AASM::SupportingClasses::State do
|
|
62
62
|
record.should_receive(:c)
|
63
63
|
record.should_receive(:foobar)
|
64
64
|
|
65
|
-
state.
|
65
|
+
state.fire_callbacks(:entering, record)
|
66
66
|
end
|
67
67
|
|
68
68
|
it "should stop calling actions if one of them raises :halt_aasm_chain" do
|
@@ -73,7 +73,7 @@ describe AASM::SupportingClasses::State do
|
|
73
73
|
record.should_receive(:b).and_throw(:halt_aasm_chain)
|
74
74
|
record.should_not_receive(:c)
|
75
75
|
|
76
|
-
state.
|
76
|
+
state.fire_callbacks(:entering, record)
|
77
77
|
end
|
78
78
|
|
79
79
|
it 'should call a proc, passing in the record for an action if the action is present' do
|
@@ -82,6 +82,6 @@ describe AASM::SupportingClasses::State do
|
|
82
82
|
record = mock('record')
|
83
83
|
record.should_receive(:foobar)
|
84
84
|
|
85
|
-
state.
|
85
|
+
state.fire_callbacks(:entering, record)
|
86
86
|
end
|
87
87
|
end
|
@@ -1,5 +1,21 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
2
|
|
3
|
+
describe 'transitions' do
|
4
|
+
|
5
|
+
it 'should raise an exception when whiny' do
|
6
|
+
process = ProcessWithNewDsl.new
|
7
|
+
lambda { process.stop! }.should raise_error(AASM::InvalidTransition)
|
8
|
+
process.should be_sleeping
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should not raise an exception when whiny' do
|
12
|
+
silencer = Silencer.new
|
13
|
+
silencer.smile!.should be_false
|
14
|
+
silencer.should be_silent
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
3
19
|
describe AASM::SupportingClasses::StateTransition do
|
4
20
|
it 'should set from, to, and opts attr readers' do
|
5
21
|
opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
|
@@ -116,9 +132,9 @@ describe AASM::SupportingClasses::StateTransition, '- when executing the transit
|
|
116
132
|
|
117
133
|
obj.should_receive(:test)
|
118
134
|
|
119
|
-
st.execute(obj, args)
|
135
|
+
st.execute(obj, args)
|
120
136
|
end
|
121
|
-
|
137
|
+
|
122
138
|
it 'should accept a Symbol for the method name' do
|
123
139
|
opts = {:from => 'foo', :to => 'bar', :on_transition => :test}
|
124
140
|
st = AASM::SupportingClasses::StateTransition.new(opts)
|
@@ -127,9 +143,9 @@ describe AASM::SupportingClasses::StateTransition, '- when executing the transit
|
|
127
143
|
|
128
144
|
obj.should_receive(:test)
|
129
145
|
|
130
|
-
st.execute(obj, args)
|
146
|
+
st.execute(obj, args)
|
131
147
|
end
|
132
|
-
|
148
|
+
|
133
149
|
it 'should pass args if the target method accepts them' do
|
134
150
|
opts = {:from => 'foo', :to => 'bar', :on_transition => :test}
|
135
151
|
st = AASM::SupportingClasses::StateTransition.new(opts)
|
@@ -144,7 +160,7 @@ describe AASM::SupportingClasses::StateTransition, '- when executing the transit
|
|
144
160
|
|
145
161
|
return_value.should == 'success'
|
146
162
|
end
|
147
|
-
|
163
|
+
|
148
164
|
it 'should NOT pass args if the target method does NOT accept them' do
|
149
165
|
opts = {:from => 'foo', :to => 'bar', :on_transition => :test}
|
150
166
|
st = AASM::SupportingClasses::StateTransition.new(opts)
|
@@ -159,5 +175,5 @@ describe AASM::SupportingClasses::StateTransition, '- when executing the transit
|
|
159
175
|
|
160
176
|
return_value.should == 'success'
|
161
177
|
end
|
162
|
-
|
178
|
+
|
163
179
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aasm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
|
-
-
|
8
|
-
- 4
|
7
|
+
- 3
|
9
8
|
- 0
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 3.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Scott Barron
|
@@ -168,20 +168,22 @@ files:
|
|
168
168
|
- lib/aasm.rb
|
169
169
|
- lib/aasm/aasm.rb
|
170
170
|
- lib/aasm/base.rb
|
171
|
-
- lib/aasm/
|
172
|
-
- lib/aasm/
|
171
|
+
- lib/aasm/deprecated/aasm.rb
|
172
|
+
- lib/aasm/errors.rb
|
173
173
|
- lib/aasm/persistence.rb
|
174
174
|
- lib/aasm/persistence/active_record_persistence.rb
|
175
|
-
- lib/aasm/state.rb
|
176
175
|
- lib/aasm/state_machine.rb
|
177
|
-
- lib/aasm/
|
178
|
-
- lib/aasm/supporting_classes.rb
|
176
|
+
- lib/aasm/supporting_classes/event.rb
|
177
|
+
- lib/aasm/supporting_classes/localizer.rb
|
178
|
+
- lib/aasm/supporting_classes/state.rb
|
179
|
+
- lib/aasm/supporting_classes/state_transition.rb
|
179
180
|
- lib/aasm/version.rb
|
180
181
|
- spec/database.yml
|
181
182
|
- spec/en.yml
|
182
183
|
- spec/models/conversation.rb
|
183
184
|
- spec/models/not_auto_loaded/process.rb
|
184
185
|
- spec/models/process_with_new_dsl.rb
|
186
|
+
- spec/models/silencer.rb
|
185
187
|
- spec/schema.rb
|
186
188
|
- spec/spec_helper.rb
|
187
189
|
- spec/spec_helpers/models_spec_helper.rb
|
@@ -236,6 +238,7 @@ test_files:
|
|
236
238
|
- spec/models/conversation.rb
|
237
239
|
- spec/models/not_auto_loaded/process.rb
|
238
240
|
- spec/models/process_with_new_dsl.rb
|
241
|
+
- spec/models/silencer.rb
|
239
242
|
- spec/schema.rb
|
240
243
|
- spec/spec_helper.rb
|
241
244
|
- spec/spec_helpers/models_spec_helper.rb
|
data/lib/aasm/event.rb
DELETED
@@ -1,127 +0,0 @@
|
|
1
|
-
class AASM::SupportingClasses::Event
|
2
|
-
attr_reader :name, :success, :options
|
3
|
-
|
4
|
-
def initialize(name, options = {}, &block)
|
5
|
-
@name = name
|
6
|
-
@transitions = []
|
7
|
-
update(options, &block)
|
8
|
-
end
|
9
|
-
|
10
|
-
# a neutered version of fire - it doesn't actually fir the event, it just
|
11
|
-
# executes the transition guards to determine if a transition is even
|
12
|
-
# an option given current conditions.
|
13
|
-
def may_fire?(obj, to_state=nil)
|
14
|
-
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
|
15
|
-
return false if transitions.size == 0
|
16
|
-
|
17
|
-
result = false
|
18
|
-
transitions.each do |transition|
|
19
|
-
next if to_state and !Array(transition.to).include?(to_state)
|
20
|
-
if transition.perform(obj)
|
21
|
-
result = true
|
22
|
-
break
|
23
|
-
end
|
24
|
-
end
|
25
|
-
result
|
26
|
-
end
|
27
|
-
|
28
|
-
def fire(obj, to_state=nil, *args)
|
29
|
-
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
|
30
|
-
raise AASM::InvalidTransition, "Event '#{name}' cannot transition from '#{obj.aasm_current_state}'" if transitions.size == 0
|
31
|
-
|
32
|
-
next_state = nil
|
33
|
-
transitions.each do |transition|
|
34
|
-
next if to_state and !Array(transition.to).include?(to_state)
|
35
|
-
if transition.perform(obj, *args)
|
36
|
-
next_state = to_state || Array(transition.to).first
|
37
|
-
transition.execute(obj, *args)
|
38
|
-
break
|
39
|
-
end
|
40
|
-
end
|
41
|
-
next_state
|
42
|
-
end
|
43
|
-
|
44
|
-
def transitions_from_state?(state)
|
45
|
-
@transitions.any? { |t| t.from == state }
|
46
|
-
end
|
47
|
-
|
48
|
-
def transitions_from_state(state)
|
49
|
-
@transitions.select { |t| t.from == state }
|
50
|
-
end
|
51
|
-
|
52
|
-
def all_transitions
|
53
|
-
@transitions
|
54
|
-
end
|
55
|
-
|
56
|
-
def call_action(action, record)
|
57
|
-
action = @options[action]
|
58
|
-
action.is_a?(Array) ?
|
59
|
-
action.each {|a| _call_action(a, record)} :
|
60
|
-
_call_action(action, record)
|
61
|
-
end
|
62
|
-
|
63
|
-
def ==(event)
|
64
|
-
if event.is_a? Symbol
|
65
|
-
name == event
|
66
|
-
else
|
67
|
-
name == event.name
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def update(options = {}, &block)
|
72
|
-
if options.key?(:success) then
|
73
|
-
@success = options[:success]
|
74
|
-
end
|
75
|
-
if options.key?(:error) then
|
76
|
-
@error = options[:error]
|
77
|
-
end
|
78
|
-
if block then
|
79
|
-
instance_eval(&block)
|
80
|
-
end
|
81
|
-
@options = options
|
82
|
-
self
|
83
|
-
end
|
84
|
-
|
85
|
-
def execute_success_callback(obj, success = nil)
|
86
|
-
callback = success || @success
|
87
|
-
case(callback)
|
88
|
-
when String, Symbol
|
89
|
-
obj.send(callback)
|
90
|
-
when Proc
|
91
|
-
callback.call(obj)
|
92
|
-
when Array
|
93
|
-
callback.each{|meth|self.execute_success_callback(obj, meth)}
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def execute_error_callback(obj, error, error_callback=nil)
|
98
|
-
callback = error_callback || @error
|
99
|
-
raise error unless callback
|
100
|
-
case(callback)
|
101
|
-
when String, Symbol
|
102
|
-
raise NoMethodError unless obj.respond_to?(callback.to_sym)
|
103
|
-
obj.send(callback, error)
|
104
|
-
when Proc
|
105
|
-
callback.call(obj, error)
|
106
|
-
when Array
|
107
|
-
callback.each{|meth|self.execute_error_callback(obj, error, meth)}
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
private
|
112
|
-
|
113
|
-
def _call_action(action, record)
|
114
|
-
case action
|
115
|
-
when Symbol, String
|
116
|
-
record.send(action)
|
117
|
-
when Proc
|
118
|
-
action.call(record)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def transitions(trans_opts)
|
123
|
-
Array(trans_opts[:from]).each do |s|
|
124
|
-
@transitions << AASM::SupportingClasses::StateTransition.new(trans_opts.merge({:from => s.to_sym}))
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
data/lib/aasm/localizer.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
class AASM::Localizer
|
2
|
-
def human_event_name(klass, event)
|
3
|
-
defaults = ancestors_list(klass).map do |ancestor|
|
4
|
-
:"#{i18n_scope(klass)}.events.#{i18n_klass(ancestor)}.#{event}"
|
5
|
-
end << event.to_s.humanize
|
6
|
-
|
7
|
-
I18n.translate(defaults.shift, :default => defaults, :raise => true)
|
8
|
-
end
|
9
|
-
|
10
|
-
def human_state(obj)
|
11
|
-
klass = obj.class
|
12
|
-
defaults = ancestors_list(klass).map do |ancestor|
|
13
|
-
:"#{i18n_scope(klass)}.attributes.#{i18n_klass(ancestor)}.#{klass.aasm_column}.#{obj.aasm_current_state}"
|
14
|
-
end << obj.aasm_current_state.to_s.humanize
|
15
|
-
|
16
|
-
I18n.translate(defaults.shift, :default => defaults, :raise => true)
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
# added for rails 2.x compatibility
|
22
|
-
def i18n_scope(klass)
|
23
|
-
klass.respond_to?(:i18n_scope) ? klass.i18n_scope : :activerecord
|
24
|
-
end
|
25
|
-
|
26
|
-
# added for rails < 3.0.3 compatibility
|
27
|
-
def i18n_klass(klass)
|
28
|
-
klass.model_name.respond_to?(:i18n_key) ? klass.model_name.i18n_key : klass.name.underscore
|
29
|
-
end
|
30
|
-
|
31
|
-
def ancestors_list(klass)
|
32
|
-
klass.ancestors.select do |ancestor|
|
33
|
-
ancestor.respond_to?(:model_name) unless ancestor == ActiveRecord::Base
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|