workflow-rails4 1.1.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.
@@ -0,0 +1,84 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+ require 'workflow'
3
+ class MultipleWorkflowsTest < ActiveRecordTestCase
4
+
5
+ test 'multiple workflows' do
6
+
7
+ ActiveRecord::Schema.define do
8
+ create_table :bookings do |t|
9
+ t.string :title, :null => false
10
+ t.string :workflow_state
11
+ t.string :workflow_type
12
+ end
13
+ end
14
+
15
+ exec "INSERT INTO bookings(title, workflow_state, workflow_type) VALUES('booking1', 'initial', 'workflow_1')"
16
+ exec "INSERT INTO bookings(title, workflow_state, workflow_type) VALUES('booking2', 'initial', 'workflow_2')"
17
+
18
+ class Booking < ActiveRecord::Base
19
+
20
+ include Workflow
21
+
22
+ def initialize_workflow
23
+ # define workflow per object instead of per class
24
+ case workflow_type
25
+ when 'workflow_1'
26
+ class << self
27
+ workflow do
28
+ state :initial do
29
+ event :progress, :transitions_to => :last
30
+ end
31
+ state :last
32
+ end
33
+ end
34
+ when 'workflow_2'
35
+ class << self
36
+ workflow do
37
+ state :initial do
38
+ event :progress, :transitions_to => :intermediate
39
+ end
40
+ state :intermediate
41
+ state :last
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ def metaclass; class << self; self; end; end
48
+
49
+ def workflow_spec
50
+ metaclass.workflow_spec
51
+ end
52
+
53
+ end
54
+
55
+ booking1 = Booking.find_by_title('booking1')
56
+ booking1.initialize_workflow
57
+
58
+ booking2 = Booking.find_by_title('booking2')
59
+ booking2.initialize_workflow
60
+
61
+ assert booking1.initial?
62
+ booking1.progress!
63
+ assert booking1.last?, 'booking1 should transition to the "last" state'
64
+
65
+ assert booking2.initial?
66
+ booking2.progress!
67
+ assert booking2.intermediate?, 'booking2 should transition to the "intermediate" state'
68
+
69
+ assert booking1.workflow_spec, 'can access the individual workflow specification'
70
+ assert_equal 2, booking1.workflow_spec.states.length
71
+ assert_equal 3, booking2.workflow_spec.states.length
72
+
73
+ # check persistence
74
+ booking2reloaded = Booking.find_by_title('booking2')
75
+ booking2reloaded.initialize_workflow
76
+ assert booking2reloaded.intermediate?, 'persistence of workflow state does not work'
77
+ end
78
+
79
+ class Object
80
+ # The hidden singleton lurks behind everyone
81
+ def metaclass; class << self; self; end; end
82
+ end
83
+
84
+ end
@@ -0,0 +1,32 @@
1
+ require 'test_helper'
2
+ require 'workflow'
3
+
4
+ class ComparableStatesOrder
5
+ include Workflow
6
+ workflow do
7
+ state :submitted do
8
+ event :accept, :transitions_to => :accepted, :meta => {:weight => 8} do |reviewer, args|
9
+ end
10
+ end
11
+ state :accepted do
12
+ event :ship, :transitions_to => :shipped
13
+ end
14
+ state :shipped
15
+ end
16
+ end
17
+
18
+ class CompareStatesTest < Test::Unit::TestCase
19
+
20
+ test 'compare states' do
21
+ o = ComparableStatesOrder.new
22
+ o.accept!
23
+ assert_equal :accepted, o.current_state.name
24
+ assert o.current_state == :accepted
25
+ assert o.current_state < :shipped
26
+ assert o.current_state > :submitted
27
+ assert_raise ArgumentError do
28
+ o.current_state > :unknown
29
+ end
30
+ end
31
+
32
+ end
@@ -0,0 +1,62 @@
1
+ require 'test_helper'
2
+ require 'active_record'
3
+ require 'logger'
4
+ require 'sqlite3'
5
+ require 'workflow'
6
+ require 'mocha/setup'
7
+ require 'stringio'
8
+
9
+ ActiveRecord::Migration.verbose = false
10
+
11
+ class PersistenceTestOrder < ActiveRecord::Base
12
+ include Workflow
13
+
14
+ workflow do
15
+ state :submitted do
16
+ event :accept, :transitions_to => :accepted, :meta => {:doc_weight => 8} do |reviewer, args|
17
+ end
18
+ end
19
+ state :accepted do
20
+ event :ship, :transitions_to => :shipped
21
+ end
22
+ state :shipped
23
+ end
24
+
25
+ attr_accessible :title # protecting all the other attributes
26
+
27
+ end
28
+
29
+ PersistenceTestOrder.logger = Logger.new(STDOUT) # active_record 2.3 expects a logger instance
30
+ PersistenceTestOrder.logger.level = Logger::WARN # switch to Logger::DEBUG to see the SQL statements
31
+
32
+ class PersistenceTest < ActiveRecordTestCase
33
+
34
+ def setup
35
+ super
36
+
37
+ ActiveRecord::Schema.define do
38
+ create_table :persistence_test_orders do |t|
39
+ t.string :title, :null => false
40
+ t.string :workflow_state
41
+ end
42
+ end
43
+
44
+ exec "INSERT INTO persistence_test_orders(title, workflow_state) VALUES('order6', 'accepted')"
45
+ end
46
+
47
+ def assert_state(title, expected_state, klass = PersistenceTestOrder)
48
+ o = klass.find_by_title(title)
49
+ assert_equal expected_state, o.read_attribute(klass.workflow_column)
50
+ o
51
+ end
52
+
53
+ test 'ensure other dirty attributes are not saved on state change' do
54
+ o = assert_state 'order6', 'accepted'
55
+ o.title = 'going to change the title'
56
+ assert o.changed?
57
+ o.ship!
58
+ assert o.changed?, 'title should not be saved and the change still stay pending'
59
+ end
60
+
61
+ end
62
+
@@ -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
@@ -0,0 +1,37 @@
1
+ require 'workflow'
2
+ class Article
3
+ include Workflow
4
+ workflow do
5
+ state :new do
6
+ event :submit, :transitions_to => :awaiting_review
7
+ end
8
+ state :awaiting_review do
9
+ event :review, :transitions_to => :being_reviewed
10
+ end
11
+ state :being_reviewed do
12
+ event :accept, :transitions_to => :accepted
13
+ event :reject, :transitions_to => :rejected
14
+ end
15
+ state :accepted
16
+ state :rejected
17
+ end
18
+ end
19
+
20
+ article = Article.new
21
+ article.accepted? # => false
22
+ article.new? # => true
23
+ article.submit!
24
+ article.review!
25
+
26
+ puts article.current_state # => being_reviewed
27
+
28
+
29
+ class Article
30
+ def reject
31
+ puts "send email to the author here explaining the reason for the rejection"
32
+ end
33
+ end
34
+
35
+ article.reject! # will cause a state transition, would persist the new
36
+ # state (if inherited from ActiveRecord), and invoke the callback -
37
+ # send email to the author.
@@ -0,0 +1,39 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'active_record'
4
+
5
+ class << Test::Unit::TestCase
6
+ def test(name, &block)
7
+ test_name = :"test_#{name.gsub(' ','_')}"
8
+ raise ArgumentError, "#{test_name} is already defined" if self.instance_methods.include? test_name.to_s
9
+ if block
10
+ define_method test_name, &block
11
+ else
12
+ puts "PENDING: #{name}"
13
+ end
14
+ end
15
+ end
16
+
17
+ class ActiveRecordTestCase < Test::Unit::TestCase
18
+ def exec(sql)
19
+ ActiveRecord::Base.connection.execute sql
20
+ end
21
+
22
+ def setup
23
+ ActiveRecord::Base.establish_connection(
24
+ :adapter => "sqlite3",
25
+ :database => ":memory:" #"tmp/test"
26
+ )
27
+
28
+ # eliminate ActiveRecord warning. TODO: delete as soon as ActiveRecord is fixed
29
+ ActiveRecord::Base.connection.reconnect!
30
+ end
31
+
32
+ def teardown
33
+ ActiveRecord::Base.connection.disconnect!
34
+ end
35
+
36
+ def default_test
37
+ end
38
+ end
39
+
@@ -0,0 +1,54 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+ require 'workflow'
3
+
4
+ class WithoutWorkflowTest < Test::Unit::TestCase
5
+ class Article
6
+ include Workflow
7
+ workflow do
8
+ state :new do
9
+ event :submit, :transitions_to => :awaiting_review
10
+ end
11
+ state :awaiting_review do
12
+ event :review, :transitions_to => :being_reviewed
13
+ end
14
+ state :being_reviewed do
15
+ event :accept, :transitions_to => :accepted
16
+ event :reject, :transitions_to => :rejected
17
+ end
18
+ state :accepted
19
+ state :rejected
20
+ end
21
+ end
22
+
23
+ def test_readme_example_article
24
+ article = Article.new
25
+ assert article.new?
26
+ end
27
+
28
+ test 'better error message on transitions_to typo' do
29
+ assert_raise Workflow::WorkflowDefinitionError do
30
+ Class.new do
31
+ include Workflow
32
+ workflow do
33
+ state :new do
34
+ event :event1, :transitionnn => :next # missing transitions_to target
35
+ end
36
+ state :next
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ test 'check transition_to alias' do
43
+ Class.new do
44
+ include Workflow
45
+ workflow do
46
+ state :new do
47
+ event :event1, :transition_to => :next
48
+ end
49
+ state :next
50
+ end
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'workflow/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "workflow-rails4"
8
+ gem.version = Workflow::VERSION
9
+ gem.authors = ["Vladimir Dobriakov", "Timon Vonk"]
10
+ gem.email = ["vladimir@geekq.net"]
11
+ gem.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 Temporary version to address possible rails4 issues"
12
+ gem.summary = %q{A replacement for acts_as_state_machine.}
13
+ gem.homepage = "http://www.geekq.net/workflow/"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.extra_rdoc_files = [
21
+ "README.markdown"
22
+ ]
23
+
24
+ gem.add_development_dependency 'rdoc', [">= 3.12"]
25
+ gem.add_development_dependency 'bundler', [">= 1.0.0"]
26
+ gem.add_development_dependency 'activerecord'
27
+ gem.add_development_dependency 'sqlite3'
28
+ gem.add_development_dependency 'mocha'
29
+ gem.add_development_dependency 'rake'
30
+ gem.add_development_dependency 'ruby-graphviz', ['>= 1.0']
31
+ end
32
+
metadata ADDED
@@ -0,0 +1,202 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: workflow-rails4
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Vladimir Dobriakov
8
+ - Timon Vonk
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-10-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rdoc
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '3.12'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '3.12'
28
+ - !ruby/object:Gem::Dependency
29
+ name: bundler
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: 1.0.0
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: 1.0.0
42
+ - !ruby/object:Gem::Dependency
43
+ name: activerecord
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: sqlite3
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: mocha
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rake
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: ruby-graphviz
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '1.0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '1.0'
112
+ description: |2-
113
+ Workflow is a finite-state-machine-inspired API for modeling and interacting
114
+ with what we tend to refer to as 'workflow'.
115
+
116
+ * nice DSL to describe your states, events and transitions
117
+ * robust integration with ActiveRecord and non relational data stores
118
+ * various hooks for single transitions, entering state etc.
119
+ * convenient access to the workflow specification: list states, possible events
120
+ for particular state
121
+ Temporary version to address possible rails4 issues
122
+ email:
123
+ - vladimir@geekq.net
124
+ executables: []
125
+ extensions: []
126
+ extra_rdoc_files:
127
+ - README.markdown
128
+ files:
129
+ - .gitignore
130
+ - .travis.yml
131
+ - Gemfile
132
+ - MIT-LICENSE
133
+ - README.markdown
134
+ - Rakefile
135
+ - gemfiles/Gemfile.rails-2.3.x
136
+ - gemfiles/Gemfile.rails-3.x
137
+ - gemfiles/Gemfile.rails-edge
138
+ - lib/workflow.rb
139
+ - lib/workflow/adapters/active_record.rb
140
+ - lib/workflow/adapters/remodel.rb
141
+ - lib/workflow/draw.rb
142
+ - lib/workflow/errors.rb
143
+ - lib/workflow/event.rb
144
+ - lib/workflow/specification.rb
145
+ - lib/workflow/state.rb
146
+ - lib/workflow/version.rb
147
+ - orders_workflow.png
148
+ - test/active_record_scopes_test.rb
149
+ - test/advanced_examples_test.rb
150
+ - test/advanced_hooks_and_validation_test.rb
151
+ - test/attr_protected_test.rb
152
+ - test/before_transition_test.rb
153
+ - test/couchtiny_example.rb
154
+ - test/inheritance_test.rb
155
+ - test/main_test.rb
156
+ - test/multiple_workflows_test.rb
157
+ - test/new_versions/compare_states_test.rb
158
+ - test/new_versions/persistence_test.rb
159
+ - test/on_error_test.rb
160
+ - test/readme_example.rb
161
+ - test/test_helper.rb
162
+ - test/without_active_record_test.rb
163
+ - workflow.gemspec
164
+ homepage: http://www.geekq.net/workflow/
165
+ licenses: []
166
+ metadata: {}
167
+ post_install_message:
168
+ rdoc_options: []
169
+ require_paths:
170
+ - lib
171
+ required_ruby_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - '>='
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ required_rubygems_version: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - '>='
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ requirements: []
182
+ rubyforge_project:
183
+ rubygems_version: 2.0.3
184
+ signing_key:
185
+ specification_version: 4
186
+ summary: A replacement for acts_as_state_machine.
187
+ test_files:
188
+ - test/active_record_scopes_test.rb
189
+ - test/advanced_examples_test.rb
190
+ - test/advanced_hooks_and_validation_test.rb
191
+ - test/attr_protected_test.rb
192
+ - test/before_transition_test.rb
193
+ - test/couchtiny_example.rb
194
+ - test/inheritance_test.rb
195
+ - test/main_test.rb
196
+ - test/multiple_workflows_test.rb
197
+ - test/new_versions/compare_states_test.rb
198
+ - test/new_versions/persistence_test.rb
199
+ - test/on_error_test.rb
200
+ - test/readme_example.rb
201
+ - test/test_helper.rb
202
+ - test/without_active_record_test.rb