stateflow 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,9 @@
1
+ = Version 0.3.0
2
+ * Added a non bang method for events (Check README)
3
+ * Added tests to persistence layers (About time!)
4
+ * Changed the way the persistence layers save to model
5
+ * Protected state column is now supported!
6
+
1
7
  = Version 0.2.3
2
8
  * Silence depreciation warnings (Fixing irritating issue)
3
9
 
@@ -12,4 +18,4 @@
12
18
  * Changed the persistence layers to use write_attribute, instead of update_attribute - Thanks to achirkunov
13
19
 
14
20
  = Version 0.1.2
15
- * Fixed Mongoid support - Thanks bmartin for pointing that out
21
+ * Fixed Mongoid support - Thanks bmartin for pointing that out
@@ -35,18 +35,18 @@ You can set the default column with the state_column function in the stateflow b
35
35
 
36
36
  require 'rubygems'
37
37
  require 'stateflow'
38
-
38
+
39
39
  # No persistence
40
40
  Stateflow.persistence :none
41
41
 
42
42
  class Robot
43
43
  include Stateflow
44
-
44
+
45
45
  stateflow do
46
46
  initial :green
47
-
47
+
48
48
  state :green, :yellow, :red
49
-
49
+
50
50
  event :change_color do
51
51
  transitions :from => :green, :to => :yellow
52
52
  transitions :from => :yellow, :to => :red
@@ -54,61 +54,65 @@ You can set the default column with the state_column function in the stateflow b
54
54
  end
55
55
  end
56
56
  end
57
-
57
+
58
58
  == Advanced Example
59
59
 
60
60
  require 'rubygems'
61
61
  require 'stateflow'
62
-
62
+
63
63
  # No persistence
64
64
  Stateflow.persistence :none
65
65
 
66
66
  class Test
67
67
  include Stateflow
68
-
68
+
69
69
  stateflow do
70
-
70
+
71
71
  initial :love
72
-
72
+
73
73
  state :love do
74
74
  enter lambda { |t| p "Entering love" }
75
75
  exit :exit_love
76
76
  end
77
-
77
+
78
78
  state :hate do
79
79
  enter lambda { |t| p "Entering hate" }
80
80
  exit lambda { |t| p "Exiting hate" }
81
81
  end
82
-
82
+
83
83
  state :mixed do
84
84
  enter lambda { |t| p "Entering mixed" }
85
85
  exit lambda { |t| p "Exiting mixed" }
86
86
  end
87
-
87
+
88
88
  event :b do
89
89
  transitions :from => :love, :to => :hate, :if => :no_ice_cream
90
90
  transitions :from => :hate, :to => :love
91
91
  end
92
-
92
+
93
93
  event :a do
94
94
  transitions :from => :love, :to => [:hate, :mixed], :decide => :likes_ice_cream?
95
95
  transitions :from => [:hate, :mixed], :to => :love
96
96
  end
97
97
  end
98
-
98
+
99
99
  def likes_ice_cream?
100
100
  rand(10) > 5 ? :mixed : :hate
101
101
  end
102
-
102
+
103
103
  def exit_love
104
104
  p "Exiting love"
105
105
  end
106
-
106
+
107
107
  def no_ice_cream
108
108
  rand(4) > 2 ? true : false
109
109
  end
110
110
  end
111
-
111
+
112
+ == Bang event vs non-bang event
113
+
114
+ Bang events will save the model after call, where the non bang event will just update the state and call the transitions. (ie. model.change! vs model.change)
115
+
112
116
  == Extra's
113
117
 
114
118
  * When transitioning states, the previous state from which you have transitioned to can be accessed via `_previous_state`. See tests for more information.
data/Rakefile CHANGED
@@ -2,11 +2,11 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- Echoe.new('stateflow', '0.2.3') do |p|
5
+ Echoe.new('stateflow', '0.3.0') do |p|
6
6
  p.description = "State machine that allows dynamic transitions for business workflows"
