merb-core 1.0.4 → 1.0.5

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/Rakefile CHANGED
@@ -66,7 +66,7 @@ spec = Gem::Specification.new do |s|
66
66
  s.add_dependency "rspec"
67
67
  s.add_dependency "rack"
68
68
  s.add_dependency "mime-types"
69
- s.add_dependency "thor", ">= 0.9.7"
69
+ s.add_dependency "thor", ">= 0.9.9"
70
70
  # this escalates to "regular" dependencies, comment it out
71
71
  # for now. RubyGems need some love.
72
72
  #s.add_development_dependency "libxml-ruby"
@@ -1,31 +1,30 @@
1
+ require 'merb-core/core_ext'
2
+ require "merb-core/controller/exceptions"
3
+ require "merb-core/controller/mixins/responder"
4
+ require "merb-core/controller/mixins/render"
5
+ require "merb-core/controller/mixins/authentication"
6
+ require "merb-core/controller/mixins/conditional_get"
7
+ require "merb-core/controller/mixins/controller"
8
+ require "merb-core/controller/abstract_controller"
9
+ require "merb-core/controller/template"
10
+ require "merb-core/controller/merb_controller"
11
+ require "merb-core/bootloader"
12
+ require "merb-core/config"
13
+ require "merb-core/constants"
14
+ require "merb-core/dispatch/dispatcher"
15
+ require "merb-core/plugins"
16
+ require "merb-core/rack"
17
+ require "merb-core/dispatch/request"
18
+ require "merb-core/dispatch/request_parsers.rb"
19
+ require "merb-core/dispatch/router"
20
+ require "merb-core/dispatch/worker"
21
+
1
22
  module Merb
2
- autoload :AbstractController, "merb-core/controller/abstract_controller"
3
- autoload :BootLoader, "merb-core/bootloader"
4
- autoload :Config, "merb-core/config"
5
- autoload :Const, "merb-core/constants"
6
- autoload :ConditionalGetMixin, "merb-core/controller/mixins/conditional_get"
7
- autoload :ControllerMixin, "merb-core/controller/mixins/controller"
8
- autoload :ControllerExceptions, "merb-core/controller/exceptions"
9
- autoload :Dispatcher, "merb-core/dispatch/dispatcher"
10
- autoload :AuthenticationMixin, "merb-core/controller/mixins/authentication"
11
- autoload :BasicAuthenticationMixin, "merb-core/controller/mixins/authentication/basic"
12
- autoload :ErubisCaptureMixin, "merb-core/controller/mixins/erubis_capture"
13
- autoload :Plugins, "merb-core/plugins"
14
- autoload :Rack, "merb-core/rack"
15
- autoload :RenderMixin, "merb-core/controller/mixins/render"
16
- autoload :Request, "merb-core/dispatch/request"
17
- autoload :Parse, "merb-core/dispatch/request_parsers.rb"
18
- autoload :ResponderMixin, "merb-core/controller/mixins/responder"
19
- autoload :Router, "merb-core/dispatch/router"
20
- autoload :Test, "merb-core/test"
21
- autoload :Worker, "merb-core/dispatch/worker"
23
+ autoload :Test, "merb-core/test"
22
24
  end
23
25
 
24
26
  # Require this rather than autoloading it so we can be sure the default template
25
27
  # gets registered
26
- require 'merb-core/core_ext'
27
- require "merb-core/controller/template"
28
- require "merb-core/controller/merb_controller"
29
28
 
30
29
  module Merb
31
30
  module InlineTemplates; end
@@ -92,622 +92,627 @@
92
92
  # <code>params[:action]</code> and <code>params[:controller]</code> have been deprecated as of
93
93
  # the 0.9.0 release. They are no longer set during dispatch, and
94
94
  # have been replaced by <code>action_name</code> and <code>controller_name</code> respectively.
95
- class Merb::AbstractController
96
- include Merb::RenderMixin
97
- include Merb::InlineTemplates
98
-
99
- class_inheritable_accessor :_layout, :_template_root, :template_roots
100
- class_inheritable_accessor :_before_filters, :_after_filters
101
- class_inheritable_accessor :_before_dispatch_callbacks, :_after_dispatch_callbacks
102
-
103
- cattr_accessor :_abstract_subclasses
104
-
105
- # :api: plugin
106
- attr_accessor :body, :action_name, :_benchmarks
107
- # :api: private
108
- attr_accessor :_thrown_content
109
-
110
- # Stub so content-type support in RenderMixin doesn't throw errors
111
- # :api: private
112
- attr_accessor :content_type
113
-
114
- FILTER_OPTIONS = [:only, :exclude, :if, :unless, :with]
115
-
116
- self._before_filters, self._after_filters = [], []
117
- self._before_dispatch_callbacks, self._after_dispatch_callbacks = [], []
118
-
119
- #---
120
- # We're using abstract_subclasses so that Merb::Controller can have its
121
- # own subclasses. We're using a Set so we don't have to worry about
122
- # uniqueness.
123
- self._abstract_subclasses = Set.new
124
-
125
- # ==== Returns
126
- # String:: The controller name in path form, e.g. "admin/items".
127
- # :api: public
128
- def self.controller_name() @controller_name ||= self.name.to_const_path end
129
-
130
- # ==== Returns
131
- # String:: The controller name in path form, e.g. "admin/items".
132
- #
133
- # :api: public
134
- def controller_name() self.class.controller_name end
95
+
96
+ module Merb
97
+ module InlineTemplates; end
135
98
 
