edge-state-machine 0.9.0 → 0.9.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/README.rdoc +28 -2
- data/edge-state-machine.gemspec +2 -1
- data/lib/edge-state-machine/state.rb +6 -6
- data/lib/edge-state-machine/version.rb +1 -1
- data/lib/mongo_mapper/edge-state-machine.rb +79 -0
- data/spec/mongo_mapper/double_machine_spec.rb +72 -0
- data/spec/mongo_mapper/mongo_mapper_helper.rb +18 -0
- data/spec/mongo_mapper/mongo_mapper_spec.rb +134 -0
- data/spec/mongo_mapper/samples/double_machine.rb +61 -0
- data/spec/mongo_mapper/samples/order.rb +54 -0
- data/spec/mongo_mapper/samples/traffic_light.rb +79 -0
- metadata +34 -16
data/README.rdoc
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
= Edge State Machine
|
2
2
|
|
3
3
|
Edge State Machine is a complete state machine solution.
|
4
|
-
It offers support for ActiveRecord and
|
4
|
+
It offers support for ActiveRecord, Mongoid and MongoMapper for persistence.
|
5
5
|
|
6
6
|
{<img src="https://secure.travis-ci.org/danpersa/edge-state-machine.png"/>}[http://travis-ci.org/danpersa/edge-state-machine]
|
7
7
|
|
@@ -67,6 +67,31 @@ If you're using Rails + Mongoid + Bundler
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
+
If you're using Rails + MongoMapper + Bundler
|
71
|
+
|
72
|
+
# in your Gemfile
|
73
|
+
gem "edge-state-machine", :require => ["edge-state-machine", "mongo_mapper/edge-state-machine"]
|
74
|
+
|
75
|
+
# in your models that will use the state machine
|
76
|
+
include ::EdgeStateMachine
|
77
|
+
include MongoMapper::EdgeStateMachine
|
78
|
+
|
79
|
+
state_machine do
|
80
|
+
state :available # first one is initial state
|
81
|
+
state :out_of_stock
|
82
|
+
state :discontinue
|
83
|
+
|
84
|
+
event :discontinue do
|
85
|
+
transitions :to => :discontinue, :from => [:available, :out_of_stock], :on_transition => :do_discontinue
|
86
|
+
end
|
87
|
+
event :out_of_stock do
|
88
|
+
transitions :to => :out_of_stock, :from => [:available, :discontinue]
|
89
|
+
end
|
90
|
+
event :available do
|
91
|
+
transitions :to => :available, :from => [:out_of_stock], :on_transition => :send_alerts
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
70
95
|
== State Machine Examples
|
71
96
|
|
72
97
|
=== Microwave State Machine
|
@@ -174,7 +199,8 @@ For other (more complex) examples, please check the following links:
|
|
174
199
|
* {Examples without Persistence}[https://github.com/danpersa/edge-state-machine/tree/master/spec/non_persistent/samples]
|
175
200
|
* {Examples with ActiveRecord}[https://github.com/danpersa/edge-state-machine/tree/master/spec/active_record/samples]
|
176
201
|
* {Examples with Mongoid}[https://github.com/danpersa/edge-state-machine/tree/master/spec/mongoid/samples]
|
177
|
-
|
202
|
+
* {Examples with Mongoid}[https://github.com/danpersa/edge-state-machine/tree/master/spec/mongoid/samples]
|
203
|
+
* {Examples with MongoMapper}[https://github.com/danpersa/edge-state-machine/tree/master/spec/mongo_mapper/samples]
|
178
204
|
== Notes
|
179
205
|
|
180
206
|
For classes with multiple state machines, the state names, machine names must be unique per class.
|
data/edge-state-machine.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.email = ["dan.persa@gmail.com"]
|
10
10
|
s.homepage = "http://github.com/danpersa/edge-state-machine"
|
11
11
|
s.summary = %q{Edge State Machine}
|
12
|
-
s.description = %q{Edge State Machine is a complete state machine solution. It offers support for ActiveRecord and
|
12
|
+
s.description = %q{Edge State Machine is a complete state machine solution. It offers support for ActiveRecord, Mongoid and MongoMapper for persistence.}
|
13
13
|
|
14
14
|
s.rubyforge_project = "edge-state-machine"
|
15
15
|
|
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_development_dependency 'rspec', '~> 2.6'
|
24
24
|
s.add_development_dependency 'rake'
|
25
25
|
s.add_development_dependency 'mongoid'
|
26
|
+
s.add_development_dependency 'mongo_mapper'
|
26
27
|
s.add_development_dependency 'bson_ext'
|
27
28
|
s.add_development_dependency 'sqlite3-ruby'
|
28
29
|
s.add_development_dependency 'activerecord'
|
@@ -34,13 +34,13 @@ module EdgeStateMachine
|
|
34
34
|
@display_name ||= name.to_s.gsub(/_/, ' ').capitalize
|
35
35
|
end
|
36
36
|
|
37
|
-
def ==(
|
38
|
-
if
|
39
|
-
name ==
|
40
|
-
elsif
|
41
|
-
name ==
|
37
|
+
def ==(st)
|
38
|
+
if st.is_a? Symbol
|
39
|
+
name == st
|
40
|
+
elsif st.is_a? String
|
41
|
+
name == st
|
42
42
|
else
|
43
|
-
name ==
|
43
|
+
name == st.name
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module EdgeStateMachine
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
include ::EdgeStateMachine
|
7
|
+
# mongo mapper does not have an after_initalize callback
|
8
|
+
before_validation :set_initial_state
|
9
|
+
validate :state_variables_presence
|
10
|
+
validate :state_inclusion
|
11
|
+
end
|
12
|
+
|
13
|
+
# The optional options argument is passed to find when reloading so you may
|
14
|
+
# do e.g. record.reload(:lock => true) to reload the same record with an
|
15
|
+
# exclusive row lock.
|
16
|
+
def reload
|
17
|
+
super.tap do
|
18
|
+
@current_states = {}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def load_from_persistence(machine_name)
|
25
|
+
machine = self.class.state_machines[machine_name]
|
26
|
+
send machine.persisted_variable_name.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
def save_to_persistence(new_state, machine_name, options = {})
|
30
|
+
machine = self.class.state_machines[machine_name]
|
31
|
+
send("#{machine.persisted_variable_name}=".to_sym, new_state)
|
32
|
+
save! if options[:save]
|
33
|
+
end
|
34
|
+
|
35
|
+
def set_initial_state
|
36
|
+
# set the initial state for each state machine in this class
|
37
|
+
self.class.state_machines.keys.each do |machine_name|
|
38
|
+
machine = self.class.state_machines[machine_name]
|
39
|
+
|
40
|
+
if persisted_variable_value(machine.persisted_variable_name).blank?
|
41
|
+
if load_from_persistence(machine_name)
|
42
|
+
send("#{machine.persisted_variable_name}=".to_sym, load_from_persistence(machine_name))
|
43
|
+
else
|
44
|
+
send("#{machine.persisted_variable_name}=".to_sym, machine.initial_state_name)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def persisted_variable_value(name)
|
51
|
+
send(name.to_s)
|
52
|
+
end
|
53
|
+
|
54
|
+
def state_variables_presence
|
55
|
+
# validate that state is in the right set of values
|
56
|
+
self.class.state_machines.keys.each do |machine_name|
|
57
|
+
machine = self.class.state_machines[machine_name]
|
58
|
+
validates_presence_of machine.persisted_variable_name.to_sym
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def state_inclusion
|
63
|
+
# validate that state is in the right set of values
|
64
|
+
self.class.state_machines.keys.each do |machine_name|
|
65
|
+
machine = self.class.state_machines[machine_name]
|
66
|
+
unless machine.states.keys.include?(persisted_variable_value(machine.persisted_variable_name).to_sym)
|
67
|
+
self.errors.add(machine.persisted_variable_name.to_sym, :inclusion, :value => persisted_variable_value(machine.persisted_variable_name))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
module ClassMethods
|
73
|
+
def add_scope(state, machine_name)
|
74
|
+
machine = state_machines[machine_name]
|
75
|
+
scope state.name, where(machine.persisted_variable_name.to_sym => state.name.to_s)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'mongo_mapper/mongo_mapper_helper'
|
2
|
+
|
3
|
+
describe DoubleMachineMongoMapper do
|
4
|
+
|
5
|
+
before do
|
6
|
+
MongoMapper.database.collections.reject { |c| c.name =~ /^system\./ }.each(&:remove)
|
7
|
+
end
|
8
|
+
|
9
|
+
let :double_machine do
|
10
|
+
DoubleMachineMongoMapper.create!
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should have a current state equals with the initial state for each machine' do
|
14
|
+
double_machine.current_state.should == :first_state
|
15
|
+
double_machine.current_state(:second).should == :red
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should have the corresponding methods for verifying the states' do
|
19
|
+
double_machine.first_state?.should == true
|
20
|
+
double_machine.second_state?.should == false
|
21
|
+
double_machine.red?.should == true
|
22
|
+
double_machine.green?.should == false
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should trigger events from the state machines' do
|
26
|
+
double_machine.first_move
|
27
|
+
double_machine.current_state.should == :second_state
|
28
|
+
double_machine.second_state?.should == true
|
29
|
+
|
30
|
+
double_machine.go_green
|
31
|
+
double_machine.current_state(:second).should == :green
|
32
|
+
double_machine.green?.should == true
|
33
|
+
|
34
|
+
double_machine.second_move
|
35
|
+
double_machine.current_state.should == :third_state
|
36
|
+
double_machine.third_state?.should == true
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should execute the on_transition method' do
|
40
|
+
double_machine.should_receive :do_move
|
41
|
+
double_machine.first_move
|
42
|
+
double_machine.go_green
|
43
|
+
|
44
|
+
double_machine.should_receive :turn_off
|
45
|
+
double_machine.should_receive :color_in_red
|
46
|
+
double_machine.go_red
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'persistence ' do
|
50
|
+
it 'should create scopes for each state machine' do
|
51
|
+
3.times { DoubleMachineMongoMapper.create(:state => 'second_state', :second_state => 'blue') }
|
52
|
+
3.times { DoubleMachineMongoMapper.create(:state => 'first_state', :second_state => 'blue') }
|
53
|
+
DoubleMachineMongoMapper.first_state.count.should == 3
|
54
|
+
DoubleMachineMongoMapper.second_state.count.should == 3
|
55
|
+
DoubleMachineMongoMapper.blue.count.should == 6 end
|
56
|
+
|
57
|
+
it 'should save the state machines in the database' do
|
58
|
+
machine = DoubleMachineMongoMapper.create(:state => 'second_state', :second_state => 'blue')
|
59
|
+
machine.go_red!
|
60
|
+
machine.current_state(:second).should == :red
|
61
|
+
machine.red?.should == true
|
62
|
+
|
63
|
+
machine.second_move!
|
64
|
+
machine.third_state?.should == true
|
65
|
+
machine.current_state.should == :third_state
|
66
|
+
|
67
|
+
loaded_machine = DoubleMachineMongoMapper.find(machine.id)
|
68
|
+
loaded_machine.third_state?.should == true
|
69
|
+
loaded_machine.current_state.should == :third_state
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mongo_mapper'
|
3
|
+
|
4
|
+
|
5
|
+
MongoMapper.connection = Mongo::Connection.new('localhost', 27017)
|
6
|
+
MongoMapper.database = "edge_state_machine_mongo_mapper_test"
|
7
|
+
MongoMapper.database.collections.each { |c| c.drop_indexes }
|
8
|
+
|
9
|
+
require 'mongo_mapper/samples/traffic_light'
|
10
|
+
require 'mongo_mapper/samples/order'
|
11
|
+
require 'mongo_mapper/samples/double_machine'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
|
16
|
+
require 'mongo_mapper/edge-state-machine'
|
17
|
+
|
18
|
+
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'mongo_mapper/mongo_mapper_helper'
|
2
|
+
|
3
|
+
describe 'mongo_mapper state machine' do
|
4
|
+
before do
|
5
|
+
MongoMapper.database.collections.reject { |c| c.name =~ /^system\./ }.each(&:remove)
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'existing mongo document' do
|
9
|
+
|
10
|
+
let :light do
|
11
|
+
MongoMapperTrafficLight.create!
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should have an initial state' do
|
15
|
+
light.off?.should == true
|
16
|
+
light.current_state.should == :off
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should go to a valid state on transition' do
|
20
|
+
light.reset
|
21
|
+
light.red?.should == true
|
22
|
+
light.current_state.should == :red
|
23
|
+
|
24
|
+
light.green_on
|
25
|
+
light.green?.should == true
|
26
|
+
light.current_state.should == :green
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should not persist state on transition' do
|
30
|
+
light.reset
|
31
|
+
light.current_state.should == :red
|
32
|
+
light.reload
|
33
|
+
light.state.should == 'off'
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should persists state on transition' do
|
37
|
+
light.reset!
|
38
|
+
light.current_state.should == :red
|
39
|
+
light.reload
|
40
|
+
light.state.should == 'red'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should initialize the current state when loaded from database' do
|
44
|
+
light.reset!
|
45
|
+
loaded_light = MongoMapperTrafficLight.find(light.id)
|
46
|
+
loaded_light.current_state.should == :red
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should raise error on transition to an invalid state' do
|
50
|
+
expect { light.yellow_on }.should raise_error EdgeStateMachine::NoTransitionFound
|
51
|
+
light.current_state.should == :off
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should persist state when state is protected on transition' do
|
55
|
+
protected_light = MongoMapperProtectedTrafficLight.create!
|
56
|
+
protected_light.reset!
|
57
|
+
protected_light.current_state.should == :red
|
58
|
+
protected_light.reload
|
59
|
+
protected_light.state.should == 'red'
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should not validate when try transition with wrong state ' do
|
63
|
+
for s in light.class.state_machines[:default].states.keys
|
64
|
+
light.state = s
|
65
|
+
light.valid?.should == true
|
66
|
+
end
|
67
|
+
light.state = 'invalid_one'
|
68
|
+
light.valid?.should_not == true
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should raise exception when model validation fails on transition' do
|
72
|
+
validating_light = MongoMapperValidatingTrafficLight.create!
|
73
|
+
expect {validating_light.reset!}.should raise_error MongoMapper::DocumentNotValid
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should state query method used in a validation condition' do
|
77
|
+
validating_light = MongoMapperConditionalValidatingTrafficLight.create!
|
78
|
+
#expect {validating_light.reset!}.should raise_error Mongoid::RecordInvalid
|
79
|
+
validating_light.off?.should == true
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should reload the model when current state resets' do
|
83
|
+
light.reset
|
84
|
+
light.red?.should == true
|
85
|
+
light.update_attribute(:state, 'green')
|
86
|
+
light.reload.green?.should == true # reloaded state should come from database
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'scopes' do
|
90
|
+
it 'should be added for each state' do
|
91
|
+
MongoMapperTrafficLight.should respond_to(:off)
|
92
|
+
MongoMapperTrafficLight.should respond_to(:red)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should not be added for each state' do
|
96
|
+
MongoMapperTrafficLightNoScope.should_not respond_to(:off)
|
97
|
+
MongoMapperTrafficLightNoScope.should_not respond_to(:red)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should behave like scopes' do
|
101
|
+
3.times { MongoMapperTrafficLight.create(:state => 'off') }
|
102
|
+
3.times { MongoMapperTrafficLight.create(:state => 'red') }
|
103
|
+
MongoMapperTrafficLight.off.count.should == 3
|
104
|
+
MongoMapperTrafficLight.red.count.should == 3
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'new active record' do
|
110
|
+
let :light do
|
111
|
+
MongoMapperTrafficLight.new
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should have the initial state set after validation' do
|
115
|
+
# mongo mapper does not have an after_initalize callback
|
116
|
+
light.valid?
|
117
|
+
light.current_state.should == :off
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'timestamp' do
|
122
|
+
|
123
|
+
def create_order(state = nil)
|
124
|
+
MongoMapperOrder.create! order_number: 234, state: state
|
125
|
+
end
|
126
|
+
|
127
|
+
# control case, no timestamp has been set so we should expect default behaviour
|
128
|
+
it 'should not raise any exceptions when moving to placed' do
|
129
|
+
@order = create_order
|
130
|
+
expect { @order.place! }.should_not raise_error
|
131
|
+
@order.state.should == 'placed'
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'mongo_mapper'
|
2
|
+
require 'mongo_mapper/edge-state-machine'
|
3
|
+
|
4
|
+
class DoubleMachineMongoMapper
|
5
|
+
include MongoMapper::Document
|
6
|
+
include MongoMapper::EdgeStateMachine
|
7
|
+
|
8
|
+
key :state, String
|
9
|
+
key :second_state, String
|
10
|
+
|
11
|
+
state_machine do
|
12
|
+
# the machine is automatically named :default
|
13
|
+
# the scopes are not created by default
|
14
|
+
create_scopes true
|
15
|
+
# the persistence instance variable is the default one (:state)
|
16
|
+
state :first_state # first one is initial state
|
17
|
+
state :second_state
|
18
|
+
state :third_state # the user in this state can't sign in
|
19
|
+
|
20
|
+
event :first_move do
|
21
|
+
transition :from => :first_state, :to => :second_state, :on_transition => :do_move
|
22
|
+
end
|
23
|
+
|
24
|
+
event :second_move do
|
25
|
+
transition :from => :second_state, :to => :third_state
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
state_machine :second do
|
30
|
+
# the scopes are not created by default
|
31
|
+
create_scopes true
|
32
|
+
# for the second machine we must specify the name of the persistence instance variable
|
33
|
+
# so there are no conflicts between the state machines
|
34
|
+
persisted_to :second_state
|
35
|
+
initial_state :red
|
36
|
+
state :blue
|
37
|
+
state :green
|
38
|
+
state :red
|
39
|
+
|
40
|
+
event :go_blue do
|
41
|
+
transition :from => [:red, :green], :to => :blue
|
42
|
+
end
|
43
|
+
|
44
|
+
event :go_red do
|
45
|
+
transition :from => [:blue, :green], :to => :red, :on_transition => [:turn_off, :color_in_red]
|
46
|
+
end
|
47
|
+
|
48
|
+
event :go_green do
|
49
|
+
transition :from => [:blue, :red], :to => :green
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def do_move
|
54
|
+
end
|
55
|
+
|
56
|
+
def turn_off
|
57
|
+
end
|
58
|
+
|
59
|
+
def color_in_red
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'mongo_mapper'
|
2
|
+
require 'mongo_mapper/edge-state-machine'
|
3
|
+
|
4
|
+
class MongoMapperOrder
|
5
|
+
include MongoMapper::Document
|
6
|
+
include MongoMapper::EdgeStateMachine
|
7
|
+
|
8
|
+
key :state, String
|
9
|
+
key :order_number, Integer
|
10
|
+
key :paid_at, DateTime
|
11
|
+
key :prepared_on, DateTime
|
12
|
+
key :dispatched_at, DateTime
|
13
|
+
key :cancellation_date, Date
|
14
|
+
|
15
|
+
state_machine do
|
16
|
+
state :opened
|
17
|
+
state :placed
|
18
|
+
state :paid
|
19
|
+
state :prepared
|
20
|
+
state :delivered
|
21
|
+
state :cancelled
|
22
|
+
|
23
|
+
# no timestamp col is being specified here - should be ignored
|
24
|
+
event :place do
|
25
|
+
transition :from => :opened, :to => :placed
|
26
|
+
end
|
27
|
+
|
28
|
+
# should set paid_at timestamp
|
29
|
+
event :pay do
|
30
|
+
transition :from => :placed, :to => :paid
|
31
|
+
end
|
32
|
+
|
33
|
+
# should set prepared_on
|
34
|
+
event :prepare do
|
35
|
+
transition :from => :paid, :to => :prepared
|
36
|
+
end
|
37
|
+
|
38
|
+
# should set dispatched_at
|
39
|
+
event :deliver do
|
40
|
+
transition :from => :prepared, :to => :delivered
|
41
|
+
end
|
42
|
+
|
43
|
+
# should set cancellation_date
|
44
|
+
event :cancel do
|
45
|
+
transition :from => [:placed, :paid, :prepared], :to => :cancelled
|
46
|
+
end
|
47
|
+
|
48
|
+
# should raise an exception as there is no timestamp col
|
49
|
+
event :reopen do
|
50
|
+
transition :from => :cancelled, :to => :opened
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'mongo_mapper'
|
2
|
+
require 'mongo_mapper/edge-state-machine'
|
3
|
+
|
4
|
+
class MongoMapperTrafficLight
|
5
|
+
include MongoMapper::Document
|
6
|
+
include MongoMapper::EdgeStateMachine
|
7
|
+
|
8
|
+
key :state, String
|
9
|
+
|
10
|
+
state_machine do
|
11
|
+
create_scopes true
|
12
|
+
persisted_to :state
|
13
|
+
state :off
|
14
|
+
|
15
|
+
state :red
|
16
|
+
state :green
|
17
|
+
state :yellow
|
18
|
+
|
19
|
+
event :red_on do
|
20
|
+
transition :to => :red, :from => [:yellow]
|
21
|
+
end
|
22
|
+
|
23
|
+
event :green_on do
|
24
|
+
transition :to => :green, :from => [:red]
|
25
|
+
end
|
26
|
+
|
27
|
+
event :yellow_on do
|
28
|
+
transition :to => :yellow, :from => [:green]
|
29
|
+
end
|
30
|
+
|
31
|
+
event :reset do
|
32
|
+
transition :to => :red, :from => [:off]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class MongoMapperProtectedTrafficLight < MongoMapperTrafficLight
|
38
|
+
attr_protected :state
|
39
|
+
end
|
40
|
+
|
41
|
+
class MongoMapperValidatingTrafficLight < MongoMapperTrafficLight
|
42
|
+
validate {|t| errors.add(:base, 'This TrafficLight will never validate after creation') unless t.new_record? }
|
43
|
+
end
|
44
|
+
|
45
|
+
class MongoMapperConditionalValidatingTrafficLight < MongoMapperTrafficLight
|
46
|
+
validates :name, :presence => true, :length => { :within => 20..40 }, :confirmation => true, :if => :red?
|
47
|
+
end
|
48
|
+
|
49
|
+
class MongoMapperTrafficLightNoScope
|
50
|
+
include MongoMapper::Document
|
51
|
+
include MongoMapper::EdgeStateMachine
|
52
|
+
|
53
|
+
key :state, String
|
54
|
+
|
55
|
+
state_machine do
|
56
|
+
persisted_to :state
|
57
|
+
state :off
|
58
|
+
|
59
|
+
state :red
|
60
|
+
state :green
|
61
|
+
state :yellow
|
62
|
+
|
63
|
+
event :red_on do
|
64
|
+
transition :to => :red, :from => [:yellow]
|
65
|
+
end
|
66
|
+
|
67
|
+
event :green_on do
|
68
|
+
transition :to => :green, :from => [:red]
|
69
|
+
end
|
70
|
+
|
71
|
+
event :yellow_on do
|
72
|
+
transition :to => :yellow, :from => [:green]
|
73
|
+
end
|
74
|
+
|
75
|
+
event :reset do
|
76
|
+
transition :to => :red, :from => [:off]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: edge-state-machine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &17648880 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '2.6'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *17648880
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake
|
27
|
-
requirement: &
|
27
|
+
requirement: &17648460 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *17648460
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: mongoid
|
38
|
-
requirement: &
|
38
|
+
requirement: &17648000 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,21 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *17648000
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: mongo_mapper
|
49
|
+
requirement: &17647580 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *17647580
|
47
58
|
- !ruby/object:Gem::Dependency
|
48
59
|
name: bson_ext
|
49
|
-
requirement: &
|
60
|
+
requirement: &17647160 !ruby/object:Gem::Requirement
|
50
61
|
none: false
|
51
62
|
requirements:
|
52
63
|
- - ! '>='
|
@@ -54,10 +65,10 @@ dependencies:
|
|
54
65
|
version: '0'
|
55
66
|
type: :development
|
56
67
|
prerelease: false
|
57
|
-
version_requirements: *
|
68
|
+
version_requirements: *17647160
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: sqlite3-ruby
|
60
|
-
requirement: &
|
71
|
+
requirement: &17646740 !ruby/object:Gem::Requirement
|
61
72
|
none: false
|
62
73
|
requirements:
|
63
74
|
- - ! '>='
|
@@ -65,10 +76,10 @@ dependencies:
|
|
65
76
|
version: '0'
|
66
77
|
type: :development
|
67
78
|
prerelease: false
|
68
|
-
version_requirements: *
|
79
|
+
version_requirements: *17646740
|
69
80
|
- !ruby/object:Gem::Dependency
|
70
81
|
name: activerecord
|
71
|
-
requirement: &
|
82
|
+
requirement: &17646320 !ruby/object:Gem::Requirement
|
72
83
|
none: false
|
73
84
|
requirements:
|
74
85
|
- - ! '>='
|
@@ -76,9 +87,9 @@ dependencies:
|
|
76
87
|
version: '0'
|
77
88
|
type: :development
|
78
89
|
prerelease: false
|
79
|
-
version_requirements: *
|
90
|
+
version_requirements: *17646320
|
80
91
|
description: Edge State Machine is a complete state machine solution. It offers support
|
81
|
-
for ActiveRecord and
|
92
|
+
for ActiveRecord, Mongoid and MongoMapper for persistence.
|
82
93
|
email:
|
83
94
|
- dan.persa@gmail.com
|
84
95
|
executables: []
|
@@ -100,6 +111,7 @@ files:
|
|
100
111
|
- lib/edge-state-machine/state.rb
|
101
112
|
- lib/edge-state-machine/transition.rb
|
102
113
|
- lib/edge-state-machine/version.rb
|
114
|
+
- lib/mongo_mapper/edge-state-machine.rb
|
103
115
|
- lib/mongoid/edge-state-machine.rb
|
104
116
|
- spec/active_record/active_record_helper.rb
|
105
117
|
- spec/active_record/active_record_spec.rb
|
@@ -112,6 +124,12 @@ files:
|
|
112
124
|
- spec/active_record/samples/traffic_light.rb
|
113
125
|
- spec/event_spec.rb
|
114
126
|
- spec/machine_spec.rb
|
127
|
+
- spec/mongo_mapper/double_machine_spec.rb
|
128
|
+
- spec/mongo_mapper/mongo_mapper_helper.rb
|
129
|
+
- spec/mongo_mapper/mongo_mapper_spec.rb
|
130
|
+
- spec/mongo_mapper/samples/double_machine.rb
|
131
|
+
- spec/mongo_mapper/samples/order.rb
|
132
|
+
- spec/mongo_mapper/samples/traffic_light.rb
|
115
133
|
- spec/mongoid/double_machine_spec.rb
|
116
134
|
- spec/mongoid/mongoid_helper.rb
|
117
135
|
- spec/mongoid/mongoid_spec.rb
|
@@ -150,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
168
|
version: '0'
|
151
169
|
requirements: []
|
152
170
|
rubyforge_project: edge-state-machine
|
153
|
-
rubygems_version: 1.8.
|
171
|
+
rubygems_version: 1.8.10
|
154
172
|
signing_key:
|
155
173
|
specification_version: 3
|
156
174
|
summary: Edge State Machine
|