7
7
  p.url = "http://github.com/ryanza/stateflow"
8
8
  p.author = "Ryan Oberholzer"
9
9
  p.email = "ryan@platform45.com"
10
10
  p.ignore_pattern = ["tmp/*", "script/*"]
11
- p.development_dependencies = ["rspec"]
12
- end
11
+ p.development_dependencies = ["rspec", "activerecord", "mongoid >=2.0.0.beta.20", "sqlite3-ruby"]
12
+ end
@@ -27,8 +27,12 @@ module Stateflow
27
27
  end
28
28
 
29
29
  @machine.events.keys.each do |key|
30
+ define_method "#{key}" do
31
+ fire_event(key, :save => false)
32
+ end
33
+
30
34
  define_method "#{key}!" do
31
- fire_event(key)
35
+ fire_event(key, :save => true)
32
36
  end
33
37
  end
34
38
  end
@@ -41,8 +45,8 @@ module Stateflow
41
45
  @current_state ||= load_from_persistence.nil? ? machine.initial_state : machine.states[load_from_persistence.to_sym]
42
46
  end
43
47
 
44
- def current_state=(new_state)
45
- save_to_persistence(new_state.name.to_s)
48
+ def set_current_state(new_state, options)
49
+ save_to_persistence(new_state.name.to_s, options)
46
50
  @current_state = new_state
47
51
  end
48
52
 
@@ -51,10 +55,10 @@ module Stateflow
51
55
  end
52
56
 
53
57
  private
54
- def fire_event(event_name)
58
+ def fire_event(event_name, options = {})
55
59
  event = machine.events[event_name.to_sym]
56
60
  raise Stateflow::NoEventFound.new("No event matches #{event_name}") if event.nil?
57
- event.fire(current_state, self)
61
+ event.fire(current_state, self, options)
58
62
  end
59
63
  end
60
64
 
@@ -10,7 +10,7 @@ module Stateflow
10
10
  instance_eval(&transitions)
11
11
  end
12
12
 
13
- def fire(current_state, klass)
13
+ def fire(current_state, klass, options)
14
14
  transition = @transitions.select{ |t| t.from.include? current_state.name }.first
15
15
  raise NoTransitionFound.new("No transition found for event #{@name}") if transition.nil?
16
16
 
@@ -20,7 +20,7 @@ module Stateflow
20
20
  raise NoStateFound.new("Invalid state #{transition.to.to_s} for transition.") if new_state.nil?
21
21
 
22
22
  current_state.execute_action(:exit, klass)
23
- klass.current_state = new_state
23
+ klass.set_current_state(new_state, options)
24
24
 
25
25
  klass._previous_state = current_state.name.to_s
26
26
  new_state.execute_action(:enter, klass)
@@ -13,8 +13,9 @@ module Stateflow
13
13
  self.send machine.state_column.to_sym
14
14
  end
15
15
 
16
- def save_to_persistence(new_state)
17
- self.update_attribute(machine.state_column.to_sym, new_state)
16
+ def save_to_persistence(new_state, options)
17
+ self.send("#{machine.state_column}=".to_sym, new_state)
18
+ self.save if options[:save]
18
19
  end
19
20
 
20
21
  def ensure_initial_state
@@ -23,4 +24,4 @@ module Stateflow
23
24
  end
24
25
  end
25
26
  end
26
- end
27
+ end
@@ -11,8 +11,9 @@ module Stateflow
11
11
  self.send machine.state_column.to_sym
12
12
  end
13
13
 
14
- def save_to_persistence(new_state)
15
- self.update_attributes(machine.state_column.to_sym => new_state)
14
+ def save_to_persistence(new_state, options)
15
+ self.send("#{machine.state_column}=".to_sym, new_state)
16
+ self.save if options[:save]
16
17
  end
17
18
 
18
19
  def ensure_initial_state
@@ -21,4 +22,4 @@ module Stateflow
21
22
  end
22
23
  end
23
24
  end
