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
@@ -20,6 +20,8 @@ module Merb
|
|
20
20
|
# :member<Hash>:
|
21
21
|
# Special settings and resources related to a specific member of this
|
22
22
|
# resource.
|
23
|
+
# :identify<Symbol|Array>: The method(s) that should be called on the object
|
24
|
+
# before inserting it into an URL.
|
23
25
|
# :keys<Array>:
|
24
26
|
# A list of the keys to be used instead of :id with the resource in the order of the url.
|
25
27
|
# :singular<Symbol>
|
@@ -63,24 +65,40 @@ module Merb
|
|
63
65
|
# r.resources :posts do |posts|
|
64
66
|
# posts.resources :comments
|
65
67
|
# end
|
66
|
-
|
67
|
-
# @public
|
68
|
+
#
|
69
|
+
# @api public
|
68
70
|
def resources(name, *args, &block)
|
69
71
|
name = name.to_s
|
70
72
|
options = extract_options_from_args!(args) || {}
|
73
|
+
match_opts = options.except(*resource_options)
|
74
|
+
options = options.only(*resource_options)
|
71
75
|
singular = options[:singular] ? options[:singular].to_s : Extlib::Inflection.singularize(name)
|
72
|
-
|
73
|
-
|
76
|
+
klass_name = args.first ? args.first.to_s : Extlib::Inflection.classify(singular)
|
77
|
+
klass = Object.full_const_get(klass_name) rescue nil
|
78
|
+
keys = options.delete(:keys) || options.delete(:key)
|
74
79
|
params = { :controller => options.delete(:controller) || name }
|
75
80
|
collection = options.delete(:collection) || {}
|
76
81
|
member = { :edit => :get, :delete => :get }.merge(options.delete(:member) || {})
|
82
|
+
|
83
|
+
# Use the identifier for the class as a default
|
84
|
+
if klass
|
85
|
+
keys ||= options[:identify]
|
86
|
+
keys ||= @identifiers[klass]
|
87
|
+
elsif options[:identify]
|
88
|
+
raise Error, "The constant #{klass_name} does not exist, please specify the constant for this resource"
|
89
|
+
end
|
90
|
+
|
91
|
+
keys = [ keys || :id ].flatten
|
92
|
+
|
77
93
|
|
78
94
|
# Try pulling :namespace out of options for backwards compatibility
|
79
95
|
options[:name_prefix] ||= nil # Don't use a name_prefix if not needed
|
80
96
|
options[:resource_prefix] ||= nil # Don't use a resource_prefix if not needed
|
81
97
|
options[:controller_prefix] ||= options.delete(:namespace)
|
82
98
|
|
83
|
-
|
99
|
+
context = options[:identify]
|
100
|
+
context = klass && options[:identify] ? identify(klass => options.delete(:identify)) : self
|
101
|
+
context.namespace(name, options).to(params) do |resource|
|
84
102
|
root_keys = keys.map { |k| ":#{k}" }.join("/")
|
85
103
|
|
86
104
|
# => index
|
@@ -102,45 +120,48 @@ module Merb
|
|
102
120
|
end
|
103
121
|
|
104
122
|
# => show
|
105
|
-
resource.match("/#{root_keys}(.:format)", :method => :get).to(:action => "show").
|
106
|
-
name(singular).register_resource(
|
123
|
+
resource.match("/#{root_keys}(.:format)", match_opts.merge(:method => :get)).to(:action => "show").
|
124
|
+
name(singular).register_resource(klass_name)
|
107
125
|
|
108
126
|
# => user defined member routes
|
109
127
|
member.each_pair do |action, method|
|
110
128
|
action = action.to_s
|
111
|
-
resource.match("/#{root_keys}/#{action}(.:format)", :method => method).
|
112
|
-
to(:action => "#{action}").name(action, singular).register_resource(
|
129
|
+
resource.match("/#{root_keys}/#{action}(.:format)", match_opts.merge(:method => method)).
|
130
|
+
to(:action => "#{action}").name(action, singular).register_resource(klass_name, action)
|
113
131
|
end
|
114
132
|
|
115
133
|
# => update
|
116
|
-
resource.match("/#{root_keys}(.:format)", :method => :put).
|
134
|
+
resource.match("/#{root_keys}(.:format)", match_opts.merge(:method => :put)).
|
117
135
|
to(:action => "update")
|
118
136
|
|
119
137
|
# => destroy
|
120
|
-
resource.match("/#{root_keys}(.:format)", :method => :delete).
|
138
|
+
resource.match("/#{root_keys}(.:format)", match_opts.merge(:method => :delete)).
|
121
139
|
to(:action => "destroy")
|
122
140
|
|
123
141
|
if block_given?
|
124
142
|
nested_keys = keys.map do |k|
|
125
143
|
k.to_s == "id" ? ":#{singular}_id" : ":#{k}"
|
126
144
|
end.join("/")
|
145
|
+
|
146
|
+
nested_match_opts = match_opts.except(:id)
|
147
|
+
nested_match_opts["#{singular}_id".to_sym] = match_opts[:id] if match_opts[:id]
|
127
148
|
|
128
149
|
# Procs for building the extra collection/member resource routes
|
129
|
-
placeholder = Router.resource_routes[ [@options[:resource_prefix],
|
150
|
+
placeholder = Router.resource_routes[ [@options[:resource_prefix], klass_name].flatten.compact ]
|
130
151
|
builders = {}
|
131
152
|
|
132
153
|
builders[:collection] = lambda do |action, to, method|
|
133
|
-
resource.before(placeholder).match("/#{action}(.:format)", :method => method).
|
154
|
+
resource.before(placeholder).match("/#{action}(.:format)", match_opts.merge(:method => method)).
|
134
155
|
to(:action => to).name(action, name).register_resource(name, action)
|
135
156
|
end
|
136
157
|
|
137
158
|
builders[:member] = lambda do |action, to, method|
|
138
|
-
resource.match("/#{root_keys}/#{action}(.:format)", :method => method).
|
139
|
-
to(:action => to).name(action, singular).register_resource(
|
159
|
+
resource.match("/#{root_keys}/#{action}(.:format)", match_opts.merge(:method => method)).
|
160
|
+
to(:action => to).name(action, singular).register_resource(klass_name, action)
|
140
161
|
end
|
141
162
|
|
142
|
-
resource.options(:name_prefix => singular, :resource_prefix =>
|
143
|
-
match("/#{nested_keys}").resource_block(builders, &block)
|
163
|
+
resource.options(:name_prefix => singular, :resource_prefix => klass_name).
|
164
|
+
match("/#{nested_keys}", nested_match_opts).resource_block(builders, &block)
|
144
165
|
end
|
145
166
|
end # namespace
|
146
167
|
end # resources
|
@@ -196,8 +217,8 @@ module Merb
|
|
196
217
|
# r.resource :account, :namespace => "admin" do |account|
|
197
218
|
# account.resources :preferences, :controller => "settings"
|
198
219
|
# end
|
199
|
-
#
|
200
|
-
# @public
|
220
|
+
#
|
221
|
+
# @api public
|
201
222
|
def resource(name, *args, &block)
|
202
223
|
name = name.to_s
|
203
224
|
options = extract_options_from_args!(args) || {}
|
@@ -210,6 +231,7 @@ module Merb
|
|
210
231
|
|
211
232
|
self.namespace(name, options).to(params) do |resource|
|
212
233
|
# => show
|
234
|
+
|
213
235
|
resource.match("(.:format)", :method => :get).to(:action => "show").
|
214
236
|
name(name).register_resource(name)
|
215
237
|
|
@@ -244,16 +266,23 @@ module Merb
|
|
244
266
|
|
245
267
|
protected
|
246
268
|
|
269
|
+
#api private
|
247
270
|
def register_resource(*key)
|
248
271
|
key = [@options[:resource_prefix], key].flatten.compact
|
249
272
|
@route.resource = key
|
250
273
|
self
|
251
274
|
end
|
252
275
|
|
276
|
+
#api private
|
253
277
|
def resource_block(builders, &block)
|
254
278
|
behavior = ResourceBehavior.new(builders, @proxy, @conditions, @params, @defaults, @identifiers, @options, @blocks)
|
255
279
|
with_behavior_context(behavior, &block)
|
256
280
|
end
|
281
|
+
|
282
|
+
def resource_options
|
283
|
+
[:singular, :keys, :key, :controller, :member, :collection, :identify,
|
284
|
+
:name_prefix, :resource_prefix, :controller_prefix, :namespace, :path]
|
285
|
+
end
|
257
286
|
|
258
287
|
end # Resources
|
259
288
|
|
@@ -264,12 +293,14 @@ module Merb
|
|
264
293
|
# Adding the collection and member methods to behavior
|
265
294
|
class ResourceBehavior < Behavior #:nodoc:
|
266
295
|
|
296
|
+
#api private
|
267
297
|
def initialize(builders, *args)
|
268
298
|
super(*args)
|
269
299
|
@collection = builders[:collection]
|
270
300
|
@member = builders[:member]
|
271
301
|
end
|
272
302
|
|
303
|
+
#api private
|
273
304
|
def collection(action, options = {})
|
274
305
|
action = action.to_s
|
275
306
|
method = options[:method]
|
@@ -277,6 +308,7 @@ module Merb
|
|
277
308
|
@collection[action, to, method]
|
278
309
|
end
|
279
310
|
|
311
|
+
# @api private
|
280
312
|
def member(action, options = {})
|
281
313
|
action = action.to_s
|
282
314
|
method = options[:method]
|
@@ -79,21 +79,48 @@ module Merb
|
|
79
79
|
@name
|
80
80
|
end
|
81
81
|
|
82
|
-
#
|
82
|
+
# Generates the URL for the route given the passed arguments. The
|
83
|
+
# method will first match the anonymous parameters to route params
|
84
|
+
# and will convert all the parameters according to the specifed
|
85
|
+
# object identifiers.
|
86
|
+
#
|
87
|
+
# Then the named parameters are passed to a compiled generation proc.
|
88
|
+
#
|
89
|
+
# ==== Parameters
|
90
|
+
# args<Array>::
|
91
|
+
# The arguments passed to the public #url method with the name
|
92
|
+
# of the route removed. This is an array of the anonymous parameters
|
93
|
+
# followed by a hash containing the named parameters.
|
94
|
+
#
|
95
|
+
# defaults<Hash>::
|
96
|
+
# A hash of parameters to use to generate the route if there are
|
97
|
+
# any missing required parameters. This is usually the parameters
|
98
|
+
# for the current request
|
99
|
+
#
|
100
|
+
# ==== Returns
|
101
|
+
# String:: The generated URL.
|
83
102
|
def generate(args = [], defaults = {})
|
84
103
|
raise GenerationError, "Cannot generate regexp Routes" if regexp?
|
85
104
|
|
86
105
|
params = extract_options_from_args!(args) || { }
|
87
106
|
|
107
|
+
params.each do |k, v|
|
108
|
+
params[k] = identify(v, k)
|
109
|
+
end
|
110
|
+
|
88
111
|
# Support for anonymous params
|
89
112
|
unless args.empty?
|
90
113
|
# First, let's determine which variables are missing
|
91
114
|
variables = @variables - params.keys
|
92
115
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
116
|
+
args.each do |param|
|
117
|
+
raise GenerationError, "The route has #{@variables.length} variables: #{@variables.inspect}" if variables.empty?
|
118
|
+
|
119
|
+
if identifier = identifier_for(param) and identifier.is_a?(Array)
|
120
|
+
identifier.each { |ident| params[variables.shift] = param.send(ident) }
|
121
|
+
else
|
122
|
+
params[variables.shift] ||= identify(param)
|
123
|
+
end
|
97
124
|
end
|
98
125
|
end
|
99
126
|
|
@@ -101,7 +128,47 @@ module Merb
|
|
101
128
|
uri = Merb::Config[:path_prefix] + uri if Merb::Config[:path_prefix]
|
102
129
|
uri
|
103
130
|
end
|
131
|
+
|
132
|
+
# Identifies the object according to the identifiers set while building
|
133
|
+
# the routes. Identifying an object means picking an instance method to
|
134
|
+
# call on the object that will return a string representation of the
|
135
|
+
# object for the route being generated. If the identifier is an array,
|
136
|
+
# then a param_key must be present and match one of the elements of the
|
137
|
+
# identifier array.
|
138
|
+
#
|
139
|
+
# param_keys that end in _id are treated slightly differently in order
|
140
|
+
# to get nested resources to work correctly.
|
141
|
+
def identify(obj, param_key = nil)
|
142
|
+
identifier = identifier_for(obj)
|
143
|
+
if identifier.is_a?(Array)
|
144
|
+
# First check if the param_key exists as an identifier
|
145
|
+
return obj.send(param_key) if identifier.include?(param_key)
|
146
|
+
# If the param_key ends in _id, just return the object id
|
147
|
+
return obj.id if "#{param_key}" =~ /_id$/
|
148
|
+
# Otherwise, raise an error
|
149
|
+
raise GenerationError, "The object #{obj.inspect} cannot be identified with #{identifier.inspect} for #{param_key}"
|
150
|
+
else
|
151
|
+
identifier ? obj.send(identifier) : obj
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Returns the identifier for the passed object. Built in core ruby classes are
|
156
|
+
# always identified with to_s. The method will return nil in that case (since
|
157
|
+
# to_s is the default for objects that do not have identifiers.)
|
158
|
+
def identifier_for(obj)
|
159
|
+
return if obj.is_a?(String) || obj.is_a?(Symbol) || obj.is_a?(Numeric) ||
|
160
|
+
obj.is_a?(TrueClass) || obj.is_a?(FalseClass) || obj.is_a?(NilClass) ||
|
161
|
+
obj.is_a?(Array) || obj.is_a?(Hash)
|
162
|
+
|
163
|
+
@identifiers.each do |klass, identifier|
|
164
|
+
return identifier if obj.is_a?(klass)
|
165
|
+
end
|
166
|
+
|
167
|
+
return nil
|
168
|
+
end
|
104
169
|
|
170
|
+
# Returns the if statement and return value for for the main
|
171
|
+
# Router.match compiled method.
|
105
172
|
def compiled_statement(first)
|
106
173
|
els_if = first ? ' if ' : ' elsif '
|
107
174
|
|
@@ -110,13 +177,9 @@ module Merb
|
|
110
177
|
|
111
178
|
# First, we need to always return the value of the
|
112
179
|
# deferred block if it explicitly matched the route
|
113
|
-
if @redirects
|
114
|
-
code << " return [#{@index.inspect}, block_result] if request.matched?" << "\n"
|
115
|
-
code << "
|
116
|
-
code << " [#{@index.inspect}, { :url => #{@redirect_url.inspect}, :status => #{@redirect_status.inspect} }]" << "\n"
|
117
|
-
elsif @redirects
|
118
|
-
code << " request.redirects!" << "\n"
|
119
|
-
code << " [#{@index.inspect}, { :url => #{@redirect_url.inspect}, :status => #{@redirect_status.inspect} }]" << "\n"
|
180
|
+
if @redirects
|
181
|
+
code << " return [#{@index.inspect}, block_result] if request.matched?" << "\n" if @deferred_procs.any?
|
182
|
+
code << " [#{@index.inspect}, Merb::Rack::Helpers.redirect(#{@redirect_url.inspect}, :status => #{@redirect_status.inspect})]" << "\n"
|
120
183
|
elsif @deferred_procs.any?
|
121
184
|
code << " [#{@index.inspect}, block_result]" << "\n"
|
122
185
|
else
|
@@ -258,7 +321,7 @@ module Merb
|
|
258
321
|
segments.each_with_index do |segment, i|
|
259
322
|
bits << case
|
260
323
|
when segment.is_a?(String) then segment
|
261
|
-
when segment.is_a?(Symbol) then '#{
|
324
|
+
when segment.is_a?(Symbol) then '#{cached_' + segment.to_s + '}'
|
262
325
|
when segment.is_a?(Array) && segment.any? { |s| !s.is_a?(String) } then "\#{#{@opt_segment_stack.last.shift}}"
|
263
326
|
else ""
|
264
327
|
end
|
@@ -267,16 +330,6 @@ module Merb
|
|
267
330
|
bits
|
268
331
|
end
|
269
332
|
|
270
|
-
def param_for_route(param)
|
271
|
-
case param
|
272
|
-
when String, Symbol, Numeric, TrueClass, FalseClass, NilClass
|
273
|
-
param
|
274
|
-
else
|
275
|
-
_, identifier = @identifiers.find { |klass, _| param.is_a?(klass) }
|
276
|
-
identifier ? param.send(identifier) : param
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
333
|
end
|
281
334
|
|
282
335
|
# === Conditions ===
|
@@ -6,6 +6,8 @@ module Merb
|
|
6
6
|
# Returns stores list constructed from
|
7
7
|
# configured session stores (:session_stores config option)
|
8
8
|
# or default one (:session_store config option).
|
9
|
+
#
|
10
|
+
# @api private
|
9
11
|
def self.session_stores
|
10
12
|
@session_stores ||= begin
|
11
13
|
config_stores = Array(
|
@@ -15,7 +17,7 @@ module Merb
|
|
15
17
|
end
|
16
18
|
end
|
17
19
|
end # Config
|
18
|
-
|
20
|
+
|
19
21
|
# The Merb::Session module gets mixed into Merb::SessionContainer to allow
|
20
22
|
# app-level functionality (usually found in app/models/merb/session.rb) for
|
21
23
|
# session.
|
@@ -23,35 +25,37 @@ module Merb
|
|
23
25
|
# You can use this module to implement additional methods to simplify
|
24
26
|
# building wizard-like application components,
|
25
27
|
# authentication frameworks, etc.
|
28
|
+
#
|
29
|
+
# Session configuration options:
|
30
|
+
#
|
31
|
+
# :session_id_key The key by which a session value/id is
|
32
|
+
# retrieved; defaults to _session_id
|
33
|
+
#
|
34
|
+
# :session_expiry When to expire the session cookie;
|
35
|
+
# by defaults session expires when browser quits.
|
36
|
+
#
|
37
|
+
# :session_secret_key A secret string which is used to sign/validate
|
38
|
+
# session data; min. 16 chars
|
39
|
+
#
|
40
|
+
# :default_cookie_domain The default domain to write cookies for.
|
26
41
|
module Session
|
27
42
|
end
|
28
|
-
|
43
|
+
|
29
44
|
# This is mixed into Merb::Controller on framework boot.
|
30
45
|
module SessionMixin
|
31
46
|
# Raised when no suitable session store has been setup.
|
32
47
|
class NoSessionContainer < StandardError; end
|
33
|
-
|
48
|
+
|
34
49
|
# Raised when storing more data than the available space reserved.
|
35
50
|
class SessionOverflow < StandardError; end
|
36
|
-
|
37
|
-
#
|
38
|
-
#
|
39
|
-
# :session_id_key The key by which a session value/id is
|
40
|
-
# retrieved; defaults to _session_id
|
41
|
-
#
|
42
|
-
# :session_expiry When to expire the session cookie;
|
43
|
-
# defaults to 2 weeks
|
44
|
-
#
|
45
|
-
# :session_secret_key A secret string which is used to sign/validate
|
46
|
-
# session data; min. 16 chars
|
47
|
-
#
|
48
|
-
# :default_cookie_domain The default domain to write cookies for.
|
51
|
+
|
52
|
+
# @api private
|
49
53
|
def self.included(base)
|
50
54
|
# Register a callback to finalize sessions - needs to run before the cookie
|
51
55
|
# callback extracts Set-Cookie headers from request.cookies.
|
52
56
|
base._after_dispatch_callbacks.unshift lambda { |c| c.request.finalize_session }
|
53
57
|
end
|
54
|
-
|
58
|
+
|
55
59
|
# ==== Parameters
|
56
60
|
# session_store<String>:: The type of session store to access.
|
57
61
|
#
|
@@ -60,9 +64,9 @@ module Merb
|
|
60
64
|
def session(session_store = nil)
|
61
65
|
request.session(session_store)
|
62
66
|
end
|
63
|
-
|
67
|
+
|
64
68
|
# Module methods
|
65
|
-
|
69
|
+
|
66
70
|
# ==== Returns
|
67
71
|
# String:: A random 32 character string for use as a unique session ID.
|
68
72
|
def rand_uuid
|
@@ -77,59 +81,76 @@ module Merb
|
|
77
81
|
]
|
78
82
|
"%04x%04x%04x%04x%04x%06x%06x" % values
|
79
83
|
end
|
80
|
-
|
84
|
+
|
81
85
|
# Marks this session as needing a new cookie.
|
86
|
+
#
|
87
|
+
# @api private
|
82
88
|
def needs_new_cookie!
|
83
89
|
@_new_cookie = true
|
84
90
|
end
|
85
|
-
|
91
|
+
|
92
|
+
# Does session need new cookie?
|
93
|
+
#
|
94
|
+
# ==== Returns
|
95
|
+
# Boolean:: true if a new cookie is needed, false otherwise.
|
96
|
+
#
|
97
|
+
# @api private
|
86
98
|
def needs_new_cookie?
|
87
99
|
@_new_cookie
|
88
100
|
end
|
89
|
-
|
101
|
+
|
90
102
|
module_function :rand_uuid, :needs_new_cookie!, :needs_new_cookie?
|
91
|
-
|
103
|
+
|
92
104
|
module RequestMixin
|
93
|
-
|
105
|
+
|
106
|
+
# Adds class methods to Merb::Request object.
|
107
|
+
# Sets up repository of session store types.
|
108
|
+
# Sets the session ID key and expiry values.
|
94
109
|
def self.included(base)
|
95
110
|
base.extend ClassMethods
|
96
|
-
|
111
|
+
|
97
112
|
# Keep track of all known session store types.
|
98
113
|
base.cattr_accessor :registered_session_types
|
99
114
|
base.registered_session_types = Dictionary.new
|
100
115
|
base.class_inheritable_accessor :_session_id_key, :_session_secret_key,
|
101
116
|
:_session_expiry
|
102
|
-
|
117
|
+
|
103
118
|
base._session_id_key = Merb::Config[:session_id_key] || '_session_id'
|
104
119
|
base._session_expiry = Merb::Config[:session_expiry] || 0
|
105
120
|
base._session_secret_key = Merb::Config[:session_secret_key]
|
106
121
|
end
|
107
|
-
|
122
|
+
|
108
123
|
module ClassMethods
|
109
|
-
|
124
|
+
|
110
125
|
# ==== Parameters
|
111
126
|
# name<~to_sym>:: Name of the session type to register.
|
112
127
|
# class_name<String>:: The corresponding class name.
|
113
128
|
#
|
114
129
|
# === Notres
|
115
130
|
# This is automatically called when Merb::SessionContainer is subclassed.
|
131
|
+
#
|
132
|
+
# @api private
|
116
133
|
def register_session_type(name, class_name)
|
117
134
|
self.registered_session_types[name.to_sym] = class_name
|
118
135
|
end
|
119
|
-
|
136
|
+
|
120
137
|
end
|
121
|
-
|
138
|
+
|
122
139
|
# The default session store type.
|
140
|
+
#
|
141
|
+
# @api private
|
123
142
|
def default_session_store
|
124
143
|
Merb::Config[:session_store] && Merb::Config[:session_store].to_sym
|
125
144
|
end
|
126
|
-
|
145
|
+
|
127
146
|
# ==== Returns
|
128
147
|
# Hash:: All active session stores by type.
|
148
|
+
#
|
149
|
+
# @api private
|
129
150
|
def session_stores
|
130
151
|
@session_stores ||= {}
|
131
152
|
end
|
132
|
-
|
153
|
+
|
133
154
|
# Returns session container. Merb is able to handle multiple session
|
134
155
|
# stores, hence a parameter to pick it.
|
135
156
|
#
|
@@ -140,6 +161,12 @@ module Merb
|
|
140
161
|
# === Notes
|
141
162
|
# If no suitable session store type is given, it defaults to
|
142
163
|
# cookie-based sessions.
|
164
|
+
#
|
165
|
+
# ==== Returns
|
166
|
+
# SessionContainer::
|
167
|
+
# an instance of a session store extending Merb::SessionContainer.
|
168
|
+
#
|
169
|
+
# @api public
|
143
170
|
def session(session_store = nil)
|
144
171
|
session_store ||= default_session_store
|
145
172
|
if class_name = self.class.registered_session_types[session_store]
|
@@ -154,12 +181,14 @@ module Merb
|
|
154
181
|
raise NoSessionContainer, msg
|
155
182
|
end
|
156
183
|
end
|
157
|
-
|
184
|
+
|
158
185
|
# ==== Parameters
|
159
186
|
# new_session<Merb::SessionContainer>:: A session store instance.
|
160
187
|
#
|
161
188
|
# === Notes
|
162
189
|
# The session is assigned internally by its session_store_type key.
|
190
|
+
#
|
191
|
+
# @api private
|
163
192
|
def session=(new_session)
|
164
193
|
if self.session?(new_session.class.session_store_type)
|
165
194
|
original_session_id = self.session(new_session.class.session_store_type).session_id
|
@@ -169,21 +198,30 @@ module Merb
|
|
169
198
|
end
|
170
199
|
session_stores[new_session.class.session_store_type] = new_session
|
171
200
|
end
|
172
|
-
|
201
|
+
|
173
202
|
# Whether a session has been setup
|
203
|
+
#
|
204
|
+
# ==== Returns
|
205
|
+
# Boolean:: true if the session is part of the session stores configured.
|
206
|
+
#
|
207
|
+
# @api private
|
174
208
|
def session?(session_store = nil)
|
175
209
|
(session_store ? [session_store] : session_stores).any? do |type, store|
|
176
210
|
store.is_a?(Merb::SessionContainer)
|
177
211
|
end
|
178
212
|
end
|
179
|
-
|
213
|
+
|
180
214
|
# Teardown and/or persist the current sessions.
|
215
|
+
#
|
216
|
+
# @api private
|
181
217
|
def finalize_session
|
182
218
|
session_stores.each { |name, store| store.finalize(self) }
|
183
219
|
end
|
184
220
|
alias :finalize_sessions :finalize_session
|
185
|
-
|
221
|
+
|
186
222
|
# Assign default cookie values
|
223
|
+
#
|
224
|
+
# @api private
|
187
225
|
def default_cookies
|
188
226
|
defaults = {}
|
189
227
|
if route && route.allow_fixation? && params.key?(_session_id_key)
|
@@ -198,6 +236,8 @@ module Merb
|
|
198
236
|
# ==== Parameters
|
199
237
|
# value<String>:: The value of the session cookie; either the session id or the actual encoded data.
|
200
238
|
# options<Hash>:: Cookie options like domain, path and expired.
|
239
|
+
#
|
240
|
+
# @api private
|
201
241
|
def set_session_cookie_value(value, options = {})
|
202
242
|
defaults = {}
|
203
243
|
defaults[:expires] = Time.now + _session_expiry if _session_expiry > 0
|
@@ -207,12 +247,16 @@ module Merb
|
|
207
247
|
|
208
248
|
# ==== Returns
|
209
249
|
# String:: The value of the session cookie; either the session id or the actual encoded data.
|
250
|
+
#
|
251
|
+
# @api private
|
210
252
|
def session_cookie_value
|
211
253
|
cookies[_session_id_key]
|
212
254
|
end
|
213
255
|
alias :session_id :session_cookie_value
|
214
256
|
|
215
257
|
# Destroy the session cookie.
|
258
|
+
#
|
259
|
+
# @api private
|
216
260
|
def destroy_session_cookie
|
217
261
|
cookies.delete(_session_id_key)
|
218
262
|
end
|