state_machine 0.3.1 → 0.4.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.rdoc +26 -0
- data/README.rdoc +254 -46
- data/Rakefile +29 -3
- data/examples/AutoShop_state.png +0 -0
- data/examples/Car_state.jpg +0 -0
- data/examples/Vehicle_state.png +0 -0
- data/lib/state_machine.rb +161 -116
- data/lib/state_machine/assertions.rb +21 -0
- data/lib/state_machine/callback.rb +168 -0
- data/lib/state_machine/eval_helpers.rb +67 -0
- data/lib/state_machine/event.rb +135 -101
- data/lib/state_machine/extensions.rb +83 -0
- data/lib/state_machine/guard.rb +115 -0
- data/lib/state_machine/integrations/active_record.rb +242 -0
- data/lib/state_machine/integrations/data_mapper.rb +198 -0
- data/lib/state_machine/integrations/data_mapper/observer.rb +153 -0
- data/lib/state_machine/integrations/sequel.rb +169 -0
- data/lib/state_machine/machine.rb +746 -352
- data/lib/state_machine/transition.rb +104 -212
- data/test/active_record.log +34865 -0
- data/test/classes/switch.rb +11 -0
- data/test/data_mapper.log +14015 -0
- data/test/functional/state_machine_test.rb +249 -15
- data/test/sequel.log +3835 -0
- data/test/test_helper.rb +3 -12
- data/test/unit/assertions_test.rb +13 -0
- data/test/unit/callback_test.rb +189 -0
- data/test/unit/eval_helpers_test.rb +92 -0
- data/test/unit/event_test.rb +247 -113
- data/test/unit/guard_test.rb +420 -0
- data/test/unit/integrations/active_record_test.rb +515 -0
- data/test/unit/integrations/data_mapper_test.rb +407 -0
- data/test/unit/integrations/sequel_test.rb +244 -0
- data/test/unit/invalid_transition_test.rb +1 -1
- data/test/unit/machine_test.rb +1056 -98
- data/test/unit/state_machine_test.rb +14 -113
- data/test/unit/transition_test.rb +269 -495
- metadata +44 -30
- data/test/app_root/app/models/auto_shop.rb +0 -34
- data/test/app_root/app/models/car.rb +0 -19
- data/test/app_root/app/models/highway.rb +0 -3
- data/test/app_root/app/models/motorcycle.rb +0 -3
- data/test/app_root/app/models/switch.rb +0 -23
- data/test/app_root/app/models/switch_observer.rb +0 -20
- data/test/app_root/app/models/toggle_switch.rb +0 -2
- data/test/app_root/app/models/vehicle.rb +0 -78
- data/test/app_root/config/environment.rb +0 -7
- data/test/app_root/db/migrate/001_create_switches.rb +0 -12
- data/test/app_root/db/migrate/002_create_auto_shops.rb +0 -13
- data/test/app_root/db/migrate/003_create_highways.rb +0 -11
- data/test/app_root/db/migrate/004_create_vehicles.rb +0 -16
- data/test/factory.rb +0 -77
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: state_machine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Pfeifer
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-12-14 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -22,40 +22,47 @@ extensions: []
|
|
22
22
|
extra_rdoc_files: []
|
23
23
|
|
24
24
|
files:
|
25
|
+
- examples/Car_state.jpg
|
26
|
+
- examples/Vehicle_state.png
|
27
|
+
- examples/AutoShop_state.png
|
25
28
|
- lib/state_machine
|
26
29
|
- lib/state_machine/event.rb
|
30
|
+
- lib/state_machine/guard.rb
|
31
|
+
- lib/state_machine/integrations
|
32
|
+
- lib/state_machine/integrations/data_mapper
|
33
|
+
- lib/state_machine/integrations/data_mapper/observer.rb
|
34
|
+
- lib/state_machine/integrations/sequel.rb
|
35
|
+
- lib/state_machine/integrations/active_record.rb
|
36
|
+
- lib/state_machine/integrations/data_mapper.rb
|
37
|
+
- lib/state_machine/eval_helpers.rb
|
27
38
|
- lib/state_machine/transition.rb
|
39
|
+
- lib/state_machine/callback.rb
|
40
|
+
- lib/state_machine/extensions.rb
|
41
|
+
- lib/state_machine/assertions.rb
|
28
42
|
- lib/state_machine/machine.rb
|
29
43
|
- lib/state_machine.rb
|
30
|
-
- test/
|
31
|
-
- test/
|
32
|
-
- test/
|
33
|
-
- test/app_root/app/models/highway.rb
|
34
|
-
- test/app_root/app/models/switch.rb
|
35
|
-
- test/app_root/app/models/motorcycle.rb
|
36
|
-
- test/app_root/app/models/toggle_switch.rb
|
37
|
-
- test/app_root/app/models/vehicle.rb
|
38
|
-
- test/app_root/app/models/car.rb
|
39
|
-
- test/app_root/app/models/switch_observer.rb
|
40
|
-
- test/app_root/app/models/auto_shop.rb
|
41
|
-
- test/app_root/config
|
42
|
-
- test/app_root/config/environment.rb
|
43
|
-
- test/app_root/db
|
44
|
-
- test/app_root/db/migrate
|
45
|
-
- test/app_root/db/migrate/002_create_auto_shops.rb
|
46
|
-
- test/app_root/db/migrate/003_create_highways.rb
|
47
|
-
- test/app_root/db/migrate/004_create_vehicles.rb
|
48
|
-
- test/app_root/db/migrate/001_create_switches.rb
|
44
|
+
- test/sequel.log
|
45
|
+
- test/active_record.log
|
46
|
+
- test/test_helper.rb
|
49
47
|
- test/functional
|
50
48
|
- test/functional/state_machine_test.rb
|
51
|
-
- test/
|
52
|
-
- test/
|
49
|
+
- test/data_mapper.log
|
50
|
+
- test/classes
|
51
|
+
- test/classes/switch.rb
|
53
52
|
- test/unit
|
54
|
-
- test/unit/
|
53
|
+
- test/unit/integrations
|
54
|
+
- test/unit/integrations/data_mapper_test.rb
|
55
|
+
- test/unit/integrations/active_record_test.rb
|
56
|
+
- test/unit/integrations/sequel_test.rb
|
57
|
+
- test/unit/state_machine_test.rb
|
58
|
+
- test/unit/callback_test.rb
|
55
59
|
- test/unit/invalid_transition_test.rb
|
56
|
-
- test/unit/
|
60
|
+
- test/unit/transition_test.rb
|
61
|
+
- test/unit/eval_helpers_test.rb
|
57
62
|
- test/unit/event_test.rb
|
58
|
-
- test/unit/
|
63
|
+
- test/unit/guard_test.rb
|
64
|
+
- test/unit/assertions_test.rb
|
65
|
+
- test/unit/machine_test.rb
|
59
66
|
- CHANGELOG.rdoc
|
60
67
|
- init.rb
|
61
68
|
- LICENSE
|
@@ -86,11 +93,18 @@ rubyforge_project: pluginaweek
|
|
86
93
|
rubygems_version: 1.2.0
|
87
94
|
signing_key:
|
88
95
|
specification_version: 2
|
89
|
-
summary: Adds support for creating state machines for attributes
|
96
|
+
summary: Adds support for creating state machines for attributes on any Ruby class
|
90
97
|
test_files:
|
91
98
|
- test/functional/state_machine_test.rb
|
92
|
-
- test/unit/
|
99
|
+
- test/unit/integrations/data_mapper_test.rb
|
100
|
+
- test/unit/integrations/active_record_test.rb
|
101
|
+
- test/unit/integrations/sequel_test.rb
|
102
|
+
- test/unit/state_machine_test.rb
|
103
|
+
- test/unit/callback_test.rb
|
93
104
|
- test/unit/invalid_transition_test.rb
|
94
|
-
- test/unit/
|
105
|
+
- test/unit/transition_test.rb
|
106
|
+
- test/unit/eval_helpers_test.rb
|
95
107
|
- test/unit/event_test.rb
|
96
|
-
- test/unit/
|
108
|
+
- test/unit/guard_test.rb
|
109
|
+
- test/unit/assertions_test.rb
|
110
|
+
- test/unit/machine_test.rb
|
@@ -1,34 +0,0 @@
|
|
1
|
-
class AutoShop < ActiveRecord::Base
|
2
|
-
state_machine :state, :initial => 'available' do
|
3
|
-
after_transition :from => 'available', :do => :increment_customers
|
4
|
-
after_transition :from => 'busy', :do => :decrement_customers
|
5
|
-
|
6
|
-
event :tow_vehicle do
|
7
|
-
transition :to => 'busy', :from => 'available'
|
8
|
-
end
|
9
|
-
|
10
|
-
event :fix_vehicle do
|
11
|
-
transition :to => 'available', :from => 'busy'
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
# Is the Auto Shop available for new customers?
|
16
|
-
def available?
|
17
|
-
state == 'available'
|
18
|
-
end
|
19
|
-
|
20
|
-
# Is the Auto Shop currently not taking new customers?
|
21
|
-
def busy?
|
22
|
-
state == 'busy'
|
23
|
-
end
|
24
|
-
|
25
|
-
# Increments the number of customers in service
|
26
|
-
def increment_customers
|
27
|
-
update_attribute(:num_customers, num_customers + 1)
|
28
|
-
end
|
29
|
-
|
30
|
-
# Decrements the number of customers in service
|
31
|
-
def decrement_customers
|
32
|
-
update_attribute(:num_customers, num_customers - 1)
|
33
|
-
end
|
34
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
class Car < Vehicle
|
2
|
-
state_machine :state do
|
3
|
-
event :reverse do
|
4
|
-
transition :to => 'backing_up', :from => %w(parked idling first_gear)
|
5
|
-
end
|
6
|
-
|
7
|
-
event :park do
|
8
|
-
transition :to => 'parked', :from => 'backing_up'
|
9
|
-
end
|
10
|
-
|
11
|
-
event :idle do
|
12
|
-
transition :to => 'idling', :from => 'backing_up'
|
13
|
-
end
|
14
|
-
|
15
|
-
event :shift_up do
|
16
|
-
transition :to => 'first_gear', :from => 'backing_up'
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
class Switch < ActiveRecord::Base
|
2
|
-
# Tracks the callbacks that were invoked
|
3
|
-
attr_reader :callbacks
|
4
|
-
|
5
|
-
# Dynamic sets the initial state
|
6
|
-
attr_accessor :initial_state
|
7
|
-
|
8
|
-
# Whether or not validations should fail
|
9
|
-
attr_accessor :fail_validation
|
10
|
-
validate Proc.new {|switch| switch.errors.add_to_base 'is invalid' if switch.fail_validation}
|
11
|
-
|
12
|
-
# Whether or not saves should fail
|
13
|
-
attr_accessor :fail_save
|
14
|
-
before_save Proc.new {|switch| !switch.fail_save}
|
15
|
-
|
16
|
-
# Arbitrary data associated with the switch
|
17
|
-
attr_accessor :data
|
18
|
-
|
19
|
-
def initialize(attributes = nil)
|
20
|
-
@callbacks = []
|
21
|
-
super
|
22
|
-
end
|
23
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
class SwitchObserver < ActiveRecord::Observer
|
2
|
-
cattr_accessor :notifications
|
3
|
-
self.notifications = []
|
4
|
-
|
5
|
-
def before_turn_on(switch, from_state, to_state)
|
6
|
-
notifications << ['before_turn_on', switch, from_state, to_state]
|
7
|
-
end
|
8
|
-
|
9
|
-
def after_turn_on(switch, from_state, to_state)
|
10
|
-
notifications << ['after_turn_on', switch, from_state, to_state]
|
11
|
-
end
|
12
|
-
|
13
|
-
def before_transition(switch, attribute, event, from_state, to_state)
|
14
|
-
notifications << ['before_transition', switch, attribute, event, from_state, to_state]
|
15
|
-
end
|
16
|
-
|
17
|
-
def after_transition(switch, attribute, event, from_state, to_state)
|
18
|
-
notifications << ['after_transition', switch, attribute, event, from_state, to_state]
|
19
|
-
end
|
20
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
class Vehicle < ActiveRecord::Base
|
2
|
-
belongs_to :auto_shop
|
3
|
-
belongs_to :highway
|
4
|
-
|
5
|
-
attr_accessor :force_idle
|
6
|
-
attr_accessor :callbacks
|
7
|
-
|
8
|
-
# Defines the state machine for the state of the vehicled
|
9
|
-
state_machine :state, :initial => Proc.new {|vehicle| vehicle.force_idle ? 'idling' : 'parked'} do
|
10
|
-
before_transition :from => 'parked', :do => :put_on_seatbelt
|
11
|
-
before_transition :to => 'stalled', :do => :increase_insurance_premium
|
12
|
-
after_transition :to => 'parked', :do => lambda {|vehicle| vehicle.update_attribute(:seatbelt_on, false)}
|
13
|
-
after_transition :on => 'crash', :do => :tow!
|
14
|
-
after_transition :on => 'repair', :do => :fix!
|
15
|
-
|
16
|
-
# Callback tracking for initial state callbacks
|
17
|
-
after_transition :to => 'parked', :do => lambda {|vehicle| (vehicle.callbacks ||= []) << 'before_enter_parked'}
|
18
|
-
before_transition :to => 'idling', :do => lambda {|vehicle| (vehicle.callbacks ||= []) << 'before_enter_idling'}
|
19
|
-
|
20
|
-
event :park do
|
21
|
-
transition :to => 'parked', :from => %w(idling first_gear)
|
22
|
-
end
|
23
|
-
|
24
|
-
event :ignite do
|
25
|
-
transition :to => 'stalled', :from => 'stalled'
|
26
|
-
transition :to => 'idling', :from => 'parked'
|
27
|
-
end
|
28
|
-
|
29
|
-
event :idle do
|
30
|
-
transition :to => 'idling', :from => 'first_gear'
|
31
|
-
end
|
32
|
-
|
33
|
-
event :shift_up do
|
34
|
-
transition :to => 'first_gear', :from => 'idling'
|
35
|
-
transition :to => 'second_gear', :from => 'first_gear'
|
36
|
-
transition :to => 'third_gear', :from => 'second_gear'
|
37
|
-
end
|
38
|
-
|
39
|
-
event :shift_down do
|
40
|
-
transition :to => 'second_gear', :from => 'third_gear'
|
41
|
-
transition :to => 'first_gear', :from => 'second_gear'
|
42
|
-
end
|
43
|
-
|
44
|
-
event :crash do
|
45
|
-
transition :to => 'stalled', :from => %w(first_gear second_gear third_gear), :if => lambda {|vehicle| vehicle.auto_shop.available?}
|
46
|
-
end
|
47
|
-
|
48
|
-
event :repair do
|
49
|
-
transition :to => 'parked', :from => 'stalled', :if => :auto_shop_busy?
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Tows the vehicle to the auto shop
|
54
|
-
def tow!
|
55
|
-
auto_shop.tow_vehicle!
|
56
|
-
end
|
57
|
-
|
58
|
-
# Fixes the vehicle; it will no longer be in the auto shop
|
59
|
-
def fix!
|
60
|
-
auto_shop.fix_vehicle!
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
# Safety first! Puts on our seatbelt
|
65
|
-
def put_on_seatbelt
|
66
|
-
self.seatbelt_on = true
|
67
|
-
end
|
68
|
-
|
69
|
-
# We crashed! Increase the insurance premium on the vehicle
|
70
|
-
def increase_insurance_premium
|
71
|
-
update_attribute(:insurance_premium, self.insurance_premium + 100)
|
72
|
-
end
|
73
|
-
|
74
|
-
# Is the auto shop currently servicing another customer?
|
75
|
-
def auto_shop_busy?
|
76
|
-
auto_shop.busy?
|
77
|
-
end
|
78
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
class CreateAutoShops < ActiveRecord::Migration
|
2
|
-
def self.up
|
3
|
-
create_table :auto_shops do |t|
|
4
|
-
t.string :name, :null => false
|
5
|
-
t.integer :num_customers, :null => false
|
6
|
-
t.string :state, :null => false
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.down
|
11
|
-
drop_table :auto_shops
|
12
|
-
end
|
13
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
class CreateVehicles < ActiveRecord::Migration
|
2
|
-
def self.up
|
3
|
-
create_table :vehicles do |t|
|
4
|
-
t.references :highway, :null => false
|
5
|
-
t.references :auto_shop, :null => false
|
6
|
-
t.boolean :seatbelt_on, :null => false
|
7
|
-
t.integer :insurance_premium, :null => false
|
8
|
-
t.string :state, :null => false
|
9
|
-
t.string :type
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.down
|
14
|
-
drop_table :vehicles
|
15
|
-
end
|
16
|
-
end
|
data/test/factory.rb
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
module Factory
|
2
|
-
# Build actions for the model
|
3
|
-
def self.build(model, &block)
|
4
|
-
name = model.to_s.underscore
|
5
|
-
|
6
|
-
define_method("#{name}_attributes", block)
|
7
|
-
define_method("valid_#{name}_attributes") {|*args| valid_attributes_for(model, *args)}
|
8
|
-
define_method("new_#{name}") {|*args| new_record(model, *args)}
|
9
|
-
define_method("create_#{name}") {|*args| create_record(model, *args)}
|
10
|
-
end
|
11
|
-
|
12
|
-
# Get valid attributes for the model
|
13
|
-
def valid_attributes_for(model, attributes = {})
|
14
|
-
name = model.to_s.underscore
|
15
|
-
send("#{name}_attributes", attributes)
|
16
|
-
attributes.stringify_keys!
|
17
|
-
attributes
|
18
|
-
end
|
19
|
-
|
20
|
-
# Build an unsaved record
|
21
|
-
def new_record(model, *args)
|
22
|
-
attributes = valid_attributes_for(model, *args)
|
23
|
-
record = model.new(attributes)
|
24
|
-
attributes.each {|attr, value| record.send("#{attr}=", value) if model.accessible_attributes && !model.accessible_attributes.include?(attr) || model.protected_attributes && model.protected_attributes.include?(attr)}
|
25
|
-
record
|
26
|
-
end
|
27
|
-
|
28
|
-
# Build and save/reload a record
|
29
|
-
def create_record(model, *args)
|
30
|
-
record = new_record(model, *args)
|
31
|
-
record.save!
|
32
|
-
record.reload
|
33
|
-
record
|
34
|
-
end
|
35
|
-
|
36
|
-
build AutoShop do |attributes|
|
37
|
-
attributes.reverse_merge!(
|
38
|
-
:name => "Joe's Auto Body",
|
39
|
-
:num_customers => 0
|
40
|
-
)
|
41
|
-
end
|
42
|
-
|
43
|
-
build Car do |attributes|
|
44
|
-
valid_vehicle_attributes(attributes)
|
45
|
-
end
|
46
|
-
|
47
|
-
build Highway do |attributes|
|
48
|
-
attributes.reverse_merge!(
|
49
|
-
:name => 'Route 66'
|
50
|
-
)
|
51
|
-
end
|
52
|
-
|
53
|
-
build Motorcycle do |attributes|
|
54
|
-
valid_car_attributes(attributes)
|
55
|
-
end
|
56
|
-
|
57
|
-
build Switch do |attributes|
|
58
|
-
attributes.reverse_merge!(
|
59
|
-
:state => 'off'
|
60
|
-
)
|
61
|
-
end
|
62
|
-
|
63
|
-
build ToggleSwitch do |attributes|
|
64
|
-
attributes.reverse_merge!(
|
65
|
-
:state => 'off'
|
66
|
-
)
|
67
|
-
end
|
68
|
-
|
69
|
-
build Vehicle do |attributes|
|
70
|
-
attributes[:highway] = create_highway unless attributes.include?(:highway)
|
71
|
-
attributes[:auto_shop] = create_auto_shop unless attributes.include?(:auto_shop)
|
72
|
-
attributes.reverse_merge!(
|
73
|
-
:seatbelt_on => false,
|
74
|
-
:insurance_premium => 50
|
75
|
-
)
|
76
|
-
end
|
77
|
-
end
|