24
- end
25
+ end
@@ -11,8 +11,9 @@ module Stateflow
11
11
  self.send machine.state_column.to_sym
12
12
  end
13
13
 
14
- def save_to_persistence(new_state)
15
- self.update_attributes(machine.state_column.to_sym => new_state)
14
+ def save_to_persistence(new_state, options = {})
15
+ self.send("#{machine.state_column}=".to_sym, new_state)
16
+ self.save if options[:save]
16
17
  end
17
18
 
18
19
  def ensure_initial_state
@@ -12,10 +12,10 @@ module Stateflow
12
12
  @state
13
13
  end
14
14
 
15
- def save_to_persistence(new_state)
15
+ def save_to_persistence(new_state, options)
16
16
  @state = new_state
17
17
  end
18
18
  end
19
19
  end
20
20
  end
21
- end
21
+ end
@@ -2,11 +2,3 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
 
4
4
  require 'stateflow'
5
-
6
- require 'spec'
7
- require 'spec/autorun'
8
-
9
- Stateflow.persistence = :none
10
-
11
- Spec::Runner.configure do |config|
12
- end
@@ -1,13 +1,15 @@
1
1
  require 'spec_helper'
2
2
 
3
+ Stateflow.persistence = :none
4
+
3
5
  class Robot
4
6
  include Stateflow
5
-
7
+
6
8
  stateflow do
7
9
  initial :green
8
-
10
+
9
11
  state :green, :yellow, :red
10
-
12
+
11
13
  event :change_color do
12
14
  transitions :from => :green, :to => :yellow
13
15
  transitions :from => :yellow, :to => :red
@@ -16,32 +18,32 @@ class Robot
16
18
  end
17
19
  end
18
20
 
19
- class Car
21
+ class Car
20
22
  include Stateflow
21
-
23
+
22
24
  stateflow do
23
25
  initial :parked
24
-
26
+
25
27
  state :parked do
26
28
  enter do
27
29
  "Entering parked"
28
30
  end
29
-
31
+
30
32
  exit do
31
33
  "Exiting parked"
32
34
  end
33
35
  end
34
-
36
+
35
37
  state :driving do
36
38
  enter do
37
39
  "Entering parked"
38
40
  end
39
41
  end
40
-
42
+
41
43
  event :drive do
42
44
  transitions :from => :parked, :to => :driving
43
45
  end
44
-
46
+
45
47
  event :park do
46
48
  transitions :from => :driving, :to => :parked
47
49
  end
@@ -50,10 +52,10 @@ end
50
52
 
51
53
  class Bob
52
54
  include Stateflow
53
-
55
+
54
56
  stateflow do
55
57
  state :yellow, :red, :purple
56
-
58
+
57
59
  event :change_hair_color do
58
60
  transitions :from => :purple, :to => :yellow
59
61
  transitions :from => :yellow, :to => :red
@@ -64,47 +66,47 @@ end
64
66
 
65
67
  class Dater
66
68
  include Stateflow
67
-
69
+
68
70
  stateflow do
69
71
  state :single, :dating, :married
70
-
72
+
71
73
  event :take_out do
72
74
  transitions :from => :single, :to => :dating
73
75
  end
74
-
76
+
75
77
  event :gift do
76
78
  transitions :from => :dating, :to => [:single, :married], :decide => :girls_mood?
77
79
  end
78
-
80
+
79
81
  event :blank_decision do
80
82
  transitions :from => :single, :to => [:single, :married], :decide => :girls_mood?
81
83
  end
82
-
84
+
83
85
  event :fail do
84
86
  transitions :from => :dating, :to => [:single, :married]
85
87
  end
86
88
  end
87
-
89
+
88
90
  def girls_mood?
89
91
  end
90
92
  end
91
93
 
92
94
  class Priority
93
95
  include Stateflow
94
-
96
+
95
97
  stateflow do
96
98
  initial :medium
97
99
  state :low, :medium, :high
98
-
100
+
99
101
  event :low do