136
- # This is called after the controller is instantiated to figure out where to
137
- # look for templates under the _template_root. Override this to define a new
138
- # structure for your app.
139
- #
140
- # ==== Parameters
141
- # context<~to_s>:: The controller context (the action or template name).
142
- # type<~to_s>:: The content type. Could be nil.
143
- # controller<~to_s>::
144
- # The name of the controller. Defaults to being called with the controller_name. Set t
145
- #
146
- #
147
- # ==== Returns
148
- # String::
149
- # Indicating where to look for the template for the current controller,
150
- # context, and content-type.
151
- #
152
- # ==== Notes
153
- # The type is irrelevant for controller-types that don't support
154
- # content-type negotiation, so we default to not include it in the
155
- # superclass.
156
- #
157
- # ==== Examples
158
- # def _template_location
159
- # "#{params[:controller]}.#{params[:action]}.#{content_type}"
160
- # end
161
- #
162
- # This would look for templates at controller.action.mime.type instead
163
- # of controller/action.mime.type
164
- #
165
- # :api: public
166
- # @overridable
167
- def _template_location(context, type, controller)
168
- controller ? "#{controller}/#{context}" : context
169
- end
99
+ class AbstractController
100
+ include Merb::RenderMixin
101
+ include Merb::InlineTemplates
170
102
 
171
- # The location to look for a template - override this method for particular behaviour.
172
- #
173
- # ==== Parameters
174
- # template<String>:: The absolute path to a template - without template extension.
175
- # type<~to_s>::
176
- # The mime-type of the template that will be rendered. Defaults to being called with nil.
177
- #
178
- # :api: public
179
- # @overridable
180
- def _absolute_template_location(template, type)
181
- template
182
- end
103
+ class_inheritable_accessor :_layout, :_template_root, :template_roots
104
+ class_inheritable_accessor :_before_filters, :_after_filters
105
+ class_inheritable_accessor :_before_dispatch_callbacks, :_after_dispatch_callbacks
183
106
 
184
- # Resets the template roots to the template root passed in.
185
- #
186
- # ==== Parameters
187
- # root<~to_s>::
188
- # The new path to set the template root to.
189
- #
190
- # :api: public
191
- def self._template_root=(root)
192
- @_template_root = root
193
- _reset_template_roots
194
- end
107
+ cattr_accessor :_abstract_subclasses
195
108
 
196
- # Reset the template root based on the @_template_root ivar.
197
- #
198
- # :api: private
199
- def self._reset_template_roots
200
- self.template_roots = [[self._template_root, :_template_location]]
201
- end
109
+ # :api: plugin
110
+ attr_accessor :body, :action_name, :_benchmarks
111
+ # :api: private
112
+ attr_accessor :_thrown_content
202
113
 
203
- # ==== Returns
204
- # roots<Array[Array]>::
205
- # Template roots as pairs of template root path and template location
206
- # method.
207
- #
208
- # :api: plugin
209
- def self._template_roots
210
- self.template_roots || _reset_template_roots
211
- end
114
+ # Stub so content-type support in RenderMixin doesn't throw errors
115
+ # :api: private
116
+ attr_accessor :content_type
212
117
 
213
- # ==== Parameters
214
- # roots<Array[Array]>::
215
- # Template roots as pairs of template root path and template location
216
- # method.
217
- #
218
- # :api: plugin
219
- def self._template_roots=(roots)
220
- self.template_roots = roots
221
- end
118
+ FILTER_OPTIONS = [:only, :exclude, :if, :unless, :with]
119
+
120
+ self._before_filters, self._after_filters = [], []
121
+ self._before_dispatch_callbacks, self._after_dispatch_callbacks = [], []
122
+
123
+ #---
124
+ # We're using abstract_subclasses so that Merb::Controller can have its
125
+ # own subclasses. We're using a Set so we don't have to worry about
126
+ # uniqueness.
127
+ self._abstract_subclasses = Set.new
128
+
129
+ # ==== Returns
130
+ # String:: The controller name in path form, e.g. "admin/items".
131
+ # :api: public
132
+ def self.controller_name() @controller_name ||= self.name.to_const_path end
133
+
134
+ # ==== Returns
135
+ # String:: The controller name in path form, e.g. "admin/items".
136
+ #
137
+ # :api: public
138
+ def controller_name() self.class.controller_name end
222
139
 
223
- # Returns the list of classes that have specifically subclassed AbstractController.
224
- # Does not include all decendents.
225
- #
226
- # ==== Returns
227
- # Set:: The subclasses.
228
- #
229
- # :api: private
230
- def self.subclasses_list() _abstract_subclasses end
140
+ # This is called after the controller is instantiated to figure out where to
141
+ # look for templates under the _template_root. Override this to define a new
142
+ # structure for your app.
143
+ #
144
+ # ==== Parameters
145
+ # context<~to_s>:: The controller context (the action or template name).
146
+ # type<~to_s>:: The content type. Could be nil.
147
+ # controller<~to_s>::
148
+ # The name of the controller. Defaults to being called with the controller_name. Set t
149
+ #
150
+ #
151
+ # ==== Returns
152
+ # String::
153
+ # Indicating where to look for the template for the current controller,
154
+ # context, and content-type.
155
+ #
156
+ # ==== Notes
157
+ # The type is irrelevant for controller-types that don't support
158
+ # content-type negotiation, so we default to not include it in the
159
+ # superclass.
160
+ #
161
+ # ==== Examples
162
+ # def _template_location
163
+ # "#{params[:controller]}.#{params[:action]}.#{content_type}"
164
+ # end
165
+ #
166
+ # This would look for templates at controller.action.mime.type instead
167
+ # of controller/action.mime.type
168
+ #
169
+ # :api: public
170
+ # @overridable
171
+ def _template_location(context, type, controller)
172
+ controller ? "#{controller}/#{context}" : context
173
+ end
174
+
175
+ # The location to look for a template - override this method for particular behaviour.
176
+ #
177
+ # ==== Parameters
178
+ # template<String>:: The absolute path to a template - without template extension.
179
+ # type<~to_s>::
180
+ # The mime-type of the template that will be rendered. Defaults to being called with nil.
181
+ #
182
+ # :api: public
183
+ # @overridable
184
+ def _absolute_template_location(template, type)
185
+ template
186
+ end
187
+
188
+ # Resets the template roots to the template root passed in.
189
+ #
190
+ # ==== Parameters
191
+ # root<~to_s>::
192
+ # The new path to set the template root to.
193
+ #
194
+ # :api: public
195
+ def self._template_root=(root)
196
+ @_template_root = root
197
+ _reset_template_roots
198
+ end
199
+
200
+ # Reset the template root based on the @_template_root ivar.
201
+ #
202
+ # :api: private
203
+ def self._reset_template_roots
204
+ self.template_roots = [[self._template_root, :_template_location]]
205
+ end
206
+
207
+ # ==== Returns
208
+ # roots<Array[Array]>::
209
+ # Template roots as pairs of template root path and template location
210
+ # method.
211
+ #
212
+ # :api: plugin
213
+ def self._template_roots
214
+ self.template_roots || _reset_template_roots
215
+ end
216
+
217
+ # ==== Parameters
218
+ # roots<Array[Array]>::
219
+ # Template roots as pairs of template root path and template location
220
+ # method.
221
+ #
222
+ # :api: plugin
223
+ def self._template_roots=(roots)
224
+ self.template_roots = roots
225
+ end
231
226
 
