merb 0.4.1 → 0.4.2
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/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
|