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/CONTRIBUTORS +33 -0
- data/README +7 -3
- data/Rakefile +3 -3
- data/lib/merb-core.rb +165 -94
- data/lib/merb-core/bootloader.rb +469 -100
- data/lib/merb-core/config.rb +79 -3
- data/lib/merb-core/constants.rb +24 -2
- data/lib/merb-core/controller/abstract_controller.rb +172 -67
- data/lib/merb-core/controller/exceptions.rb +50 -6
- data/lib/merb-core/controller/merb_controller.rb +215 -108
- data/lib/merb-core/controller/mime.rb +36 -12
- data/lib/merb-core/controller/mixins/authentication.rb +52 -7
- data/lib/merb-core/controller/mixins/conditional_get.rb +14 -0
- data/lib/merb-core/controller/mixins/controller.rb +90 -58
- data/lib/merb-core/controller/mixins/render.rb +34 -10
- data/lib/merb-core/controller/mixins/responder.rb +40 -16
- data/lib/merb-core/controller/template.rb +37 -16
- data/lib/merb-core/core_ext/hash.rb +9 -0
- data/lib/merb-core/core_ext/kernel.rb +92 -41
- data/lib/merb-core/dispatch/dispatcher.rb +29 -45
- data/lib/merb-core/dispatch/request.rb +186 -82
- data/lib/merb-core/dispatch/router.rb +141 -53
- data/lib/merb-core/dispatch/router/behavior.rb +296 -139
- data/lib/merb-core/dispatch/router/resources.rb +51 -19
- data/lib/merb-core/dispatch/router/route.rb +76 -23
- data/lib/merb-core/dispatch/session.rb +80 -36
- data/lib/merb-core/dispatch/session/container.rb +31 -15
- data/lib/merb-core/dispatch/session/cookie.rb +51 -22
- data/lib/merb-core/dispatch/session/memcached.rb +10 -6
- data/lib/merb-core/dispatch/session/memory.rb +17 -5
- data/lib/merb-core/dispatch/session/store_container.rb +21 -9
- data/lib/merb-core/dispatch/worker.rb +16 -2
- data/lib/merb-core/gem_ext/erubis.rb +4 -0
- data/lib/merb-core/plugins.rb +13 -0
- data/lib/merb-core/rack.rb +1 -0
- data/lib/merb-core/rack/adapter.rb +1 -0
- data/lib/merb-core/rack/adapter/abstract.rb +95 -17
- data/lib/merb-core/rack/adapter/irb.rb +50 -5
- data/lib/merb-core/rack/application.rb +27 -5
- data/lib/merb-core/rack/handler/mongrel.rb +6 -6
- data/lib/merb-core/rack/helpers.rb +33 -0
- data/lib/merb-core/rack/middleware/conditional_get.rb +1 -1
- data/lib/merb-core/rack/middleware/path_prefix.rb +3 -3
- data/lib/merb-core/rack/middleware/static.rb +11 -7
- data/lib/merb-core/server.rb +134 -69
- data/lib/merb-core/tasks/gem_management.rb +153 -80
- data/lib/merb-core/tasks/merb_rake_helper.rb +12 -4
- data/lib/merb-core/tasks/stats.rake +1 -1
- data/lib/merb-core/test/helpers/mock_request_helper.rb +29 -22
- data/lib/merb-core/test/helpers/request_helper.rb +1 -1
- data/lib/merb-core/test/helpers/route_helper.rb +50 -4
- data/lib/merb-core/test/matchers/request_matchers.rb +2 -36
- data/lib/merb-core/test/matchers/view_matchers.rb +32 -22
- data/lib/merb-core/test/run_specs.rb +6 -5
- data/lib/merb-core/test/test_ext/rspec.rb +6 -19
- data/lib/merb-core/version.rb +1 -1
- metadata +5 -4
data/lib/merb-core/config.rb
CHANGED
@@ -6,21 +6,26 @@ module Merb
|
|
6
6
|
|
7
7
|
class << self
|
8
8
|
|
9
|
+
# Returns the hash of default config values for Merb.
|
10
|
+
#
|
9
11
|
# ==== Returns
|
10
12
|
# Hash:: The defaults for the config.
|
13
|
+
#
|
14
|
+
# @api private
|
11
15
|
def defaults
|
12
16
|
@defaults ||= {
|
13
17
|
:host => "0.0.0.0",
|
14
18
|
:port => "4000",
|
15
19
|
:adapter => "runner",
|
16
20
|
:reload_classes => true,
|
17
|
-
:fork_for_class_load => !RUBY_PLATFORM
|
21
|
+
:fork_for_class_load => !(RUBY_PLATFORM =~ /(:?mswin|mingw|java)/),
|
18
22
|
:environment => "development",
|
19
23
|
:merb_root => Dir.pwd,
|
20
24
|
:use_mutex => true,
|
21
25
|
:log_delimiter => " ~ ",
|
22
26
|
:log_auto_flush => false,
|
23
27
|
:log_level => :info,
|
28
|
+
:log_stream => STDOUT,
|
24
29
|
:disabled_components => [],
|
25
30
|
:deferred_actions => [],
|
26
31
|
:verbose => false,
|
@@ -36,30 +41,47 @@ module Merb
|
|
36
41
|
# ==== Examples
|
37
42
|
# Merb::Config.use do |config|
|
38
43
|
# config[:exception_details] = false
|
44
|
+
# config[:log_stream] = STDOUT
|
39
45
|
# end
|
46
|
+
#
|
47
|
+
# ==== Returns
|
48
|
+
# nil
|
49
|
+
#
|
50
|
+
# @api public
|
40
51
|
def use
|
41
52
|
@configuration ||= {}
|
42
53
|
yield @configuration
|
54
|
+
nil
|
43
55
|
end
|
44
|
-
|
56
|
+
|
57
|
+
# Detects whether the provided key is in the config.
|
58
|
+
#
|
45
59
|
# ==== Parameters
|
46
60
|
# key<Object>:: The key to check.
|
47
61
|
#
|
48
62
|
# ==== Returns
|
49
63
|
# Boolean:: True if the key exists in the config.
|
64
|
+
#
|
65
|
+
# @api public
|
50
66
|
def key?(key)
|
51
67
|
@configuration.key?(key)
|
52
68
|
end
|
53
69
|
|
70
|
+
# Retrieve the value of a config entry.
|
71
|
+
#
|
54
72
|
# ==== Parameters
|
55
73
|
# key<Object>:: The key to retrieve the parameter for.
|
56
74
|
#
|
57
75
|
# ==== Returns
|
58
76
|
# Object:: The value of the configuration parameter.
|
77
|
+
#
|
78
|
+
# @api public
|
59
79
|
def [](key)
|
60
80
|
(@configuration ||= setup)[key]
|
61
81
|
end
|
62
82
|
|
83
|
+
# Set the value of a config entry.
|
84
|
+
#
|
63
85
|
# ==== Parameters
|
64
86
|
# key<Object>:: The key to set the parameter for.
|
65
87
|
# val<Object>:: The value of the parameter.
|
@@ -67,12 +89,21 @@ module Merb
|
|
67
89
|
(@configuration ||= setup)[key] = val
|
68
90
|
end
|
69
91
|
|
92
|
+
# Remove the value of a config entry.
|
93
|
+
#
|
70
94
|
# ==== Parameters
|
71
95
|
# key<Object>:: The key of the parameter to delete.
|
96
|
+
#
|
97
|
+
# ==== Returns
|
98
|
+
# Object:: The value of the removed entry.
|
99
|
+
#
|
100
|
+
# @api public
|
72
101
|
def delete(key)
|
73
102
|
@configuration.delete(key)
|
74
103
|
end
|
75
104
|
|
105
|
+
# Retrieve the value of a config entry, returning the provided default if the key is not present
|
106
|
+
#
|
76
107
|
# ==== Parameters
|
77
108
|
# key<Object>:: The key to retrieve the parameter for.
|
78
109
|
# default<Object>::
|
@@ -84,14 +115,22 @@ module Merb
|
|
84
115
|
@configuration.fetch(key, default)
|
85
116
|
end
|
86
117
|
|
118
|
+
# Returns the configuration as a hash.
|
119
|
+
#
|
87
120
|
# ==== Returns
|
88
121
|
# Hash:: The config as a hash.
|
122
|
+
#
|
123
|
+
# @api public
|
89
124
|
def to_hash
|
90
125
|
@configuration
|
91
126
|
end
|
92
127
|
|
128
|
+
# Returns the config as YAML.
|
129
|
+
#
|
93
130
|
# ==== Returns
|
94
131
|
# String:: The config as YAML.
|
132
|
+
#
|
133
|
+
# @api public
|
95
134
|
def to_yaml
|
96
135
|
require "yaml"
|
97
136
|
@configuration.to_yaml
|
@@ -102,6 +141,11 @@ module Merb
|
|
102
141
|
# ==== Parameters
|
103
142
|
# settings<Hash>::
|
104
143
|
# Configuration settings to use. These are merged with the defaults.
|
144
|
+
#
|
145
|
+
# ==== Returns
|
146
|
+
# The configuration as a hash.
|
147
|
+
#
|
148
|
+
# @api private
|
105
149
|
def setup(settings = {})
|
106
150
|
@configuration = defaults.merge(settings)
|
107
151
|
|
@@ -116,6 +160,11 @@ module Merb
|
|
116
160
|
#
|
117
161
|
# ==== Parameters
|
118
162
|
# argv<String>:: The command line arguments. Defaults to +ARGV+.
|
163
|
+
#
|
164
|
+
# ==== Returns
|
165
|
+
# The configuration as a hash.
|
166
|
+
#
|
167
|
+
# @api private
|
119
168
|
def parse_args(argv = ARGV)
|
120
169
|
@configuration ||= {}
|
121
170
|
# Our primary configuration hash for the length of this method
|
@@ -275,7 +324,7 @@ module Merb
|
|
275
324
|
|
276
325
|
opts.on("-k", "--kill PORT", "Force kill one merb worker " \
|
277
326
|
"by port number. This will cause the worker to" \
|
278
|
-
"be respawned.
|
327
|
+
"be respawned.") do |port|
|
279
328
|
options[:action] = :kill_9
|
280
329
|
port = "main" if port == "all"
|
281
330
|
options[:port] = port
|
@@ -348,9 +397,16 @@ module Merb
|
|
348
397
|
# Merb::Config.configure do
|
349
398
|
# environment "development"
|
350
399
|
# log_level "debug"
|
400
|
+
# log_file Merb.root / "log" / "special.log"
|
351
401
|
# end
|
402
|
+
#
|
403
|
+
# ==== Returns
|
404
|
+
# nil
|
405
|
+
#
|
406
|
+
# @api public
|
352
407
|
def configure(&block)
|
353
408
|
ConfigBlock.new(self, &block) if block_given?
|
409
|
+
nil
|
354
410
|
end
|
355
411
|
|
356
412
|
# Allows retrieval of single key config values via Merb.config.<key>
|
@@ -359,6 +415,11 @@ module Merb
|
|
359
415
|
# ==== Parameters
|
360
416
|
# method<~to_s>:: Method name as hash key value.
|
361
417
|
# *args:: Value to set the configuration parameter to.
|
418
|
+
#
|
419
|
+
# ==== Returns
|
420
|
+
# The value of the entry fetched or assigned to.
|
421
|
+
#
|
422
|
+
# @api public
|
362
423
|
def method_missing(method, *args)
|
363
424
|
if method.to_s[-1,1] == '='
|
364
425
|
@configuration[method.to_s.tr('=','').to_sym] = *args
|
@@ -371,11 +432,26 @@ module Merb
|
|
371
432
|
|
372
433
|
class ConfigBlock
|
373
434
|
|
435
|
+
# Evaluates the provided block, where any call to a method causes
|
436
|
+
# #[]= to be called on klass with the method name as the key and the arguments
|
437
|
+
# as the value.
|
438
|
+
#
|
439
|
+
# ==== Parameters
|
440
|
+
# klass<Object~[]=>:: The object on which to assign values.
|
441
|
+
# &block:: The block which specifies the config values to set.
|
442
|
+
#
|
443
|
+
# ==== Returns
|
444
|
+
# nil
|
445
|
+
#
|
446
|
+
# @api private
|
374
447
|
def initialize(klass, &block)
|
375
448
|
@klass = klass
|
376
449
|
instance_eval(&block)
|
377
450
|
end
|
378
451
|
|
452
|
+
# Assign args as the value of the entry keyed by method.
|
453
|
+
#
|
454
|
+
# @api private
|
379
455
|
def method_missing(method, *args)
|
380
456
|
@klass[method] = *args
|
381
457
|
end
|
data/lib/merb-core/constants.rb
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
# Most of this list is simply constants frozen for efficiency
|
2
|
+
# and lowered memory consumption. Every time Ruby VM comes
|
3
|
+
# across a string or a number or a regexp literal,
|
4
|
+
# new object is created.
|
5
|
+
#
|
6
|
+
# This means if you refer to the same string 6 times per request
|
7
|
+
# and your application takes 100 requests per second, there are
|
8
|
+
# 600 objects for weak MRI garbage collector to work on.
|
9
|
+
#
|
10
|
+
# GC cycles take up to 80% (!) time of request processing in
|
11
|
+
# some cases. Eventually Rubinius and maybe MRI 2.0 gonna
|
12
|
+
# improve this situation but at the moment, all commonly used
|
13
|
+
# strings, regexp and numbers used as constants so no extra
|
14
|
+
# objects created and VM just operate pointers.
|
2
15
|
module Merb
|
3
|
-
|
16
|
+
module Const
|
4
17
|
|
5
18
|
DEFAULT_SEND_FILE_OPTIONS = {
|
6
19
|
:type => 'application/octet-stream'.freeze,
|
@@ -27,7 +40,6 @@ module Merb
|
|
27
40
|
ETAG = 'ETag'.freeze
|
28
41
|
LAST_MODIFIED = "Last-Modified".freeze
|
29
42
|
SLASH = "/".freeze
|
30
|
-
REQUEST_METHOD = "REQUEST_METHOD".freeze
|
31
43
|
GET = "GET".freeze
|
32
44
|
POST = "POST".freeze
|
33
45
|
HEAD = "HEAD".freeze
|
@@ -35,11 +47,21 @@ module Merb
|
|
35
47
|
HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR".freeze
|
36
48
|
HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE".freeze
|
37
49
|
HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH".freeze
|
50
|
+
HTTP_CONTENT_TYPE = "HTTP_CONTENT_TYPE".freeze
|
51
|
+
HTTP_CONTENT_LENGTH = "HTTP_CONTENT_LENGTH".freeze
|
38
52
|
UPLOAD_ID = "upload_id".freeze
|
39
53
|
PATH_INFO = "PATH_INFO".freeze
|
40
54
|
SCRIPT_NAME = "SCRIPT_NAME".freeze
|
41
55
|
REQUEST_URI = "REQUEST_URI".freeze
|
42
56
|
REQUEST_PATH = "REQUEST_PATH".freeze
|
57
|
+
REQUEST_METHOD = "REQUEST_METHOD".freeze
|
43
58
|
REMOTE_ADDR = "REMOTE_ADDR".freeze
|
59
|
+
BREAK_TAG = "<br/>".freeze
|
60
|
+
EMPTY_STRING = "".freeze
|
61
|
+
NEWLINE = "\n".freeze
|
62
|
+
DOUBLE_NEWLINE = "\n\n".freeze
|
63
|
+
LOCATION = "Location".freeze
|
64
|
+
TEXT_SLASH_HTML = "text/html".freeze
|
65
|
+
|
44
66
|
end
|
45
67
|
end
|
@@ -103,7 +103,7 @@ class Merb::AbstractController
|
|
103
103
|
cattr_accessor :_abstract_subclasses
|
104
104
|
|
105
105
|
#---
|
106
|
-
# @semipublic
|
106
|
+
# @api semipublic
|
107
107
|
attr_accessor :body
|
108
108
|
attr_accessor :action_name
|
109
109
|
attr_accessor :_benchmarks, :_thrown_content
|
@@ -124,12 +124,13 @@ class Merb::AbstractController
|
|
124
124
|
|
125
125
|
# ==== Returns
|
126
126
|
# String:: The controller name in path form, e.g. "admin/items".
|
127
|
-
|
128
|
-
# @public
|
127
|
+
# @api public
|
129
128
|
def self.controller_name() @controller_name ||= self.name.to_const_path end
|
130
129
|
|
131
130
|
# ==== Returns
|
132
131
|
# String:: The controller name in path form, e.g. "admin/items".
|
132
|
+
#
|
133
|
+
# @api public
|
133
134
|
def controller_name() self.class.controller_name end
|
134
135
|
|
135
136
|
# This is called after the controller is instantiated to figure out where to
|
@@ -138,9 +139,9 @@ class Merb::AbstractController
|
|
138
139
|
#
|
139
140
|
# ==== Parameters
|
140
141
|
# context<~to_s>:: The controller context (the action or template name).
|
141
|
-
# type<~to_s>:: The content type.
|
142
|
+
# type<~to_s>:: The content type. Could be nil.
|
142
143
|
# controller<~to_s>::
|
143
|
-
# The name of the controller. Defaults to controller_name.
|
144
|
+
# The name of the controller. Defaults to being called with the controller_name. Set t
|
144
145
|
#
|
145
146
|
#
|
146
147
|
# ==== Returns
|
@@ -160,29 +161,41 @@ class Merb::AbstractController
|
|
160
161
|
#
|
161
162
|
# This would look for templates at controller.action.mime.type instead
|
162
163
|
# of controller/action.mime.type
|
163
|
-
|
164
|
-
# @public
|
164
|
+
#
|
165
|
+
# @api public
|
166
|
+
# @overridable
|
165
167
|
def _template_location(context, type, controller)
|
166
168
|
controller ? "#{controller}/#{context}" : context
|
167
169
|
end
|
168
170
|
|
169
|
-
# The location to look for a template -
|
171
|
+
# The location to look for a template - override this method for particular behaviour.
|
170
172
|
#
|
171
173
|
# ==== Parameters
|
172
174
|
# template<String>:: The absolute path to a template - without template extension.
|
173
175
|
# type<~to_s>::
|
174
|
-
# The mime-type of the template that will be rendered. Defaults to nil.
|
176
|
+
# The mime-type of the template that will be rendered. Defaults to being called with nil.
|
175
177
|
#
|
176
|
-
# @public
|
178
|
+
# @api public
|
179
|
+
# @overridable
|
177
180
|
def _absolute_template_location(template, type)
|
178
181
|
template
|
179
182
|
end
|
180
183
|
|
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
|
181
191
|
def self._template_root=(root)
|
182
192
|
@_template_root = root
|
183
193
|
_reset_template_roots
|
184
194
|
end
|
185
195
|
|
196
|
+
# Reset the template root based on the @_template_root ivar.
|
197
|
+
#
|
198
|
+
# @api private
|
186
199
|
def self._reset_template_roots
|
187
200
|
self.template_roots = [[self._template_root, :_template_location]]
|
188
201
|
end
|
@@ -191,6 +204,8 @@ class Merb::AbstractController
|
|
191
204
|
# roots<Array[Array]>::
|
192
205
|
# Template roots as pairs of template root path and template location
|
193
206
|
# method.
|
207
|
+
#
|
208
|
+
# @api unknown
|
194
209
|
def self._template_roots
|
195
210
|
self.template_roots || _reset_template_roots
|
196
211
|
end
|
@@ -199,45 +214,62 @@ class Merb::AbstractController
|
|
199
214
|
# roots<Array[Array]>::
|
200
215
|
# Template roots as pairs of template root path and template location
|
201
216
|
# method.
|
217
|
+
#
|
218
|
+
# @api unknown
|
202
219
|
def self._template_roots=(roots)
|
203
220
|
self.template_roots = roots
|
204
221
|
end
|
205
222
|
|
223
|
+
# Returns the list of classes that have specifically subclassed AbstractController.
|
224
|
+
# Does not include all decendents.
|
225
|
+
#
|
206
226
|
# ==== Returns
|
207
227
|
# Set:: The subclasses.
|
228
|
+
#
|
229
|
+
# @api private
|
208
230
|
def self.subclasses_list() _abstract_subclasses end
|
209
231
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
end
|
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
|
224
246
|
|
247
|
+
# This will initialize the controller, it is designed to be overridden in subclasses (like MerbController)
|
225
248
|
# ==== Parameters
|
226
|
-
# *args:: The args are ignored
|
249
|
+
# *args:: The args are ignored in this class, but we need this so that subclassed initializes can have parameters
|
250
|
+
#
|
251
|
+
# @overridable
|
227
252
|
def initialize(*args)
|
228
253
|
@_benchmarks = {}
|
229
254
|
@_caught_content = {}
|
230
255
|
end
|
231
256
|
|
232
|
-
# This will dispatch the request, calling internal before/after
|
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.
|
233
259
|
#
|
234
260
|
# ==== Parameters
|
235
261
|
# action<~to_s>::
|
236
262
|
# The action to dispatch to. This will be #send'ed in _call_action.
|
237
263
|
# Defaults to :to_s.
|
238
264
|
#
|
265
|
+
# ==== Returns
|
266
|
+
# <~to_s>::
|
267
|
+
# Returns the string that was returned from the action.
|
268
|
+
#
|
239
269
|
# ==== Raises
|
240
|
-
#
|
270
|
+
# ArgumentError:: Invalid result caught from before filters.
|
271
|
+
#
|
272
|
+
# @api plugin
|
241
273
|
def _dispatch(action)
|
242
274
|
self._before_dispatch_callbacks.each { |cb| cb.call(self) }
|
243
275
|
self.action_name = action
|
@@ -252,7 +284,8 @@ class Merb::AbstractController
|
|
252
284
|
@body = case caught
|
253
285
|
when :filter_chain_completed then _call_action(action_name)
|
254
286
|
when String then caught
|
255
|
-
|
287
|
+
# return *something* if you throw halt with nothing
|
288
|
+
when nil then "<html><body><h1>Filter Chain Halted!</h1></body></html>"
|
256
289
|
when Symbol then __send__(caught)
|
257
290
|
when Proc then self.instance_eval(&caught)
|
258
291
|
else
|
@@ -267,14 +300,19 @@ class Merb::AbstractController
|
|
267
300
|
@body
|
268
301
|
end
|
269
302
|
|
270
|
-
# This method exists to provide an overridable hook for ActionArgs
|
303
|
+
# This method exists to provide an overridable hook for ActionArgs. It uses #send to call the action method.
|
271
304
|
#
|
272
305
|
# ==== Parameters
|
273
306
|
# action<~to_s>:: the action method to dispatch to
|
307
|
+
#
|
308
|
+
# @api plugin
|
309
|
+
# @overridable
|
274
310
|
def _call_action(action)
|
275
311
|
send(action)
|
276
312
|
end
|
277
313
|
|
314
|
+
# Calls a filter chain.
|
315
|
+
#
|
278
316
|
# ==== Parameters
|
279
317
|
# filter_set<Array[Filter]>::
|
280
318
|
# A set of filters in the form [[:filter, rule], [:filter, rule]]
|
@@ -290,6 +328,8 @@ class Merb::AbstractController
|
|
290
328
|
# Procs::
|
291
329
|
# Execute the +Proc+, in the context of the controller (self will be the
|
292
330
|
# controller)
|
331
|
+
#
|
332
|
+
# @api private
|
293
333
|
def _call_filters(filter_set)
|
294
334
|
(filter_set || []).each do |filter, rule|
|
295
335
|
if _call_filter_for_action?(rule, action_name) && _filter_condition_met?(rule)
|
@@ -308,6 +348,8 @@ class Merb::AbstractController
|
|
308
348
|
return :filter_chain_completed
|
309
349
|
end
|
310
350
|
|
351
|
+
# Determine whether the filter should be called for the current action using :only and :exclude.
|
352
|
+
#
|
311
353
|
# ==== Parameters
|
312
354
|
# rule<Hash>:: Rules for the filter (see below).
|
313
355
|
# action_name<~to_s>:: The name of the action to be called.
|
@@ -322,6 +364,8 @@ class Merb::AbstractController
|
|
322
364
|
#
|
323
365
|
# ==== Returns
|
324
366
|
# Boolean:: True if the action should be called.
|
367
|
+
#
|
368
|
+
# @api private
|
325
369
|
def _call_filter_for_action?(rule, action_name)
|
326
370
|
# Both:
|
327
371
|
# * no :only or the current action is in the :only list
|
@@ -330,6 +374,8 @@ class Merb::AbstractController
|
|
330
374
|
(!rule.key?(:exclude) || !rule[:exclude].include?(action_name))
|
331
375
|
end
|
332
376
|
|
377
|
+
# Determines whether the filter should be run based on the conditions passed (:if and :unless)
|
378
|
+
#
|
333
379
|
# ==== Parameters
|
334
380
|
# rule<Hash>:: Rules for the filter (see below).
|
335
381
|
#
|
@@ -340,6 +386,8 @@ class Merb::AbstractController
|
|
340
386
|
#
|
341
387
|
# ==== Returns
|
342
388
|
# Boolean:: True if the conditions are met.
|
389
|
+
#
|
390
|
+
# @api private
|
343
391
|
def _filter_condition_met?(rule)
|
344
392
|
# Both:
|
345
393
|
# * no :if or the if condition evaluates to true
|
@@ -348,6 +396,8 @@ class Merb::AbstractController
|
|
348
396
|
(!rule.key?(:unless) || ! _evaluate_condition(rule[:unless]))
|
349
397
|
end
|
350
398
|
|
399
|
+
# Evaluates a filter condition (:if or :unless)
|
400
|
+
#
|
351
401
|
# ==== Parameters
|
352
402
|
# condition<Symbol, Proc>:: The condition to evaluate.
|
353
403
|
#
|
@@ -360,6 +410,8 @@ class Merb::AbstractController
|
|
360
410
|
# ==== Alternatives
|
361
411
|
# If condition is a symbol, it will be send'ed. If it is a Proc it will be
|
362
412
|
# called directly with self as an argument.
|
413
|
+
#
|
414
|
+
# @api private
|
363
415
|
def _evaluate_condition(condition)
|
364
416
|
case condition
|
365
417
|
when Symbol : self.send(condition)
|
@@ -370,6 +422,7 @@ class Merb::AbstractController
|
|
370
422
|
end
|
371
423
|
end
|
372
424
|
|
425
|
+
# Adds a filter to the after filter chain
|
373
426
|
# ==== Parameters
|
374
427
|
# filter<Symbol, Proc>:: The filter to add. Defaults to nil.
|
375
428
|
# opts<Hash>::
|
@@ -377,11 +430,15 @@ class Merb::AbstractController
|
|
377
430
|
# &block:: A block to use as a filter if filter is nil.
|
378
431
|
#
|
379
432
|
# ==== Notes
|
380
|
-
# If the filter already exists, its options will be replaced with opts
|
433
|
+
# If the filter already exists, its options will be replaced with opts.;
|
434
|
+
#
|
435
|
+
# @api public
|
381
436
|
def self.after(filter = nil, opts = {}, &block)
|
382
437
|
add_filter(self._after_filters, filter || block, opts)
|
383
438
|
end
|
384
439
|
|
440
|
+
# Adds a filter to the before filter chain.
|
441
|
+
#
|
385
442
|
# ==== Parameters
|
386
443
|
# filter<Symbol, Proc>:: The filter to add. Defaults to nil.
|
387
444
|
# opts<Hash>::
|
@@ -390,44 +447,90 @@ class Merb::AbstractController
|
|
390
447
|
#
|
391
448
|
# ==== Notes
|
392
449
|
# If the filter already exists, its options will be replaced with opts.
|
450
|
+
#
|
451
|
+
# @api public
|
393
452
|
def self.before(filter = nil, opts = {}, &block)
|
394
453
|
add_filter(self._before_filters, filter || block, opts)
|
395
454
|
end
|
396
455
|
|
397
|
-
#
|
398
|
-
#
|
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.
|
399
459
|
#
|
400
460
|
# ==== Parameters
|
401
|
-
# filter<Symbol>:: A filter name to skip.
|
461
|
+
# filter<Symbol, String>:: A filter name to skip.
|
462
|
+
#
|
463
|
+
# @api public
|
402
464
|
def self.skip_after(filter)
|
403
465
|
skip_filter(self._after_filters, filter)
|
404
466
|
end
|
405
467
|
|
406
|
-
#
|
407
|
-
#
|
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.
|
408
471
|
#
|
409
472
|
# ==== Parameters
|
410
|
-
# filter<Symbol>:: A filter name to skip.
|
473
|
+
# filter<Symbol, String>:: A filter name to skip.
|
474
|
+
#
|
475
|
+
# @api public
|
411
476
|
def self.skip_before(filter)
|
412
477
|
skip_filter(self._before_filters , filter)
|
413
478
|
end
|
414
|
-
|
415
|
-
|
416
|
-
#
|
417
|
-
|
418
|
-
|
419
|
-
#
|
420
|
-
#
|
421
|
-
#
|
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.
|
422
504
|
#
|
423
505
|
# ==== Returns
|
424
506
|
# String:: The generated URL.
|
425
507
|
#
|
426
|
-
# ====
|
427
|
-
#
|
428
|
-
#
|
429
|
-
#
|
430
|
-
#
|
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
|
431
534
|
def url(name, *args)
|
432
535
|
args << {}
|
433
536
|
Merb::Router.url(name, *args)
|
@@ -435,22 +538,12 @@ class Merb::AbstractController
|
|
435
538
|
|
436
539
|
alias_method :relative_url, :url
|
437
540
|
|
438
|
-
#
|
439
|
-
#
|
440
|
-
#
|
441
|
-
#
|
442
|
-
# ==== Returns
|
443
|
-
# String:: The generated url with protocol + hostname + URL.
|
444
|
-
#
|
445
|
-
# ==== Options
|
446
|
-
#
|
447
|
-
# :protocol and :host options are special: use them to explicitly
|
448
|
-
# specify protocol and host of resulting url. If you omit them,
|
449
|
-
# protocol and host of request are used.
|
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.
|
450
545
|
#
|
451
|
-
#
|
452
|
-
# If a hash is used as the first argument, a default route will be
|
453
|
-
# generated based on it and rparams.
|
546
|
+
# @api public
|
454
547
|
def absolute_url(name, *args)
|
455
548
|
# FIXME: arrgh, why request.protocol returns http://?
|
456
549
|
# :// is not part of protocol name
|
@@ -494,8 +587,9 @@ class Merb::AbstractController
|
|
494
587
|
# resource(:users, :new) # => /users/new
|
495
588
|
# resource(:@user, :edit) # => /users/10/edit
|
496
589
|
#
|
590
|
+
# @api public
|
497
591
|
def resource(*args)
|
498
|
-
args <<
|
592
|
+
args << {}
|
499
593
|
Merb::Router.resource(*args)
|
500
594
|
end
|
501
595
|
|
@@ -507,6 +601,8 @@ class Merb::AbstractController
|
|
507
601
|
#
|
508
602
|
# ==== Returns
|
509
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
|
510
606
|
def capture(*args, &block)
|
511
607
|
ret = nil
|
512
608
|
|
@@ -523,13 +619,16 @@ class Merb::AbstractController
|
|
523
619
|
# ==== Parameters
|
524
620
|
# str<String>:: The string to concatenate to the buffer.
|
525
621
|
# binding<Binding>:: The binding to use for the buffer.
|
622
|
+
#
|
623
|
+
# @api public
|
526
624
|
def concat(str, binding)
|
527
625
|
send("concat_#{@_engine}", str, binding)
|
528
626
|
end
|
529
627
|
|
530
628
|
private
|
629
|
+
# adds a filter to the specified filter chain
|
531
630
|
# ==== Parameters
|
532
|
-
# filters<Array[Filter]>:: The filter
|
631
|
+
# filters<Array[Filter]>:: The filter chain that this should be added to.
|
533
632
|
# filter<Filter>:: A filter that should be added.
|
534
633
|
# opts<Hash>::
|
535
634
|
# Filter options (see class documentation under <tt>Filter Options</tt>).
|
@@ -538,6 +637,8 @@ class Merb::AbstractController
|
|
538
637
|
# ArgumentError::
|
539
638
|
# Both :only and :exclude, or :if and :unless given, if filter is not a
|
540
639
|
# Symbol, String or Proc, or if an unknown option is passed.
|
640
|
+
#
|
641
|
+
# @api private
|
541
642
|
def self.add_filter(filters, filter, opts={})
|
542
643
|
raise(ArgumentError,
|
543
644
|
"You can specify either :only or :exclude but
|
@@ -576,11 +677,13 @@ class Merb::AbstractController
|
|
576
677
|
# inheritence hierarchies.
|
577
678
|
#
|
578
679
|
# ==== Parameters
|
579
|
-
# filters<Array[Filter]>:: The filter
|
680
|
+
# filters<Array[Filter]>:: The filter chain that this should be removed from.
|
580
681
|
# filter<Filter>:: A filter that should be removed.
|
581
682
|
#
|
582
683
|
# ==== Raises
|
583
684
|
# ArgumentError:: filter not Symbol or String.
|
685
|
+
#
|
686
|
+
# @api private
|
584
687
|
def self.skip_filter(filters, filter)
|
585
688
|
raise(ArgumentError, 'You can only skip filters that have a String or Symbol name.') unless
|
586
689
|
[Symbol, String].include? filter.class
|
@@ -600,6 +703,8 @@ class Merb::AbstractController
|
|
600
703
|
#
|
601
704
|
# ==== Examples
|
602
705
|
# normalize_filters!(:only => :new) #=> {:only => [:new]}
|
706
|
+
#
|
707
|
+
# @api public
|
603
708
|
def self.normalize_filters!(opts={})
|
604
709
|
opts[:only] = Array(opts[:only]).map {|x| x.to_s} if opts[:only]
|
605
710
|
opts[:exclude] = Array(opts[:exclude]).map {|x| x.to_s} if opts[:exclude]
|