stonepath 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/stonepath/group.rb +9 -0
- data/lib/stonepath/role.rb +4 -0
- data/lib/stonepath/task.rb +22 -8
- data/lib/stonepath/work_bench.rb +1 -1
- data/lib/stonepath/work_item.rb +29 -19
- data/lib/stonepath/work_owner.rb +7 -0
- data/stonepath.gemspec +2 -1
- data/stonepath.pdf +0 -0
- data/test/app_root/app/models/assignment.rb +1 -1
- data/test/app_root/app/models/case.rb +13 -1
- data/test/app_root/app/models/custom_assignment.rb +0 -1
- data/test/app_root/db/migrate/02_create_assignments.rb +5 -1
- data/test/app_root/db/migrate/03_create_cases.rb +2 -0
- data/test/task_test.rb +47 -0
- data/test/workitem_test.rb +6 -0
- metadata +2 -1
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.4
|
data/lib/stonepath/group.rb
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
# This is a concept that existed in the older Journeyman workflow engine, but I'm not sure
|
2
|
+
# that StonePath needs it. It is proving more worthwhile to ust rely on any number of other
|
3
|
+
# active_record models for providing group functionality, and you can see this id pretty much
|
4
|
+
# an empty stub.
|
5
|
+
|
6
|
+
# Groups were another aggregation of work much like users were. With the general concept of
|
7
|
+
# WorkBench, I think this will be leaving the framework soon.
|
8
|
+
# -db!
|
9
|
+
|
1
10
|
module StonePath
|
2
11
|
module Group
|
3
12
|
def self.included(base)
|
data/lib/stonepath/role.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# This is a concept that existed in the older Journeyman workflow engine, but I'm not sure
|
2
|
+
# that StonePath needs it. It is proving more worthwhile to ust rely on any number of other
|
3
|
+
# gems for providing role functionality, and you can see this id pretty much an empty stub.
|
4
|
+
|
1
5
|
module StonePath
|
2
6
|
module Role
|
3
7
|
def self.included(base)
|
data/lib/stonepath/task.rb
CHANGED
@@ -1,11 +1,21 @@
|
|
1
|
+
# A Task in this framework is simply a relation between a workitem and a workbench. It has
|
2
|
+
# some default workflow, and should be extended with whatever attributes make sense for the
|
3
|
+
# business domain you are modeling.
|
4
|
+
|
1
5
|
module StonePath
|
2
6
|
module SPTask
|
3
7
|
|
8
|
+
# This will move from here shortly, into another class/module for containing things like this.
|
9
|
+
# This is the workflow definition for a default task. This is defined this way so that users
|
10
|
+
# can provide their own task workflow definition as a block to the stonepath_task declaration.
|
11
|
+
# This lanbda is passed in if the user doesn't provide anything.
|
12
|
+
# It is possible that we will identify other useful options and want to provide them as config
|
13
|
+
# blocks in the StonePath gem.
|
4
14
|
def self.default_config_block
|
5
15
|
lambda {
|
6
16
|
aasm_initial_state :active
|
7
17
|
aasm_state :active, :after_enter => :notify_created
|
8
|
-
aasm_state :completed, :
|
18
|
+
aasm_state :completed, :after_enter => [:timestamp_complete, :notify_closed]
|
9
19
|
aasm_state :expired, :after_enter => :notify_closed
|
10
20
|
aasm_state :cancelled, :after_enter => :notify_closed
|
11
21
|
|
@@ -31,16 +41,20 @@ module StonePath
|
|
31
41
|
}
|
32
42
|
end
|
33
43
|
|
44
|
+
|
34
45
|
def self.included(base)
|
35
46
|
base.instance_eval do
|
36
47
|
|
37
|
-
|
48
|
+
# Tasks are now completely polymorphic between workbenches.
|
49
|
+
# as long as an activerecord model declares itself as a workbench and declares itself
|
50
|
+
# a workbench for the specific kind of task, everything just works.
|
51
|
+
belongs_to :workbench, :polymorphic => true
|
52
|
+
|
53
|
+
# Tasks are now completely polymorphic between workitems.
|
54
|
+
# as long as an activerecord model declares itself as a workitem and declares itself
|
55
|
+
# a workitem for the specific kind of task, everything just works.
|
56
|
+
belongs_to :workitem, :polymorphic => true
|
38
57
|
|
39
|
-
def task_for(workitem, options={})
|
40
|
-
options.merge!(:class_name => workitem.to_s.classify)
|
41
|
-
belongs_to :workitem, options
|
42
|
-
end
|
43
|
-
|
44
58
|
def audits_transitions
|
45
59
|
puts "#{self.class} audits transitions"
|
46
60
|
end
|
@@ -68,7 +82,7 @@ module StonePath
|
|
68
82
|
end
|
69
83
|
|
70
84
|
def notify_closed
|
71
|
-
|
85
|
+
if workitem.respond_to?(:task_closed)
|
72
86
|
workitem.task_closed(self)
|
73
87
|
end
|
74
88
|
end
|
data/lib/stonepath/work_bench.rb
CHANGED
data/lib/stonepath/work_item.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# The WorkItem is the center of this framework. It is the thing that has a workflow,
|
2
|
+
# is the subject of ownership and tasks. Tis is the place the primaey state machine will
|
3
|
+
# exist
|
4
|
+
|
1
5
|
module StonePath
|
2
6
|
module WorkItem
|
3
7
|
def self.included(base)
|
@@ -9,15 +13,12 @@ module StonePath
|
|
9
13
|
belongs_to :owner, options
|
10
14
|
end
|
11
15
|
|
12
|
-
def
|
13
|
-
has_many tasks,
|
16
|
+
def tasked_through(tasks, options={})
|
17
|
+
has_many tasks, :as => :workitem
|
14
18
|
end
|
15
19
|
|
16
20
|
def stonepath_acl()
|
17
21
|
require File.expand_path(File.dirname(__FILE__)) + "/acl.rb"
|
18
|
-
#require File.expand_path(File.dirname(__FILE__)) + "/acl/acl.rb"
|
19
|
-
#require File.expand_path(File.dirname(__FILE__)) + "/acl/acl_role.rb"
|
20
|
-
#require File.expand_path(File.dirname(__FILE__)) + "/acl/acl_state.rb"
|
21
22
|
cattr_accessor :acl
|
22
23
|
self.acl = StonePath::ACL::Controller.new(self)
|
23
24
|
yield self.acl
|
@@ -31,23 +32,32 @@ module StonePath
|
|
31
32
|
class << self
|
32
33
|
alias_method "define_attribute_methods_without_hook", "define_attribute_methods"
|
33
34
|
alias_method "define_attribute_methods", "define_attribute_methods_with_hook"
|
35
|
+
end
|
36
|
+
end #base.instance_eval
|
37
|
+
|
38
|
+
def allowed?(method)
|
39
|
+
acl.allowed?(aasm_current_state, current_user, method)
|
40
|
+
end
|
41
|
+
|
42
|
+
# modifies to_xml do that it includes all the possible events from this state.
|
43
|
+
# useful when you are using WorkItems as resources with ActiveResource
|
44
|
+
def to_xml_with_events
|
45
|
+
to_xml_without_events do |xml|
|
46
|
+
xml.aasm_events_for_current_state(:type=>"array") do
|
47
|
+
aasm_events_for_current_state.each do |e|
|
48
|
+
xml.aasm_event do
|
49
|
+
xml.name e.to_s
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
34
53
|
end
|
35
54
|
end
|
36
55
|
|
37
|
-
|
38
|
-
|
56
|
+
base.instance_eval do
|
57
|
+
alias_method_chain :to_xml, :events
|
39
58
|
end
|
40
59
|
|
41
|
-
end
|
60
|
+
end #self.included
|
61
|
+
|
42
62
|
end
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
# if table_exists? <workitem>_transition_log_entries
|
47
|
-
#define WorkItem::TransitionLogEntry
|
48
|
-
# then for each transition method, have an after proc that
|
49
|
-
# creates workitem_transition_log
|
50
|
-
# workitem_id
|
51
|
-
# transitioned_to
|
52
|
-
# transitioned_by
|
53
|
-
# transitioned_at
|
63
|
+
end
|
data/lib/stonepath/work_owner.rb
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# every WorkItem has one and exactly one owner. In some domains, WorkOwners and WorkBenches will
|
2
|
+
# be the same thing, but in other domains they are separate concepts. the owner is 'responsible'
|
3
|
+
# for the WorkItem in a larger sense - but the WorkBenches are 'responsible' for the completion of
|
4
|
+
# tasks associated with the WorkItem.
|
5
|
+
#
|
6
|
+
# This separation allows workflows where the owner assigns out work, and may oe may not be
|
7
|
+
# responsible for the actual completion of the work.
|
1
8
|
module StonePath
|
2
9
|
module WorkOwner
|
3
10
|
def self.included(base)
|
data/stonepath.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{stonepath}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.4"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["David Bock"]
|
@@ -42,6 +42,7 @@ Gem::Specification.new do |s|
|
|
42
42
|
"script/destroy",
|
43
43
|
"script/generate",
|
44
44
|
"stonepath.gemspec",
|
45
|
+
"stonepath.pdf",
|
45
46
|
"test/acl_test.rb",
|
46
47
|
"test/app_root/app/controllers/application_controller.rb",
|
47
48
|
"test/app_root/app/models/assignment.rb",
|
data/stonepath.pdf
ADDED
Binary file
|
@@ -18,7 +18,7 @@ class Case < ActiveRecord::Base
|
|
18
18
|
end
|
19
19
|
|
20
20
|
owned_by :user
|
21
|
-
|
21
|
+
tasked_through :assignments
|
22
22
|
|
23
23
|
|
24
24
|
|
@@ -63,5 +63,17 @@ class Case < ActiveRecord::Base
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
+
|
67
|
+
def task_created(task)
|
68
|
+
self.notification_method = "created"
|
69
|
+
self.notified_id = task.id
|
70
|
+
self.save
|
71
|
+
end
|
66
72
|
|
73
|
+
def task_closed(task)
|
74
|
+
self.notification_method = "closed"
|
75
|
+
self.notified_id = task.id
|
76
|
+
self.save
|
77
|
+
end
|
78
|
+
|
67
79
|
end
|
@@ -3,8 +3,12 @@ class CreateAssignments < ActiveRecord::Migration
|
|
3
3
|
def self.up
|
4
4
|
create_table :assignments do |t|
|
5
5
|
t.string :aasm_state
|
6
|
-
t.integer :
|
6
|
+
t.integer :workitem_id
|
7
|
+
t.string :workitem_type
|
8
|
+
t.integer :workbench_id
|
9
|
+
t.string :workbench_type
|
7
10
|
t.datetime :completed_at
|
11
|
+
t.datetime :due_at
|
8
12
|
t.timestamps
|
9
13
|
end
|
10
14
|
end
|
data/test/task_test.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
2
|
|
3
|
+
require 'flexmock/test_unit'
|
4
|
+
|
3
5
|
class TaskTest < Test::Unit::TestCase
|
4
6
|
|
5
7
|
def setup
|
@@ -38,6 +40,51 @@ class TaskTest < Test::Unit::TestCase
|
|
38
40
|
assert_equal("expired", a.aasm_state)
|
39
41
|
end
|
40
42
|
|
43
|
+
should "be overdue? if due_at is in the past" do
|
44
|
+
c = Case.create
|
45
|
+
a = c.assignments.create(:due_at => 1.week.ago)
|
46
|
+
assert(a.overdue?)
|
47
|
+
end
|
48
|
+
|
49
|
+
should "be able to set up the relationship between a case and an assignment" do
|
50
|
+
c = Case.create
|
51
|
+
a = c.assignments.create
|
52
|
+
assert_equal(a, c.assignments[0])
|
53
|
+
assert_equal(c, c.assignments[0].workitem)
|
54
|
+
end
|
55
|
+
|
56
|
+
should "be able to set up the relationship between a user (as a workbench) and an assignment" do
|
57
|
+
u = User.create
|
58
|
+
c = Case.create
|
59
|
+
a = c.assignments.create(:workbench => u)
|
60
|
+
|
61
|
+
assert_equal(a, u.assignments[0])
|
62
|
+
assert_equal(u, a.workbench)
|
63
|
+
end
|
64
|
+
|
65
|
+
# This whole event notification thing is ugly.
|
66
|
+
# Putting aside the ugly way I tested this, the whole AASM callback mechanism
|
67
|
+
# has a problem that the id isn't set after the callback from a create.
|
68
|
+
# Looking at the code of aasm, I cannot easily figure out why.
|
69
|
+
should "callback the workitem when a task is created" do
|
70
|
+
c = Case.create
|
71
|
+
cid = c.id
|
72
|
+
a = c.assignments.create
|
73
|
+
c = Case.find cid
|
74
|
+
assert_equal("created", c.notification_method)
|
75
|
+
#assert_equal(a.id, c.notified_id)
|
76
|
+
end
|
77
|
+
|
78
|
+
should "callback the workitem when a task is completed" do
|
79
|
+
c = Case.create
|
80
|
+
cid = c.id
|
81
|
+
a = c.assignments.create
|
82
|
+
a.complete!
|
83
|
+
c = Case.find cid
|
84
|
+
assert_equal("closed", c.notification_method)
|
85
|
+
#assert_equal(a.id, c.notified_id)
|
86
|
+
end
|
87
|
+
|
41
88
|
end
|
42
89
|
|
43
90
|
|
data/test/workitem_test.rb
CHANGED
@@ -8,4 +8,10 @@ class WorkitemTest < Test::Unit::TestCase
|
|
8
8
|
should "not do much of anything yet" do
|
9
9
|
c = Case.new
|
10
10
|
end
|
11
|
+
|
12
|
+
should "contain xml for the possible events" do
|
13
|
+
c = Case.create
|
14
|
+
xml = c.to_xml
|
15
|
+
assert(xml.include?("<aasm_events_for_current_state type=\"array\">"))
|
16
|
+
end
|
11
17
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stonepath
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Bock
|
@@ -57,6 +57,7 @@ files:
|
|
57
57
|
- script/destroy
|
58
58
|
- script/generate
|
59
59
|
- stonepath.gemspec
|
60
|
+
- stonepath.pdf
|
60
61
|
- test/acl_test.rb
|
61
62
|
- test/app_root/app/controllers/application_controller.rb
|
62
63
|
- test/app_root/app/models/assignment.rb
|