stonepath 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/stonepath.rb +2 -3
- data/lib/stonepath/extensions/action_view.rb +1 -1
- data/lib/stonepath/extensions/rails_generator_commands.rb +42 -0
- data/rails_generators/{stonepath → stonepath_event_log}/stonepath_event_log_generator.rb +0 -0
- data/rails_generators/{stonepath → stonepath_event_log}/templates/create_event_records.rb +0 -0
- data/rails_generators/{stonepath → stonepath_event_log}/templates/event_record.rb +0 -0
- data/rails_generators/stonepath_task/USAGE +1 -0
- data/rails_generators/stonepath_task/stonepath_task_generator.rb +29 -0
- data/rails_generators/stonepath_task/templates/generic_task.rb +23 -0
- data/rails_generators/stonepath_task/templates/generic_task_migration.rb +36 -0
- data/rails_generators/stonepath_workitem/USAGE +51 -0
- data/rails_generators/stonepath_workitem/stonepath_workitem_generator.rb +196 -0
- data/rails_generators/stonepath_workitem/templates/actions/create.rb +9 -0
- data/rails_generators/stonepath_workitem/templates/actions/destroy.rb +6 -0
- data/rails_generators/stonepath_workitem/templates/actions/edit.rb +3 -0
- data/rails_generators/stonepath_workitem/templates/actions/index.rb +3 -0
- data/rails_generators/stonepath_workitem/templates/actions/new.rb +3 -0
- data/rails_generators/stonepath_workitem/templates/actions/show.rb +3 -0
- data/rails_generators/stonepath_workitem/templates/actions/update.rb +9 -0
- data/rails_generators/stonepath_workitem/templates/controller.rb +3 -0
- data/rails_generators/stonepath_workitem/templates/event_controller.rb +25 -0
- data/rails_generators/stonepath_workitem/templates/fixtures.yml +9 -0
- data/rails_generators/stonepath_workitem/templates/helper.rb +2 -0
- data/rails_generators/stonepath_workitem/templates/migration.rb +24 -0
- data/rails_generators/stonepath_workitem/templates/model.rb +33 -0
- data/rails_generators/stonepath_workitem/templates/tests/testunit/actions/create.rb +11 -0
- data/rails_generators/stonepath_workitem/templates/tests/testunit/actions/destroy.rb +6 -0
- data/rails_generators/stonepath_workitem/templates/tests/testunit/actions/edit.rb +4 -0
- data/rails_generators/stonepath_workitem/templates/tests/testunit/actions/index.rb +4 -0
- data/rails_generators/stonepath_workitem/templates/tests/testunit/actions/new.rb +4 -0
- data/rails_generators/stonepath_workitem/templates/tests/testunit/actions/show.rb +4 -0
- data/rails_generators/stonepath_workitem/templates/tests/testunit/actions/update.rb +11 -0
- data/rails_generators/stonepath_workitem/templates/tests/testunit/controller.rb +5 -0
- data/rails_generators/stonepath_workitem/templates/tests/testunit/model.rb +7 -0
- data/rails_generators/stonepath_workitem/templates/views/erb/_form.html.erb +10 -0
- data/rails_generators/stonepath_workitem/templates/views/erb/edit.html.erb +12 -0
- data/rails_generators/stonepath_workitem/templates/views/erb/index.html.erb +27 -0
- data/rails_generators/stonepath_workitem/templates/views/erb/new.html.erb +5 -0
- data/rails_generators/stonepath_workitem/templates/views/erb/show.html.erb +26 -0
- metadata +39 -12
- data/lib/stonepath/extensions/action_controller.rb +0 -50
- data/lib/stonepath/extensions/kernel.rb +0 -5
- data/rails_generators/stonepath/stonepath_task_generator.rb +0 -9
- data/rails_generators/stonepath/stonepath_workitem_generator.rb +0 -8
- data/rails_generators/stonepath/templates/generic_task.rb +0 -8
- data/rails_generators/stonepath/templates/generic_task_migration.rb +0 -20
- data/rails_generators/stonepath/templates/workitem_readme.txt +0 -14
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/stonepath.rb
CHANGED
@@ -7,9 +7,10 @@ module StonePath
|
|
7
7
|
|
8
8
|
base.instance_eval {
|
9
9
|
|
10
|
-
def stonepath_workitem
|
10
|
+
def stonepath_workitem(&config_block)
|
11
11
|
require File.expand_path(File.dirname(__FILE__)) + "/stonepath/work_item.rb"
|
12
12
|
include StonePath::WorkItem
|
13
|
+
instance_eval &config_block if config_block
|
13
14
|
end
|
14
15
|
|
15
16
|
def stonepath_task(&config_block)
|
@@ -51,8 +52,6 @@ require "stonepath/config"
|
|
51
52
|
# init.rb chokes on load. I suspect this is an artificial issue because of the way the
|
52
53
|
# embedded test app works.
|
53
54
|
load File.expand_path( File.dirname(__FILE__)) + "/stonepath/extensions/activerecordbase.rb"
|
54
|
-
load File.expand_path( File.dirname(__FILE__)) + "/stonepath/extensions/action_controller.rb"
|
55
|
-
load File.expand_path( File.dirname(__FILE__)) + "/stonepath/extensions/kernel.rb"
|
56
55
|
load File.expand_path( File.dirname(__FILE__)) + '/stonepath/extensions/action_view.rb'
|
57
56
|
|
58
57
|
|
@@ -6,7 +6,7 @@ if Object.const_defined?(:ActionView)
|
|
6
6
|
module UrlHelper
|
7
7
|
|
8
8
|
def link_to_stonepath_event(object, event)
|
9
|
-
path_method = object.class.to_s.
|
9
|
+
path_method = object.class.to_s.tableize.singularize + "_event_path"
|
10
10
|
path = self.send(path_method, object, :id => event.to_s)
|
11
11
|
link_to(event.to_s.humanize, path, :method => :post)
|
12
12
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Rails
|
2
|
+
module Generator
|
3
|
+
module Commands
|
4
|
+
|
5
|
+
Create.class_eval {
|
6
|
+
def route_stonepath_workitems(resource)
|
7
|
+
sentinel = 'ActionController::Routing::Routes.draw do |map|'
|
8
|
+
logger.route "map.stonepath_workitems #{resource}"
|
9
|
+
unless options[:pretend]
|
10
|
+
gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
|
11
|
+
"#{match}
|
12
|
+
|
13
|
+
map.resources :#{resource} do |o|
|
14
|
+
o.resource :event, {:only => \"create\", :controller => \"#{resource.singularize}_events\"}
|
15
|
+
end
|
16
|
+
"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
}
|
21
|
+
|
22
|
+
|
23
|
+
Destroy.class_eval {
|
24
|
+
def route_stonepath_workitems(*resources)
|
25
|
+
resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
|
26
|
+
look_for = "\n map.stonepath_workitems #{resource_list}\n"
|
27
|
+
logger.route "map.stonepath_workitems #{resource_list}"
|
28
|
+
gsub_file 'config/routes.rb', /(#{look_for})/mi, ''
|
29
|
+
end
|
30
|
+
}
|
31
|
+
|
32
|
+
|
33
|
+
List.class_eval {
|
34
|
+
def route_stonepath_workitems(*resources)
|
35
|
+
resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
|
36
|
+
logger.route "map.stonepath_workitems #{resource_list}"
|
37
|
+
end
|
38
|
+
}
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
Usage goes here.
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class StonepathTaskGenerator < Rails::Generator::Base
|
2
|
+
|
3
|
+
|
4
|
+
attr_accessor :name, :attributes
|
5
|
+
|
6
|
+
def initialize(runtime_args, runtime_options = {})
|
7
|
+
super
|
8
|
+
usage if @args.empty?
|
9
|
+
|
10
|
+
@name = @args.first
|
11
|
+
@controller_actions = []
|
12
|
+
@attributes = []
|
13
|
+
|
14
|
+
@args[1..-1].each do |arg|
|
15
|
+
if arg.include? ':'
|
16
|
+
@attributes << Rails::Generator::GeneratedAttribute.new(*arg.split(":"))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
@attributes.uniq!
|
21
|
+
end
|
22
|
+
|
23
|
+
def manifest
|
24
|
+
record do |m|
|
25
|
+
m.template('generic_task.rb', "app/models/#{@name.tableize.singularize}.rb")
|
26
|
+
m.migration_template("generic_task_migration.rb", "db/migrate", :migration_file_name => "create_#{@name.tableize}")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class <%= args[0].classify %> < ActiveRecord::Base
|
2
|
+
include StonePath
|
3
|
+
|
4
|
+
stonepath_task
|
5
|
+
|
6
|
+
#logs_transitions # uncomment this if you generate the event log.
|
7
|
+
|
8
|
+
attr_accessible <%= attributes.map { |a| ":#{a.name}" }.join(", ") %>
|
9
|
+
|
10
|
+
# you might think 'overdue' should be a state, but no, part of the stonepath
|
11
|
+
# methodology is that states should be as free of time definition as possible.
|
12
|
+
# Thinking about it, this should make sense. Think of the conversation:
|
13
|
+
# A: "That isn't done yet?"
|
14
|
+
# B: "No, it's overdue"
|
15
|
+
# A: "Well, where is it then?"
|
16
|
+
# B: "It's still on Mike's desk, in process".
|
17
|
+
#
|
18
|
+
# so the state would be 'in process', even though it is 'overdue'.
|
19
|
+
def overdue?
|
20
|
+
(Time.now > due_at) && !self.completed?
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Create<%= args[0].tableize.classify.pluralize %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :<%= args[0].tableize %> do |t|
|
4
|
+
|
5
|
+
# don't change these unless you want to get deep into meta in the
|
6
|
+
# stonepath gem.
|
7
|
+
t.string :aasm_state
|
8
|
+
t.references :workitem, :polymorphic => true
|
9
|
+
t.references :workbench, :polymorphic => true
|
10
|
+
|
11
|
+
t.datetime :due_at
|
12
|
+
t.datetime :completed_at
|
13
|
+
t.timestamps
|
14
|
+
|
15
|
+
# This "urgent at' concept was useful in one of the domains StonePath
|
16
|
+
# was written/extracted from. The idea is thatm while something is 'due'
|
17
|
+
# at a specific time, it might become urgent shortly before it is due.
|
18
|
+
# In that domain, we color-coded tasks as green (due date is far out)
|
19
|
+
# yellow (urgent timestap has passed), and red (overdue - due date
|
20
|
+
# has passed). This won't become part of the framework, but I like the
|
21
|
+
# idea so much I thought I'd comment it here until it gets in some
|
22
|
+
# official documentation for 'advanced usage'.
|
23
|
+
# t.datetime :urgent_at
|
24
|
+
|
25
|
+
# Your attributes should be defined here.
|
26
|
+
<%- for attribute in attributes -%>
|
27
|
+
t.<%= attribute.type %> :<%= attribute.name %>
|
28
|
+
<%- end -%>
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.down
|
34
|
+
drop_table :<%= args[0].tableize %>
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
Description:
|
2
|
+
Scaffolds an entire resource, from model and migration to controller and
|
3
|
+
views. The resource is ready to use as a starting point for your restful,
|
4
|
+
resource-oriented application. Tests or specs are also generated depending
|
5
|
+
on if you have a "spec" directory or not.
|
6
|
+
|
7
|
+
IMPORTANT: This generator uses the "title" helper method which is generated
|
8
|
+
by the nifty_layout generator. You may want to run that generator first.
|
9
|
+
|
10
|
+
Usage:
|
11
|
+
Pass the name of the model, either CamelCased or under_scored, as the first
|
12
|
+
argument, and an optional list of attribute pairs and controller actions.
|
13
|
+
|
14
|
+
If no controller actions are specified, they will default to index, show,
|
15
|
+
new, create, edit, update, and destroy.
|
16
|
+
|
17
|
+
IMPORTANT: If no attribute pairs are specified, no model will be generated.
|
18
|
+
It will try to determine the attributes from an existing model.
|
19
|
+
|
20
|
+
Attribute pairs are column_name:sql_type arguments specifying the
|
21
|
+
model's attributes. Timestamps are added by default, so you don't have to
|
22
|
+
specify them by hand as 'created_at:datetime updated_at:datetime'.
|
23
|
+
|
24
|
+
For example, `nifty_scaffold post name:string content:text hidden:boolean`
|
25
|
+
gives you a model with those three attributes, a controller that handles
|
26
|
+
the create/show/update/destroy, forms to create and edit your posts, and
|
27
|
+
an index that lists them all, as well as a map.resources :posts
|
28
|
+
declaration in config/routes.rb.
|
29
|
+
|
30
|
+
Adding an "!" in the mix of arguments will invert the passed controller
|
31
|
+
actions. This will include all 7 controller actitons except the ones
|
32
|
+
mentioned. This option doesn't effect model attributes.
|
33
|
+
|
34
|
+
Examples:
|
35
|
+
script/generate nifty_scaffold post
|
36
|
+
|
37
|
+
Will create a controller called "posts" it will contain all seven
|
38
|
+
CRUD actions along with the views. A model will NOT be created,
|
39
|
+
instead it will look for an existing model and use those attributes.
|
40
|
+
|
41
|
+
script/generate nifty_scaffold post name:string content:text index new edit
|
42
|
+
|
43
|
+
Will create a Post model and migration file with the name and content
|
44
|
+
attributes. It will also create a controller with index, new, create,
|
45
|
+
edit, and update actions. Notice the create and update actions are
|
46
|
+
added automatically with new and edit.
|
47
|
+
|
48
|
+
script/generate nifty_scaffold post ! show new
|
49
|
+
|
50
|
+
Creates a posts controller (no model) with index, edit, update, and
|
51
|
+
destroy actions.
|
@@ -0,0 +1,196 @@
|
|
1
|
+
class StonepathWorkitemGenerator < Rails::Generator::Base
|
2
|
+
|
3
|
+
load File.expand_path( File.dirname(__FILE__)) + '/../../lib/stonepath/extensions/rails_generator_commands.rb'
|
4
|
+
|
5
|
+
attr_accessor :name, :attributes
|
6
|
+
|
7
|
+
def initialize(runtime_args, runtime_options = {})
|
8
|
+
super
|
9
|
+
usage if @args.empty?
|
10
|
+
|
11
|
+
@name = @args.first
|
12
|
+
@attributes = []
|
13
|
+
@args[1..-1].each do |arg|
|
14
|
+
if arg.include? ':'
|
15
|
+
@attributes << Rails::Generator::GeneratedAttribute.new(*arg.split(":"))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
@attributes.uniq!
|
19
|
+
@controller_actions = all_actions
|
20
|
+
end
|
21
|
+
|
22
|
+
def manifest
|
23
|
+
record do |m|
|
24
|
+
|
25
|
+
m.directory "app/models"
|
26
|
+
m.template "model.rb", "app/models/#{singular_name}.rb"
|
27
|
+
m.migration_template "migration.rb", "db/migrate", :migration_file_name => "create_#{plural_name}"
|
28
|
+
m.directory "test/unit"
|
29
|
+
m.template "tests/#{test_framework}/model.rb", "test/unit/#{singular_name}_test.rb"
|
30
|
+
m.directory "test/fixtures"
|
31
|
+
m.template "fixtures.yml", "test/fixtures/#{plural_name}.yml"
|
32
|
+
|
33
|
+
m.directory "app/controllers"
|
34
|
+
m.template "controller.rb", "app/controllers/#{plural_name}_controller.rb"
|
35
|
+
m.template "event_controller.rb", "app/controllers/#{singular_name}_events_controller.rb"
|
36
|
+
|
37
|
+
m.directory "app/helpers"
|
38
|
+
m.template "helper.rb", "app/helpers/#{plural_name}_helper.rb"
|
39
|
+
|
40
|
+
m.directory "app/views/#{plural_name}"
|
41
|
+
@controller_actions.each do |action|
|
42
|
+
if File.exist? source_path("views/#{view_language}/#{action}.html.#{view_language}")
|
43
|
+
m.template "views/#{view_language}/#{action}.html.#{view_language}", "app/views/#{plural_name}/#{action}.html.#{view_language}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if form_partial?
|
48
|
+
m.template "views/#{view_language}/_form.html.#{view_language}", "app/views/#{plural_name}/_form.html.#{view_language}"
|
49
|
+
end
|
50
|
+
|
51
|
+
m.route_stonepath_workitems plural_name
|
52
|
+
|
53
|
+
m.directory "test/functional"
|
54
|
+
m.template "tests/#{test_framework}/controller.rb", "test/functional/#{plural_name}_controller_test.rb"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def form_partial?
|
59
|
+
actions? :new, :edit
|
60
|
+
end
|
61
|
+
|
62
|
+
def all_actions
|
63
|
+
%w[index show new create edit update destroy]
|
64
|
+
end
|
65
|
+
|
66
|
+
def action?(name)
|
67
|
+
@controller_actions.include? name.to_s
|
68
|
+
end
|
69
|
+
|
70
|
+
def actions?(*names)
|
71
|
+
names.all? { |n| action? n.to_s }
|
72
|
+
end
|
73
|
+
|
74
|
+
def singular_name
|
75
|
+
name.underscore
|
76
|
+
end
|
77
|
+
|
78
|
+
def plural_name
|
79
|
+
name.underscore.pluralize
|
80
|
+
end
|
81
|
+
|
82
|
+
def class_name
|
83
|
+
name.camelize
|
84
|
+
end
|
85
|
+
|
86
|
+
def object_id_name
|
87
|
+
(class_name.tableize.singularize + "_id")
|
88
|
+
end
|
89
|
+
|
90
|
+
def plural_class_name
|
91
|
+
plural_name.camelize
|
92
|
+
end
|
93
|
+
|
94
|
+
def controller_methods(dir_name)
|
95
|
+
@controller_actions.map do |action|
|
96
|
+
read_template("#{dir_name}/#{action}.rb")
|
97
|
+
end.join(" \n").strip
|
98
|
+
end
|
99
|
+
|
100
|
+
def render_form
|
101
|
+
if form_partial?
|
102
|
+
if options[:haml]
|
103
|
+
"= render :partial => 'form'"
|
104
|
+
else
|
105
|
+
"<%= render :partial => 'form' %>"
|
106
|
+
end
|
107
|
+
else
|
108
|
+
read_template("views/#{view_language}/_form.html.#{view_language}")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def items_path(suffix = 'path')
|
113
|
+
if action? :index
|
114
|
+
"#{plural_name}_#{suffix}"
|
115
|
+
else
|
116
|
+
"root_#{suffix}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def item_path(suffix = 'path')
|
121
|
+
if action? :show
|
122
|
+
"@#{singular_name}"
|
123
|
+
else
|
124
|
+
items_path(suffix)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def item_path_for_spec(suffix = 'path')
|
129
|
+
if action? :show
|
130
|
+
"#{singular_name}_#{suffix}(assigns[:#{singular_name}])"
|
131
|
+
else
|
132
|
+
items_path(suffix)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def item_path_for_test(suffix = 'path')
|
137
|
+
if action? :show
|
138
|
+
"#{singular_name}_#{suffix}(assigns(:#{singular_name}))"
|
139
|
+
else
|
140
|
+
items_path(suffix)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def model_columns_for_attributes
|
145
|
+
class_name.constantize.columns.reject do |column|
|
146
|
+
column.name.to_s =~ /^(id|created_at|updated_at)$/
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def rspec?
|
151
|
+
test_framework == :rspec
|
152
|
+
end
|
153
|
+
|
154
|
+
protected
|
155
|
+
|
156
|
+
def view_language
|
157
|
+
options[:haml] ? 'haml' : 'erb'
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_framework
|
161
|
+
options[:test_framework] ||= default_test_framework
|
162
|
+
end
|
163
|
+
|
164
|
+
def default_test_framework
|
165
|
+
File.exist?(destination_path("spec")) ? :rspec : :testunit
|
166
|
+
end
|
167
|
+
|
168
|
+
def add_options!(opt)
|
169
|
+
opt.separator ''
|
170
|
+
opt.separator 'Options:'
|
171
|
+
# opt.on("--skip-model", "Don't generate a model or migration file.") { |v| options[:skip_model] = v }
|
172
|
+
# opt.on("--skip-migration", "Don't generate migration file for model.") { |v| options[:skip_migration] = v }
|
173
|
+
# opt.on("--skip-timestamps", "Don't add timestamps to migration file.") { |v| options[:skip_timestamps] = v }
|
174
|
+
# opt.on("--skip-controller", "Don't generate controller, helper, or views.") { |v| options[:skip_controller] = v }
|
175
|
+
# opt.on("--invert", "Generate all controller actions except these mentioned.") { |v| options[:invert] = v }
|
176
|
+
# opt.on("--haml", "Generate HAML views instead of ERB.") { |v| options[:haml] = v }
|
177
|
+
# opt.on("--testunit", "Use test/unit for test files.") { options[:test_framework] = :testunit }
|
178
|
+
# opt.on("--rspec", "Use RSpec for test files.") { options[:test_framework] = :rspec }
|
179
|
+
# opt.on("--shoulda", "Use Shoulda for test files.") { options[:test_framework] = :shoulda }
|
180
|
+
end
|
181
|
+
|
182
|
+
# is there a better way to do this? Perhaps with const_defined?
|
183
|
+
def model_exists?
|
184
|
+
File.exist? destination_path("app/models/#{singular_name}.rb")
|
185
|
+
end
|
186
|
+
|
187
|
+
def read_template(relative_path)
|
188
|
+
ERB.new(File.read(source_path(relative_path)), nil, '-').result(binding)
|
189
|
+
end
|
190
|
+
|
191
|
+
def banner
|
192
|
+
<<-EOS
|
193
|
+
Creates a WorkItem as defined by the Stonepath Workflow Methodology
|
194
|
+
EOS
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
def create
|
2
|
+
@<%= singular_name %> = <%= class_name %>.new(params[:<%= singular_name %>])
|
3
|
+
if @<%= singular_name %>.save
|
4
|
+
flash[:notice] = "Successfully created <%= name.underscore.humanize.downcase %>."
|
5
|
+
redirect_to <%= item_path('url') %>
|
6
|
+
else
|
7
|
+
render :action => 'new'
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
def update
|
2
|
+
@<%= singular_name %> = <%= class_name %>.find(params[:id])
|
3
|
+
if @<%= singular_name %>.update_attributes(params[:<%= singular_name %>])
|
4
|
+
flash[:notice] = "Successfully updated <%= name.underscore.humanize.downcase %>."
|
5
|
+
redirect_to <%= item_path('url') %>
|
6
|
+
else
|
7
|
+
render :action => 'edit'
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# this is now your file to do with as you see fit. Before you modify it though, make sure you
|
2
|
+
# understand how the nested restful routes are defined in the routes.rb file!
|
3
|
+
|
4
|
+
class <%= class_name %>EventsController < ApplicationController
|
5
|
+
|
6
|
+
def create
|
7
|
+
if request.post?
|
8
|
+
@object = <%= class_name %>.find(params[:<%= object_id_name %>])
|
9
|
+
event = params[:id]
|
10
|
+
if <%= class_name %>.aasm_events.keys.include?(event.to_sym)
|
11
|
+
respond_to do |format|
|
12
|
+
if @object.send(event + "!")
|
13
|
+
flash[:notice] = "Event '#{event}' was successfully performed."
|
14
|
+
format.html { redirect_to(@object) }
|
15
|
+
format.xml { render :xml => @object }
|
16
|
+
else
|
17
|
+
flash[:notice] = "Event '#{event}' was NOT successfully performed."
|
18
|
+
format.html { redirect_to(@object) }
|
19
|
+
format.xml { render :xml => @object.errors, :status => :unprocessable_entity }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Create<%= plural_class_name %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :<%= plural_name %> do |t|
|
4
|
+
# These are the attributes of a workitem
|
5
|
+
t.string :aasm_state
|
6
|
+
t.integer :owner_id
|
7
|
+
|
8
|
+
# Your attributes should be defined here.
|
9
|
+
<%- for attribute in attributes -%>
|
10
|
+
t.<%= attribute.type %> :<%= attribute.name %>
|
11
|
+
<%- end -%>
|
12
|
+
<%- unless options[:skip_timestamps] -%>
|
13
|
+
t.timestamps
|
14
|
+
<%- end -%>
|
15
|
+
end
|
16
|
+
|
17
|
+
#I'd like to create an index on aasm_state here.
|
18
|
+
# you might optionally want to index owner_id
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.down
|
22
|
+
drop_table :<%= plural_name %>
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class <%= class_name %> < ActiveRecord::Base
|
2
|
+
include StonePath
|
3
|
+
|
4
|
+
stonepath_workitem do
|
5
|
+
#owned_by :your_owning class
|
6
|
+
|
7
|
+
#tasked_through :your_implementation_of_stonepath_task
|
8
|
+
|
9
|
+
# This is an example trivial workflow. This is now yours to change as
|
10
|
+
# you see fit.
|
11
|
+
aasm_initial_state :pending
|
12
|
+
|
13
|
+
aasm_state :pending
|
14
|
+
aasm_state :in_process
|
15
|
+
aasm_state :completed
|
16
|
+
|
17
|
+
aasm_event :activate do
|
18
|
+
transitions :to => :in_process, :from => :pending
|
19
|
+
end
|
20
|
+
|
21
|
+
aasm_event :complete do
|
22
|
+
transitions :to => :completed, :from => :in_process
|
23
|
+
end
|
24
|
+
|
25
|
+
aasm_event :reactivate do
|
26
|
+
transitions :to => :in_process, :from => :completed
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_accessible <%= attributes.map { |a| ":#{a.name}" }.join(", ") %>
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
def test_create_invalid
|
2
|
+
<%= class_name %>.any_instance.stubs(:valid?).returns(false)
|
3
|
+
post :create
|
4
|
+
assert_template 'new'
|
5
|
+
end
|
6
|
+
|
7
|
+
def test_create_valid
|
8
|
+
<%= class_name %>.any_instance.stubs(:valid?).returns(true)
|
9
|
+
post :create
|
10
|
+
assert_redirected_to <%= item_path_for_test('url') %>
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
def test_update_invalid
|
2
|
+
<%= class_name %>.any_instance.stubs(:valid?).returns(false)
|
3
|
+
put :update, :id => <%= class_name %>.first
|
4
|
+
assert_template 'edit'
|
5
|
+
end
|
6
|
+
|
7
|
+
def test_update_valid
|
8
|
+
<%= class_name %>.any_instance.stubs(:valid?).returns(true)
|
9
|
+
put :update, :id => <%= class_name %>.first
|
10
|
+
assert_redirected_to <%= item_path_for_test('url') %>
|
11
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<%% form_for @<%= singular_name %> do |f| %>
|
2
|
+
<%%= f.error_messages %>
|
3
|
+
<%- for attribute in attributes -%>
|
4
|
+
<p>
|
5
|
+
<%%= f.label :<%= attribute.name %> %><br />
|
6
|
+
<%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
|
7
|
+
</p>
|
8
|
+
<%- end -%>
|
9
|
+
<p><%%= f.submit "Submit" %></p>
|
10
|
+
<%% end %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%= render_form %>
|
2
|
+
|
3
|
+
<%- if actions? :show, :index -%>
|
4
|
+
<p>
|
5
|
+
<%- if action? :show -%>
|
6
|
+
<%%= link_to "Show", @<%= singular_name %> %> |
|
7
|
+
<%- end -%>
|
8
|
+
<%- if action? :index -%>
|
9
|
+
<%%= link_to "View All", <%= plural_name %>_path %>
|
10
|
+
<%- end -%>
|
11
|
+
</p>
|
12
|
+
<%- end -%>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<table>
|
2
|
+
<tr>
|
3
|
+
<%- for attribute in attributes -%>
|
4
|
+
<th><%= attribute.column.human_name.titleize %></th>
|
5
|
+
<%- end -%>
|
6
|
+
</tr>
|
7
|
+
<%% for <%= singular_name %> in @<%= plural_name %> %>
|
8
|
+
<tr>
|
9
|
+
<%- for attribute in attributes -%>
|
10
|
+
<td><%%=h <%= singular_name %>.<%= attribute.name %> %></td>
|
11
|
+
<%- end -%>
|
12
|
+
<%- if action? :show -%>
|
13
|
+
<td><%%= link_to "Show", <%= singular_name %> %></td>
|
14
|
+
<%- end -%>
|
15
|
+
<%- if action? :edit -%>
|
16
|
+
<td><%%= link_to "Edit", edit_<%= singular_name %>_path(<%= singular_name %>) %></td>
|
17
|
+
<%- end -%>
|
18
|
+
<%- if action? :destroy -%>
|
19
|
+
<td><%%= link_to "Destroy", <%= singular_name %>, :confirm => 'Are you sure?', :method => :delete %></td>
|
20
|
+
<%- end -%>
|
21
|
+
</tr>
|
22
|
+
<%% end %>
|
23
|
+
</table>
|
24
|
+
|
25
|
+
<%- if action? :new -%>
|
26
|
+
<p><%%= link_to "New <%= singular_name.titleize %>", new_<%= singular_name %>_path %></p>
|
27
|
+
<%- end -%>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<%- for attribute in attributes -%>
|
2
|
+
<p>
|
3
|
+
<strong><%= attribute.column.human_name.titleize %>:</strong>
|
4
|
+
<%%=h @<%= singular_name %>.<%= attribute.name %> %>
|
5
|
+
</p>
|
6
|
+
<%- end -%>
|
7
|
+
|
8
|
+
<p>
|
9
|
+
<strong>Current state: </strong><%%= @<%= singular_name %>.aasm_state.humanize %>
|
10
|
+
</p>
|
11
|
+
|
12
|
+
<p>
|
13
|
+
<%% @<%= singular_name %>.aasm_events_for_current_state.each do |event| %>
|
14
|
+
<%%= link_to_stonepath_event(@<%= singular_name %>, event) %> |
|
15
|
+
<%% end %>
|
16
|
+
|
17
|
+
<%- if action? :edit -%>
|
18
|
+
<%%= link_to "Edit", edit_<%= singular_name %>_path(@<%= singular_name %>) %> |
|
19
|
+
<%- end -%>
|
20
|
+
<%- if action? :destroy -%>
|
21
|
+
<%%= link_to "Destroy", @<%= singular_name %>, :confirm => 'Are you sure?', :method => :delete %> |
|
22
|
+
<%- end -%>
|
23
|
+
<%- if action? :index -%>
|
24
|
+
<%%= link_to "View All", <%= plural_name %>_path %>
|
25
|
+
<%- end -%>
|
26
|
+
</p>
|
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.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Bock
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-07 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -45,10 +45,9 @@ files:
|
|
45
45
|
- lib/stonepath/config.rb
|
46
46
|
- lib/stonepath/controller_hooks.rb
|
47
47
|
- lib/stonepath/event_logging.rb
|
48
|
-
- lib/stonepath/extensions/action_controller.rb
|
49
48
|
- lib/stonepath/extensions/action_view.rb
|
50
49
|
- lib/stonepath/extensions/activerecordbase.rb
|
51
|
-
- lib/stonepath/extensions/
|
50
|
+
- lib/stonepath/extensions/rails_generator_commands.rb
|
52
51
|
- lib/stonepath/group.rb
|
53
52
|
- lib/stonepath/role.rb
|
54
53
|
- lib/stonepath/task.rb
|
@@ -56,14 +55,42 @@ files:
|
|
56
55
|
- lib/stonepath/work_item.rb
|
57
56
|
- lib/stonepath/work_owner.rb
|
58
57
|
- rails/init.rb
|
59
|
-
- rails_generators/
|
60
|
-
- rails_generators/
|
61
|
-
- rails_generators/
|
62
|
-
- rails_generators/
|
63
|
-
- rails_generators/
|
64
|
-
- rails_generators/
|
65
|
-
- rails_generators/
|
66
|
-
- rails_generators/
|
58
|
+
- rails_generators/stonepath_event_log/stonepath_event_log_generator.rb
|
59
|
+
- rails_generators/stonepath_event_log/templates/create_event_records.rb
|
60
|
+
- rails_generators/stonepath_event_log/templates/event_record.rb
|
61
|
+
- rails_generators/stonepath_task/USAGE
|
62
|
+
- rails_generators/stonepath_task/stonepath_task_generator.rb
|
63
|
+
- rails_generators/stonepath_task/templates/generic_task.rb
|
64
|
+
- rails_generators/stonepath_task/templates/generic_task_migration.rb
|
65
|
+
- rails_generators/stonepath_workitem/USAGE
|
66
|
+
- rails_generators/stonepath_workitem/stonepath_workitem_generator.rb
|
67
|
+
- rails_generators/stonepath_workitem/templates/actions/create.rb
|
68
|
+
- rails_generators/stonepath_workitem/templates/actions/destroy.rb
|
69
|
+
- rails_generators/stonepath_workitem/templates/actions/edit.rb
|
70
|
+
- rails_generators/stonepath_workitem/templates/actions/index.rb
|
71
|
+
- rails_generators/stonepath_workitem/templates/actions/new.rb
|
72
|
+
- rails_generators/stonepath_workitem/templates/actions/show.rb
|
73
|
+
- rails_generators/stonepath_workitem/templates/actions/update.rb
|
74
|
+
- rails_generators/stonepath_workitem/templates/controller.rb
|
75
|
+
- rails_generators/stonepath_workitem/templates/event_controller.rb
|
76
|
+
- rails_generators/stonepath_workitem/templates/fixtures.yml
|
77
|
+
- rails_generators/stonepath_workitem/templates/helper.rb
|
78
|
+
- rails_generators/stonepath_workitem/templates/migration.rb
|
79
|
+
- rails_generators/stonepath_workitem/templates/model.rb
|
80
|
+
- rails_generators/stonepath_workitem/templates/tests/testunit/actions/create.rb
|
81
|
+
- rails_generators/stonepath_workitem/templates/tests/testunit/actions/destroy.rb
|
82
|
+
- rails_generators/stonepath_workitem/templates/tests/testunit/actions/edit.rb
|
83
|
+
- rails_generators/stonepath_workitem/templates/tests/testunit/actions/index.rb
|
84
|
+
- rails_generators/stonepath_workitem/templates/tests/testunit/actions/new.rb
|
85
|
+
- rails_generators/stonepath_workitem/templates/tests/testunit/actions/show.rb
|
86
|
+
- rails_generators/stonepath_workitem/templates/tests/testunit/actions/update.rb
|
87
|
+
- rails_generators/stonepath_workitem/templates/tests/testunit/controller.rb
|
88
|
+
- rails_generators/stonepath_workitem/templates/tests/testunit/model.rb
|
89
|
+
- rails_generators/stonepath_workitem/templates/views/erb/_form.html.erb
|
90
|
+
- rails_generators/stonepath_workitem/templates/views/erb/edit.html.erb
|
91
|
+
- rails_generators/stonepath_workitem/templates/views/erb/index.html.erb
|
92
|
+
- rails_generators/stonepath_workitem/templates/views/erb/new.html.erb
|
93
|
+
- rails_generators/stonepath_workitem/templates/views/erb/show.html.erb
|
67
94
|
- script/console
|
68
95
|
- script/destroy
|
69
96
|
- script/generate
|
@@ -1,50 +0,0 @@
|
|
1
|
-
if Object.const_defined?(:ActionController)
|
2
|
-
|
3
|
-
module ActionController
|
4
|
-
module Resources
|
5
|
-
|
6
|
-
def define_events_controller(object_sym)
|
7
|
-
class_name = object_sym.to_s.classify
|
8
|
-
controller_name = class_name + "EventsController"
|
9
|
-
|
10
|
-
# This is some amazing bit of meta that will probably go away when we have
|
11
|
-
# a work_item generator. In short, at runtime, this defines the controller
|
12
|
-
# that handles events for something declared in the routes file as a
|
13
|
-
# stonepath_workitem
|
14
|
-
Object.const_set(controller_name, ApplicationController.clone).class_eval do
|
15
|
-
id_name = (class_name.downcase + "_id").to_sym
|
16
|
-
#still need generic http error handling
|
17
|
-
define_method("create") do
|
18
|
-
if request.post?
|
19
|
-
@object = get_class(class_name).find(params[id_name])
|
20
|
-
event = params[:id]
|
21
|
-
if get_class(class_name).aasm_events.keys.include?(event.to_sym)
|
22
|
-
respond_to do |format|
|
23
|
-
if @object.send(event + "!")
|
24
|
-
flash[:notice] = "Event '#{event}' was successfully performed."
|
25
|
-
format.html { redirect_to(@object) }
|
26
|
-
format.xml { render :xml => @object }
|
27
|
-
else
|
28
|
-
flash[:notice] = "Event '#{event}' was NOT successfully performed."
|
29
|
-
format.html { redirect_to(@object) }
|
30
|
-
format.xml { render :xml => @object.errors, :status => :unprocessable_entity }
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
def stonepath_workitems(resources_symbol, params={})
|
41
|
-
singular_resource_name = resources_symbol.to_s.singularize
|
42
|
-
self.resources resources_symbol, params do |o|
|
43
|
-
o.resource :event, {:only => "create", :controller => "#{singular_resource_name}_events"}
|
44
|
-
end
|
45
|
-
define_events_controller(resources_symbol)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
@@ -1,9 +0,0 @@
|
|
1
|
-
class StonepathTaskGenerator < Rails::Generator::Base
|
2
|
-
def manifest
|
3
|
-
record do |m|
|
4
|
-
task_name = args[0]
|
5
|
-
m.template('generic_task.rb', "app/models/#{task_name}.rb")
|
6
|
-
m.migration_template("generic_task_migration.rb", "db/migrate", :migration_file_name => "create_#{task_name.tableize}")
|
7
|
-
end
|
8
|
-
end
|
9
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
class Create<%= args[0].tableize.classify.pluralize %> < ActiveRecord::Migration
|
2
|
-
def self.up
|
3
|
-
create_table :<%= args[0].tableize %> do |t|
|
4
|
-
|
5
|
-
t.string :aasm_state
|
6
|
-
t.references :workitem, :polymorphic => true
|
7
|
-
t.references :workbench, :polymorphic => true
|
8
|
-
|
9
|
-
t.datetime :due_at
|
10
|
-
t.datetime :completed_at
|
11
|
-
t.timestamps
|
12
|
-
|
13
|
-
# customize your task here
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.down
|
18
|
-
drop_table :<%= args[0].tableize %>
|
19
|
-
end
|
20
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
We will eventually have a real generator here that will even include some default config for AASM settings, restful routes for the workflow actions, etc. Until then, it would be best to start a workitem by:
|
2
|
-
|
3
|
-
1) Using scaffold generator
|
4
|
-
2) adding aasm_state:string and owner_id:integer to the migration.
|
5
|
-
3) adding:
|
6
|
-
|
7
|
-
require 'aasm'
|
8
|
-
require 'stonepath'
|
9
|
-
|
10
|
-
stonepath_workitem
|
11
|
-
|
12
|
-
to the model
|
13
|
-
|
14
|
-
4) defining a state machine.
|