100
102
  transitions :from => any, :to => :low
101
103
  end
102
-
103
- event :medium do
104
+
105
+ event :medium do
104
106
  transitions :from => any, :to => :medium
105
- end
106
-
107
- event :high do
107
+ end
108
+
109
+ event :high do
108
110
  transitions :from => any, :to => :high
109
111
  end
110
112
  end
@@ -112,176 +114,185 @@ end
112
114
 
113
115
  class Stater
114
116
  include Stateflow
115
-
117
+
116
118
  stateflow do
117
119
  initial :bill
118
-
120
+
119
121
  state :bob, :bill
120
-
122
+
121
123
  event :lolcats do
122
124
  transitions :from => :bill, :to => :bob
123
125
  end
124
126
  end
125
127
  end
126
-
128
+
127
129
 
128
130
  describe Stateflow do
129
131
  describe "class methods" do
130
132
  it "should respond to stateflow block to setup the intial stateflow" do
131
133
  Robot.should respond_to(:stateflow)
132
134
  end
133
-
135
+
134
136
  it "should respond to the machine attr accessor" do
135
137
  Robot.should respond_to(:machine)
136
138
  end
137
139
  end
138
-
140
+
139
141
  describe "instance methods" do
140
142
  before(:each) do
141
143
  @r = Robot.new
142
144
  end
143
-
145
+
144
146
  it "should respond to current state" do
145
147
  @r.should respond_to(:current_state)
146
148
  end
147
-
149
+
148
150
  it "should respond to the current state setter" do
149
- @r.should respond_to(:current_state=)
151
+ @r.should respond_to(:set_current_state)
150
152
  end
151
-
153
+
152
154
  it "should respond to the current machine" do
153
155
  @r.should respond_to(:machine)
154
156
  end
155
-
157
+
156
158
  it "should respond to load from persistence" do
157
159
  @r.should respond_to(:load_from_persistence)
158
160
  end
159
-
161
+
160
162
  it "should respond to save to persistence" do
161
163
  @r.should respond_to(:save_to_persistence)
162
164
  end
163
165
  end
164
-
166
+
165
167
  describe "initial state" do
166
168
  it "should set the initial state" do
167
169
  robot = Robot.new
168
170
  robot.current_state.name.should == :green
169
171
  end
170
-
172
+
171
173
  it "should return true for green?" do
172
174
  robot = Robot.new
173
175
  robot.green?.should be_true
174
176
  end
175
-
177
+
176
178
  it "should return false for yellow?" do
177
179
  robot = Robot.new
178
180
  robot.yellow?.should be_false
179
181
  end
180
-
182
+
181
183
  it "should return false for red?" do
182
184
  robot = Robot.new
183
185
  robot.red?.should be_false
184
186
  end
185
-
187
+
186
188
  it "should set the initial state to the first state set" do
187
189
  bob = Bob.new
188
190
  bob.current_state.name.should == :yellow
189
191
  bob.yellow?.should be_true
190
192
  end
191
193
  end
192
-
194
+
193
195
  it "robot class should contain red, yellow and green states" do
194
196
  robot = Robot.new
195
197
  robot.machine.states.keys.should include(:red, :yellow, :green)
196
198
  end
197
-
199
+
198
200
  describe "firing events" do
199
- it "should call the fire method on event" do
200
- robot = Robot.new
201
- robot.machine.events[:change_color].should_receive(:fire)
202
- robot.change_color!
203
- end
204
-
205
- it "should call the fire_event method" do
206
- robot = Robot.new
207
- robot.should_receive(:fire_event).with(:change_color)
208
- robot.change_color!
209
- end
210
-
201
+ let(:robot) { Robot.new }
202
+ let(:event) { :change_color }
203
+ subject { robot }
204
+
211
205
  it "should raise an exception if the event does not exist" do
212
- robot = Robot.new
213
206
  lambda { robot.send(:fire_event, :fake) }.should raise_error(Stateflow::NoEventFound)
