transitions 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.rvmrc +1 -1
- data/CHANGELOG.md +8 -0
- data/README.rdoc +27 -21
- data/lib/transitions/event.rb +4 -0
- data/lib/transitions/machine.rb +3 -5
- data/lib/transitions/state.rb +2 -19
- data/lib/transitions/version.rb +1 -1
- data/test/{test_active_record.rb → active_record/test_active_record.rb} +7 -98
- data/test/active_record/test_active_record_scopes.rb +74 -0
- data/test/{test_active_record_timestamps.rb → active_record/test_active_record_timestamps.rb} +17 -9
- data/test/{test_event.rb → event/test_event.rb} +0 -0
- data/test/{test_event_arguments.rb → event/test_event_arguments.rb} +0 -0
- data/test/{test_event_being_fired.rb → event/test_event_being_fired.rb} +0 -0
- data/test/event/test_event_checks.rb +34 -0
- data/test/helper.rb +13 -11
- data/test/{test_available_states_listing.rb → machine/test_available_states_listing.rb} +1 -1
- data/test/{test_machine.rb → machine/test_machine.rb} +4 -0
- data/test/{test_state.rb → state/test_state.rb} +5 -35
- data/test/state/test_state_predicate_method.rb +20 -0
- data/test/{test_state_transition.rb → state_transition/test_state_transition.rb} +0 -0
- data/test/state_transition/test_state_transition_event_failed_callback.rb +36 -0
- data/test/state_transition/test_state_transition_event_fired_callback.rb +44 -0
- data/test/{test_state_transition_guard_check.rb → state_transition/test_state_transition_guard_check.rb} +0 -0
- data/test/{test_state_transition_callbacks.rb → state_transition/test_state_transition_on_transition_callback.rb} +0 -8
- data/test/{test_state_transition_success_callback.rb → state_transition/test_state_transition_success_callback.rb} +0 -11
- data/transitions.gemspec +2 -2
- metadata +26 -22
- data/test/db/create_db.rb +0 -22
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm 1.9.
|
1
|
+
rvm 1.9.3@transitions --create
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
# 1.0.1
|
2
|
+
|
3
|
+
* (troessner) Remove feature:
|
4
|
+
`Do not override existing methods when defining state query methods but warn the user.`
|
5
|
+
since this turned out to cause some problems when loading models, see
|
6
|
+
https://github.com/troessner/transitions/issues/62 for details.
|
7
|
+
* (bnmrrs) Add helper methods to check if a given transition is possible.
|
8
|
+
|
1
9
|
# 1.0.0
|
2
10
|
|
3
11
|
(troessner) Remove suppport for multipe state machines
|
data/README.rdoc
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
|
1
|
+
=== Travis Build Status
|
2
2
|
|
3
3
|
{<img src="https://secure.travis-ci.org/troessner/transitions.png?branch=master"/>}[http://travis-ci.org/troessner/transitions]
|
4
4
|
|
5
|
-
|
5
|
+
=== Synopsis
|
6
6
|
|
7
7
|
<tt>transitions</tt> is a ruby state machine implementation.
|
8
8
|
|
9
|
-
|
9
|
+
=== Installation
|
10
10
|
|
11
|
-
|
11
|
+
==== Rails
|
12
12
|
|
13
13
|
This goes into your Gemfile:
|
14
14
|
|
@@ -18,11 +18,11 @@ This goes into your Gemfile:
|
|
18
18
|
|
19
19
|
include ActiveModel::Transitions
|
20
20
|
|
21
|
-
|
21
|
+
==== Standalone
|
22
22
|
|
23
23
|
gem install transitions
|
24
24
|
|
25
|
-
|
25
|
+
=== Using transitions
|
26
26
|
|
27
27
|
class Product
|
28
28
|
include ActiveModel::Transitions
|
@@ -51,15 +51,18 @@ If this is not the case for you you have to add
|
|
51
51
|
|
52
52
|
whereever you load your dependencies in your application.
|
53
53
|
|
54
|
-
|
54
|
+
<b>A word of warning:</b> Use symbols, not strings for declaring the state machine. Using strings is *not* supported as is using whitespace in names (because `transitions` possibly generates methods out of this).
|
55
55
|
|
56
|
-
|
56
|
+
=== Features
|
57
57
|
|
58
|
-
|
59
|
-
you: <tt>discontinue</tt> and <tt>discontinue!</tt>. Both events will modify the <tt>state</tt> attribute on successful transition,
|
60
|
-
but only the bang(!)-version will call <tt>save!</tt>.
|
58
|
+
==== Events
|
61
59
|
|
62
|
-
|
60
|
+
When you declare an event, say <tt>discontinue</tt>, three methods are declared for
|
61
|
+
you: <tt>discontinue</tt>, <tt>discontinue!</tt> and <tt>can_discontinue?</tt>. The first two events will modify the <tt>state</tt> attribute on successful transition,
|
62
|
+
but only the bang(!)-version will call <tt>save!</tt>. The <tt>can_discontinue?</tt> method will
|
63
|
+
not modify state but instead returns a boolean letting you know if a given transition is possible.
|
64
|
+
|
65
|
+
==== Automatic scope generation
|
63
66
|
|
64
67
|
<tt>transitions</tt> will automatically generate scopes for you if you are using ActiveRecord and tell it to do so via the <tt>auto_scopes</tt> option:
|
65
68
|
|
@@ -82,7 +85,7 @@ you can use this feature a la:
|
|
82
85
|
>> Order.pick_line_items
|
83
86
|
=> [#<Order id: 3, state: "pick_line_items", description: nil, created_at: "2011-08-23 15:48:46", updated_at: "2011-08-23 15:48:46">]
|
84
87
|
|
85
|
-
|
88
|
+
==== Using <tt>on_transition</tt>
|
86
89
|
|
87
90
|
Each event definition takes an optional "on_transition" argument, which allows you to execute methods on transition.
|
88
91
|
You can pass in a Symbol, a String, a Proc or an Array containing method names as Symbol or String like this:
|
@@ -91,7 +94,7 @@ You can pass in a Symbol, a String, a Proc or an Array containing method names a
|
|
91
94
|
transitions :to => :discontinued, :from => [:available, :out_of_stock], :on_transition => [:do_discontinue, :notify_clerk]
|
92
95
|
end
|
93
96
|
|
94
|
-
|
97
|
+
==== Using <tt>success</tt>
|
95
98
|
|
96
99
|
In case you need to trigger a method call after a successful transition you can use <tt>success</tt>:
|
97
100
|
|
@@ -106,7 +109,7 @@ perfom some more complex success callbacks:
|
|
106
109
|
transitions :to => :discontinued, :from => [:available, :out_of_stock]
|
107
110
|
end
|
108
111
|
|
109
|
-
|
112
|
+
==== Timestamps
|
110
113
|
|
111
114
|
If you'd like to note the time of a state change, Transitions comes with timestamps free!
|
112
115
|
To activate them, simply pass the :timestamp option to the event definition with a value of either true or
|
@@ -124,7 +127,7 @@ the name of the timestamp column.
|
|
124
127
|
transitions :from => :exploded, :to => :rebuilt
|
125
128
|
end
|
126
129
|
|
127
|
-
|
130
|
+
==== Using <tt>event_fired</tt> and <tt>event_failed</tt>
|
128
131
|
|
129
132
|
In case you define `event_fired` and / or `event_failed`, `transitions` will use those callbacks correspondingly.
|
130
133
|
You can use those callbacks like this:
|
@@ -137,21 +140,24 @@ You can use those callbacks like this:
|
|
137
140
|
MyLogger.warn "Event failed #{event.inspect}"
|
138
141
|
end
|
139
142
|
|
140
|
-
|
143
|
+
==== Listing all the available states
|
141
144
|
|
142
145
|
You can easily get a listing of all available states:
|
143
146
|
|
144
147
|
Order.available_states # Uses the <tt>default</tt> state machine
|
145
148
|
# => [:pick_line_items, :picking_line_items]
|
146
149
|
|
147
|
-
|
150
|
+
==== Explicitly setting the initial state with the <tt>initial</tt> option
|
148
151
|
|
149
|
-
|
152
|
+
state_machine :initial => :closed do
|
153
|
+
state :open
|
154
|
+
state :closed
|
155
|
+
end
|
150
156
|
|
151
|
-
|
157
|
+
=== Documentation, Guides & Examples
|
152
158
|
|
153
159
|
- {Online API Documentation}[http://rdoc.info/github/troessner/transitions/master/Transitions]
|
154
160
|
|
155
|
-
|
161
|
+
=== Copyright
|
156
162
|
|
157
163
|
Copyright (c) 2010 Jakub Kuźma, Timo Rößner. See LICENSE for details.
|
data/lib/transitions/event.rb
CHANGED
@@ -34,6 +34,10 @@ module Transitions
|
|
34
34
|
machine.klass.send(:define_method, name.to_s) do |*args|
|
35
35
|
machine.fire_event(name, self, false, *args)
|
36
36
|
end
|
37
|
+
|
38
|
+
machine.klass.send(:define_method, "can_#{name.to_s}?") do |*args|
|
39
|
+
machine.events_for(current_state).include?(name.to_sym)
|
40
|
+
end
|
37
41
|
end
|
38
42
|
update(options, &block)
|
39
43
|
end
|
data/lib/transitions/machine.rb
CHANGED
@@ -43,6 +43,7 @@ module Transitions
|
|
43
43
|
self
|
44
44
|
end
|
45
45
|
|
46
|
+
# TODO Refactor me please?
|
46
47
|
def fire_event(event, record, persist, *args)
|
47
48
|
state_index[record.current_state].call_action(:exit, record)
|
48
49
|
begin
|
@@ -70,17 +71,14 @@ module Transitions
|
|
70
71
|
end
|
71
72
|
end
|
72
73
|
|
73
|
-
def states_for_select
|
74
|
-
states.map { |st| [st.display_name, st.name.to_s] }
|
75
|
-
end
|
76
|
-
|
77
74
|
def events_for(state)
|
78
75
|
events = @events.values.select { |event| event.transitions_from_state?(state) }
|
79
76
|
events.map! { |event| event.name }
|
80
77
|
end
|
81
78
|
|
82
79
|
def current_state_variable
|
83
|
-
|
80
|
+
# TODO Refactor me away.
|
81
|
+
:@current_state
|
84
82
|
end
|
85
83
|
|
86
84
|
private
|
data/lib/transitions/state.rb
CHANGED
@@ -67,25 +67,8 @@ module Transitions
|
|
67
67
|
private
|
68
68
|
def define_state_query_method(machine)
|
69
69
|
method_name, state_name = "#{@name}?", @name # Instance vars are out of scope when calling define_method below, so we use local variables.
|
70
|
-
|
71
|
-
|
72
|
-
else
|
73
|
-
machine.klass.send :define_method, method_name do
|
74
|
-
current_state.to_s == state_name.to_s
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def method_already_defined_on_recipient?(machine, method_name)
|
80
|
-
machine.klass.new.respond_to?(method_name)
|
81
|
-
end
|
82
|
-
|
83
|
-
def override_warning(method_name)
|
84
|
-
warning = "Transitions: Can not define method #{method_name} because it is already defined, please rename either the existing method or the state."
|
85
|
-
if Rails && Rails.logger
|
86
|
-
Rails.logger.warn warning
|
87
|
-
else
|
88
|
-
puts warning
|
70
|
+
machine.klass.send :define_method, method_name do
|
71
|
+
current_state.to_s == state_name.to_s
|
89
72
|
end
|
90
73
|
end
|
91
74
|
end
|
data/lib/transitions/version.rb
CHANGED
@@ -1,38 +1,15 @@
|
|
1
1
|
require "helper"
|
2
|
-
require 'active_support/core_ext/module/aliasing'
|
3
|
-
|
4
|
-
# TODO Tests here are quite messy, clean up.
|
5
|
-
|
6
|
-
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
7
2
|
|
8
3
|
class CreateTrafficLights < ActiveRecord::Migration
|
9
4
|
def self.up
|
10
|
-
create_table(:traffic_lights) do |t|
|
5
|
+
create_table(:traffic_lights, :force => true) do |t|
|
11
6
|
t.string :state
|
12
7
|
t.string :name
|
13
8
|
end
|
14
9
|
end
|
15
10
|
end
|
16
11
|
|
17
|
-
|
18
|
-
def self.up
|
19
|
-
create_table(:light_bulbs) do |t|
|
20
|
-
t.string :state
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
class CreateLights < ActiveRecord::Migration
|
26
|
-
def self.up
|
27
|
-
create_table(:lights) do |t|
|
28
|
-
t.string :state
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
CreateTrafficLights.migrate(:up)
|
34
|
-
CreateLightBulbs.migrate(:up)
|
35
|
-
CreateLights.migrate(:up)
|
12
|
+
set_up_db CreateTrafficLights
|
36
13
|
|
37
14
|
class TrafficLight < ActiveRecord::Base
|
38
15
|
include ActiveModel::Transitions
|
@@ -74,18 +51,9 @@ class ConditionalValidatingTrafficLight < TrafficLight
|
|
74
51
|
validates(:name, :presence => true, :if => :red?)
|
75
52
|
end
|
76
53
|
|
77
|
-
class LightBulb < ActiveRecord::Base
|
78
|
-
include ActiveModel::Transitions
|
79
|
-
|
80
|
-
state_machine do
|
81
|
-
state :off
|
82
|
-
state :on
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
54
|
class TestActiveRecord < Test::Unit::TestCase
|
87
55
|
def setup
|
88
|
-
|
56
|
+
set_up_db CreateTrafficLights
|
89
57
|
@light = TrafficLight.create!
|
90
58
|
end
|
91
59
|
|
@@ -94,6 +62,10 @@ class TestActiveRecord < Test::Unit::TestCase
|
|
94
62
|
assert_equal "off", @light.state
|
95
63
|
end
|
96
64
|
|
65
|
+
test "new active records defaults current state to the initial state" do
|
66
|
+
assert_equal :off, @light.current_state
|
67
|
+
end
|
68
|
+
|
97
69
|
test "states initial state" do
|
98
70
|
assert @light.off?
|
99
71
|
assert_equal :off, @light.current_state
|
@@ -174,67 +146,4 @@ class TestActiveRecord < Test::Unit::TestCase
|
|
174
146
|
assert_equal "green", @light.state
|
175
147
|
assert_equal "red", @light.reload.state
|
176
148
|
end
|
177
|
-
|
178
|
-
end
|
179
|
-
|
180
|
-
class TestNewActiveRecord < TestActiveRecord
|
181
|
-
|
182
|
-
def setup
|
183
|
-
create_database
|
184
|
-
@light = TrafficLight.new
|
185
|
-
end
|
186
|
-
|
187
|
-
test "new active records defaults current state to the initial state" do
|
188
|
-
assert_equal :off, @light.current_state
|
189
|
-
end
|
190
|
-
|
191
|
-
end
|
192
|
-
|
193
|
-
class CreateBunnies < ActiveRecord::Migration
|
194
|
-
def self.up
|
195
|
-
create_table(:bunnies) do |t|
|
196
|
-
t.string :state
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
CreateBunnies.migrate(:up)
|
202
|
-
|
203
|
-
class Bunny < ActiveRecord::Base
|
204
|
-
include ActiveModel::Transitions
|
205
|
-
|
206
|
-
state_machine :auto_scopes => true do
|
207
|
-
state :hobbling
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
class TestScopes < Test::Unit::TestCase
|
212
|
-
def setup
|
213
|
-
create_database
|
214
|
-
@bunny = Bunny.create!
|
215
|
-
end
|
216
|
-
|
217
|
-
test "scopes exist" do
|
218
|
-
assert_respond_to Bunny, :hobbling
|
219
|
-
end
|
220
|
-
|
221
|
-
test "scope returns correct object" do
|
222
|
-
assert_equal Bunny.hobbling.first, @bunny
|
223
|
-
end
|
224
|
-
|
225
|
-
test 'scopes are only generated if we explicitly say so' do
|
226
|
-
assert_not_respond_to LightBulb, :off
|
227
|
-
end
|
228
|
-
|
229
|
-
test 'scope generation raises an exception if we try to overwrite an existing method' do
|
230
|
-
assert_raise(Transitions::InvalidMethodOverride) {
|
231
|
-
class TrafficLight < ActiveRecord::Base
|
232
|
-
include ActiveModel::Transitions
|
233
|
-
|
234
|
-
state_machine :auto_scopes => true do
|
235
|
-
state :new
|
236
|
-
end
|
237
|
-
end
|
238
|
-
}
|
239
|
-
end
|
240
149
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class CreateBears < ActiveRecord::Migration
|
4
|
+
def self.up
|
5
|
+
create_table(:bears, :force => true) do |t|
|
6
|
+
t.string :state
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class CreatePuppies < ActiveRecord::Migration
|
12
|
+
def self.up
|
13
|
+
create_table(:puppies, :force => true) do |t|
|
14
|
+
t.string :state
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class CreateBunnies < ActiveRecord::Migration
|
20
|
+
def self.up
|
21
|
+
create_table(:bunnies, :force => true) do |t|
|
22
|
+
t.string :state
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
set_up_db CreateBunnies, CreatePuppies
|
28
|
+
|
29
|
+
class Bunny < ActiveRecord::Base
|
30
|
+
include ActiveModel::Transitions
|
31
|
+
|
32
|
+
state_machine :auto_scopes => true do
|
33
|
+
state :hobbling
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Puppy < ActiveRecord::Base
|
38
|
+
include ActiveModel::Transitions
|
39
|
+
|
40
|
+
state_machine do
|
41
|
+
state :barking
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class TestScopes < Test::Unit::TestCase
|
46
|
+
def setup
|
47
|
+
set_up_db CreateBears, CreateBunnies, CreatePuppies
|
48
|
+
@bunny = Bunny.create!
|
49
|
+
end
|
50
|
+
|
51
|
+
test "scopes exist" do
|
52
|
+
assert_respond_to Bunny, :hobbling
|
53
|
+
end
|
54
|
+
|
55
|
+
test "scope returns correct object" do
|
56
|
+
assert_equal Bunny.hobbling.first, @bunny
|
57
|
+
end
|
58
|
+
|
59
|
+
test 'scopes are only generated if we explicitly say so' do
|
60
|
+
assert_not_respond_to Puppy, :barking
|
61
|
+
end
|
62
|
+
|
63
|
+
test 'scope generation raises an exception if we try to overwrite an existing method' do
|
64
|
+
assert_raise(Transitions::InvalidMethodOverride) {
|
65
|
+
class Bear < ActiveRecord::Base
|
66
|
+
include ActiveModel::Transitions
|
67
|
+
|
68
|
+
state_machine :auto_scopes => true do
|
69
|
+
state :new
|
70
|
+
end
|
71
|
+
end
|
72
|
+
}
|
73
|
+
end
|
74
|
+
end
|
data/test/{test_active_record_timestamps.rb → active_record/test_active_record_timestamps.rb}
RENAMED
@@ -1,7 +1,19 @@
|
|
1
1
|
require "helper"
|
2
|
-
require 'active_support/core_ext/module/aliasing'
|
3
2
|
|
4
|
-
|
3
|
+
class CreateOrders < ActiveRecord::Migration
|
4
|
+
def self.up
|
5
|
+
create_table(:orders, :force => true) do |t|
|
6
|
+
t.string :state
|
7
|
+
t.string :order_number
|
8
|
+
t.datetime :paid_at
|
9
|
+
t.datetime :prepared_on
|
10
|
+
t.datetime :dispatched_at
|
11
|
+
t.date :cancellation_date
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
set_up_db CreateOrders
|
5
17
|
|
6
18
|
class Order < ActiveRecord::Base
|
7
19
|
include ActiveModel::Transitions
|
@@ -43,19 +55,16 @@ class Order < ActiveRecord::Base
|
|
43
55
|
event :reopen, :timestamp => true do
|
44
56
|
transitions :from => :cancelled, :to => :opened
|
45
57
|
end
|
46
|
-
|
47
58
|
end
|
48
59
|
end
|
49
60
|
|
50
|
-
|
51
61
|
class TestActiveRecordTimestamps < Test::Unit::TestCase
|
52
|
-
|
53
62
|
require "securerandom"
|
54
|
-
|
63
|
+
|
55
64
|
def setup
|
56
|
-
|
65
|
+
set_up_db CreateOrders
|
57
66
|
end
|
58
|
-
|
67
|
+
|
59
68
|
def create_order(state = nil)
|
60
69
|
Order.create! :order_number => SecureRandom.hex(4), :state => state
|
61
70
|
end
|
@@ -114,5 +123,4 @@ class TestActiveRecordTimestamps < Test::Unit::TestCase
|
|
114
123
|
end
|
115
124
|
end
|
116
125
|
end
|
117
|
-
|
118
126
|
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class ChecksTestSubject
|
4
|
+
include Transitions
|
5
|
+
|
6
|
+
state_machine :initial => :initial do
|
7
|
+
state :initial
|
8
|
+
state :opened
|
9
|
+
state :closed
|
10
|
+
|
11
|
+
event :open do
|
12
|
+
transitions :from => :initial, :to => :opened
|
13
|
+
end
|
14
|
+
|
15
|
+
event :close do
|
16
|
+
transitions :from => :opened, :to => :closed
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class StateMachineChecksTest < Test::Unit::TestCase
|
22
|
+
test "checks if a given transition is possible" do
|
23
|
+
subject = ChecksTestSubject.new
|
24
|
+
assert_equal :initial, subject.current_state
|
25
|
+
assert_equal true, subject.can_open?
|
26
|
+
assert_equal false, subject.can_close?
|
27
|
+
|
28
|
+
subject.open
|
29
|
+
|
30
|
+
assert_equal false, subject.can_open?
|
31
|
+
assert_equal true, subject.can_close?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
data/test/helper.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
-
|
2
|
-
require
|
3
|
-
require "active_support/all"
|
4
|
-
require "active_record"
|
5
|
-
require "mocha"
|
6
|
-
require "db/create_db"
|
1
|
+
require 'test/unit'
|
2
|
+
require 'active_record'
|
7
3
|
|
8
|
-
require
|
9
|
-
require
|
4
|
+
require 'transitions'
|
5
|
+
require 'active_model/transitions'
|
6
|
+
|
7
|
+
require 'mocha'
|
10
8
|
require 'random_data'
|
11
9
|
|
12
|
-
def
|
13
|
-
ActiveRecord::Base.establish_connection(:adapter =>
|
10
|
+
def db_defaults!
|
11
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
14
12
|
ActiveRecord::Migration.verbose = false
|
15
|
-
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_up_db(*migrations)
|
16
|
+
db_defaults!
|
17
|
+
migrations.each { |klass| klass.send :migrate, :up }
|
16
18
|
end
|
@@ -11,7 +11,7 @@ class Bender
|
|
11
11
|
end
|
12
12
|
|
13
13
|
class TestAvailableStatesListing < Test::Unit::TestCase
|
14
|
-
test 'available_states should return the states for the
|
14
|
+
test 'available_states should return the states for the state machine' do
|
15
15
|
assert_equal [:drinking, :gambling, :smoking], Bender.available_states
|
16
16
|
end
|
17
17
|
end
|
@@ -2,15 +2,14 @@ require "helper"
|
|
2
2
|
|
3
3
|
class TestState < Test::Unit::TestCase
|
4
4
|
def setup
|
5
|
-
|
5
|
+
machine = Class.new do
|
6
6
|
include Transitions
|
7
7
|
state_machine do
|
8
8
|
end
|
9
|
-
end
|
10
|
-
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@state = Transitions::State.new(@state_name, @options)
|
9
|
+
end.get_state_machine
|
10
|
+
state_name = :astate
|
11
|
+
@options = { :machine => machine, :custom_key => :my_key }
|
12
|
+
@state = Transitions::State.new(state_name, @options)
|
14
13
|
end
|
15
14
|
|
16
15
|
def new_state_name
|
@@ -70,32 +69,3 @@ class TestState < Test::Unit::TestCase
|
|
70
69
|
state.call_action(:entering, record)
|
71
70
|
end
|
72
71
|
end
|
73
|
-
|
74
|
-
class StateOverrideMethodTestSubject
|
75
|
-
include Transitions
|
76
|
-
|
77
|
-
state_machine do
|
78
|
-
end
|
79
|
-
|
80
|
-
def a_state_name?; :foo; end
|
81
|
-
end
|
82
|
-
|
83
|
-
|
84
|
-
class TestStateQueryOverrideMethod < Test::Unit::TestCase
|
85
|
-
def setup
|
86
|
-
@state_name = 'a_state_name'
|
87
|
-
@machine = StateOverrideMethodTestSubject.state_machine
|
88
|
-
@options = { :machine => @machine }
|
89
|
-
end
|
90
|
-
|
91
|
-
test "warn on creation when we try to overwrite an existing method" do
|
92
|
-
# TODO
|
93
|
-
end
|
94
|
-
|
95
|
-
test "should not override an already existing method" do
|
96
|
-
Transitions::State.new :dummy, @options
|
97
|
-
expected_result = :foo
|
98
|
-
actual_result = StateOverrideMethodTestSubject.new.a_state_name?
|
99
|
-
assert_equal expected_result, actual_result
|
100
|
-
end
|
101
|
-
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class Bus
|
4
|
+
include Transitions
|
5
|
+
|
6
|
+
state_machine do
|
7
|
+
state :parking
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class TestStatePredicateMethod < Test::Unit::TestCase
|
12
|
+
def setup
|
13
|
+
@bus = Bus.new
|
14
|
+
end
|
15
|
+
|
16
|
+
test "should generate predicate methods for states" do
|
17
|
+
assert_true @bus.respond_to?(:parking?)
|
18
|
+
assert_true @bus.send(:parking?)
|
19
|
+
end
|
20
|
+
end
|
File without changes
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class Car
|
4
|
+
include Transitions
|
5
|
+
|
6
|
+
state_machine do
|
7
|
+
state :parked
|
8
|
+
state :driving
|
9
|
+
state :switched_off
|
10
|
+
|
11
|
+
event :start_driving do
|
12
|
+
transitions :from => :parked, :to => :driving
|
13
|
+
end
|
14
|
+
|
15
|
+
event :switch_off_engine do
|
16
|
+
transitions :from => :parked, :to => :switched_off
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class TestStateTransitionEventFailedCallback < Test::Unit::TestCase
|
22
|
+
def setup
|
23
|
+
@car = Car.new
|
24
|
+
end
|
25
|
+
|
26
|
+
test "should execute the event_failed_callback and don't raise error if callback is defined" do
|
27
|
+
@car.start_driving
|
28
|
+
@car.expects(:event_failed).with(:switch_off_engine)
|
29
|
+
@car.switch_off_engine
|
30
|
+
end
|
31
|
+
|
32
|
+
test "should just re-raise any error on transition if the event_failed_callback isn't defined" do
|
33
|
+
@car.start_driving
|
34
|
+
assert_raise(Transitions::InvalidTransition) { @car.switch_off_engine }
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class Car
|
4
|
+
include Transitions
|
5
|
+
|
6
|
+
state_machine do
|
7
|
+
state :parked
|
8
|
+
state :driving
|
9
|
+
|
10
|
+
event :start_driving do
|
11
|
+
transitions :from => :parked, :to => :driving
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TestStateTransitionEventFiredCallback < Test::Unit::TestCase
|
17
|
+
def setup
|
18
|
+
@car = Car.new
|
19
|
+
end
|
20
|
+
|
21
|
+
test "should execute the event_fired callback after successfull event execution if it callback is defined" do
|
22
|
+
@car.stubs(:event_fired)
|
23
|
+
@car.expects(:event_fired).with(:parked, :driving, :start_driving).once
|
24
|
+
|
25
|
+
@car.start_driving!
|
26
|
+
end
|
27
|
+
|
28
|
+
test "should not execute the event_fired callback after successfull event execution if it callback is not defined" do
|
29
|
+
pend 'Test fails right now although functionality is working as expected'
|
30
|
+
# This test fails right now even though it works as expected in the console.
|
31
|
+
# The reason for this is, that mocha's `expects` does a little bit more than just set up an expectation,
|
32
|
+
# it actually defines this method if it doesn't exist or at least it overwrites respond_to?
|
33
|
+
# @car.respond_to?(:event_fired)
|
34
|
+
# returns false before the `expects` call, but true after.
|
35
|
+
# Hence, this test fails.
|
36
|
+
# Something like
|
37
|
+
# @car.instance_eval { undef :event_fired }
|
38
|
+
# doesn't work either, probably because expects just overwrites respond_to?
|
39
|
+
# but does not define the method
|
40
|
+
# How to fix?
|
41
|
+
@car.expects(:event_fired).never
|
42
|
+
@car.start_driving!
|
43
|
+
end
|
44
|
+
end
|
File without changes
|
@@ -17,9 +17,6 @@ class Car
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def event_fired(current_state, new_state, event)
|
21
|
-
end
|
22
|
-
|
23
20
|
%w!start_engine loosen_handbrake push_gas_pedal!.each do |m|
|
24
21
|
define_method(m){}
|
25
22
|
end
|
@@ -43,9 +40,4 @@ class TestStateTransitionCallbacks < Test::Unit::TestCase
|
|
43
40
|
@car.expects(:push_gas_pedal).in_sequence(on_transition_sequence)
|
44
41
|
@car.start_driving!
|
45
42
|
end
|
46
|
-
|
47
|
-
test "should pass event when calling event_fired_callback" do
|
48
|
-
@car.expects(:event_fired).with(:parked, :driving, :start_driving)
|
49
|
-
@car.start_driving!
|
50
|
-
end
|
51
43
|
end
|
@@ -46,15 +46,4 @@ class TestStateTransitionSuccessCallback < Test::Unit::TestCase
|
|
46
46
|
@car.expects(:loosen_handbrake).raises("Drive with handbrake fail!")
|
47
47
|
@car.start_driving!
|
48
48
|
end
|
49
|
-
|
50
|
-
test "should execute the event_failed_callback and don't raise error if callback is defined" do
|
51
|
-
@car.start_driving
|
52
|
-
@car.expects(:event_failed).with(:switch_off_engine)
|
53
|
-
@car.switch_off_engine
|
54
|
-
end
|
55
|
-
|
56
|
-
test "should just re-raise any error on transition if the event_failed_callback isn't defined" do
|
57
|
-
@car.start_driving
|
58
|
-
assert_raise(Transitions::InvalidTransition) { @car.switch_off_engine }
|
59
|
-
end
|
60
49
|
end
|
data/transitions.gemspec
CHANGED
@@ -15,8 +15,8 @@ Gem::Specification.new do |s|
|
|
15
15
|
s.rubyforge_project = "transitions"
|
16
16
|
|
17
17
|
s.add_development_dependency "bundler", "~> 1"
|
18
|
-
s.add_development_dependency "test-unit", "~> 2.
|
19
|
-
s.add_development_dependency "mocha"
|
18
|
+
s.add_development_dependency "test-unit", "~> 2.5"
|
19
|
+
s.add_development_dependency "mocha", '~> 0.11.0' # With mocha 0.12 we get: undefined method `run' for #<StateMachineMachineTest:0x94918b8> (NoMethodError)
|
20
20
|
s.add_development_dependency "rake"
|
21
21
|
s.add_development_dependency "random_data"
|
22
22
|
s.add_development_dependency "sqlite3"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: transitions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-08-06 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -35,7 +35,7 @@ dependencies:
|
|
35
35
|
requirements:
|
36
36
|
- - ~>
|
37
37
|
- !ruby/object:Gem::Version
|
38
|
-
version: '2.
|
38
|
+
version: '2.5'
|
39
39
|
type: :development
|
40
40
|
prerelease: false
|
41
41
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -43,23 +43,23 @@ dependencies:
|
|
43
43
|
requirements:
|
44
44
|
- - ~>
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: '2.
|
46
|
+
version: '2.5'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: mocha
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 0.11.0
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
57
|
version_requirements: !ruby/object:Gem::Requirement
|
58
58
|
none: false
|
59
59
|
requirements:
|
60
|
-
- -
|
60
|
+
- - ~>
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version:
|
62
|
+
version: 0.11.0
|
63
63
|
- !ruby/object:Gem::Dependency
|
64
64
|
name: rake
|
65
65
|
requirement: !ruby/object:Gem::Requirement
|
@@ -146,20 +146,24 @@ files:
|
|
146
146
|
- lib/transitions/state.rb
|
147
147
|
- lib/transitions/state_transition.rb
|
148
148
|
- lib/transitions/version.rb
|
149
|
-
- test/
|
149
|
+
- test/active_record/test_active_record.rb
|
150
|
+
- test/active_record/test_active_record_scopes.rb
|
151
|
+
- test/active_record/test_active_record_timestamps.rb
|
152
|
+
- test/event/test_event.rb
|
153
|
+
- test/event/test_event_arguments.rb
|
154
|
+
- test/event/test_event_being_fired.rb
|
155
|
+
- test/event/test_event_checks.rb
|
150
156
|
- test/helper.rb
|
151
|
-
- test/
|
152
|
-
- test/
|
153
|
-
- test/
|
154
|
-
- test/
|
155
|
-
- test/
|
156
|
-
- test/
|
157
|
-
- test/
|
158
|
-
- test/
|
159
|
-
- test/
|
160
|
-
- test/
|
161
|
-
- test/test_state_transition_guard_check.rb
|
162
|
-
- test/test_state_transition_success_callback.rb
|
157
|
+
- test/machine/test_available_states_listing.rb
|
158
|
+
- test/machine/test_machine.rb
|
159
|
+
- test/state/test_state.rb
|
160
|
+
- test/state/test_state_predicate_method.rb
|
161
|
+
- test/state_transition/test_state_transition.rb
|
162
|
+
- test/state_transition/test_state_transition_event_failed_callback.rb
|
163
|
+
- test/state_transition/test_state_transition_event_fired_callback.rb
|
164
|
+
- test/state_transition/test_state_transition_guard_check.rb
|
165
|
+
- test/state_transition/test_state_transition_on_transition_callback.rb
|
166
|
+
- test/state_transition/test_state_transition_success_callback.rb
|
163
167
|
- transitions.gemspec
|
164
168
|
homepage: http://github.com/troessner/transitions
|
165
169
|
licenses: []
|
@@ -175,7 +179,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
175
179
|
version: '0'
|
176
180
|
segments:
|
177
181
|
- 0
|
178
|
-
hash: -
|
182
|
+
hash: -930958051
|
179
183
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
180
184
|
none: false
|
181
185
|
requirements:
|
data/test/db/create_db.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
# Use this schema to create all required tables
|
2
|
-
class CreateDb < ActiveRecord::Migration
|
3
|
-
def self.up
|
4
|
-
create_table(:traffic_lights, :force => true) do |t|
|
5
|
-
t.string :state
|
6
|
-
t.string :name
|
7
|
-
end
|
8
|
-
create_table(:bunnies, :force => true) do |t|
|
9
|
-
t.string :state
|
10
|
-
end
|
11
|
-
|
12
|
-
create_table(:orders, :force => true) do |t|
|
13
|
-
t.string :state
|
14
|
-
t.string :order_number
|
15
|
-
t.datetime :paid_at
|
16
|
-
t.datetime :prepared_on
|
17
|
-
t.datetime :dispatched_at
|
18
|
-
t.date :cancellation_date
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
22
|
-
end
|