transitions 0.1.0 → 0.1.1
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/.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
|