214
207
  end
215
-
216
- it "should fire the event" do
217
- robot = Robot.new
218
- robot.should_receive(:fire_event).with(:change_color)
219
- robot.change_color!
208
+
209
+ shared_examples_for "an entity supporting state changes" do
210
+ context "when firing" do
211
+ after(:each) { subject.send(event_method) }
212
+ it "should call the fire method on event" do
213
+ subject.machine.events[event].should_receive(:fire)
214
+ end
215
+
216
+ it "should call the fire_event method" do
217
+ subject.should_receive(:fire_event).with(event, {:save=>persisted})
218
+ end
219
+ end
220
+
221
+ it "should update the current state" do
222
+ subject.current_state.name.should == :green
223
+ subject.send(event_method)
224
+ subject.current_state.name.should == :yellow
225
+ end
220
226
  end
221
-
222
- it "should update the event" do
223
- robot = Robot.new
224
- robot.current_state.name.should == :green
225
- robot.change_color!
226
- robot.current_state.name.should == :yellow
227
+
228
+ describe "bang event" do
229
+ let(:event_method) { :change_color! }
230
+ let(:persisted) { true }
231
+ it_should_behave_like "an entity supporting state changes"
232
+ end
233
+
234
+ describe "non-bang event" do
235
+ let(:event_method) { :change_color }
236
+ let(:persisted) { false }
237
+ it_should_behave_like "an entity supporting state changes"
227
238
  end
228
-
239
+
229
240
  describe "before filters" do
230
241
  before(:each) do
231
242
  @car = Car.new
232
243
  end
233
-
244
+
234
245
  it "should call the exit state before filter on the exiting old state" do
235
246
  @car.machine.states[:parked].should_receive(:execute_action).with(:exit, @car)
236
247
  @car.drive!
237
248
  end
238
-
249
+
239
250
  it "should call the enter state before filter on the entering new state" do
240
251
  @car.machine.states[:driving].should_receive(:execute_action).with(:enter, @car)
241
252
  @car.drive!
242
253
  end
243
254
  end
244
255
  end
245
-
246
- describe "persistence" do
256
+
257
+ describe "persistence" do
247
258
  it "should attempt to persist the new state and the name should be a string" do
248
259
  robot = Robot.new
249
- robot.should_receive(:save_to_persistence).with("yellow")
260
+ robot.should_receive(:save_to_persistence).with("yellow", {:save=>true})
250
261
  robot.change_color!
251
262
  end
252
-
263
+
253
264
  it "should attempt to read the initial state from the persistence" do
254
265
  robot = Robot.new
255
-
266
+
256
267
  def robot.load_from_persistence
257
268
  :red
258
269
  end
259
-
270
+
260
271
  robot.current_state.name.should == :red
261
272
  end
262
273
  end
263
-
274
+
264
275
  describe "dynamic to transitions" do
265
276
  it "should raise an error without any decide argument" do
266
277
  date = Dater.new
267
-
278
+
268
279
  def date.load_from_persistence
269
280
  :dating
270
281
  end
271
-
282
+
272
283
  lambda { date.fail! }.should raise_error(Stateflow::IncorrectTransition)
273
284
  end
274
-
285
+
275
286
  it "should raise an error if the decision method does not return a valid state" do
276
287
  date = Dater.new
277
-
288
+
278
289
  def date.girls_mood?
279
290
  :lol
280
291
  end
281
-
292
+
282
293
  lambda { date.blank_decision! }.should raise_error(Stateflow::NoStateFound, "Decision did not return a state that was set in the 'to' argument")
283
294
  end
284
-
295
+
285
296
  it "should raise an error if the decision method returns blank/nil" do
286
297
  date = Dater.new
287
298
 
@@ -290,27 +301,27 @@ describe Stateflow do
290
301
 
291
302
  lambda { date.blank_decision! }.should raise_error(Stateflow::NoStateFound, "Decision did not return a state that was set in the 'to' argument")