232
- # ==== Parameters
233
- # klass<Merb::AbstractController>::
234
- # The controller that is being inherited from Merb::AbstractController
235
- #
236
- # :api: private
237
- def self.inherited(klass)
238
- _abstract_subclasses << klass.to_s
239
- helper_module_name = klass.to_s =~ /^(#|Merb::)/ ? "#{klass}Helper" : "Merb::#{klass}Helper"
240
- Object.make_module helper_module_name
241
- klass.class_eval <<-HERE
242
- include Object.full_const_get("#{helper_module_name}") rescue nil
243
- HERE
244
- super
245
- end
227
+ # Returns the list of classes that have specifically subclassed AbstractController.
228
+ # Does not include all decendents.
229
+ #
230
+ # ==== Returns
231
+ # Set:: The subclasses.
232
+ #
233
+ # :api: private
234
+ def self.subclasses_list() _abstract_subclasses end
246
235
 
247
- # This will initialize the controller, it is designed to be overridden in subclasses (like MerbController)
248
- # ==== Parameters
249
- # *args:: The args are ignored in this class, but we need this so that subclassed initializes can have parameters
250
- #
251
- # :api: private
252
- def initialize(*args)
253
- @_benchmarks = {}
254
- @_caught_content = {}
255
- end
236
+ # ==== Parameters
237
+ # klass<Merb::AbstractController>::
238
+ # The controller that is being inherited from Merb::AbstractController
239
+ #
240
+ # :api: private
241
+ def self.inherited(klass)
242
+ _abstract_subclasses << klass.to_s
243
+ helper_module_name = klass.to_s =~ /^(#|Merb::)/ ? "#{klass}Helper" : "Merb::#{klass}Helper"
244
+ Object.make_module helper_module_name
245
+ klass.class_eval <<-HERE
246
+ include Object.full_const_get("#{helper_module_name}") rescue nil
247
+ HERE
248
+ super
249
+ end
256
250
 
257
- # This will dispatch the request, calling internal before/after dispatch callbacks.
258
- # If the return value of _call_filters is not :filter_chain_completed the action is not called, and the return from the filters is used instead.
259
- #
260
- # ==== Parameters
261
- # action<~to_s>::
262
- # The action to dispatch to. This will be #send'ed in _call_action.
263
- # Defaults to :to_s.
264
- #
265
- # ==== Returns
266
- # <~to_s>::
267
- # Returns the string that was returned from the action.
268
- #
269
- # ==== Raises
270
- # ArgumentError:: Invalid result caught from before filters.
271
- #
272
- # :api: plugin
273
- def _dispatch(action)
274
- self.action_name = action
275
- self._before_dispatch_callbacks.each { |cb| cb.call(self) }
276
-
277
- caught = catch(:halt) do
278
- start = Time.now
279
- result = _call_filters(_before_filters)
280
- @_benchmarks[:before_filters_time] = Time.now - start if _before_filters
281
- result
251
+ # This will initialize the controller, it is designed to be overridden in subclasses (like MerbController)
252
+ # ==== Parameters
253
+ # *args:: The args are ignored in this class, but we need this so that subclassed initializes can have parameters
254
+ #
255
+ # :api: private
256
+ def initialize(*args)
257
+ @_benchmarks = {}
258
+ @_caught_content = {}
282
259
  end
283
260
 
284
- @body = case caught
285
- when :filter_chain_completed then _call_action(action_name)
286
- when String then caught
287
- # return *something* if you throw halt with nothing
288
- when nil then "<html><body><h1>Filter Chain Halted!</h1></body></html>"
289
- when Symbol then __send__(caught)
290
- when Proc then self.instance_eval(&caught)
291
- else
292
- raise ArgumentError, "Threw :halt, #{caught}. Expected String, nil, Symbol, Proc."
293
- end
294
- start = Time.now
295
- _call_filters(_after_filters)
296
- @_benchmarks[:after_filters_time] = Time.now - start if _after_filters
261
+ # This will dispatch the request, calling internal before/after dispatch callbacks.
262
+ # If the return value of _call_filters is not :filter_chain_completed the action is not called, and the return from the filters is used instead.
263
+ #
264
+ # ==== Parameters
265
+ # action<~to_s>::
266
+ # The action to dispatch to. This will be #send'ed in _call_action.
267
+ # Defaults to :to_s.
268
+ #
269
+ # ==== Returns
270
+ # <~to_s>::
271
+ # Returns the string that was returned from the action.
272
+ #
273
+ # ==== Raises
274
+ # ArgumentError:: Invalid result caught from before filters.
275
+ #
276
+ # :api: plugin
277
+ def _dispatch(action)
278
+ self.action_name = action
279
+ self._before_dispatch_callbacks.each { |cb| cb.call(self) }
280
+
281
+ caught = catch(:halt) do
282
+ start = Time.now
283
+ result = _call_filters(_before_filters)
284
+ @_benchmarks[:before_filters_time] = Time.now - start if _before_filters
285
+ result
286
+ end
287
+
288
+ @body = case caught
289
+ when :filter_chain_completed then _call_action(action_name)
290
+ when String then caught
291
+ # return *something* if you throw halt with nothing
292
+ when nil then "<html><body><h1>Filter Chain Halted!</h1></body></html>"
293
+ when Symbol then __send__(caught)
294
+ when Proc then self.instance_eval(&caught)
295
+ else
296
+ raise ArgumentError, "Threw :halt, #{caught}. Expected String, nil, Symbol, Proc."
297
+ end
298
+ start = Time.now
299
+ _call_filters(_after_filters)
300
+ @_benchmarks[:after_filters_time] = Time.now - start if _after_filters
297
301
 
298
- self._after_dispatch_callbacks.each { |cb| cb.call(self) }
302
+ self._after_dispatch_callbacks.each { |cb| cb.call(self) }
299
303
 
300
- @body
301
- end
304
+ @body
305
+ end
302
306
 
303
- # This method exists to provide an overridable hook for ActionArgs. It uses #send to call the action method.
304
- #
305
- # ==== Parameters
306
- # action<~to_s>:: the action method to dispatch to
307
- #
308
- # :api: plugin
309
- # @overridable
310
- def _call_action(action)
311
- send(action)
312
- end
307
+ # This method exists to provide an overridable hook for ActionArgs. It uses #send to call the action method.
308
+ #
309
+ # ==== Parameters
310
+ # action<~to_s>:: the action method to dispatch to
311
+ #
312
+ # :api: plugin
313
+ # @overridable
314
+ def _call_action(action)
315
+ send(action)
316
+ end
313
317
 
314
- # Calls a filter chain.
315
- #
316
- # ==== Parameters
317
- # filter_set<Array[Filter]>::
318
- # A set of filters in the form [[:filter, rule], [:filter, rule]]
319
- #
320
- # ==== Returns
321
- # Symbol:: :filter_chain_completed.
322
- #
323
- # ==== Notes
324
- # Filter rules can be Symbols, Strings, or Procs.
325
- #
326
- # Symbols or Strings::
327
- # Call the method represented by the +Symbol+ or +String+.
328
- # Procs::
329
- # Execute the +Proc+, in the context of the controller (self will be the
330
- # controller)
331
- #
332
- # :api: private
333
- def _call_filters(filter_set)
334
- (filter_set || []).each do |filter, rule|
335
- if _call_filter_for_action?(rule, action_name) && _filter_condition_met?(rule)
336
- case filter
337
- when Symbol, String
338
- if rule.key?(:with)
339
- args = rule[:with]
340
- send(filter, *args)
341
- else
342
- send(filter)
318
+ # Calls a filter chain.
319
+ #
320
+ # ==== Parameters
321
+ # filter_set<Array[Filter]>::
322
+ # A set of filters in the form [[:filter, rule], [:filter, rule]]
323
+ #
324
+ # ==== Returns
325
+ # Symbol:: :filter_chain_completed.
326
+ #
327
+ # ==== Notes
328
+ # Filter rules can be Symbols, Strings, or Procs.
329
+ #
330
+ # Symbols or Strings::
331
+ # Call the method represented by the +Symbol+ or +String+.
332
+ # Procs::
333
+ # Execute the +Proc+, in the context of the controller (self will be the
334
+ # controller)
335
+ #
336
+ # :api: private
337
+ def _call_filters(filter_set)
338
+ (filter_set || []).each do |filter, rule|
339
+ if _call_filter_for_action?(rule, action_name) && _filter_condition_met?(rule)
340
+ case filter
341
+ when Symbol, String
342
+ if rule.key?(:with)
343
+ args = rule[:with]
344
+ send(filter, *args)
345
+ else
346
+ send(filter)
347
+ end
348
+ when Proc then self.instance_eval(&filter)
343
349
  end
344
- when Proc then self.instance_eval(&filter)
345
350
  end
346
351
  end
352
+ return :filter_chain_completed
347
353
  end
348
- return :filter_chain_completed
349
- end
350
354
 
351
- # Determine whether the filter should be called for the current action using :only and :exclude.
352
- #
353
- # ==== Parameters
354
- # rule<Hash>:: Rules for the filter (see below).
355
- # action_name<~to_s>:: The name of the action to be called.
356
- #
357
- # ==== Options (rule)
358
- # :only<Array>::
359
- # Optional list of actions to fire. If given, action_name must be a part of
360
- # it for this function to return true.
361
- # :exclude<Array>::
362
- # Optional list of actions not to fire. If given, action_name must not be a
363
- # part of it for this function to return true.
364
- #
365
- # ==== Returns
366
- # Boolean:: True if the action should be called.
367
- #
368
- # :api: private
369
- def _call_filter_for_action?(rule, action_name)
370
- # Both:
371
- # * no :only or the current action is in the :only list
372
- # * no :exclude or the current action is not in the :exclude list
373
- (!rule.key?(:only) || rule[:only].include?(action_name)) &&
374
- (!rule.key?(:exclude) || !rule[:exclude].include?(action_name))
375
- end
355
+ # Determine whether the filter should be called for the current action using :only and :exclude.
356
+ #
357
+ # ==== Parameters
358
+ # rule<Hash>:: Rules for the filter (see below).
359
+ # action_name<~to_s>:: The name of the action to be called.
360
+ #
361
+ # ==== Options (rule)
362
+ # :only<Array>::
363
+ # Optional list of actions to fire. If given, action_name must be a part of
364
+ # it for this function to return true.
365
+ # :exclude<Array>::
366
+ # Optional list of actions not to fire. If given, action_name must not be a
367
+ # part of it for this function to return true.
368
+ #
369
+ # ==== Returns
370
+ # Boolean:: True if the action should be called.
371
+ #
372
+ # :api: private
373
+ def _call_filter_for_action?(rule, action_name)
374
+ # Both:
375
+ # * no :only or the current action is in the :only list
376
+ # * no :exclude or the current action is not in the :exclude list
377
+ (!rule.key?(:only) || rule[:only].include?(action_name)) &&
378
+ (!rule.key?(:exclude) || !rule[:exclude].include?(action_name))
379
+ end
376
380
 
377
- # Determines whether the filter should be run based on the conditions passed (:if and :unless)
378
- #
379
- # ==== Parameters
380
- # rule<Hash>:: Rules for the filter (see below).
381
- #
382
- # ==== Options (rule)
383
- # :if<Array>:: Optional conditions that must be met for the filter to fire.
384
- # :unless<Array>::
385
- # Optional conditions that must not be met for the filter to fire.
386
- #
387
- # ==== Returns
388
- # Boolean:: True if the conditions are met.
389
- #
390
- # :api: private
391
- def _filter_condition_met?(rule)
392
- # Both:
393
- # * no :if or the if condition evaluates to true
394
- # * no :unless or the unless condition evaluates to false
395
- (!rule.key?(:if) || _evaluate_condition(rule[:if])) &&
396
- (!rule.key?(:unless) || ! _evaluate_condition(rule[:unless]))
397
- end
381
+ # Determines whether the filter should be run based on the conditions passed (:if and :unless)
382
+ #
383
+ # ==== Parameters
384
+ # rule<Hash>:: Rules for the filter (see below).
385
+ #
386
+ # ==== Options (rule)
387
+ # :if<Array>:: Optional conditions that must be met for the filter to fire.
388
+ # :unless<Array>::
389
+ # Optional conditions that must not be met for the filter to fire.
390
+ #
391
+ # ==== Returns
392
+ # Boolean:: True if the conditions are met.
393
+ #
394
+ # :api: private
395
+ def _filter_condition_met?(rule)
396
+ # Both:
397
+ # * no :if or the if condition evaluates to true
398
+ # * no :unless or the unless condition evaluates to false
399
+ (!rule.key?(:if) || _evaluate_condition(rule[:if])) &&
400
+ (!rule.key?(:unless) || ! _evaluate_condition(rule[:unless]))
401
+ end
398
402
 
399
- # Evaluates a filter condition (:if or :unless)
400
- #
401
- # ==== Parameters
402
- # condition<Symbol, Proc>:: The condition to evaluate.
403
- #
404
- # ==== Raises
405
- # ArgumentError:: condition not a Symbol or Proc.
406
- #
407
- # ==== Returns
408
- # Boolean:: True if the condition is met.
409
- #
410
- # ==== Alternatives
411
- # If condition is a symbol, it will be send'ed. If it is a Proc it will be
412
- # called directly with self as an argument.
413
- #
414
- # :api: private
415
- def _evaluate_condition(condition)
416
- case condition
417
- when Symbol then self.send(condition)
418
- when Proc then self.instance_eval(&condition)
419
- else
420
- raise ArgumentError,
421
- 'Filter condtions need to be either a Symbol or a Proc'
403
+ # Evaluates a filter condition (:if or :unless)
404
+ #
405
+ # ==== Parameters
406
+ # condition<Symbol, Proc>:: The condition to evaluate.
407
+ #
408
+ # ==== Raises
409
+ # ArgumentError:: condition not a Symbol or Proc.
410
+ #
411
+ # ==== Returns
412
+ # Boolean:: True if the condition is met.
413
+ #
414
+ # ==== Alternatives
415
+ # If condition is a symbol, it will be send'ed. If it is a Proc it will be
416
+ # called directly with self as an argument.
417
+ #
418
+ # :api: private
419
+ def _evaluate_condition(condition)
420
+ case condition
421
+ when Symbol then self.send(condition)
422
+ when Proc then self.instance_eval(&condition)
423
+ else
424
+ raise ArgumentError,
425
+ 'Filter condtions need to be either a Symbol or a Proc'
426
+ end
422
427
  end
423
- end
424
428
 
425
- # Adds a filter to the after filter chain
426
- # ==== Parameters
427
- # filter<Symbol, Proc>:: The filter to add. Defaults to nil.
428
- # opts<Hash>::
429
- # Filter options (see class documentation under <tt>Filter Options</tt>).
430
- # &block:: A block to use as a filter if filter is nil.
431
- #
432
- # ==== Notes
433
- # If the filter already exists, its options will be replaced with opts.;
434
- #
435
- # :api: public
436
- def self.after(filter = nil, opts = {}, &block)
437
- add_filter(self._after_filters, filter || block, opts)
438
- end
429
+ # Adds a filter to the after filter chain
430
+ # ==== Parameters
431
+ # filter<Symbol, Proc>:: The filter to add. Defaults to nil.
432
+ # opts<Hash>::
433
+ # Filter options (see class documentation under <tt>Filter Options</tt>).
434
+ # &block:: A block to use as a filter if filter is nil.
435
+ #
436
+ # ==== Notes
437
+ # If the filter already exists, its options will be replaced with opts.;
438
+ #
439
+ # :api: public
440
+ def self.after(filter = nil, opts = {}, &block)
441
+ add_filter(self._after_filters, filter || block, opts)
442
+ end
439
443
 
440
- # Adds a filter to the before filter chain.
441
- #
442
- # ==== Parameters
443
- # filter<Symbol, Proc>:: The filter to add. Defaults to nil.
444
- # opts<Hash>::
445
- # Filter options (see class documentation under <tt>Filter Options</tt>).
446
- # &block:: A block to use as a filter if filter is nil.
447
- #
448
- # ==== Notes
449
- # If the filter already exists, its options will be replaced with opts.
450
- #
451
- # :api: public
452
- def self.before(filter = nil, opts = {}, &block)
453
- add_filter(self._before_filters, filter || block, opts)
454
- end
444
+ # Adds a filter to the before filter chain.
445
+ #
446
+ # ==== Parameters
447
+ # filter<Symbol, Proc>:: The filter to add. Defaults to nil.
448
+ # opts<Hash>::
449
+ # Filter options (see class documentation under <tt>Filter Options</tt>).
450
+ # &block:: A block to use as a filter if filter is nil.
451
+ #
452
+ # ==== Notes
453
+ # If the filter already exists, its options will be replaced with opts.
454
+ #
455
+ # :api: public
456
+ def self.before(filter = nil, opts = {}, &block)
457
+ add_filter(self._before_filters, filter || block, opts)
458
+ end
455
459
 
456
- # Removes a filter from the after filter chain. This removes the
457
- # filter from the filter chain for the whole controller and does not
458
- # take any options.
459
- #
460
- # ==== Parameters
461
- # filter<Symbol, String>:: A filter name to skip.
462
- #
463
- # :api: public
464
- def self.skip_after(filter)
465
- skip_filter(self._after_filters, filter)
466
- end
460
+ # Removes a filter from the after filter chain. This removes the
461
+ # filter from the filter chain for the whole controller and does not
462
+ # take any options.
463
+ #
464
+ # ==== Parameters
465
+ # filter<Symbol, String>:: A filter name to skip.
466
+ #
467
+ # :api: public
468
+ def self.skip_after(filter)
469
+ skip_filter(self._after_filters, filter)
470
+ end
467
471
 
468
- # Removes a filter from the before filter chain. This removes the
469
- # filter from the filter chain for the whole controller and does not
470
- # take any options.
471
- #
472
- # ==== Parameters
473
- # filter<Symbol, String>:: A filter name to skip.
474
- #
475
- # :api: public
476
- def self.skip_before(filter)
477
- skip_filter(self._before_filters , filter)
478
- end
479
-
480
- # There are three possible ways to use this method. First, if you have a named route,
481
- # you can specify the route as the first parameter as a symbol and any paramters in a
482
- # hash. Second, you can generate the default route by just passing the params hash,
483
- # just passing the params hash. Finally, you can use the anonymous parameters. This
484
- # allows you to specify the parameters to a named route in the order they appear in the
485
- # router.
486
- #
487
- # ==== Parameters(Named Route)
488
- # name<Symbol>::
489
- # The name of the route.
490
- # args<Hash>::
491
- # Parameters for the route generation.
492
- #
493
- # ==== Parameters(Default Route)
494
- # args<Hash>::
495
- # Parameters for the route generation. This route will use the default route.
496
- #
497
- # ==== Parameters(Anonymous Parameters)
498
- # name<Symbol>::
499
- # The name of the route.
500
- # args<Array>::
501
- # An array of anonymous parameters to generate the route
502
- # with. These parameters are assigned to the route parameters
503
- # in the order that they are passed.
504
- #
505
- # ==== Returns
506
- # String:: The generated URL.
507
- #
508
- # ==== Examples
509
- # Named Route
510
- #
511
- # Merb::Router.prepare do
512
- # match("/articles/:title").to(:controller => :articles, :action => :show).name("articles")
513
- # end
514
- #
515
- # url(:articles, :title => "new_article")
516
- #
517
- # Default Route
518
- #
519
- # Merb::Router.prepare do
520
- # default_routes
521
- # end
522
- #
523
- # url(:controller => "articles", :action => "new")
524
- #
525
- # Anonymous Paramters
526
- #
527
- # Merb::Router.prepare do
528
- # match("/articles/:year/:month/:title").to(:controller => :articles, :action => :show).name("articles")
529
- # end
530
- #
531
- # url(:articles, 2008, 10, "test_article")
532
- #
533
- # :api: public
534
- def url(name, *args)
535
- args << {}
536
- Merb::Router.url(name, *args)
537
- end
472
+ # Removes a filter from the before filter chain. This removes the
473
+ # filter from the filter chain for the whole controller and does not
474
+ # take any options.
475
+ #
476
+ # ==== Parameters
477
+ # filter<Symbol, String>:: A filter name to skip.
478
+ #
479
+ # :api: public
480
+ def self.skip_before(filter)
481
+ skip_filter(self._before_filters , filter)
482
+ end
483
+
484
+ # There are three possible ways to use this method. First, if you have a named route,
485
+ # you can specify the route as the first parameter as a symbol and any paramters in a
486
+ # hash. Second, you can generate the default route by just passing the params hash,
487
+ # just passing the params hash. Finally, you can use the anonymous parameters. This
488
+ # allows you to specify the parameters to a named route in the order they appear in the
489
+ # router.
490
+ #
491
+ # ==== Parameters(Named Route)
492
+ # name<Symbol>::
493
+ # The name of the route.
494
+ # args<Hash>::
495
+ # Parameters for the route generation.
496
+ #
497
+ # ==== Parameters(Default Route)
498
+ # args<Hash>::
499
+ # Parameters for the route generation. This route will use the default route.
500
+ #
501
+ # ==== Parameters(Anonymous Parameters)
502
+ # name<Symbol>::
503
+ # The name of the route.
504
+ # args<Array>::
505
+ # An array of anonymous parameters to generate the route
506
+ # with. These parameters are assigned to the route parameters
507
+ # in the order that they are passed.
508
+ #
509
+ # ==== Returns
510
+ # String:: The generated URL.
511
+ #
512
+ # ==== Examples
513
+ # Named Route
514
+ #
515
+ # Merb::Router.prepare do
516
+ # match("/articles/:title").to(:controller => :articles, :action => :show).name("articles")
517
+ # end
518
+ #
519
+ # url(:articles, :title => "new_article")
520
+ #
521
+ # Default Route
522
+ #
523
+ # Merb::Router.prepare do
524
+ # default_routes
525
+ # end
526
+ #
527
+ # url(:controller => "articles", :action => "new")
528
+ #
529
+ # Anonymous Paramters
530
+ #
531
+ # Merb::Router.prepare do
532
+ # match("/articles/:year/:month/:title").to(:controller => :articles, :action => :show).name("articles")
533
+ # end
534
+ #
535
+ # url(:articles, 2008, 10, "test_article")
536
+ #
537
+ # :api: public
538
+ def url(name, *args)
539
+ args << {}
540
+ Merb::Router.url(name, *args)
541
+ end
538
542
 
539
- alias_method :relative_url, :url
540
-
541
- # Returns the absolute url including the passed protocol and host.
542
- #
543
- # This uses the same arguments as the url method, with added requirements
544
- # of protocol and host options.
545
- #
546
- # :api: public
547
- def absolute_url(*args)
548
- # FIXME: arrgh, why request.protocol returns http://?
549
- # :// is not part of protocol name
550
- options = extract_options_from_args!(args) || {}
551
- protocol = options.delete(:protocol)
552
- host = options.delete(:host)
543
+ alias_method :relative_url, :url
544
+
545
+ # Returns the absolute url including the passed protocol and host.
546
+ #
547
+ # This uses the same arguments as the url method, with added requirements
548
+ # of protocol and host options.
549
+ #
550
+ # :api: public
551
+ def absolute_url(*args)
552
+ # FIXME: arrgh, why request.protocol returns http://?
553
+ # :// is not part of protocol name
554
+ options = extract_options_from_args!(args) || {}
555
+ protocol = options.delete(:protocol)
556
+ host = options.delete(:host)
553
557
 
554
- raise ArgumentError, "The :protocol option must be specified" unless protocol
555
- raise ArgumentError, "The :host option must be specified" unless host
558
+ raise ArgumentError, "The :protocol option must be specified" unless protocol
559
+ raise ArgumentError, "The :host option must be specified" unless host
556
560
 
557
- args << options
561
+ args << options
558
562
 
559
- protocol + "://" + host + url(*args)
560
- end
563
+ protocol + "://" + host + url(*args)
564
+ end
561
565
 
562
- # Generates a URL for a single or nested resource.
563
- #
564
- # ==== Parameters
565
- # resources<Symbol,Object>:: The resources for which the URL
566
- # should be generated. These resources should be specified
567
- # in the router.rb file using #resources and #resource.
568
- #
569
- # options<Hash>:: Any extra parameters that are needed to
570
- # generate the URL.
571
- #
572
- # ==== Returns
573
- # String:: The generated URL.
574
- #
575
- # ==== Examples
576
- #
577
- # Merb::Router.prepare do
578
- # resources :users do
579
- # resources :comments
580
- # end
581
- # end
582
- #
583
- # resource(:users) # => /users
584
- # resource(@user) # => /users/10
585
- # resource(@user, :comments) # => /users/10/comments
586
- # resource(@user, @comment) # => /users/10/comments/15
587
- # resource(:users, :new) # => /users/new
588
- # resource(:@user, :edit) # => /users/10/edit
589
- #
590
- # :api: public
591
- def resource(*args)
592
- args << {}
593
- Merb::Router.resource(*args)
594
- end
595
-
596
- # Calls the capture method for the selected template engine.
597
- #
598
- # ==== Parameters
599
- # *args:: Arguments to pass to the block.
600
- # &block:: The block to call.
601
- #
602
- # ==== Returns
603
- # String:: The output of a template block or the return value of a non-template block converted to a string.
604
- #
605
- # :api: public
606
- def capture(*args, &block)
607
- ret = nil
608
-
609
- captured = send("capture_#{@_engine}", *args) do |*args|
610
- ret = yield *args
566
+ # Generates a URL for a single or nested resource.
567
+ #
568
+ # ==== Parameters
569
+ # resources<Symbol,Object>:: The resources for which the URL
570
+ # should be generated. These resources should be specified
571
+ # in the router.rb file using #resources and #resource.
572
+ #
573
+ # options<Hash>:: Any extra parameters that are needed to
574
+ # generate the URL.
575
+ #
576
+ # ==== Returns
577
+ # String:: The generated URL.
578
+ #
579
+ # ==== Examples
580
+ #
581
+ # Merb::Router.prepare do
582
+ # resources :users do
583
+ # resources :comments
584
+ # end
585
+ # end
586
+ #
587
+ # resource(:users) # => /users
588
+ # resource(@user) # => /users/10
589
+ # resource(@user, :comments) # => /users/10/comments
590
+ # resource(@user, @comment) # => /users/10/comments/15
591
+ # resource(:users, :new) # => /users/new
592
+ # resource(:@user, :edit) # => /users/10/edit
593
+ #
594
+ # :api: public
595
+ def resource(*args)
596
+ args << {}
597
+ Merb::Router.resource(*args)
611
598
  end
612
599
 
613
- # return captured value only if it is not empty
614
- captured.empty? ? ret.to_s : captured
615
- end
600
+ # Calls the capture method for the selected template engine.
601
+ #
602
+ # ==== Parameters
603
+ # *args:: Arguments to pass to the block.
604
+ # &block:: The block to call.
605
+ #
606
+ # ==== Returns
607
+ # String:: The output of a template block or the return value of a non-template block converted to a string.
608
+ #
609
+ # :api: public
610
+ def capture(*args, &block)
611
+ ret = nil
616
612
 
617
- # Calls the concatenate method for the selected template engine.
618
- #
619
- # ==== Parameters
620
- # str<String>:: The string to concatenate to the buffer.
621
- # binding<Binding>:: The binding to use for the buffer.
622
- #
623
- # :api: public
624
- def concat(str, binding)
625
- send("concat_#{@_engine}", str, binding)
626
- end
613
+ captured = send("capture_#{@_engine}", *args) do |*args|
614
+ ret = yield *args
615
+ end
616
+
617
+ # return captured value only if it is not empty
618
+ captured.empty? ? ret.to_s : captured
619
+ end
620
+
621
+ # Calls the concatenate method for the selected template engine.
622
+ #
623
+ # ==== Parameters
624
+ # str<String>:: The string to concatenate to the buffer.
625
+ # binding<Binding>:: The binding to use for the buffer.
626
+ #
627
+ # :api: public
628
+ def concat(str, binding)
629
+ send("concat_#{@_engine}", str, binding)
630
+ end
627
631
 
628
- private
629
- # adds a filter to the specified filter chain
630
- # ==== Parameters
631
- # filters<Array[Filter]>:: The filter chain that this should be added to.
632
- # filter<Filter>:: A filter that should be added.
633
- # opts<Hash>::
634
- # Filter options (see class documentation under <tt>Filter Options</tt>).
635
- #
636
- # ==== Raises
637
- # ArgumentError::
638
- # Both :only and :exclude, or :if and :unless given, if filter is not a
639
- # Symbol, String or Proc, or if an unknown option is passed.
640
- #
641
- # :api: private
642
- def self.add_filter(filters, filter, opts={})
643
- raise(ArgumentError,
644
- "You can specify either :only or :exclude but
645
- not both at the same time for the same filter.") if opts.key?(:only) && opts.key?(:exclude)
632
+ private
633
+ # adds a filter to the specified filter chain
634
+ # ==== Parameters
635
+ # filters<Array[Filter]>:: The filter chain that this should be added to.
636
+ # filter<Filter>:: A filter that should be added.
637
+ # opts<Hash>::
638
+ # Filter options (see class documentation under <tt>Filter Options</tt>).
639
+ #
640
+ # ==== Raises
641
+ # ArgumentError::
642
+ # Both :only and :exclude, or :if and :unless given, if filter is not a
643
+ # Symbol, String or Proc, or if an unknown option is passed.
644
+ #
645
+ # :api: private
646
+ def self.add_filter(filters, filter, opts={})
647
+ raise(ArgumentError,
648
+ "You can specify either :only or :exclude but
649
+ not both at the same time for the same filter.") if opts.key?(:only) && opts.key?(:exclude)
646
650
 
647
- raise(ArgumentError,
648
- "You can specify either :if or :unless but
649
- not both at the same time for the same filter.") if opts.key?(:if) && opts.key?(:unless)
651
+ raise(ArgumentError,
652
+ "You can specify either :if or :unless but
653
+ not both at the same time for the same filter.") if opts.key?(:if) && opts.key?(:unless)
650
654
 
651
- opts.each_key do |key| raise(ArgumentError,
652
- "You can only specify known filter options, #{key} is invalid.") unless FILTER_OPTIONS.include?(key)
653
- end
655
+ opts.each_key do |key| raise(ArgumentError,
656
+ "You can only specify known filter options, #{key} is invalid.") unless FILTER_OPTIONS.include?(key)
657
+ end
654
658
 
655
- opts = normalize_filters!(opts)
659
+ opts = normalize_filters!(opts)
656
660
 
657
- case filter
658
- when Proc
659
- # filters with procs created via class methods have identical signature
660
- # regardless if they handle content differently or not. So procs just
661
- # get appended
662
- filters << [filter, opts]
663
- when Symbol, String
664
- if existing_filter = filters.find {|f| f.first.to_s == filter.to_s}
665
- filters[ filters.index(existing_filter) ] = [filter, opts]
666
- else
661
+ case filter
662
+ when Proc
663
+ # filters with procs created via class methods have identical signature
664
+ # regardless if they handle content differently or not. So procs just
665
+ # get appended
667
666
  filters << [filter, opts]
667
+ when Symbol, String
668
+ if existing_filter = filters.find {|f| f.first.to_s == filter.to_s}
669
+ filters[ filters.index(existing_filter) ] = [filter, opts]
670
+ else
671
+ filters << [filter, opts]
672
+ end
673
+ else
674
+ raise(ArgumentError,
675
+ 'Filters need to be either a Symbol, String or a Proc'
676
+ )
668
677
  end
669
- else
670
- raise(ArgumentError,
671
- 'Filters need to be either a Symbol, String or a Proc'
672
- )
678
+ end
679
+
680
+ # Skip a filter that was previously added to the filter chain. Useful in
681
+ # inheritence hierarchies.
682
+ #
683
+ # ==== Parameters
684
+ # filters<Array[Filter]>:: The filter chain that this should be removed from.
685
+ # filter<Filter>:: A filter that should be removed.
686
+ #
687
+ # ==== Raises
688
+ # ArgumentError:: filter not Symbol or String.
689
+ #
690
+ # :api: private
691
+ def self.skip_filter(filters, filter)
692
+ raise(ArgumentError, 'You can only skip filters that have a String or Symbol name.') unless
693
+ [Symbol, String].include? filter.class
694
+
695
+ Merb.logger.warn("Filter #{filter} was not found in your filter chain.") unless
696
+ filters.reject! {|f| f.first.to_s[filter.to_s] }
673
697
  end
674
- end
675
-
676
- # Skip a filter that was previously added to the filter chain. Useful in
677
- # inheritence hierarchies.
678
- #
679
- # ==== Parameters
680
- # filters<Array[Filter]>:: The filter chain that this should be removed from.
681
- # filter<Filter>:: A filter that should be removed.
682
- #
683
- # ==== Raises
684
- # ArgumentError:: filter not Symbol or String.
685
- #
686
- # :api: private
687
- def self.skip_filter(filters, filter)
688
- raise(ArgumentError, 'You can only skip filters that have a String or Symbol name.') unless
689
- [Symbol, String].include? filter.class
690
-
691
- Merb.logger.warn("Filter #{filter} was not found in your filter chain.") unless
692
- filters.reject! {|f| f.first.to_s[filter.to_s] }
693
- end
694
698
 
695
- # Ensures that the passed in hash values are always arrays.
696
- #
697
- # ==== Parameters
698
- # opts<Hash>:: Options for the filters (see below).
699
- #
700
- # ==== Options (opts)
701
- # :only<Symbol, Array[Symbol]>:: A list of actions.
702
- # :exclude<Symbol, Array[Symbol]>:: A list of actions.
703
- #
704
- # ==== Examples
705
- # normalize_filters!(:only => :new) #=> {:only => [:new]}
706
- #
707
- # :api: public
708
- def self.normalize_filters!(opts={})
709
- opts[:only] = Array(opts[:only]).map {|x| x.to_s} if opts[:only]
710
- opts[:exclude] = Array(opts[:exclude]).map {|x| x.to_s} if opts[:exclude]
711
- return opts
699
+ # Ensures that the passed in hash values are always arrays.
700
+ #
701
+ # ==== Parameters
702
+ # opts<Hash>:: Options for the filters (see below).
703
+ #
704
+ # ==== Options (opts)
705
+ # :only<Symbol, Array[Symbol]>:: A list of actions.
706
+ # :exclude<Symbol, Array[Symbol]>:: A list of actions.
707
+ #
708
+ # ==== Examples
709
+ # normalize_filters!(:only => :new) #=> {:only => [:new]}
710
+ #
711
+ # :api: public
712
+ def self.normalize_filters!(opts={})
713
+ opts[:only] = Array(opts[:only]).map {|x| x.to_s} if opts[:only]
714
+ opts[:exclude] = Array(opts[:exclude]).map {|x| x.to_s} if opts[:exclude]
715
+ return opts
716
+ end
712
717
  end
713
- end
718
+ end