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.
Files changed (52) hide show
  1. data/CHANGELOG.rdoc +26 -0
  2. data/README.rdoc +254 -46
  3. data/Rakefile +29 -3
  4. data/examples/AutoShop_state.png +0 -0
  5. data/examples/Car_state.jpg +0 -0
  6. data/examples/Vehicle_state.png +0 -0
  7. data/lib/state_machine.rb +161 -116
  8. data/lib/state_machine/assertions.rb +21 -0
  9. data/lib/state_machine/callback.rb +168 -0
  10. data/lib/state_machine/eval_helpers.rb +67 -0
  11. data/lib/state_machine/event.rb +135 -101
  12. data/lib/state_machine/extensions.rb +83 -0
  13. data/lib/state_machine/guard.rb +115 -0
  14. data/lib/state_machine/integrations/active_record.rb +242 -0
  15. data/lib/state_machine/integrations/data_mapper.rb +198 -0
  16. data/lib/state_machine/integrations/data_mapper/observer.rb +153 -0
  17. data/lib/state_machine/integrations/sequel.rb +169 -0
  18. data/lib/state_machine/machine.rb +746 -352
  19. data/lib/state_machine/transition.rb +104 -212
  20. data/test/active_record.log +34865 -0
  21. data/test/classes/switch.rb +11 -0
  22. data/test/data_mapper.log +14015 -0
  23. data/test/functional/state_machine_test.rb +249 -15
  24. data/test/sequel.log +3835 -0
  25. data/test/test_helper.rb +3 -12
  26. data/test/unit/assertions_test.rb +13 -0
  27. data/test/unit/callback_test.rb +189 -0
  28. data/test/unit/eval_helpers_test.rb +92 -0
  29. data/test/unit/event_test.rb +247 -113
  30. data/test/unit/guard_test.rb +420 -0
  31. data/test/unit/integrations/active_record_test.rb +515 -0
  32. data/test/unit/integrations/data_mapper_test.rb +407 -0
  33. data/test/unit/integrations/sequel_test.rb +244 -0
  34. data/test/unit/invalid_transition_test.rb +1 -1
  35. data/test/unit/machine_test.rb +1056 -98
  36. data/test/unit/state_machine_test.rb +14 -113
  37. data/test/unit/transition_test.rb +269 -495
  38. metadata +44 -30
  39. data/test/app_root/app/models/auto_shop.rb +0 -34
  40. data/test/app_root/app/models/car.rb +0 -19
  41. data/test/app_root/app/models/highway.rb +0 -3
  42. data/test/app_root/app/models/motorcycle.rb +0 -3
  43. data/test/app_root/app/models/switch.rb +0 -23
  44. data/test/app_root/app/models/switch_observer.rb +0 -20
  45. data/test/app_root/app/models/toggle_switch.rb +0 -2
  46. data/test/app_root/app/models/vehicle.rb +0 -78
  47. data/test/app_root/config/environment.rb +0 -7
  48. data/test/app_root/db/migrate/001_create_switches.rb +0 -12
  49. data/test/app_root/db/migrate/002_create_auto_shops.rb +0 -13
  50. data/test/app_root/db/migrate/003_create_highways.rb +0 -11
  51. data/test/app_root/db/migrate/004_create_vehicles.rb +0 -16
  52. 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.3.1
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-10-26 00:00:00 -04:00
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/app_root
31
- - test/app_root/app
32
- - test/app_root/app/models
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/test_helper.rb
52
- - test/factory.rb
49
+ - test/data_mapper.log
50
+ - test/classes
51
+ - test/classes/switch.rb
53
52
  - test/unit
54
- - test/unit/transition_test.rb
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/machine_test.rb
60
+ - test/unit/transition_test.rb
61
+ - test/unit/eval_helpers_test.rb
57
62
  - test/unit/event_test.rb
58
- - test/unit/state_machine_test.rb
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 within a model
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/transition_test.rb
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/machine_test.rb
105
+ - test/unit/transition_test.rb
106
+ - test/unit/eval_helpers_test.rb
95
107
  - test/unit/event_test.rb
96
- - test/unit/state_machine_test.rb
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,3 +0,0 @@
1
- class Highway < ActiveRecord::Base
2
- has_many :vehicles
3
- end
@@ -1,3 +0,0 @@
1
- class Motorcycle < Vehicle
2
- state_machine :state, :initial => 'idling'
3
- 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,2 +0,0 @@
1
- class ToggleSwitch < Switch
2
- 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,7 +0,0 @@
1
- require 'config/boot'
2
-
3
- Rails::Initializer.run do |config|
4
- config.cache_classes = false
5
- config.whiny_nils = true
6
- config.active_record.observers = :switch_observer
7
- end
@@ -1,12 +0,0 @@
1
- class CreateSwitches < ActiveRecord::Migration
2
- def self.up
3
- create_table :switches do |t|
4
- t.string :state, :null => false
5
- t.string :kind
6
- end
7
- end
8
-
9
- def self.down
10
- drop_table :switches
11
- end
12
- 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,11 +0,0 @@
1
- class CreateHighways < ActiveRecord::Migration
2
- def self.up
3
- create_table :highways do |t|
4
- t.string :name, :null => false
5
- end
6
- end
7
-
8
- def self.down
9
- drop_table :highways
10
- end
11
- 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