292
303
  end
293
-
304
+
294
305
  it "should calculate the decide block or method and transition to the correct state" do
295
306
  date = Dater.new
296
-
307
+
297
308
  def date.load_from_persistence
298
309
  :dating
299
310
  end
300
-
311
+
301
312
  date.current_state.name.should == :dating
302
-
313
+
303
314
  def date.girls_mood?
304
315
  :single
305
316
  end
306
-
317
+
307
318
  date.gift!
308
-
319
+
309
320
  date.current_state.name.should == :single
310
321
  end
311
322
  end
312
-
313
- describe "transitions from any" do
323
+
324
+ describe "transitions from any" do
314
325
  it "should properly change state" do
315
326
  priority = Priority.new
316
327
  priority.low!
@@ -321,12 +332,12 @@ describe Stateflow do
321
332
  priority.should be_high
322
333
  end
323
334
  end
324
-
335
+
325
336
  describe "previous state" do
326
337
  it "should display the previous state" do
327
338
  stater = Stater.new
328
339
  stater.lolcats!
329
-
340
+
330
341
  stater._previous_state.should == "bill"
331
342
  stater.current_state == "bob"
332
343
  end
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{stateflow}
5
- s.version = "0.2.3"
5
+ s.version = "0.3.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Ryan Oberholzer"]
9
- s.date = %q{2010-11-16}
9
+ s.date = %q{2010-12-08}
10
10
  s.description = %q{State machine that allows dynamic transitions for business workflows}
11
11
  s.email = %q{ryan@platform45.com}
12
12
  s.extra_rdoc_files = ["CHANGELOG.rdoc", "README.rdoc", "lib/stateflow.rb", "lib/stateflow/event.rb", "lib/stateflow/exception.rb", "lib/stateflow/machine.rb", "lib/stateflow/persistence.rb", "lib/stateflow/persistence/active_record.rb", "lib/stateflow/persistence/mongo_mapper.rb", "lib/stateflow/persistence/mongoid.rb", "lib/stateflow/persistence/none.rb", "lib/stateflow/state.rb", "lib/stateflow/transition.rb"]
@@ -24,10 +24,19 @@ Gem::Specification.new do |s|
24
24
 
25
25
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
26
  s.add_development_dependency(%q<rspec>, [">= 0"])
27
+ s.add_development_dependency(%q<activerecord>, [">= 0"])
28
+ s.add_development_dependency(%q<mongoid>, [">= 2.0.0.beta.20"])
29
+ s.add_development_dependency(%q<sqlite3-ruby>, [">= 0"])
27
30
  else
28
31
  s.add_dependency(%q<rspec>, [">= 0"])
32
+ s.add_dependency(%q<activerecord>, [">= 0"])
33
+ s.add_dependency(%q<mongoid>, [">= 2.0.0.beta.20"])
34
+ s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
29
35
  end
30
36
  else
31
37
  s.add_dependency(%q<rspec>, [">= 0"])
38
+ s.add_dependency(%q<activerecord>, [">= 0"])
39
+ s.add_dependency(%q<mongoid>, [">= 2.0.0.beta.20"])
40
+ s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
32
41
  end
33
42
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stateflow
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 2
9
8
  - 3
10
- version: 0.2.3
9
+ - 0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ryan Oberholzer
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-11-16 00:00:00 +02:00
18
+ date: 2010-12-08 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -32,6 +32,52 @@ dependencies:
32
32
  version: "0"
33
33
  type: :development
34
34
  version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: activerecord
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: mongoid
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 62196427
58
+ segments:
59
+ - 2
60
+ - 0
61
+ - 0
62
+ - beta
63
+ - 20
64
+ version: 2.0.0.beta.20
65
+ type: :development
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: sqlite3-ruby
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ type: :development
80
+ version_requirements: *id004
35
81
  description: State machine that allows dynamic transitions for business workflows
36
82
  email: ryan@platform45.com
37
83
  executables: []