workflow 0.8.1 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +9 -0
- data/README.markdown +32 -0
- data/Rakefile +22 -16
- data/VERSION +1 -1
- data/lib/workflow.rb +49 -8
- data/test/advanced_hooks_and_validation_test.rb +3 -2
- data/test/main_test.rb +40 -1
- data/test/on_error_test.rb +52 -0
- data/workflow.gemspec +36 -19
- metadata +161 -39
data/Gemfile
ADDED
data/README.markdown
CHANGED
@@ -67,6 +67,18 @@ of possible events and other meta information:
|
|
67
67
|
@transitions_to=:awaiting_review, @name=:submit, @meta={}>},
|
68
68
|
name:new, meta{}
|
69
69
|
|
70
|
+
On Ruby 1.9 and above, you can check whether a state comes before or
|
71
|
+
after another state (by the order they were defined):
|
72
|
+
|
73
|
+
article.current_state
|
74
|
+
=> being_reviewed
|
75
|
+
article.current_state < :accepted
|
76
|
+
=> true
|
77
|
+
article.current_state >= :accepted
|
78
|
+
=> false
|
79
|
+
article.between? :awaiting_review, :rejected
|
80
|
+
=> true
|
81
|
+
|
70
82
|
Now we can call the submit event, which transitions to the
|
71
83
|
<tt>:awaiting_review</tt> state:
|
72
84
|
|
@@ -330,6 +342,26 @@ example][advanced_hooks_and_validation_test].
|
|
330
342
|
|
331
343
|
[advanced_hooks_and_validation_test]: http://github.com/geekq/workflow/blob/master/test/advanced_hooks_and_validation_test.rb
|
332
344
|
|
345
|
+
### on_error
|
346
|
+
|
347
|
+
If you want to do custom exception handling internal to workflow, you can define an `on_error` hook in your workflow.
|
348
|
+
For example:
|
349
|
+
|
350
|
+
workflow do
|
351
|
+
state :first do
|
352
|
+
event :forward, :transitions_to => :second
|
353
|
+
end
|
354
|
+
state :second
|
355
|
+
|
356
|
+
on_error do |error, from, to, event, *args|
|
357
|
+
Log.info "Exception(#error.class) on #{from} -> #{to}"
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
If forward! results in an exception, `on_error` is invoked and the workflow stays in a 'first' state. This capability
|
362
|
+
is particularly useful if your errors are transient and you want to queue up a job to retry in the future without
|
363
|
+
affecting the existing workflow state.
|
364
|
+
|
333
365
|
### Guards
|
334
366
|
|
335
367
|
If you want to halt the transition conditionally, you can just raise an
|
data/Rakefile
CHANGED
@@ -1,10 +1,20 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
require 'bundler'
|
2
3
|
require 'rubygems/package_task'
|
3
4
|
require 'rake/testtask'
|
4
5
|
require 'rdoc/task'
|
5
6
|
|
6
7
|
task :default => [:test]
|
7
8
|
|
9
|
+
begin
|
10
|
+
Bundler.setup(:default, :development)
|
11
|
+
rescue Bundler::BundlerError => e
|
12
|
+
$stderr.puts e.message
|
13
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
14
|
+
exit e.status_code
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'rake'
|
8
18
|
Rake::TestTask.new do |t|
|
9
19
|
t.verbose = true
|
10
20
|
t.warning = true
|
@@ -16,16 +26,16 @@ Rake::RDocTask.new do |rdoc|
|
|
16
26
|
rdoc.options << "-S"
|
17
27
|
end
|
18
28
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
+
require 'jeweler'
|
30
|
+
|
31
|
+
Jeweler::Tasks.new do |gemspec|
|
32
|
+
gemspec.name = "workflow"
|
33
|
+
gemspec.rubyforge_project = 'workflow'
|
34
|
+
gemspec.email = "vladimir@geekq.net"
|
35
|
+
gemspec.homepage = "http://www.geekq.net/workflow/"
|
36
|
+
gemspec.authors = ["Vladimir Dobriakov"]
|
37
|
+
gemspec.summary = "A replacement for acts_as_state_machine."
|
38
|
+
gemspec.description = <<-EOS
|
29
39
|
Workflow is a finite-state-machine-inspired API for modeling and interacting
|
30
40
|
with what we tend to refer to as 'workflow'.
|
31
41
|
|
@@ -34,11 +44,7 @@ begin
|
|
34
44
|
* various hooks for single transitions, entering state etc.
|
35
45
|
* convenient access to the workflow specification: list states, possible events
|
36
46
|
for particular state
|
37
|
-
|
47
|
+
EOS
|
38
48
|
|
39
|
-
|
40
|
-
end
|
41
|
-
rescue LoadError
|
42
|
-
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
49
|
+
Jeweler::GemcutterTasks.new
|
43
50
|
end
|
44
|
-
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.8.
|
1
|
+
0.8.3
|
data/lib/workflow.rb
CHANGED
@@ -6,7 +6,7 @@ module Workflow
|
|
6
6
|
class Specification
|
7
7
|
|
8
8
|
attr_accessor :states, :initial_state, :meta,
|
9
|
-
:on_transition_proc, :before_transition_proc, :after_transition_proc
|
9
|
+
:on_transition_proc, :before_transition_proc, :after_transition_proc, :on_error_proc
|
10
10
|
|
11
11
|
def initialize(meta = {}, &specification)
|
12
12
|
@states = Hash.new
|
@@ -22,7 +22,7 @@ module Workflow
|
|
22
22
|
|
23
23
|
def state(name, meta = {:meta => {}}, &events_and_etc)
|
24
24
|
# meta[:meta] to keep the API consistent..., gah
|
25
|
-
new_state = Workflow::State.new(name, meta[:meta])
|
25
|
+
new_state = Workflow::State.new(name, self, meta[:meta])
|
26
26
|
@initial_state = new_state if @states.empty?
|
27
27
|
@states[name.to_sym] = new_state
|
28
28
|
@scoped_state = new_state
|
@@ -57,6 +57,10 @@ module Workflow
|
|
57
57
|
def on_transition(&proc)
|
58
58
|
@on_transition_proc = proc
|
59
59
|
end
|
60
|
+
|
61
|
+
def on_error(&proc)
|
62
|
+
@on_error_proc = proc
|
63
|
+
end
|
60
64
|
end
|
61
65
|
|
62
66
|
class TransitionHalted < Exception
|
@@ -79,9 +83,26 @@ module Workflow
|
|
79
83
|
class State
|
80
84
|
|
81
85
|
attr_accessor :name, :events, :meta, :on_entry, :on_exit
|
82
|
-
|
83
|
-
|
84
|
-
|
86
|
+
attr_reader :spec
|
87
|
+
|
88
|
+
def initialize(name, spec, meta = {})
|
89
|
+
@name, @spec, @events, @meta = name, spec, Hash.new, meta
|
90
|
+
end
|
91
|
+
|
92
|
+
unless RUBY_VERSION < '1.9'
|
93
|
+
include Comparable
|
94
|
+
|
95
|
+
def <=>(other_state)
|
96
|
+
states = spec.states.keys
|
97
|
+
raise ArgumentError, "state `#{other_state}' does not exist" unless other_state.in? states
|
98
|
+
if states.index(self.to_sym) < states.index(other_state.to_sym)
|
99
|
+
-1
|
100
|
+
elsif states.index(self.to_sym) > states.index(other_state.to_sym)
|
101
|
+
1
|
102
|
+
else
|
103
|
+
0
|
104
|
+
end
|
105
|
+
end
|
85
106
|
end
|
86
107
|
|
87
108
|
def to_s
|
@@ -143,6 +164,7 @@ module Workflow
|
|
143
164
|
end
|
144
165
|
|
145
166
|
module WorkflowInstanceMethods
|
167
|
+
|
146
168
|
def current_state
|
147
169
|
loaded_state = load_workflow_state
|
148
170
|
res = spec.states[loaded_state.to_sym] if loaded_state
|
@@ -177,7 +199,12 @@ module Workflow
|
|
177
199
|
run_before_transition(from, to, name, *args)
|
178
200
|
return false if @halted
|
179
201
|
|
180
|
-
|
202
|
+
begin
|
203
|
+
return_value = run_action(event.action, *args) || run_action_callback(event.name, *args)
|
204
|
+
rescue Exception => e
|
205
|
+
run_on_error(e, from, to, name, *args)
|
206
|
+
end
|
207
|
+
|
181
208
|
return false if @halted
|
182
209
|
|
183
210
|
run_on_transition(from, to, name, *args)
|
@@ -236,6 +263,15 @@ module Workflow
|
|
236
263
|
spec.before_transition_proc
|
237
264
|
end
|
238
265
|
|
266
|
+
def run_on_error(error, from, to, event, *args)
|
267
|
+
if spec.on_error_proc
|
268
|
+
instance_exec(error, from.name, to.name, event, *args, &spec.on_error_proc)
|
269
|
+
halt(error.message)
|
270
|
+
else
|
271
|
+
raise error
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
239
275
|
def run_on_transition(from, to, event, *args)
|
240
276
|
instance_exec(from.name, to.name, event, *args, &spec.on_transition_proc) if spec.on_transition_proc
|
241
277
|
end
|
@@ -248,9 +284,14 @@ module Workflow
|
|
248
284
|
def run_action(action, *args)
|
249
285
|
instance_exec(*args, &action) if action
|
250
286
|
end
|
287
|
+
|
288
|
+
def has_callback?(action)
|
289
|
+
self.respond_to?(action) or self.class.private_method_defined?(action)
|
290
|
+
end
|
251
291
|
|
252
292
|
def run_action_callback(action_name, *args)
|
253
|
-
|
293
|
+
action = action_name.to_sym
|
294
|
+
self.send(action, *args) if has_callback?(action)
|
254
295
|
end
|
255
296
|
|
256
297
|
def run_on_entry(state, prior_state, triggering_event, *args)
|
@@ -297,7 +338,7 @@ module Workflow
|
|
297
338
|
# On transition the new workflow state is immediately saved in the
|
298
339
|
# database.
|
299
340
|
def persist_workflow_state(new_value)
|
300
|
-
|
341
|
+
update_attributes self.class.workflow_column => new_value
|
301
342
|
end
|
302
343
|
|
303
344
|
private
|
@@ -51,8 +51,9 @@ class Article < ActiveRecord::Base
|
|
51
51
|
}
|
52
52
|
end
|
53
53
|
|
54
|
-
singleton.send :define_method, :
|
55
|
-
|
54
|
+
singleton.send :define_method, :validate_for_transition, &validations
|
55
|
+
validate_for_transition
|
56
|
+
halt! "Event[#{triggering_event}]'s transitions_to[#{to}] is not valid." unless self.errors.empty?
|
56
57
|
end
|
57
58
|
end
|
58
59
|
end
|
data/test/main_test.rb
CHANGED
@@ -244,6 +244,17 @@ class MainTest < ActiveRecordTestCase
|
|
244
244
|
assert !o.shipped?
|
245
245
|
end
|
246
246
|
|
247
|
+
unless RUBY_VERSION < '1.9'
|
248
|
+
test 'compare states' do
|
249
|
+
o = assert_state 'some order', 'accepted'
|
250
|
+
assert o.current_state < :shipped
|
251
|
+
assert o.current_state > :submitted
|
252
|
+
assert_raise ArgumentError do
|
253
|
+
o.current_state > :unknown
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
247
258
|
test 'correct exception for event, that is not allowed in current state' do
|
248
259
|
o = assert_state 'some order', 'accepted'
|
249
260
|
assert_raise Workflow::NoTransitionAllowed do
|
@@ -268,8 +279,36 @@ class MainTest < ActiveRecordTestCase
|
|
268
279
|
end
|
269
280
|
state :two
|
270
281
|
end
|
282
|
+
|
283
|
+
private
|
284
|
+
def another_transition(args)
|
285
|
+
args.another_tran
|
286
|
+
end
|
287
|
+
end
|
288
|
+
a = c.new
|
289
|
+
a.my_transition!(args)
|
290
|
+
end
|
291
|
+
|
292
|
+
test '#53 Support for private transition callbacks' do
|
293
|
+
args = mock()
|
294
|
+
args.expects(:log).once
|
295
|
+
c = Class.new
|
296
|
+
c.class_eval do
|
297
|
+
include Workflow
|
298
|
+
workflow do
|
299
|
+
state :new do
|
300
|
+
event :assign, :transitions_to => :assigned
|
301
|
+
end
|
302
|
+
state :assigned
|
303
|
+
end
|
304
|
+
|
305
|
+
private
|
306
|
+
def assign(args)
|
307
|
+
args.log('Assigned')
|
308
|
+
end
|
271
309
|
end
|
272
|
-
c.new
|
310
|
+
a = c.new
|
311
|
+
a.assign!(args)
|
273
312
|
end
|
274
313
|
|
275
314
|
test 'Single table inheritance (STI)' do
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
require 'workflow'
|
3
|
+
|
4
|
+
class OnErrorTest < Test::Unit::TestCase
|
5
|
+
# A class that does not handle errors in an error block
|
6
|
+
class NoErrorBlock
|
7
|
+
include Workflow
|
8
|
+
workflow do
|
9
|
+
state :first do
|
10
|
+
event :forward, :transitions_to => :second do
|
11
|
+
raise "This is some random runtime error"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
state :second
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# A class that handles errors in an error block
|
19
|
+
class ErrorBlock
|
20
|
+
attr_reader :errors
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@errors = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
include Workflow
|
27
|
+
workflow do
|
28
|
+
state :first do
|
29
|
+
event :forward, :transitions_to => :second do
|
30
|
+
raise "This is some random runtime error"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
state :second
|
34
|
+
on_error { |error, from, to, event, *args| @errors.merge!({:error => error.class, :from => from, :to => to, :event => event, :args => args}) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
test 'that an exception is raised if there is no associated on_error block' do
|
40
|
+
flow = NoErrorBlock.new
|
41
|
+
assert_raise( RuntimeError, "This is some random runtime error" ) { flow.forward! }
|
42
|
+
assert_equal(true, flow.first?)
|
43
|
+
end
|
44
|
+
|
45
|
+
test 'that on_error block is called when an exception is raised and the transition is halted' do
|
46
|
+
flow = ErrorBlock.new
|
47
|
+
assert_nothing_raised { flow.forward! }
|
48
|
+
assert_equal({:error => RuntimeError, :from=>:first, :to=>:second, :event=>:forward, :args=>[]}, flow.errors)
|
49
|
+
# transition should not happen
|
50
|
+
assert_equal(true, flow.first?)
|
51
|
+
end
|
52
|
+
end
|
data/workflow.gemspec
CHANGED
@@ -4,26 +4,19 @@
|
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
8
|
-
s.version = "0.8.
|
7
|
+
s.name = "workflow"
|
8
|
+
s.version = "0.8.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Vladimir Dobriakov"]
|
12
|
-
s.date =
|
13
|
-
s.description =
|
14
|
-
|
15
|
-
|
16
|
-
* nice DSL to describe your states, events and transitions
|
17
|
-
* robust integration with ActiveRecord and non relational data stores
|
18
|
-
* various hooks for single transitions, entering state etc.
|
19
|
-
* convenient access to the workflow specification: list states, possible events
|
20
|
-
for particular state
|
21
|
-
}
|
22
|
-
s.email = %q{vladimir@geekq.net}
|
12
|
+
s.date = "2012-12-04"
|
13
|
+
s.description = " Workflow is a finite-state-machine-inspired API for modeling and interacting\n with what we tend to refer to as 'workflow'.\n\n * nice DSL to describe your states, events and transitions\n * robust integration with ActiveRecord and non relational data stores\n * various hooks for single transitions, entering state etc.\n * convenient access to the workflow specification: list states, possible events\n for particular state\n"
|
14
|
+
s.email = "vladimir@geekq.net"
|
23
15
|
s.extra_rdoc_files = [
|
24
16
|
"README.markdown"
|
25
17
|
]
|
26
18
|
s.files = [
|
19
|
+
"Gemfile",
|
27
20
|
"MIT-LICENSE",
|
28
21
|
"README.markdown",
|
29
22
|
"Rakefile",
|
@@ -34,26 +27,50 @@ Gem::Specification.new do |s|
|
|
34
27
|
"test/couchtiny_example.rb",
|
35
28
|
"test/main_test.rb",
|
36
29
|
"test/multiple_workflows_test.rb",
|
30
|
+
"test/on_error_test.rb",
|
37
31
|
"test/readme_example.rb",
|
38
32
|
"test/test_helper.rb",
|
39
33
|
"test/without_active_record_test.rb",
|
40
34
|
"workflow.gemspec",
|
41
35
|
"workflow.rb"
|
42
36
|
]
|
43
|
-
s.homepage =
|
37
|
+
s.homepage = "http://www.geekq.net/workflow/"
|
44
38
|
s.require_paths = ["lib"]
|
45
|
-
s.rubyforge_project =
|
46
|
-
s.rubygems_version =
|
47
|
-
s.summary =
|
39
|
+
s.rubyforge_project = "workflow"
|
40
|
+
s.rubygems_version = "1.8.24"
|
41
|
+
s.summary = "A replacement for acts_as_state_machine."
|
48
42
|
|
49
43
|
if s.respond_to? :specification_version then
|
50
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
51
44
|
s.specification_version = 3
|
52
45
|
|
53
|
-
if Gem::Version.new(Gem::
|
46
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
|
+
s.add_runtime_dependency(%q<workflow>, [">= 0"])
|
48
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
49
|
+
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
50
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
51
|
+
s.add_development_dependency(%q<rake>, [">= 0"])
|
52
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<activerecord>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<sqlite3>, [">= 0"])
|
54
55
|
else
|
56
|
+
s.add_dependency(%q<workflow>, [">= 0"])
|
57
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
58
|
+
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
59
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
60
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
61
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
62
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
63
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
55
64
|
end
|
56
65
|
else
|
66
|
+
s.add_dependency(%q<workflow>, [">= 0"])
|
67
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
68
|
+
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
69
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
70
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
71
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
72
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
73
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
57
74
|
end
|
58
75
|
end
|
59
76
|
|
metadata
CHANGED
@@ -1,32 +1,157 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: workflow
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 8
|
8
|
-
- 1
|
9
|
-
version: 0.8.1
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.8.3
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Vladimir Dobriakov
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
12
|
+
date: 2012-12-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: workflow
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rdoc
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '3.12'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '3.12'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: bundler
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.0.0
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.0.0
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: jeweler
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.8.4
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.8.4
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: mocha
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: activerecord
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: sqlite3
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
description: ! " Workflow is a finite-state-machine-inspired API for modeling and
|
143
|
+
interacting\n with what we tend to refer to as 'workflow'.\n\n * nice DSL
|
144
|
+
to describe your states, events and transitions\n * robust integration with ActiveRecord
|
145
|
+
and non relational data stores\n * various hooks for single transitions, entering
|
146
|
+
state etc.\n * convenient access to the workflow specification: list states,
|
147
|
+
possible events\n for particular state\n"
|
22
148
|
email: vladimir@geekq.net
|
23
149
|
executables: []
|
24
|
-
|
25
150
|
extensions: []
|
26
|
-
|
27
|
-
extra_rdoc_files:
|
151
|
+
extra_rdoc_files:
|
28
152
|
- README.markdown
|
29
|
-
files:
|
153
|
+
files:
|
154
|
+
- Gemfile
|
30
155
|
- MIT-LICENSE
|
31
156
|
- README.markdown
|
32
157
|
- Rakefile
|
@@ -37,40 +162,37 @@ files:
|
|
37
162
|
- test/couchtiny_example.rb
|
38
163
|
- test/main_test.rb
|
39
164
|
- test/multiple_workflows_test.rb
|
165
|
+
- test/on_error_test.rb
|
40
166
|
- test/readme_example.rb
|
41
167
|
- test/test_helper.rb
|
42
168
|
- test/without_active_record_test.rb
|
43
169
|
- workflow.gemspec
|
44
170
|
- workflow.rb
|
45
|
-
has_rdoc: true
|
46
171
|
homepage: http://www.geekq.net/workflow/
|
47
172
|
licenses: []
|
48
|
-
|
49
173
|
post_install_message:
|
50
174
|
rdoc_options: []
|
51
|
-
|
52
|
-
require_paths:
|
175
|
+
require_paths:
|
53
176
|
- lib
|
54
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
-
requirements:
|
63
|
-
- - ">="
|
64
|
-
- !ruby/object:Gem::Version
|
65
|
-
segments:
|
177
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
178
|
+
none: false
|
179
|
+
requirements:
|
180
|
+
- - ! '>='
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
segments:
|
66
184
|
- 0
|
67
|
-
|
185
|
+
hash: 3639477061676612937
|
186
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
187
|
+
none: false
|
188
|
+
requirements:
|
189
|
+
- - ! '>='
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
version: '0'
|
68
192
|
requirements: []
|
69
|
-
|
70
193
|
rubyforge_project: workflow
|
71
|
-
rubygems_version: 1.
|
194
|
+
rubygems_version: 1.8.24
|
72
195
|
signing_key:
|
73
196
|
specification_version: 3
|
74
197
|
summary: A replacement for acts_as_state_machine.
|
75
198
|
test_files: []
|
76
|
-
|