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 CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 0.0.4
@@ -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)
@@ -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)
@@ -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, :before_enter => :timestamp_complete, :after_enter => :notify_closed
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
- belongs_to :assignee, :polymorphic => true
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
- if workitem.respond_to?(:task_closed)
85
+ if workitem.respond_to?(:task_closed)
72
86
  workitem.task_closed(self)
73
87
  end
74
88
  end
@@ -5,7 +5,7 @@ module StonePath
5
5
  def workbench_for(tasks, options={})
6
6
  #options.merge!(:foreign_key => :assignee_id)
7
7
  #puts options
8
- has_many tasks, :as => :assignee
8
+ has_many tasks, :as => :workbench
9
9
  end
10
10
  end
11
11
  end
@@ -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 subject_of(tasks, options={})
13
- has_many tasks, options
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
- def allowed?(method)
38
- acl.allowed?(aasm_current_state, current_user, method)
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
@@ -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.3"
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
@@ -3,7 +3,7 @@ class Assignment < ActiveRecord::Base
3
3
 
4
4
  stonepath_task
5
5
 
6
- task_for :case
6
+ #task_for :case
7
7
 
8
8
  audits_transitions
9
9
 
@@ -18,7 +18,7 @@ class Case < ActiveRecord::Base
18
18
  end
19
19
 
20
20
  owned_by :user
21
- subject_of :assignments
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
@@ -17,6 +17,5 @@ class CustomAssignment < ActiveRecord::Base
17
17
  end
18
18
  end
19
19
 
20
- task_for :case
21
20
 
22
21
  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 :case_id
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
@@ -5,6 +5,8 @@ class CreateCases < ActiveRecord::Migration
5
5
  t.string :name
6
6
  t.string :regarding
7
7
  t.string :aasm_state
8
+ t.string :notification_method
9
+ t.integer :notified_id
8
10
  t.timestamps
9
11
  end
10
12
  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
 
@@ -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.3
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