stencils 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest +7 -0
- data/README +14 -0
- data/Rakefile +15 -0
- data/lib/stencils.rb +8 -0
- data/lib/stencils/stencil.rb +59 -0
- data/lib/stencils/stencil_context.rb +331 -0
- data/stencils.gemspec +30 -0
- data/stencils.tmproj +39 -0
- metadata +70 -0
data/Manifest
ADDED
data/README
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
= stencils
|
2
|
+
|
3
|
+
Rails gem that provides a way to reuse 'stencils' for common actions and views.
|
4
|
+
Stencils lets you define an action and views once and reuse them for different models.
|
5
|
+
A Stencil might typically be used for generic CRUD operations.
|
6
|
+
|
7
|
+
== Install
|
8
|
+
|
9
|
+
gem install stencils
|
10
|
+
|
11
|
+
== Usage
|
12
|
+
|
13
|
+
...coming soon
|
14
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
|
5
|
+
Echoe.new('stencils', '0.0.0') do |p|
|
6
|
+
p.description = "Lets you define an action and views once and reuse them for different models."
|
7
|
+
p.project = 'stencils'
|
8
|
+
p.url = "http://rubyforge.org/projects/stencils"
|
9
|
+
p.author = "Ryan Owens"
|
10
|
+
p.email = "ryan@infoether.com"
|
11
|
+
p.ignore_pattern = ["tmp/*", "script/*", "stencils_notes.txt"]
|
12
|
+
p.development_dependencies = []
|
13
|
+
end
|
14
|
+
|
15
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
data/lib/stencils.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
module Stencils
|
2
|
+
|
3
|
+
module Stencil
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def stencil(name, options={})
|
12
|
+
@stencil_name = name
|
13
|
+
@stencil_options = options
|
14
|
+
@stencil_options[:name] = name
|
15
|
+
@stencil_options[:view_dir] ||= "stencils/#{name}"
|
16
|
+
|
17
|
+
#define a method here like setup_rest_stencil for the before filter.
|
18
|
+
#make the include and attr_accessor conditional so it only happens once.
|
19
|
+
#do whatever else is necessary to alow multiple stencils. (use instance_var_set with :@rest_stencil_options)
|
20
|
+
|
21
|
+
include RestStencil
|
22
|
+
attr_accessor :stencil
|
23
|
+
helper_method :stencil
|
24
|
+
before_filter :stencil_filter
|
25
|
+
helper "#{name.to_s.camelize}StencilHelper".constantize
|
26
|
+
end
|
27
|
+
|
28
|
+
def stencil_options
|
29
|
+
@stencil_options
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def stencil_filter
|
35
|
+
setup_stencil(self)
|
36
|
+
end
|
37
|
+
|
38
|
+
def setup_stencil(model_or_class_or_symbol)
|
39
|
+
@stencil ||= StencilContext.new(self.response.template, model_or_class_or_symbol, self.class.stencil_options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def render_stencil(action=nil, options={})
|
43
|
+
action, options = nil, action if action.is_a? Hash
|
44
|
+
action ||= params[:action]
|
45
|
+
render(:template => stencil_template(action)) unless custom_stencil_template_exists?(action)
|
46
|
+
end
|
47
|
+
|
48
|
+
def stencil_template(action)
|
49
|
+
"stencils/#{stencil.stencil_name}/#{action}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def custom_stencil_template_exists?(action=params[:action])
|
53
|
+
custom_template_path = File.join(RAILS_ROOT, 'app', 'views', "#{stencil.collection_name}", action.to_s)
|
54
|
+
File.exist?("#{custom_template_path}.html.erb") || File.exist?("#{custom_template_path}.erb")
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,331 @@
|
|
1
|
+
module Stencils
|
2
|
+
|
3
|
+
class StencilContext
|
4
|
+
|
5
|
+
attr_accessor :template
|
6
|
+
attr_accessor :base_name
|
7
|
+
attr_accessor :stencil_name, :stencil_view_dir
|
8
|
+
|
9
|
+
def initialize(template, model_or_class_or_symbol, options={})
|
10
|
+
@template = template
|
11
|
+
@base_name = base_name_for(model_or_class_or_symbol)
|
12
|
+
@stencil_name = options.delete :name
|
13
|
+
@stencil_view_dir = options.delete :view_dir
|
14
|
+
end
|
15
|
+
|
16
|
+
def base_name_for(model_or_class_or_symbol)
|
17
|
+
full_base_name = if model_or_class_or_symbol.kind_of? Class
|
18
|
+
model_or_class_or_symbol.name
|
19
|
+
elsif model_or_class_or_symbol.kind_of? Symbol
|
20
|
+
model_or_class_or_symbol.to_s.camelize
|
21
|
+
# elsif model_or_class_or_symbol.respond_to?(:controller)
|
22
|
+
elsif model_or_class_or_symbol.respond_to?(:controller)
|
23
|
+
model_or_class_or_symbol.controller.class.name
|
24
|
+
else
|
25
|
+
model_or_class_or_symbol.class.name
|
26
|
+
end
|
27
|
+
name = full_base_name.chomp('Test').chomp('Controller')
|
28
|
+
index = name.rindex(':')
|
29
|
+
index = index ? index+1 : 0
|
30
|
+
name[index,name.size]
|
31
|
+
end
|
32
|
+
|
33
|
+
def collection_class_name
|
34
|
+
#this singularize/pluralize chain lets you provide eg people/person and get people back, as opposed to peoples.
|
35
|
+
base_name.singularize.pluralize
|
36
|
+
end
|
37
|
+
|
38
|
+
def collection_name_base
|
39
|
+
collection_class_name.underscore.downcase
|
40
|
+
end
|
41
|
+
|
42
|
+
def collection_name
|
43
|
+
name = collection_name_base
|
44
|
+
name = "#{name}_collection" if uncountable? name
|
45
|
+
name
|
46
|
+
end
|
47
|
+
|
48
|
+
def collection_label
|
49
|
+
collection_name.titleize
|
50
|
+
end
|
51
|
+
|
52
|
+
def collection_symbol
|
53
|
+
collection_name.intern
|
54
|
+
end
|
55
|
+
|
56
|
+
def partial(name)
|
57
|
+
"#{collection_name}/#{name}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def collection_partial
|
61
|
+
partial 'list_item'
|
62
|
+
end
|
63
|
+
|
64
|
+
def render_collection_partial(model)
|
65
|
+
template.render :partial => collection_partial, :locals => {model_symbol => model}
|
66
|
+
end
|
67
|
+
|
68
|
+
def render_collection
|
69
|
+
html = []
|
70
|
+
collection.each do |model|
|
71
|
+
html << render_collection_partial(model)
|
72
|
+
end
|
73
|
+
html.join
|
74
|
+
end
|
75
|
+
|
76
|
+
def model_partial
|
77
|
+
# partial model_name
|
78
|
+
partial 'model'
|
79
|
+
end
|
80
|
+
|
81
|
+
def render_model
|
82
|
+
template.render :partial => model_partial, :locals => {model_symbol => model}
|
83
|
+
end
|
84
|
+
|
85
|
+
def form_partial
|
86
|
+
partial 'form'
|
87
|
+
end
|
88
|
+
|
89
|
+
def render_form(form)
|
90
|
+
template.render :partial => form_partial, :locals => {:form => form, model_symbol => model}
|
91
|
+
end
|
92
|
+
|
93
|
+
def model_class_name
|
94
|
+
collection_class_name.singularize
|
95
|
+
end
|
96
|
+
|
97
|
+
def model_name
|
98
|
+
model_class_name.underscore.downcase
|
99
|
+
end
|
100
|
+
|
101
|
+
def model_label
|
102
|
+
model_class_name.titleize
|
103
|
+
end
|
104
|
+
|
105
|
+
def new_or_old_label(new_label, old_label)
|
106
|
+
new_record? ? new_label : old_label
|
107
|
+
end
|
108
|
+
|
109
|
+
def new_or_edit_label(new_label="Add New #{model_label}", edit_label="Edit #{model_label}")
|
110
|
+
new_or_old_label new_label, edit_label
|
111
|
+
end
|
112
|
+
|
113
|
+
def model_instance_variable_name
|
114
|
+
"@#{model_name}"
|
115
|
+
end
|
116
|
+
|
117
|
+
def collection_instance_variable_name
|
118
|
+
"@#{collection_name}"
|
119
|
+
end
|
120
|
+
|
121
|
+
def collection_route
|
122
|
+
route = collection_name_base
|
123
|
+
route = "#{route}_index" if uncountable? route
|
124
|
+
route
|
125
|
+
end
|
126
|
+
|
127
|
+
def collection_url(options=nil)
|
128
|
+
args = adjust_hash_arg_to_last options
|
129
|
+
args.pop if args.last && args.last.empty?
|
130
|
+
args.delete_if {|arg| arg == nil || arg.kind_of?(ActiveRecord::Base)}
|
131
|
+
template.send "#{collection_route}_url", *args
|
132
|
+
end
|
133
|
+
|
134
|
+
def collection_path(options=nil)
|
135
|
+
args = adjust_hash_arg_to_last options
|
136
|
+
args.pop if args.last && args.last.empty?
|
137
|
+
args.delete_if {|arg| arg == nil || arg.kind_of?(ActiveRecord::Base)}
|
138
|
+
template.send "#{collection_route}_path", *args
|
139
|
+
end
|
140
|
+
|
141
|
+
def link_to_collection(options=nil)
|
142
|
+
template.link_to(collection_label, collection_path(options))
|
143
|
+
end
|
144
|
+
|
145
|
+
def show_route
|
146
|
+
"#{get_path_prefix}#{model_name}"
|
147
|
+
end
|
148
|
+
|
149
|
+
def show_path(model=self.model, options=nil)
|
150
|
+
|
151
|
+
args = adjust_hash_arg_to_last model, options
|
152
|
+
args.pop if args.last && args.last.empty?
|
153
|
+
args.delete_if {|arg| arg == nil}
|
154
|
+
|
155
|
+
puts "***show_path: "
|
156
|
+
puts "***model: #{model.inspect}"
|
157
|
+
puts "***args: #{args.inspect}"
|
158
|
+
|
159
|
+
template.send "#{show_route}_path", *args
|
160
|
+
end
|
161
|
+
|
162
|
+
def show_url(model=self.model, options=nil)
|
163
|
+
args = adjust_hash_arg_to_last model, options
|
164
|
+
args.pop if args.last && args.last.empty?
|
165
|
+
args.delete_if {|arg| arg == nil}
|
166
|
+
template.send "#{show_route}_url", *args
|
167
|
+
end
|
168
|
+
|
169
|
+
def edit_route
|
170
|
+
"edit_#{get_path_prefix}#{model_name}"
|
171
|
+
end
|
172
|
+
|
173
|
+
def edit_path(model=self.model, options=nil)
|
174
|
+
args = adjust_hash_arg_to_last model, options
|
175
|
+
args.pop if args.last && args.last.empty?
|
176
|
+
args.delete_if {|arg| arg == nil}
|
177
|
+
template.send "#{edit_route}_path", *args
|
178
|
+
end
|
179
|
+
|
180
|
+
def edit_path_url(model=self.model, options=nil)
|
181
|
+
args = adjust_hash_arg_to_last model, options
|
182
|
+
args.pop if args.last && args.last.empty?
|
183
|
+
args.delete_if {|arg| arg == nil}
|
184
|
+
template.send "#{edit_route}_url", *args
|
185
|
+
end
|
186
|
+
|
187
|
+
def new_route
|
188
|
+
"new_#{get_path_prefix}#{model_name}"
|
189
|
+
end
|
190
|
+
|
191
|
+
def new_path(options=nil)
|
192
|
+
route = "#{new_route}_path"
|
193
|
+
if options.blank?
|
194
|
+
template.send route
|
195
|
+
else
|
196
|
+
template.send route, options
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def new_path_url(options=nil)
|
201
|
+
route = "#{new_route}_url"
|
202
|
+
if options.blank?
|
203
|
+
template.send route
|
204
|
+
else
|
205
|
+
template.send route, options
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def get_path_prefix
|
210
|
+
path_prefix ? "#{path_prefix}_" : nil
|
211
|
+
end
|
212
|
+
|
213
|
+
def path_prefix
|
214
|
+
nil
|
215
|
+
end
|
216
|
+
|
217
|
+
def collection
|
218
|
+
instance_variable_get collection_instance_variable_name
|
219
|
+
end
|
220
|
+
|
221
|
+
def collection=(collection)
|
222
|
+
instance_variable_set collection_instance_variable_name, collection
|
223
|
+
end
|
224
|
+
alias_method :set_collection, :collection=
|
225
|
+
|
226
|
+
def model
|
227
|
+
instance_variable_get model_instance_variable_name
|
228
|
+
end
|
229
|
+
|
230
|
+
def model=(model)
|
231
|
+
puts "***model= : #{model_instance_variable_name}"
|
232
|
+
instance_variable_set model_instance_variable_name, model
|
233
|
+
end
|
234
|
+
alias_method :set_model, :model=
|
235
|
+
|
236
|
+
def model_class
|
237
|
+
Kernel.const_get(model_class_name)
|
238
|
+
end
|
239
|
+
|
240
|
+
def fixture_model(name=nil)
|
241
|
+
template.send collection_name_base, name
|
242
|
+
end
|
243
|
+
|
244
|
+
def model_symbol
|
245
|
+
model_name.intern
|
246
|
+
end
|
247
|
+
|
248
|
+
def adjust_hash_arg_to_last(*args)
|
249
|
+
hash_arg = nil
|
250
|
+
args.each_with_index do |arg,index|
|
251
|
+
if arg.kind_of? Hash
|
252
|
+
hash_arg = arg
|
253
|
+
end
|
254
|
+
if hash_arg
|
255
|
+
if index == args.size-1
|
256
|
+
args[index] = hash_arg
|
257
|
+
else
|
258
|
+
args[index] = nil
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
args
|
263
|
+
end
|
264
|
+
|
265
|
+
##UTILS MOVED THESE OUT OF RestControllerExtension so they could be used separately
|
266
|
+
|
267
|
+
def find_model_with_param_id
|
268
|
+
model_id = "#{model_name}_id"
|
269
|
+
param = params[model_id] || params[:id]
|
270
|
+
self.set_model model_class.find(param)
|
271
|
+
end
|
272
|
+
|
273
|
+
def new_model
|
274
|
+
self.set_model model_class.new
|
275
|
+
end
|
276
|
+
|
277
|
+
def new_model_with_params
|
278
|
+
self.set_model model_class.new(model_params)
|
279
|
+
end
|
280
|
+
|
281
|
+
def create_model_with_params
|
282
|
+
self.set_model model_class.create(model_params)
|
283
|
+
end
|
284
|
+
|
285
|
+
def update_model_with_params
|
286
|
+
find_model_with_param_id
|
287
|
+
self.model.update_attributes(model_params)
|
288
|
+
end
|
289
|
+
|
290
|
+
def init_model_with_params
|
291
|
+
find_model_with_param_id
|
292
|
+
self.model.attributes = model_params
|
293
|
+
end
|
294
|
+
|
295
|
+
def destroy_model_with_param_id
|
296
|
+
find_model_with_param_id.destroy
|
297
|
+
end
|
298
|
+
|
299
|
+
def save_model
|
300
|
+
self.model.save
|
301
|
+
end
|
302
|
+
|
303
|
+
def new_record?
|
304
|
+
model.new_record?
|
305
|
+
end
|
306
|
+
|
307
|
+
def model_params
|
308
|
+
params[model_symbol]
|
309
|
+
end
|
310
|
+
|
311
|
+
def params
|
312
|
+
template.params
|
313
|
+
end
|
314
|
+
|
315
|
+
def instance_variable_set(name, value)
|
316
|
+
super
|
317
|
+
template.instance_variable_set name, value
|
318
|
+
template.controller.instance_variable_set name, value
|
319
|
+
end
|
320
|
+
|
321
|
+
def instance_variable_get(name)
|
322
|
+
super || template.instance_variable_get(name) || template.controller.instance_variable_get(name)
|
323
|
+
end
|
324
|
+
|
325
|
+
def uncountable?(name)
|
326
|
+
ActiveSupport::Inflector.inflections.uncountables.include? name
|
327
|
+
end
|
328
|
+
|
329
|
+
end
|
330
|
+
|
331
|
+
end
|
data/stencils.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{stencils}
|
5
|
+
s.version = "0.0.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Ryan Owens"]
|
9
|
+
s.date = %q{2009-07-24}
|
10
|
+
s.description = %q{Lets you define an action and views once and reuse them for different models.}
|
11
|
+
s.email = %q{ryan@infoether.com}
|
12
|
+
s.extra_rdoc_files = ["lib/stencils/stencil.rb", "lib/stencils/stencil_context.rb", "lib/stencils.rb", "README"]
|
13
|
+
s.files = ["lib/stencils/stencil.rb", "lib/stencils/stencil_context.rb", "lib/stencils.rb", "Rakefile", "README", "stencils.tmproj", "Manifest", "stencils.gemspec"]
|
14
|
+
s.homepage = %q{http://rubyforge.org/projects/stencils}
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Stencils", "--main", "README"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubyforge_project = %q{stencils}
|
18
|
+
s.rubygems_version = %q{1.3.3}
|
19
|
+
s.summary = %q{Lets you define an action and views once and reuse them for different models.}
|
20
|
+
|
21
|
+
if s.respond_to? :specification_version then
|
22
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
23
|
+
s.specification_version = 3
|
24
|
+
|
25
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
|
+
else
|
27
|
+
end
|
28
|
+
else
|
29
|
+
end
|
30
|
+
end
|
data/stencils.tmproj
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>documents</key>
|
6
|
+
<array>
|
7
|
+
<dict>
|
8
|
+
<key>expanded</key>
|
9
|
+
<true/>
|
10
|
+
<key>name</key>
|
11
|
+
<string>stencils</string>
|
12
|
+
<key>regexFolderFilter</key>
|
13
|
+
<string>!.*/(\coverage|\.svn|\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
|
14
|
+
<key>sourceDirectory</key>
|
15
|
+
<string></string>
|
16
|
+
</dict>
|
17
|
+
</array>
|
18
|
+
<key>fileHierarchyDrawerWidth</key>
|
19
|
+
<integer>370</integer>
|
20
|
+
<key>metaData</key>
|
21
|
+
<dict/>
|
22
|
+
<key>showFileHierarchyDrawer</key>
|
23
|
+
<false/>
|
24
|
+
<key>showFileHierarchyPanel</key>
|
25
|
+
<true/>
|
26
|
+
<key>treeState</key>
|
27
|
+
<dict>
|
28
|
+
<key>stencils</key>
|
29
|
+
<dict>
|
30
|
+
<key>isExpanded</key>
|
31
|
+
<true/>
|
32
|
+
<key>subItems</key>
|
33
|
+
<dict/>
|
34
|
+
</dict>
|
35
|
+
</dict>
|
36
|
+
<key>windowFrame</key>
|
37
|
+
<string>{{0, 64}, {1680, 964}}</string>
|
38
|
+
</dict>
|
39
|
+
</plist>
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stencils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ryan Owens
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-24 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Lets you define an action and views once and reuse them for different models.
|
17
|
+
email: ryan@infoether.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- lib/stencils/stencil.rb
|
24
|
+
- lib/stencils/stencil_context.rb
|
25
|
+
- lib/stencils.rb
|
26
|
+
- README
|
27
|
+
files:
|
28
|
+
- lib/stencils/stencil.rb
|
29
|
+
- lib/stencils/stencil_context.rb
|
30
|
+
- lib/stencils.rb
|
31
|
+
- Rakefile
|
32
|
+
- README
|
33
|
+
- stencils.tmproj
|
34
|
+
- Manifest
|
35
|
+
- stencils.gemspec
|
36
|
+
has_rdoc: true
|
37
|
+
homepage: http://rubyforge.org/projects/stencils
|
38
|
+
licenses: []
|
39
|
+
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options:
|
42
|
+
- --line-numbers
|
43
|
+
- --inline-source
|
44
|
+
- --title
|
45
|
+
- Stencils
|
46
|
+
- --main
|
47
|
+
- README
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "1.2"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project: stencils
|
65
|
+
rubygems_version: 1.3.3
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Lets you define an action and views once and reuse them for different models.
|
69
|
+
test_files: []
|
70
|
+
|