merb 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README +138 -56
- data/Rakefile +23 -8
- data/app_generators/merb/templates/Rakefile +13 -0
- data/app_generators/merb/templates/app/helpers/global_helper.rb +1 -1
- data/app_generators/merb/templates/app/views/exceptions/internal_server_error.html.erb +12 -3
- data/app_generators/merb/templates/config/merb.yml +14 -1
- data/app_generators/merb/templates/spec/spec_helper.rb +6 -0
- data/app_generators/merb/templates/test/test_helper.rb +1 -0
- data/lib/merb.rb +27 -7
- data/lib/merb/abstract_controller.rb +76 -36
- data/lib/merb/caching/store/memcache.rb +20 -0
- data/lib/merb/constants.rb +2 -4
- data/lib/merb/controller.rb +44 -2
- data/lib/merb/core_ext/get_args.rb +23 -4
- data/lib/merb/core_ext/hash.rb +16 -11
- data/lib/merb/core_ext/inflections.rb +1 -1
- data/lib/merb/core_ext/kernel.rb +106 -26
- data/lib/merb/core_ext/numeric.rb +1 -1
- data/lib/merb/core_ext/string.rb +10 -13
- data/lib/merb/dispatcher.rb +2 -2
- data/lib/merb/exceptions.rb +3 -1
- data/lib/merb/logger.rb +15 -6
- data/lib/merb/mail_controller.rb +18 -2
- data/lib/merb/mailer.rb +1 -1
- data/lib/merb/mixins/controller.rb +64 -228
- data/lib/merb/mixins/erubis_capture.rb +1 -1
- data/lib/merb/mixins/general_controller.rb +258 -0
- data/lib/merb/mixins/render.rb +45 -24
- data/lib/merb/mixins/responder.rb +89 -18
- data/lib/merb/mixins/view_context.rb +32 -5
- data/lib/merb/mixins/web_controller.rb +8 -1
- data/lib/merb/mongrel_handler.rb +27 -17
- data/lib/merb/part_controller.rb +10 -0
- data/lib/merb/request.rb +34 -14
- data/lib/merb/router.rb +77 -45
- data/lib/merb/server.rb +116 -72
- data/lib/merb/session/cookie_store.rb +14 -22
- data/lib/merb/session/mem_cache_session.rb +2 -2
- data/lib/merb/session/memory_session.rb +12 -1
- data/lib/merb/template/erubis.rb +31 -0
- data/lib/merb/template/haml.rb +4 -14
- data/lib/merb/template/xml_builder.rb +1 -1
- data/lib/merb/test/helper.rb +90 -18
- data/lib/merb/test/rspec.rb +145 -74
- data/lib/merb/version.rb +11 -0
- data/lib/merb/view_context.rb +3 -6
- data/lib/patch +69 -0
- data/lib/tasks/merb.rake +1 -1
- data/spec/fixtures/config/environments/environment_config_test.yml +1 -0
- data/spec/fixtures/controllers/render_spec_controllers.rb +63 -4
- data/spec/fixtures/views/examples/template_throw_content_without_block.html.erb +3 -0
- data/spec/fixtures/views/partials/_erubis.html.erb +1 -1
- data/spec/merb/abstract_controller_spec.rb +1 -0
- data/spec/merb/controller_filters_spec.rb +68 -3
- data/spec/merb/controller_spec.rb +35 -68
- data/spec/merb/cookie_store_spec.rb +7 -20
- data/spec/merb/core_ext_spec.rb +35 -1
- data/spec/merb/dispatch_spec.rb +8 -2
- data/spec/merb/generator_spec.rb +12 -4
- data/spec/merb/mail_controller_spec.rb +33 -0
- data/spec/merb/part_controller_spec.rb +33 -1
- data/spec/merb/render_spec.rb +74 -0
- data/spec/merb/request_spec.rb +43 -0
- data/spec/merb/responder_spec.rb +1 -0
- data/spec/merb/router_spec.rb +118 -13
- data/spec/merb/server_spec.rb +19 -0
- data/spec/merb/view_context_spec.rb +31 -3
- data/spec/spec_helper.rb +8 -0
- data/spec/spec_helpers/url_shared_behaviour.rb +112 -0
- metadata +124 -87
@@ -48,7 +48,16 @@ module Merb
|
|
48
48
|
# image_tag('http://test.com/foo.gif')
|
49
49
|
# # => <img src="http://test.com/foo.gif">
|
50
50
|
def image_tag(img, opts={})
|
51
|
-
opts[:path] ||=
|
51
|
+
opts[:path] ||=
|
52
|
+
if img =~ %r{^https?://}
|
53
|
+
''
|
54
|
+
else
|
55
|
+
if Merb::Server.config[:path_prefix]
|
56
|
+
Merb::Server.config[:path_prefix] + '/images/'
|
57
|
+
else
|
58
|
+
'/images/'
|
59
|
+
end
|
60
|
+
end
|
52
61
|
opts[:src] ||= opts.delete(:path) + img
|
53
62
|
%{<img #{ opts.to_xml_attributes } />}
|
54
63
|
end
|
@@ -258,7 +267,9 @@ module Merb
|
|
258
267
|
include_tag = ""
|
259
268
|
scripts.each do |script|
|
260
269
|
script = script.to_s
|
261
|
-
|
270
|
+
url = "/javascripts/#{script =~ /\.js$/ ? script : script + '.js'}"
|
271
|
+
url = Merb::Server.config[:path_prefix] + url if Merb::Server.config[:path_prefix]
|
272
|
+
include_tag << %Q|<script src="#{url}" type="text/javascript">//</script>\n|
|
262
273
|
end
|
263
274
|
include_tag
|
264
275
|
end
|
@@ -287,7 +298,9 @@ module Merb
|
|
287
298
|
include_tag = ""
|
288
299
|
scripts.each do |script|
|
289
300
|
script = script.to_s
|
290
|
-
|
301
|
+
url = "/stylesheets/#{script =~ /\.css$/ ? script : script + '.css'}"
|
302
|
+
url = Merb::Server.config[:path_prefix] + url if Merb::Server.config[:path_prefix]
|
303
|
+
include_tag << %Q|<link href="#{url}" media="all" rel="Stylesheet" type="text/css"/>\n|
|
291
304
|
end
|
292
305
|
include_tag
|
293
306
|
end
|
@@ -339,8 +352,22 @@ module Merb
|
|
339
352
|
# You can use catch_content :header anywhere in your templates.
|
340
353
|
#
|
341
354
|
# <%= catch_content :header %>
|
342
|
-
|
343
|
-
|
355
|
+
#
|
356
|
+
# You may find that you have trouble using thrown content inside a helper method
|
357
|
+
# There are a couple of mechanisms to get around this.
|
358
|
+
#
|
359
|
+
# 1. Pass the content in as a string instead of a block
|
360
|
+
#
|
361
|
+
# Example:
|
362
|
+
#
|
363
|
+
# throw_content(:header, "Hello World")
|
364
|
+
#
|
365
|
+
# In Haml Templates, use the
|
366
|
+
#
|
367
|
+
#
|
368
|
+
def throw_content(name, content = "", &block)
|
369
|
+
content << capture(&block) if block_given?
|
370
|
+
controller.thrown_content[name] << content
|
344
371
|
end
|
345
372
|
|
346
373
|
# Concat will concatenate text directly to the buffer of the template.
|
@@ -1,5 +1,8 @@
|
|
1
|
+
# Used by secondary actions (a PartsController or the view)
|
2
|
+
# to provide the standard objects associated with each request.
|
3
|
+
|
1
4
|
module Merb
|
2
|
-
module WebControllerMixin
|
5
|
+
module WebControllerMixin #:nodoc:
|
3
6
|
|
4
7
|
def request
|
5
8
|
@web_controller.request
|
@@ -24,6 +27,10 @@ module Merb
|
|
24
27
|
def response
|
25
28
|
@web_controller.response
|
26
29
|
end
|
30
|
+
|
31
|
+
def route
|
32
|
+
request.route
|
33
|
+
end
|
27
34
|
|
28
35
|
end
|
29
36
|
end
|
data/lib/merb/mongrel_handler.rb
CHANGED
@@ -26,8 +26,9 @@ class MerbHandler < Mongrel::HttpHandler
|
|
26
26
|
# Take the name of a directory and use that as the doc root or public
|
27
27
|
# directory of your site. This is set to the root of your merb app + '/public'
|
28
28
|
# by default.
|
29
|
-
def initialize(dir, opts = {})
|
29
|
+
def initialize(dir, mongrel_x_sendfile=true, opts = {})
|
30
30
|
@files = Mongrel::DirHandler.new(dir,false)
|
31
|
+
@mongrel_x_sendfile = mongrel_x_sendfile
|
31
32
|
end
|
32
33
|
|
33
34
|
# process incoming http requests and do a number of things
|
@@ -42,12 +43,12 @@ class MerbHandler < Mongrel::HttpHandler
|
|
42
43
|
# header. if you set this header to the path of a file in your controller
|
43
44
|
# then mongrel will serve the file directly and your controller can go on
|
44
45
|
# processing other requests.
|
45
|
-
def process(request, response)
|
46
|
+
def process(request, response)
|
47
|
+
return if response.socket.closed?
|
48
|
+
|
46
49
|
start = Time.now
|
47
50
|
benchmarks = {}
|
48
51
|
|
49
|
-
return if response.socket.closed?
|
50
|
-
|
51
52
|
MERB_LOGGER.info("\nRequest: REQUEST_URI: #{
|
52
53
|
request.params[Mongrel::Const::REQUEST_URI]} (#{Time.now.strftime("%Y-%m-%d %H:%M:%S")})")
|
53
54
|
|
@@ -107,19 +108,28 @@ class MerbHandler < Mongrel::HttpHandler
|
|
107
108
|
end
|
108
109
|
|
109
110
|
if sendfile
|
110
|
-
|
111
|
-
|
112
|
-
benchmarks[:sendfile_time]
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
111
|
+
if @mongrel_x_sendfile
|
112
|
+
# we want to emulate X-Sendfile header internally in mongrel
|
113
|
+
benchmarks[:sendfile_time] = Time.now - start
|
114
|
+
MERB_LOGGER.info("X-SENDFILE: #{sendfile}\nComplete Request took: #{
|
115
|
+
benchmarks[:sendfile_time]} seconds")
|
116
|
+
file_status = File.stat(sendfile)
|
117
|
+
response.status = 200
|
118
|
+
# Set the last modified times as well and etag for all files
|
119
|
+
response.header[Mongrel::Const::LAST_MODIFIED] = file_status.mtime.httpdate
|
120
|
+
# Calculated the same as apache, not sure how well the works on win32
|
121
|
+
response.header[Mongrel::Const::ETAG] = Mongrel::Const::ETAG_FORMAT % [file_status.mtime.to_i, file_status.size, file_status.ino]
|
122
|
+
# Send a status with out content length
|
123
|
+
response.send_status(file_status.size)
|
124
|
+
response.send_header
|
125
|
+
response.send_file(sendfile)
|
126
|
+
else
|
127
|
+
# we want to pass thru the X-Sendfile header so apache or whatever
|
128
|
+
# front server can handle it
|
129
|
+
response.header['X-Sendfile'] = sendfile
|
130
|
+
response.header['Content-length'] = clength || File.size(sendfile)
|
131
|
+
response.finished
|
132
|
+
end
|
123
133
|
elsif controller.body.respond_to? :read
|
124
134
|
response.send_status(clength)
|
125
135
|
response.send_header
|
data/lib/merb/part_controller.rb
CHANGED
@@ -15,5 +15,15 @@ module Merb
|
|
15
15
|
params[:action] = old_action
|
16
16
|
@_body
|
17
17
|
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# This method is here to overwrite the one in the general_controller mixin
|
22
|
+
# The method ensures that when a url is generated with a hash, it contains a controller
|
23
|
+
def get_controller_for_url_generation(opts)
|
24
|
+
controller = opts[:controller] || @web_controller.params[:controller]
|
25
|
+
raise "No Controller Specified for url()" unless controller
|
26
|
+
controller
|
27
|
+
end
|
18
28
|
end
|
19
29
|
end
|
data/lib/merb/request.rb
CHANGED
@@ -22,7 +22,11 @@ module Merb
|
|
22
22
|
when :get, :head, :put, :delete
|
23
23
|
request_method
|
24
24
|
when :post
|
25
|
-
|
25
|
+
if self.class.parse_multipart_params
|
26
|
+
m = body_and_query_params.merge(multipart_params)['_method']
|
27
|
+
else
|
28
|
+
m = body_and_query_params['_method']
|
29
|
+
end
|
26
30
|
m.downcase! if m
|
27
31
|
METHODS.include?(m) ? m.to_sym : :post
|
28
32
|
else
|
@@ -65,21 +69,31 @@ module Merb
|
|
65
69
|
@body_and_query_params ||= begin
|
66
70
|
h = query_params
|
67
71
|
h.merge!(body_params) if body_params
|
68
|
-
h
|
72
|
+
h.to_mash
|
69
73
|
end
|
70
74
|
end
|
71
75
|
|
72
76
|
def multipart_params
|
73
|
-
@multipart_params ||=
|
74
|
-
|
75
|
-
|
77
|
+
@multipart_params ||=
|
78
|
+
begin
|
79
|
+
if Merb::Const::MULTIPART_REGEXP =~ content_type
|
80
|
+
if @body.size <= 0
|
81
|
+
{}
|
82
|
+
else
|
83
|
+
self.class.parse_multipart(@body, $1, content_length)
|
84
|
+
end
|
85
|
+
else
|
86
|
+
{}
|
87
|
+
end
|
88
|
+
rescue ControllerExceptions::MultiPartParseError => e
|
89
|
+
@multipart_params = {}
|
90
|
+
raise e
|
76
91
|
end
|
77
|
-
end
|
78
92
|
end
|
79
93
|
|
80
94
|
def json_params
|
81
95
|
@json_params ||= begin
|
82
|
-
if
|
96
|
+
if Merb::Const::JSON_MIME_TYPE_REGEXP.match(content_type)
|
83
97
|
JSON.parse(raw_post)
|
84
98
|
end
|
85
99
|
end
|
@@ -87,7 +101,7 @@ module Merb
|
|
87
101
|
|
88
102
|
def xml_params
|
89
103
|
@xml_params ||= begin
|
90
|
-
if
|
104
|
+
if Merb::Const::XML_MIME_TYPE_REGEXP.match(content_type)
|
91
105
|
Hash.from_xml(raw_post) rescue Mash.new
|
92
106
|
end
|
93
107
|
end
|
@@ -97,7 +111,7 @@ module Merb
|
|
97
111
|
|
98
112
|
def params
|
99
113
|
@params ||= begin
|
100
|
-
h =
|
114
|
+
h = body_and_query_params.merge(route_params)
|
101
115
|
h.merge!(multipart_params) if self.class.parse_multipart_params && multipart_params
|
102
116
|
h.merge!(json_params) if self.class.parse_json_params && json_params
|
103
117
|
h.merge!(xml_params) if self.class.parse_xml_params && xml_params
|
@@ -128,7 +142,11 @@ module Merb
|
|
128
142
|
end
|
129
143
|
|
130
144
|
def controller_name
|
131
|
-
route_params[:
|
145
|
+
if route_params[:namespace]
|
146
|
+
route_params[:namespace] + '/' + route_params[:controller]
|
147
|
+
else
|
148
|
+
route_params[:controller]
|
149
|
+
end
|
132
150
|
end
|
133
151
|
|
134
152
|
def controller_class
|
@@ -157,7 +175,9 @@ module Merb
|
|
157
175
|
|
158
176
|
def raw_post
|
159
177
|
@body.rewind
|
160
|
-
@body.read
|
178
|
+
res = @body.read
|
179
|
+
@body.rewind
|
180
|
+
res
|
161
181
|
end
|
162
182
|
|
163
183
|
# Returns true if the request is an Ajax request.
|
@@ -334,7 +354,7 @@ module Merb
|
|
334
354
|
bufsize = 16384
|
335
355
|
content_length -= boundary_size
|
336
356
|
status = input.read(boundary_size)
|
337
|
-
raise
|
357
|
+
raise ControllerExceptions::MultiPartParseError, "bad content body:\n'#{status}' should == '#{boundary + EOL}'" unless status == boundary + EOL
|
338
358
|
rx = /(?:#{EOL})?#{Regexp.quote(boundary,'n')}(#{EOL}|--)/
|
339
359
|
loop {
|
340
360
|
head = nil
|
@@ -369,7 +389,7 @@ module Merb
|
|
369
389
|
read_size = bufsize < content_length ? bufsize : content_length
|
370
390
|
if( read_size > 0 )
|
371
391
|
c = input.read(read_size)
|
372
|
-
raise
|
392
|
+
raise ControllerExceptions::MultiPartParseError, "bad content body" if c.nil? || c.empty?
|
373
393
|
buf << c
|
374
394
|
content_length -= c.size
|
375
395
|
end
|
@@ -389,7 +409,7 @@ module Merb
|
|
389
409
|
:filename => File.basename(filename),
|
390
410
|
:content_type => content_type,
|
391
411
|
:tempfile => body,
|
392
|
-
:size => File.size(body)
|
412
|
+
:size => File.size(body.path)
|
393
413
|
}
|
394
414
|
else
|
395
415
|
data = body
|
data/lib/merb/router.rb
CHANGED
@@ -14,18 +14,18 @@ module Merb
|
|
14
14
|
def append(&block)
|
15
15
|
prepare(@@routes, [], &block)
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def prepend(&block)
|
19
19
|
prepare([], @@routes, &block)
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def prepare(first = [], last = [], &block)
|
23
23
|
@@routes = []
|
24
24
|
yield Behavior.new({}, {:action => 'index'}) # defaults
|
25
25
|
@@routes = first + @@routes + last
|
26
26
|
compile
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def compiled_statement
|
30
30
|
@@compiled_statement = "lambda { |request, params|\n"
|
31
31
|
@@compiled_statement << " cached_path = request.path\n cached_method = request.method.to_s\n "
|
@@ -35,17 +35,17 @@ module Merb
|
|
35
35
|
@@compiled_statement << " end\n"
|
36
36
|
@@compiled_statement << "}"
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def compile
|
40
40
|
meta_def(:match, &eval(compiled_statement))
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
def generate(name, params = {}, fallback = {})
|
44
44
|
raise "Named route not found: #{name}" unless @@named_routes.has_key? name
|
45
|
-
@@named_routes[name].generate(params, fallback)
|
45
|
+
@@named_routes[name].generate(params, fallback).sub(/\/$/, '').squeeze("/")
|
46
46
|
end
|
47
47
|
end # self
|
48
|
-
|
48
|
+
|
49
49
|
# Cache procs for future reference in eval statement
|
50
50
|
class CachedProc
|
51
51
|
@@index = 0
|
@@ -70,7 +70,7 @@ module Merb
|
|
70
70
|
def [](index) @@list[index] end
|
71
71
|
end
|
72
72
|
end # CachedProc
|
73
|
-
|
73
|
+
|
74
74
|
class Route
|
75
75
|
attr_reader :conditions, :conditional_block
|
76
76
|
attr_reader :params, :behavior, :segments, :index, :symbol
|
@@ -82,19 +82,31 @@ module Merb
|
|
82
82
|
@segments = segments_from_path(path)
|
83
83
|
end
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
|
+
def to_s
|
87
|
+
r = ""
|
88
|
+
segments.each {|s|
|
89
|
+
if s.is_a?(Symbol)
|
90
|
+
r << ":#{s}"
|
91
|
+
else
|
92
|
+
r << s
|
93
|
+
end
|
94
|
+
}
|
95
|
+
r
|
96
|
+
end
|
97
|
+
|
86
98
|
# Registers itself in the Router.routes array
|
87
99
|
def register
|
88
100
|
@index = Router.routes.size
|
89
101
|
Router.routes << self
|
90
102
|
self
|
91
103
|
end
|
92
|
-
|
104
|
+
|
93
105
|
# Get the symbols out of the segments array
|
94
106
|
def symbol_segments
|
95
107
|
segments.select{ |s| s.is_a?(Symbol) }
|
96
108
|
end
|
97
|
-
|
109
|
+
|
98
110
|
# Turn a path into string and symbol segments so it can be reconstructed, as in the
|
99
111
|
# case of a named route.
|
100
112
|
def segments_from_path(path)
|
@@ -109,17 +121,17 @@ module Merb
|
|
109
121
|
segments << strip[path] unless path.empty?
|
110
122
|
segments
|
111
123
|
end
|
112
|
-
|
124
|
+
|
113
125
|
# Name this route
|
114
126
|
def name(symbol = nil)
|
115
127
|
@symbol = symbol
|
116
128
|
Router.named_routes[@symbol] = self
|
117
129
|
end
|
118
|
-
|
130
|
+
|
119
131
|
def regexp?
|
120
132
|
behavior.regexp? || behavior.send(:ancestors).any?{ |a| a.regexp? }
|
121
133
|
end
|
122
|
-
|
134
|
+
|
123
135
|
# Given a hash of +params+, returns a string using the stored route segments
|
124
136
|
# for reconstruction of the URL.
|
125
137
|
def generate(params = {}, fallback = {})
|
@@ -143,7 +155,7 @@ module Merb
|
|
143
155
|
(value.respond_to?(:to_param) ? value.to_param : value).to_s
|
144
156
|
end.join
|
145
157
|
end
|
146
|
-
|
158
|
+
|
147
159
|
def if_conditions(params_as_string)
|
148
160
|
cond = []
|
149
161
|
condition_string = proc do |key, value, regexp_string|
|
@@ -157,7 +169,7 @@ module Merb
|
|
157
169
|
" (#{value.inspect} =~ #{regexp_string}" + captures + ")"
|
158
170
|
end
|
159
171
|
@conditions.each_pair do |key, value|
|
160
|
-
|
172
|
+
|
161
173
|
# Note: =~ is slightly faster than .match
|
162
174
|
cond << case key
|
163
175
|
when :path then condition_string[key, value, "cached_path"]
|
@@ -194,7 +206,7 @@ module Merb
|
|
194
206
|
code << " [#{@index.inspect}, {#{params_as_string}}]\n"
|
195
207
|
end
|
196
208
|
end
|
197
|
-
|
209
|
+
|
198
210
|
def behavior_trace
|
199
211
|
if @behavior
|
200
212
|
puts @behavior.send(:ancestors).reverse.map{|a| a.inspect}.join("\n"); puts @behavior.inspect; puts
|
@@ -203,7 +215,7 @@ module Merb
|
|
203
215
|
end
|
204
216
|
end
|
205
217
|
end # Route
|
206
|
-
|
218
|
+
|
207
219
|
# The Behavior class is an interim route-building class that ties pattern-matching +conditions+ to
|
208
220
|
# output parameters, +params+.
|
209
221
|
class Behavior
|
@@ -223,7 +235,7 @@ module Merb
|
|
223
235
|
def add(path, params = {})
|
224
236
|
match(path).to(params)
|
225
237
|
end
|
226
|
-
|
238
|
+
|
227
239
|
# Matches a +path+ and any number of optional request methods as conditions of a route.
|
228
240
|
# Alternatively, +path+ can be a hash of conditions, in which case +conditions+ is ignored.
|
229
241
|
# Yields 'self' so that sub-matching may occur.
|
@@ -235,7 +247,7 @@ module Merb
|
|
235
247
|
end
|
236
248
|
match_without_path(conditions, &block)
|
237
249
|
end
|
238
|
-
|
250
|
+
|
239
251
|
def match_without_path(conditions = {})
|
240
252
|
new_behavior = self.class.new(conditions, {}, self)
|
241
253
|
conditions.delete :path if ['', '^$'].include?(conditions[:path])
|
@@ -247,7 +259,7 @@ module Merb
|
|
247
259
|
@params.merge!(params)
|
248
260
|
Route.new(compiled_conditions, compiled_params, self, &conditional_block)
|
249
261
|
end
|
250
|
-
|
262
|
+
|
251
263
|
# Creates a Route from one or more Behavior objects, unless a +block+ is passed in.
|
252
264
|
# If a block is passed in, a Behavior object is yielded and further .to operations
|
253
265
|
# may be called in the block. For example:
|
@@ -266,7 +278,7 @@ module Merb
|
|
266
278
|
to_route(params).register
|
267
279
|
end
|
268
280
|
end
|
269
|
-
|
281
|
+
|
270
282
|
# Takes a block and stores it for defered conditional routes. The block takes the
|
271
283
|
# +request+ object and the +params+ hash as parameters and should return a hash of params.
|
272
284
|
# For example:
|
@@ -281,7 +293,7 @@ module Merb
|
|
281
293
|
def default_routes(params = {}, &block)
|
282
294
|
match(%r[/:controller(/:action(/:id)?)?(\.:format)?]).to(params, &block)
|
283
295
|
end
|
284
|
-
|
296
|
+
|
285
297
|
def to_resources(params = {}, &block)
|
286
298
|
many_behaviors_to(resources_behaviors, params, &block)
|
287
299
|
end
|
@@ -293,34 +305,47 @@ module Merb
|
|
293
305
|
|
294
306
|
singular = name.to_s.singularize
|
295
307
|
|
296
|
-
|
297
|
-
|
308
|
+
namespace = options[:namespace] || merged_params[:namespace]
|
309
|
+
|
310
|
+
if options[:name_prefix].nil? && namespace != nil
|
311
|
+
options[:name_prefix] = "#{namespace}_"
|
312
|
+
end
|
298
313
|
|
314
|
+
name_prefix = options.delete(:name_prefix)
|
315
|
+
|
316
|
+
|
317
|
+
route_plural_name = "#{name_prefix}#{name}"
|
318
|
+
route_singular_name = "#{name_prefix}#{singular}"
|
319
|
+
|
320
|
+
member = options.delete(:member)
|
321
|
+
collection = options.delete(:collection)
|
322
|
+
|
299
323
|
# Add optional member actions
|
300
|
-
|
324
|
+
|
325
|
+
member.each_pair do |action, methods|
|
301
326
|
conditions = {:path => %r[^/:id[/;]#{action}$], :method => /^(#{[methods].flatten.join("|")})$/}
|
302
327
|
behaviors << Behavior.new(conditions, {:action => action.to_s}, next_level)
|
303
328
|
next_level.match("/:id/#{action}").
|
304
329
|
to_route.name(:"#{action}_#{route_singular_name}")
|
305
|
-
end if
|
306
|
-
|
330
|
+
end if member
|
331
|
+
|
307
332
|
# Add optional collection actions
|
308
|
-
|
333
|
+
collection.each_pair do |action, methods|
|
309
334
|
conditions = {:path => %r[^[/;]#{action}$], :method => /^(#{[methods].flatten.join("|")})$/}
|
310
335
|
behaviors << Behavior.new(conditions, {:action => action.to_s}, next_level)
|
311
336
|
next_level.match("/#{action}").to_route.name(:"#{action}_#{route_plural_name}")
|
312
|
-
end if
|
337
|
+
end if collection
|
338
|
+
|
339
|
+
options[:controller] ||= merged_params[:controller] || name.to_s
|
340
|
+
routes = many_behaviors_to(behaviors + next_level.send(:resources_behaviors), options)
|
313
341
|
|
314
|
-
controller = options[:controller] || merged_params[:controller] || name.to_s
|
315
|
-
routes = many_behaviors_to(behaviors + next_level.send(:resources_behaviors), :controller => controller)
|
316
|
-
|
317
342
|
# Add names to some routes
|
318
343
|
next_level.match("").to_route.name(:"#{route_plural_name}")
|
319
344
|
next_level.match("/:id").to_route.name(:"#{route_singular_name}")
|
320
345
|
next_level.match("/new").to_route.name(:"new_#{route_singular_name}")
|
321
346
|
next_level.match("/:id/edit").to_route.name(:"edit_#{route_singular_name}")
|
322
347
|
next_level.match("/:action/:id").to_route.name(:"custom_#{route_singular_name}")
|
323
|
-
|
348
|
+
|
324
349
|
yield next_level.match("/:#{singular}_id") if block_given?
|
325
350
|
routes
|
326
351
|
end
|
@@ -332,10 +357,17 @@ module Merb
|
|
332
357
|
def resource(name, options = {})
|
333
358
|
next_level = match("/#{name}")
|
334
359
|
|
335
|
-
|
336
|
-
|
360
|
+
options[:controller] ||= merged_params[:controller] || name.to_s
|
361
|
+
name_prefix = options.delete(:name_prefix)
|
362
|
+
routes = next_level.to_resource(options)
|
363
|
+
|
364
|
+
namespace = options[:namespace] || merged_params[:namespace]
|
365
|
+
|
366
|
+
if options[:name_prefix].nil? && namespace != nil
|
367
|
+
options[:name_prefix] = "#{namespace}_"
|
368
|
+
end
|
337
369
|
|
338
|
-
route_name =
|
370
|
+
route_name = "#{name_prefix}#{name}"
|
339
371
|
|
340
372
|
next_level.match("").to_route.name(:"#{route_name}")
|
341
373
|
next_level.match("/new").to_route.name(:"new_#{route_name}")
|
@@ -356,7 +388,7 @@ module Merb
|
|
356
388
|
merged_so_far.merge(@original_conditions)
|
357
389
|
end
|
358
390
|
end
|
359
|
-
|
391
|
+
|
360
392
|
def merged_conditions
|
361
393
|
if parent.nil?
|
362
394
|
@conditions
|
@@ -387,11 +419,11 @@ module Merb
|
|
387
419
|
end
|
388
420
|
placeholders
|
389
421
|
end
|
390
|
-
|
422
|
+
|
391
423
|
def inspect
|
392
424
|
"[captures: #{path_captures}, conditions: #{@original_conditions.inspect}, params: #{@params.inspect}, placeholders: #{@placeholders.inspect}]"
|
393
425
|
end
|
394
|
-
|
426
|
+
|
395
427
|
def regexp?
|
396
428
|
@conditions_have_regexp
|
397
429
|
end
|
@@ -409,7 +441,7 @@ module Merb
|
|
409
441
|
Behavior.new({:path => %r[^/:id(\.:format)?$], :method => :delete}, {:action => "destroy"}, parent)
|
410
442
|
]
|
411
443
|
end
|
412
|
-
|
444
|
+
|
413
445
|
def resource_behaviors(parent = self)
|
414
446
|
[
|
415
447
|
Behavior.new({:path => %r{^[;/]new$}, :method => :get}, {:action => "new"}, parent),
|
@@ -452,7 +484,7 @@ module Merb
|
|
452
484
|
end
|
453
485
|
@original_conditions
|
454
486
|
end
|
455
|
-
|
487
|
+
|
456
488
|
def deduce_placeholders
|
457
489
|
@conditions.each_pair do |match_key, source|
|
458
490
|
while match = SEGMENT_REGEXP.match(source)
|
@@ -475,13 +507,13 @@ module Merb
|
|
475
507
|
list
|
476
508
|
end
|
477
509
|
end
|
478
|
-
|
510
|
+
|
479
511
|
# Count the number of regexp captures in the :path condition
|
480
512
|
def path_captures
|
481
513
|
return 0 unless conditions[:path]
|
482
514
|
Behavior.count_parens_up_to(conditions[:path], conditions[:path].size)
|
483
515
|
end
|
484
|
-
|
516
|
+
|
485
517
|
def total_previous_captures
|
486
518
|
ancestors.map{|a| a.path_captures}.inject(0){|sum, n| sum + n}
|
487
519
|
end
|
@@ -571,6 +603,6 @@ module Merb
|
|
571
603
|
code
|
572
604
|
end
|
573
605
|
end # Behavior
|
574
|
-
|
606
|
+
|
575
607
|
end
|
576
608
|
end
|