wycats-merb-core 0.9.8 → 0.9.9
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.
- data/CHANGELOG +136 -2
- data/CONTRIBUTORS +6 -0
- data/PUBLIC_CHANGELOG +15 -0
- data/Rakefile +12 -14
- data/lib/merb-core.rb +82 -43
- data/lib/merb-core/bootloader.rb +268 -60
- data/lib/merb-core/config.rb +119 -34
- data/lib/merb-core/controller/abstract_controller.rb +58 -18
- data/lib/merb-core/controller/exceptions.rb +2 -15
- data/lib/merb-core/controller/merb_controller.rb +28 -1
- data/lib/merb-core/controller/mime.rb +4 -0
- data/lib/merb-core/controller/mixins/controller.rb +14 -17
- data/lib/merb-core/controller/mixins/render.rb +23 -28
- data/lib/merb-core/controller/mixins/responder.rb +0 -1
- data/lib/merb-core/controller/template.rb +44 -20
- data/lib/merb-core/core_ext/kernel.rb +8 -3
- data/lib/merb-core/dispatch/default_exception/default_exception.rb +1 -1
- data/lib/merb-core/dispatch/default_exception/views/_css.html.erb +3 -1
- data/lib/merb-core/dispatch/default_exception/views/_javascript.html.erb +71 -67
- data/lib/merb-core/dispatch/default_exception/views/index.html.erb +6 -2
- data/lib/merb-core/dispatch/dispatcher.rb +5 -9
- data/lib/merb-core/dispatch/request.rb +46 -57
- data/lib/merb-core/dispatch/router.rb +83 -6
- data/lib/merb-core/dispatch/router/behavior.rb +87 -27
- data/lib/merb-core/dispatch/router/resources.rb +281 -167
- data/lib/merb-core/dispatch/router/route.rb +141 -27
- data/lib/merb-core/logger.rb +213 -202
- data/lib/merb-core/rack.rb +3 -1
- data/lib/merb-core/rack/adapter.rb +7 -4
- data/lib/merb-core/rack/adapter/ebb.rb +12 -13
- data/lib/merb-core/rack/adapter/evented_mongrel.rb +2 -15
- data/lib/merb-core/rack/adapter/irb.rb +3 -2
- data/lib/merb-core/rack/adapter/mongrel.rb +22 -15
- data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +4 -16
- data/lib/merb-core/rack/adapter/thin.rb +21 -22
- data/lib/merb-core/rack/adapter/thin_turbo.rb +4 -11
- data/lib/merb-core/rack/adapter/webrick.rb +54 -18
- data/lib/merb-core/rack/handler/mongrel.rb +12 -13
- data/lib/merb-core/rack/middleware/csrf.rb +1 -1
- data/lib/merb-core/server.rb +135 -98
- data/lib/merb-core/tasks/gem_management.rb +50 -12
- data/lib/merb-core/tasks/merb.rb +1 -0
- data/lib/merb-core/tasks/merb_rake_helper.rb +9 -38
- data/lib/merb-core/tasks/stats.rake +2 -2
- data/lib/merb-core/test.rb +9 -3
- data/lib/merb-core/test/helpers.rb +1 -0
- data/lib/merb-core/test/helpers/multipart_request_helper.rb +3 -2
- data/lib/merb-core/test/helpers/request_helper.rb +40 -372
- data/lib/merb-core/test/helpers/route_helper.rb +15 -7
- data/lib/merb-core/test/matchers.rb +1 -0
- data/lib/merb-core/test/matchers/controller_matchers.rb +4 -247
- data/lib/merb-core/test/matchers/view_matchers.rb +22 -4
- data/lib/merb-core/test/run_specs.rb +117 -25
- data/lib/merb-core/version.rb +1 -1
- metadata +1 -1
- data/lib/merb-core/vendor/facets.rb +0 -2
- data/lib/merb-core/vendor/facets/dictionary.rb +0 -433
- data/lib/merb-core/vendor/facets/inflect.rb +0 -342
@@ -1,191 +1,305 @@
|
|
1
1
|
module Merb
|
2
2
|
class Router
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
3
|
+
|
4
|
+
module Resources
|
5
|
+
# Behavior#+resources+ is a route helper for defining a collection of
|
6
|
+
# RESTful resources. It yields to a block for child routes.
|
7
|
+
#
|
8
|
+
# ==== Parameters
|
9
|
+
# name<String, Symbol>:: The name of the resources
|
10
|
+
# options<Hash>::
|
11
|
+
# Ovverides and parameters to be associated with the route
|
12
|
+
#
|
13
|
+
# ==== Options (options)
|
14
|
+
# :namespace<~to_s>: The namespace for this route.
|
15
|
+
# :name_prefix<~to_s>:
|
16
|
+
# A prefix for the named routes. If a namespace is passed and there
|
17
|
+
# isn't a name prefix, the namespace will become the prefix.
|
18
|
+
# :controller<~to_s>: The controller for this route
|
19
|
+
# :collection<~to_s>: Special settings for the collections routes
|
20
|
+
# :member<Hash>:
|
21
|
+
# Special settings and resources related to a specific member of this
|
22
|
+
# resource.
|
23
|
+
# :identify<Symbol|Array>: The method(s) that should be called on the object
|
24
|
+
# before inserting it into an URL.
|
25
|
+
# :keys<Array>:
|
26
|
+
# A list of the keys to be used instead of :id with the resource in the order of the url.
|
27
|
+
# :singular<Symbol>
|
28
|
+
#
|
29
|
+
# ==== Block parameters
|
30
|
+
# next_level<Behavior>:: The child behavior.
|
31
|
+
#
|
32
|
+
# ==== Returns
|
33
|
+
# Array::
|
34
|
+
# Routes which will define the specified RESTful collection of resources
|
35
|
+
#
|
36
|
+
# ==== Examples
|
37
|
+
#
|
38
|
+
# r.resources :posts # will result in the typical RESTful CRUD
|
39
|
+
# # lists resources
|
40
|
+
# # GET /posts/?(\.:format)? :action => "index"
|
41
|
+
# # GET /posts/index(\.:format)? :action => "index"
|
42
|
+
#
|
43
|
+
# # shows new resource form
|
44
|
+
# # GET /posts/new :action => "new"
|
45
|
+
#
|
46
|
+
# # creates resource
|
47
|
+
# # POST /posts/?(\.:format)?, :action => "create"
|
48
|
+
#
|
49
|
+
# # shows resource
|
50
|
+
# # GET /posts/:id(\.:format)? :action => "show"
|
51
|
+
#
|
52
|
+
# # shows edit form
|
53
|
+
# # GET /posts/:id/edit :action => "edit"
|
54
|
+
#
|
55
|
+
# # updates resource
|
56
|
+
# # PUT /posts/:id(\.:format)? :action => "update"
|
57
|
+
#
|
58
|
+
# # shows deletion confirmation page
|
59
|
+
# # GET /posts/:id/delete :action => "delete"
|
60
|
+
#
|
61
|
+
# # destroys resources
|
62
|
+
# # DELETE /posts/:id(\.:format)? :action => "destroy"
|
63
|
+
#
|
64
|
+
# # Nesting resources
|
65
|
+
# r.resources :posts do |posts|
|
66
|
+
# posts.resources :comments
|
67
|
+
# end
|
68
|
+
#---
|
69
|
+
# @public
|
70
|
+
def resources(name, *args, &block)
|
71
|
+
name = name.to_s
|
72
|
+
options = extract_options_from_args!(args) || {}
|
73
|
+
singular = options[:singular] ? options[:singular].to_s : Extlib::Inflection.singularize(name)
|
74
|
+
klass_name = args.first ? args.first.to_s : Extlib::Inflection.classify(singular)
|
75
|
+
klass = Object.full_const_get(klass_name) rescue nil
|
76
|
+
keys = options.delete(:keys) || options.delete(:key)
|
77
|
+
params = { :controller => options.delete(:controller) || name }
|
78
|
+
collection = options.delete(:collection) || {}
|
79
|
+
member = { :edit => :get, :delete => :get }.merge(options.delete(:member) || {})
|
80
|
+
|
81
|
+
# Use the identifier for the class as a default
|
82
|
+
if klass
|
83
|
+
keys ||= options[:identify]
|
84
|
+
keys ||= @identifiers[klass]
|
85
|
+
elsif options[:identify]
|
86
|
+
raise Error, "The constant #{klass_name} does not exist, please specify the constant for this resource"
|
87
|
+
end
|
88
|
+
|
89
|
+
keys = [ keys || :id ].flatten
|
90
|
+
|
74
91
|
|
75
|
-
|
76
|
-
|
77
|
-
|
92
|
+
# Try pulling :namespace out of options for backwards compatibility
|
93
|
+
options[:name_prefix] ||= nil # Don't use a name_prefix if not needed
|
94
|
+
options[:resource_prefix] ||= nil # Don't use a resource_prefix if not needed
|
95
|
+
options[:controller_prefix] ||= options.delete(:namespace)
|
78
96
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
97
|
+
context = options[:identify]
|
98
|
+
context = klass && options[:identify] ? identify(klass => options.delete(:identify)) : self
|
99
|
+
context.namespace(name, options).to(params) do |resource|
|
100
|
+
root_keys = keys.map { |k| ":#{k}" }.join("/")
|
101
|
+
|
102
|
+
# => index
|
103
|
+
resource.match("(/index)(.:format)", :method => :get).to(:action => "index").
|
104
|
+
name(name).register_resource(name)
|
105
|
+
|
106
|
+
# => create
|
107
|
+
resource.match("(.:format)", :method => :post).to(:action => "create")
|
108
|
+
|
109
|
+
# => new
|
110
|
+
resource.match("/new(.:format)", :method => :get).to(:action => "new").
|
111
|
+
name("new", singular).register_resource(name, "new")
|
87
112
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
113
|
+
# => user defined collection routes
|
114
|
+
collection.each_pair do |action, method|
|
115
|
+
action = action.to_s
|
116
|
+
resource.match("/#{action}(.:format)", :method => method).to(:action => "#{action}").
|
117
|
+
name(action, name).register_resource(name, action)
|
118
|
+
end
|
92
119
|
|
93
|
-
|
94
|
-
|
120
|
+
# => show
|
121
|
+
resource.match("/#{root_keys}(.:format)", :method => :get).to(:action => "show").
|
122
|
+
name(singular).register_resource(klass_name)
|
95
123
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
124
|
+
# => user defined member routes
|
125
|
+
member.each_pair do |action, method|
|
126
|
+
action = action.to_s
|
127
|
+
resource.match("/#{root_keys}/#{action}(.:format)", :method => method).
|
128
|
+
to(:action => "#{action}").name(action, singular).register_resource(klass_name, action)
|
129
|
+
end
|
100
130
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
131
|
+
# => update
|
132
|
+
resource.match("/#{root_keys}(.:format)", :method => :put).
|
133
|
+
to(:action => "update")
|
134
|
+
|
135
|
+
# => destroy
|
136
|
+
resource.match("/#{root_keys}(.:format)", :method => :delete).
|
137
|
+
to(:action => "destroy")
|
105
138
|
|
106
|
-
|
107
|
-
|
108
|
-
|
139
|
+
if block_given?
|
140
|
+
nested_keys = keys.map do |k|
|
141
|
+
k.to_s == "id" ? ":#{singular}_id" : ":#{k}"
|
142
|
+
end.join("/")
|
143
|
+
|
144
|
+
# Procs for building the extra collection/member resource routes
|
145
|
+
placeholder = Router.resource_routes[ [@options[:resource_prefix], klass_name].flatten.compact ]
|
146
|
+
builders = {}
|
147
|
+
|
148
|
+
builders[:collection] = lambda do |action, to, method|
|
149
|
+
resource.before(placeholder).match("/#{action}(.:format)", :method => method).
|
150
|
+
to(:action => to).name(action, name).register_resource(name, action)
|
109
151
|
end
|
110
|
-
|
152
|
+
|
153
|
+
builders[:member] = lambda do |action, to, method|
|
154
|
+
resource.match("/#{root_keys}/#{action}(.:format)", :method => method).
|
155
|
+
to(:action => to).name(action, singular).register_resource(klass_name, action)
|
156
|
+
end
|
157
|
+
|
158
|
+
resource.options(:name_prefix => singular, :resource_prefix => klass_name).
|
159
|
+
match("/#{nested_keys}").resource_block(builders, &block)
|
111
160
|
end
|
112
|
-
end
|
161
|
+
end # namespace
|
162
|
+
end # resources
|
113
163
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
164
|
+
# Behavior#+resource+ is a route helper for defining a singular RESTful
|
165
|
+
# resource. It yields to a block for child routes.
|
166
|
+
#
|
167
|
+
# ==== Parameters
|
168
|
+
# name<String, Symbol>:: The name of the resource.
|
169
|
+
# options<Hash>::
|
170
|
+
# Overides and parameters to be associated with the route.
|
171
|
+
#
|
172
|
+
# ==== Options (options)
|
173
|
+
# :namespace<~to_s>: The namespace for this route.
|
174
|
+
# :name_prefix<~to_s>:
|
175
|
+
# A prefix for the named routes. If a namespace is passed and there
|
176
|
+
# isn't a name prefix, the namespace will become the prefix.
|
177
|
+
# :controller<~to_s>: The controller for this route
|
178
|
+
#
|
179
|
+
# ==== Block parameters
|
180
|
+
# next_level<Behavior>:: The child behavior.
|
181
|
+
#
|
182
|
+
# ==== Returns
|
183
|
+
# Array:: Routes which define a RESTful single resource.
|
184
|
+
#
|
185
|
+
# ==== Examples
|
186
|
+
#
|
187
|
+
# r.resource :account # will result in the typical RESTful CRUD
|
188
|
+
# # shows new resource form
|
189
|
+
# # GET /account/new :action => "new"
|
190
|
+
#
|
191
|
+
# # creates resource
|
192
|
+
# # POST /account/?(\.:format)?, :action => "create"
|
193
|
+
#
|
194
|
+
# # shows resource
|
195
|
+
# # GET /account/(\.:format)? :action => "show"
|
196
|
+
#
|
197
|
+
# # shows edit form
|
198
|
+
# # GET /account//edit :action => "edit"
|
199
|
+
#
|
200
|
+
# # updates resource
|
201
|
+
# # PUT /account/(\.:format)? :action => "update"
|
202
|
+
#
|
203
|
+
# # shows deletion confirmation page
|
204
|
+
# # GET /account//delete :action => "delete"
|
205
|
+
#
|
206
|
+
# # destroys resources
|
207
|
+
# # DELETE /account/(\.:format)? :action => "destroy"
|
208
|
+
#
|
209
|
+
# You can optionally pass :namespace and :controller to refine the routing
|
210
|
+
# or pass a block to nest resources.
|
211
|
+
#
|
212
|
+
# r.resource :account, :namespace => "admin" do |account|
|
213
|
+
# account.resources :preferences, :controller => "settings"
|
214
|
+
# end
|
215
|
+
# ---
|
216
|
+
# @public
|
217
|
+
def resource(name, *args, &block)
|
218
|
+
name = name.to_s
|
219
|
+
options = extract_options_from_args!(args) || {}
|
220
|
+
params = { :controller => options.delete(:controller) || name.pluralize }
|
221
|
+
member = { :new => :get, :edit => :get, :delete => :get }.merge(options.delete(:member) || {})
|
169
222
|
|
170
|
-
|
171
|
-
|
223
|
+
options[:name_prefix] ||= nil # Don't use a name_prefix if not needed
|
224
|
+
options[:resource_prefix] ||= nil # Don't use a resource_prefix if not needed
|
225
|
+
options[:controller_prefix] ||= options.delete(:namespace)
|
172
226
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
227
|
+
self.namespace(name, options).to(params) do |resource|
|
228
|
+
# => show
|
229
|
+
resource.match("(.:format)", :method => :get).to(:action => "show").
|
230
|
+
name(name).register_resource(name)
|
231
|
+
|
232
|
+
# => create
|
233
|
+
resource.match("(.:format)", :method => :post).to(:action => "create")
|
234
|
+
|
235
|
+
# => update
|
236
|
+
resource.match("(.:format)", :method => :put).to(:action => "update")
|
237
|
+
|
238
|
+
# => destroy
|
239
|
+
resource.match("(.:format)", :method => :delete).to(:action => "destroy")
|
240
|
+
|
241
|
+
member.each_pair do |action, method|
|
242
|
+
action = action.to_s
|
243
|
+
resource.match("/#{action}(.:format)", :method => method).to(:action => action).
|
244
|
+
name(action, name).register_resource(name, action)
|
245
|
+
end
|
181
246
|
|
182
|
-
|
247
|
+
if block_given?
|
248
|
+
builders = {}
|
249
|
+
|
250
|
+
builders[:member] = lambda do |action, to, method|
|
251
|
+
resource.match("/#{action}(.:format)", :method => method).to(:action => to).
|
252
|
+
name(action, name).register_resource(name, action)
|
253
|
+
end
|
254
|
+
|
255
|
+
resource.options(:name_prefix => name, :resource_prefix => name).
|
256
|
+
resource_block(builders, &block)
|
183
257
|
end
|
184
258
|
end
|
259
|
+
end
|
260
|
+
|
261
|
+
protected
|
262
|
+
|
263
|
+
def register_resource(*key)
|
264
|
+
key = [@options[:resource_prefix], key].flatten.compact
|
265
|
+
@route.resource = key
|
266
|
+
self
|
267
|
+
end
|
185
268
|
|
269
|
+
def resource_block(builders, &block)
|
270
|
+
behavior = ResourceBehavior.new(builders, @proxy, @conditions, @params, @defaults, @identifiers, @options, @blocks)
|
271
|
+
with_behavior_context(behavior, &block)
|
186
272
|
end
|
187
273
|
|
274
|
+
end # Resources
|
275
|
+
|
276
|
+
class Behavior
|
188
277
|
include Resources
|
189
278
|
end
|
279
|
+
|
280
|
+
# Adding the collection and member methods to behavior
|
281
|
+
class ResourceBehavior < Behavior #:nodoc:
|
282
|
+
|
283
|
+
def initialize(builders, *args)
|
284
|
+
super(*args)
|
285
|
+
@collection = builders[:collection]
|
286
|
+
@member = builders[:member]
|
287
|
+
end
|
288
|
+
|
289
|
+
def collection(action, options = {})
|
290
|
+
action = action.to_s
|
291
|
+
method = options[:method]
|
292
|
+
to = options[:to] || action
|
293
|
+
@collection[action, to, method]
|
294
|
+
end
|
295
|
+
|
296
|
+
def member(action, options = {})
|
297
|
+
action = action.to_s
|
298
|
+
method = options[:method]
|
299
|
+
to = options[:to] || action
|
300
|
+
@member[action, to, method]
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
190
304
|
end
|
191
305
|
end
|