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
@@ -9,7 +9,7 @@ class Numeric
|
|
9
9
|
# after the number:
|
10
10
|
# 1.5.to_currency nil, ",", ".", "$USD" #=> "1.50$USD"
|
11
11
|
# 67_000.5.to_currency nil, ".", ",", "DM" #=> "67.000,50DM"
|
12
|
-
def to_currency(pre_symbol='$', thousands=',', decimal='.', post_symbol=nil)
|
12
|
+
def to_currency(pre_symbol='$', thousands=',', decimal='.', post_symbol=nil)
|
13
13
|
"#{pre_symbol}#{("%.2f" % self ).gsub(".", decimal).gsub(/(\d)(?=(?:\d{3})+(?:$|[\\#{decimal}]))/,"\\1#{thousands}")}#{post_symbol}"
|
14
14
|
end
|
15
15
|
|
data/lib/merb/core_ext/string.rb
CHANGED
@@ -2,7 +2,10 @@ require 'strscan'
|
|
2
2
|
|
3
3
|
class String
|
4
4
|
class InvalidPathConversion < Exception; end
|
5
|
-
|
5
|
+
|
6
|
+
# Escapes any characters in the string that would have special meaning in a
|
7
|
+
# regular expression.
|
8
|
+
# $ "\*?{}.".escape_regexp #=> "\\*\\?\\{\\}\\."
|
6
9
|
def escape_regexp
|
7
10
|
Regexp.escape self
|
8
11
|
end
|
@@ -17,6 +20,8 @@ class String
|
|
17
20
|
split('_').map{|e| e.capitalize}.join
|
18
21
|
end
|
19
22
|
|
23
|
+
# "merb/core_ext/string" #=> "Merb::CoreExt::String"
|
24
|
+
#
|
20
25
|
# About 50% faster than string.split('/').map{ |s| s.camel_case }.join('::')
|
21
26
|
def to_const_string
|
22
27
|
new_string = ""
|
@@ -33,24 +38,16 @@ class String
|
|
33
38
|
end
|
34
39
|
|
35
40
|
# Concatenates a path
|
41
|
+
# $ "merb"/"core_ext" #=> "merb/core_ext"
|
36
42
|
def /(o)
|
37
43
|
File.join(self, o.to_s)
|
38
44
|
end
|
39
45
|
|
40
46
|
# Takes lines of text, removes any indentation, and
|
41
47
|
# adds +indentation+ number of spaces to each line
|
48
|
+
# $ " Hello\n Bob\nHow are you?".indent(3)
|
49
|
+
# #=> " Hello\n Bob\n How are you?"
|
42
50
|
def indent(indentation)
|
43
|
-
|
44
|
-
initial_indentation = lines.first.scan(/^(\s+)/).flatten.first
|
45
|
-
lines.map do |line|
|
46
|
-
if initial_indentation.nil?
|
47
|
-
" " * indentation + line
|
48
|
-
elsif line.index(initial_indentation) == 0
|
49
|
-
" " * indentation + line[initial_indentation.size..-1]
|
50
|
-
else
|
51
|
-
" " * indentation + line
|
52
|
-
end
|
53
|
-
end.join
|
51
|
+
match(/\s*/) && gsub(/^\s{0,#{$&.length}}/, " " * indentation)
|
54
52
|
end
|
55
|
-
|
56
53
|
end
|
data/lib/merb/dispatcher.rb
CHANGED
@@ -25,9 +25,9 @@ module Merb
|
|
25
25
|
MERB_LOGGER.info("Cookies: #{request.cookies.inspect}")
|
26
26
|
# user friendly error messages
|
27
27
|
if request.route_params.empty?
|
28
|
-
raise ControllerExceptions::
|
28
|
+
raise ControllerExceptions::BadRequest, "No routes match the request"
|
29
29
|
elsif request.controller_name.nil?
|
30
|
-
raise ControllerExceptions::
|
30
|
+
raise ControllerExceptions::BadRequest, "Route matched, but route did not specify a controller"
|
31
31
|
end
|
32
32
|
MERB_LOGGER.debug("Routed to: #{request.route_params.inspect}")
|
33
33
|
# set controller class and the action to call
|
data/lib/merb/exceptions.rb
CHANGED
@@ -136,6 +136,7 @@ module Merb
|
|
136
136
|
class TemporaryRedirect < Merb::ControllerExceptions::Redirection; STATUS = 307; end
|
137
137
|
class ClientError < Merb::ControllerExceptions::Base; end
|
138
138
|
class BadRequest < Merb::ControllerExceptions::ClientError; STATUS = 400; end
|
139
|
+
class MultiPartParseError < Merb::ControllerExceptions::BadRequest; end
|
139
140
|
class Unauthorized < Merb::ControllerExceptions::ClientError; STATUS = 401; end
|
140
141
|
class PaymentRequired < Merb::ControllerExceptions::ClientError; STATUS = 402; end
|
141
142
|
class Forbidden < Merb::ControllerExceptions::ClientError; STATUS = 403; end
|
@@ -162,7 +163,8 @@ module Merb
|
|
162
163
|
class ServiceUnavailable < Merb::ControllerExceptions::ServerError; STATUS = 503; end
|
163
164
|
class GatewayTimeout < Merb::ControllerExceptions::ServerError; STATUS = 504; end
|
164
165
|
class HTTPVersionNotSupported < Merb::ControllerExceptions::ServerError; STATUS = 505; end
|
165
|
-
class InternalServerError < Merb::ControllerExceptions::ServerError;
|
166
|
+
class InternalServerError < Merb::ControllerExceptions::ServerError;
|
167
|
+
STATUS = 500
|
166
168
|
DEFAULT_TEMPLATE = ::Merb::Dispatcher::DEFAULT_ERROR_TEMPLATE
|
167
169
|
|
168
170
|
def initialize(exception = nil)
|
data/lib/merb/logger.rb
CHANGED
@@ -17,6 +17,7 @@ module Merb
|
|
17
17
|
def initialize(log, level = DEBUG)
|
18
18
|
@level = level
|
19
19
|
@buffer = []
|
20
|
+
@aio = false
|
20
21
|
if log.respond_to?(:write)
|
21
22
|
@log = log
|
22
23
|
elsif File.exist?(log)
|
@@ -27,16 +28,24 @@ module Merb
|
|
27
28
|
@log.sync = true
|
28
29
|
@log.write("# Logfile created on %s\n" % [Time.now.to_s])
|
29
30
|
end
|
31
|
+
if !MERB_ENV.match(/development|test/) &&
|
32
|
+
!RUBY_PLATFORM.match(/java|mswin/) &&
|
33
|
+
!(@log == STDOUT) &&
|
34
|
+
@log.respond_to?(:write_nonblock)
|
35
|
+
@aio = true
|
36
|
+
end
|
30
37
|
end
|
31
|
-
|
38
|
+
|
32
39
|
def flush
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
40
|
+
unless @buffer.size == 0
|
41
|
+
if @aio
|
42
|
+
@log.write_nonblock(@buffer.slice!(0..-1).to_s)
|
43
|
+
else
|
44
|
+
@log.write(@buffer.slice!(0..-1).to_s)
|
45
|
+
end
|
37
46
|
end
|
38
47
|
end
|
39
|
-
|
48
|
+
|
40
49
|
def close
|
41
50
|
flush
|
42
51
|
@log.close if @log.respond_to?(:close)
|
data/lib/merb/mail_controller.rb
CHANGED
@@ -245,9 +245,25 @@ module Merb
|
|
245
245
|
|
246
246
|
# A convenience method that creates a blank copy of the MailController and runs
|
247
247
|
# dispatch_and_deliver on it.
|
248
|
-
def self.dispatch_and_deliver(method, mail_params)
|
249
|
-
new(
|
248
|
+
def self.dispatch_and_deliver(method, mail_params, send_params = {})
|
249
|
+
new(send_params).dispatch_and_deliver method, mail_params
|
250
250
|
end
|
251
251
|
|
252
|
+
protected
|
253
|
+
def route
|
254
|
+
@base_controller.route if @base_controller
|
255
|
+
end
|
256
|
+
|
257
|
+
private
|
258
|
+
# This method is here to overwrite the one in the general_controller mixin
|
259
|
+
# The method ensures that when a url is generated with a hash, it contains a controller
|
260
|
+
def get_controller_for_url_generation(opts)
|
261
|
+
puts @base_controller.params[:controller] if @base_controller
|
262
|
+
controller = opts[:controller] || ( @base_controller.params[:controller] if @base_controller)
|
263
|
+
raise "No Controller Specified for url()" unless controller
|
264
|
+
controller
|
265
|
+
end
|
266
|
+
|
267
|
+
|
252
268
|
end
|
253
269
|
end
|
data/lib/merb/mailer.rb
CHANGED
@@ -53,7 +53,7 @@ module Merb
|
|
53
53
|
def net_smtp
|
54
54
|
Net::SMTP.start(config[:host], config[:port].to_i, config[:domain],
|
55
55
|
config[:user], config[:pass], config[:auth]) { |smtp|
|
56
|
-
smtp.send_message(@mail.to_s, @mail.from.first, @mail.to)
|
56
|
+
smtp.send_message(@mail.to_s, @mail.from.first, @mail.to.to_s.split(/[,;]/))
|
57
57
|
}
|
58
58
|
end
|
59
59
|
|
@@ -1,201 +1,32 @@
|
|
1
1
|
module Merb
|
2
|
+
# Module that is mixed in to all implemented controllers.
|
2
3
|
module ControllerMixin
|
3
4
|
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# hash fills in the dynamic parts of the route.
|
5
|
+
# Renders the block given as a parameter using chunked
|
6
|
+
# encoding.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
# the route, then knowing the controller & action won't be enough
|
10
|
-
# to reverse-generate the route. However, if you use the default
|
11
|
-
# /controller/action/id?query route, +default_route+ can generate
|
12
|
-
# it for you.
|
8
|
+
# ==== Examples
|
13
9
|
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
# [:comment, "/blogposts/:blogpost_id/comments/:id"]
|
30
|
-
# [:edit_comment, "/blogposts/:blogpost_id/comments/:id/edit"]
|
31
|
-
# [:new_comment, "/blogposts/:blogpost_id/comments/new"]
|
32
|
-
# [:custom_new_comment, "/blogposts/:blogpost_id/comments/new/:action"]
|
33
|
-
#
|
34
|
-
# Examples:
|
35
|
-
#
|
36
|
-
# @post = Post.find(1)
|
37
|
-
# @comment = @post.comments.find(1)
|
38
|
-
#
|
39
|
-
# url(:blogposts) # => /blogposts
|
40
|
-
# url(:new_post) # => /blogposts/new
|
41
|
-
# url(:blogpost, @post) # => /blogposts/1
|
42
|
-
# url(:edit_blogpost, @post) # => /blogposts/1/edit
|
43
|
-
# url(:custom_new_blogpost, :action => 'alternate') # => /blogposts/new/alternate
|
44
|
-
#
|
45
|
-
# url(:comments, :blogpost => @post) # => /blogposts/1/comments
|
46
|
-
# url(:new_comment, :blogpost => @post) # => /blogposts/1/comments/new
|
47
|
-
# url(:comment, @comment) # => /blogposts/1/comments/1
|
48
|
-
# url(:edit_comment, @comment) # => /blogposts/1/comments/1/edit
|
49
|
-
# url(:custom_new_comment, :blogpost => @post)
|
50
|
-
#
|
51
|
-
# url(:page => 2) # => /posts/show/1?page=2
|
52
|
-
# url(:new_post, :page => 3) # => /posts/new?page=3
|
53
|
-
# url('/go/here', :page => 3) # => /go/here?page=3
|
54
|
-
#
|
55
|
-
# url(:controller => "welcome") # => /welcome
|
56
|
-
# url(:controller => "welcome", :action => "greet")
|
57
|
-
# # => /welcome/greet
|
58
|
-
#
|
59
|
-
def url(route_name = nil, new_params = {})
|
60
|
-
if route_name.is_a?(Hash)
|
61
|
-
new_params = route_name
|
62
|
-
route_name = nil
|
63
|
-
end
|
64
|
-
|
65
|
-
url = if new_params.respond_to?(:keys) && route_name.nil? &&
|
66
|
-
!(new_params.keys & [:controller, :action, :id]).empty?
|
67
|
-
url_from_default_route(new_params)
|
68
|
-
elsif route_name.nil? && !route.regexp?
|
69
|
-
url_from_route(route, new_params)
|
70
|
-
elsif route_name.nil?
|
71
|
-
request.path + (new_params.empty? ? "" : "?" + params_to_query_string(new_params))
|
72
|
-
elsif route_name.is_a?(Symbol)
|
73
|
-
url_from_route(route_name, new_params)
|
74
|
-
elsif route_name.is_a?(String)
|
75
|
-
route_name + (new_params.empty? ? "" : "?" + params_to_query_string(new_params))
|
76
|
-
else
|
77
|
-
raise "URL not generated: #{route_name.inspect}, #{new_params.inspect}"
|
78
|
-
end
|
79
|
-
url = MerbHandler.path_prefix + url if MerbHandler.path_prefix
|
80
|
-
url
|
81
|
-
end
|
82
|
-
|
83
|
-
def url_from_route(symbol, new_params = {})
|
84
|
-
if new_params.respond_to?(:new_record?) && new_params.new_record?
|
85
|
-
symbol = "#{symbol}".singularize.to_sym
|
86
|
-
new_params = {}
|
87
|
-
end
|
88
|
-
route = symbol.is_a?(Symbol) ? Merb::Router.named_routes[symbol] : symbol
|
89
|
-
raise "URL could not be constructed. Route symbol not found: #{symbol.inspect}" unless route
|
90
|
-
path = route.generate(new_params, params)
|
91
|
-
keys = route.symbol_segments
|
92
|
-
if new_params.is_a? Hash
|
93
|
-
if ext = format_extension(new_params)
|
94
|
-
new_params.delete(:format)
|
95
|
-
path += "." + ext
|
96
|
-
end
|
97
|
-
extras = new_params.reject{ |k, v| keys.include?(k) }
|
98
|
-
path += "?" + params_to_query_string(extras) unless extras.empty?
|
99
|
-
end
|
100
|
-
path
|
101
|
-
end
|
102
|
-
|
103
|
-
# this is pretty ugly, but it works. TODO: make this cleaner
|
104
|
-
def url_from_default_route(new_params)
|
105
|
-
query_params = new_params.reject do |k,v|
|
106
|
-
[:controller, :action, :id, :format].include?(k)
|
107
|
-
end
|
108
|
-
controller = new_params[:controller] || params[:controller]
|
109
|
-
controller = params[:controller] if controller == :current
|
110
|
-
url = "/#{controller}"
|
111
|
-
if new_params[:action] || new_params[:id] ||
|
112
|
-
new_params[:format] || !query_params.empty?
|
113
|
-
action = new_params[:action] || params[:action]
|
114
|
-
url += "/#{action}"
|
115
|
-
end
|
116
|
-
if new_params[:id]
|
117
|
-
url += "/#{new_params[:id]}"
|
118
|
-
end
|
119
|
-
if format = new_params[:format]
|
120
|
-
format = params[:format] if format == :current
|
121
|
-
url += ".#{format}"
|
122
|
-
end
|
123
|
-
unless query_params.empty?
|
124
|
-
url += "?" + params_to_query_string(query_params)
|
125
|
-
end
|
126
|
-
url
|
127
|
-
end
|
128
|
-
|
129
|
-
protected
|
130
|
-
|
131
|
-
# Creates query string from params, supporting nested arrays and hashes.
|
132
|
-
# ==== Example
|
133
|
-
# params_to_query_string(:user => {:filter => {:name => "quux*"}, :order => ["name"]})
|
134
|
-
# # => user[filter][name]=quux%2A&user[order][]=name
|
135
|
-
def params_to_query_string(value, prefix = nil)
|
136
|
-
case value
|
137
|
-
when Array
|
138
|
-
value.map { |v|
|
139
|
-
params_to_query_string(v, "#{prefix}[]")
|
140
|
-
} * "&"
|
141
|
-
when Hash
|
142
|
-
value.map { |k, v|
|
143
|
-
params_to_query_string(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
|
144
|
-
} * "&"
|
145
|
-
else
|
146
|
-
"#{prefix}=#{escape(value)}"
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
# +format_extension+ dictates when named route urls generated by #url
|
151
|
-
# will have a file-extension. It will return false or the format
|
152
|
-
# extension to append.
|
153
|
-
#
|
154
|
-
# url(:post, :id => post, :format => 'xml')
|
155
|
-
#
|
156
|
-
# generates:
|
157
|
-
#
|
158
|
-
# /posts/34.xml
|
159
|
-
#
|
160
|
-
# by default NON-HTML urls will be given an extension. it is posible
|
161
|
-
# to override this behaviour by setting +:use_format_in_urls+ in your
|
162
|
-
# server config (merb.yml) to either true/false
|
163
|
-
#
|
164
|
-
# +true+ would result in ALL urls (even html) being given extensions
|
165
|
-
# this is often desirable when you have many formats and dont
|
166
|
-
# wish to treat .html any differently from
|
167
|
-
# +false+ would result in NO urls being given extensions, and format
|
168
|
-
# gets treated just like any other param. leave it unset for
|
169
|
-
# the default behavior
|
170
|
-
#
|
171
|
-
def format_extension(new_params={})
|
172
|
-
use_format = Merb::Server.config[:use_format_in_urls]
|
173
|
-
if use_format.nil?
|
174
|
-
prms = params.merge(new_params)
|
175
|
-
use_format = prms[:format] != 'html' && prms[:format]
|
176
|
-
end
|
177
|
-
use_format
|
178
|
-
end
|
179
|
-
|
180
|
-
# render using chunked encoding
|
181
|
-
# def stream
|
182
|
-
# prefix = '<p>'
|
183
|
-
# suffix = "</p>\r\n"
|
184
|
-
# render_chunked do
|
185
|
-
# IO.popen("cat /tmp/test.log") do |io|
|
186
|
-
# done = false
|
187
|
-
# until done
|
188
|
-
# sleep 0.3
|
189
|
-
# line = io.gets.chomp
|
190
|
-
# if line == 'EOF'
|
191
|
-
# done = true
|
192
|
-
# else
|
193
|
-
# send_chunk(prefix + line + suffix)
|
10
|
+
# def stream
|
11
|
+
# prefix = '<p>'
|
12
|
+
# suffix = "</p>\r\n"
|
13
|
+
# render_chunked do
|
14
|
+
# IO.popen("cat /tmp/test.log") do |io|
|
15
|
+
# done = false
|
16
|
+
# until done
|
17
|
+
# sleep 0.3
|
18
|
+
# line = io.gets.chomp
|
19
|
+
#
|
20
|
+
# if line == 'EOF'
|
21
|
+
# done = true
|
22
|
+
# else
|
23
|
+
# send_chunk(prefix + line + suffix)
|
24
|
+
# end
|
194
25
|
# end
|
195
26
|
# end
|
196
27
|
# end
|
197
28
|
# end
|
198
|
-
#
|
29
|
+
#
|
199
30
|
def render_chunked(&blk)
|
200
31
|
headers['Transfer-Encoding'] = 'chunked'
|
201
32
|
Proc.new {
|
@@ -206,6 +37,9 @@ module Merb
|
|
206
37
|
}
|
207
38
|
end
|
208
39
|
|
40
|
+
# Returns a +Proc+ that Mongrel can call later, allowing
|
41
|
+
# Merb to release the thread lock and render another request.
|
42
|
+
#
|
209
43
|
def render_deferred(&blk)
|
210
44
|
Proc.new {
|
211
45
|
result = blk.call
|
@@ -215,25 +49,36 @@ module Merb
|
|
215
49
|
}
|
216
50
|
end
|
217
51
|
|
218
|
-
#
|
52
|
+
# Writes a chunk from render_chunked to the response that
|
53
|
+
# is sent back to the client.
|
219
54
|
def send_chunk(data)
|
220
55
|
response.write('%x' % data.size + "\r\n")
|
221
56
|
response.write(data + "\r\n")
|
222
57
|
end
|
223
58
|
|
224
|
-
#
|
225
|
-
#
|
226
|
-
#
|
59
|
+
# Redirects to a URL. The +url+ parameter can be either
|
60
|
+
# a relative URL (e.g., +/posts/34+) or a fully-qualified URL
|
61
|
+
# (e.g., +http://www.merbivore.com/+).
|
62
|
+
#
|
63
|
+
# ==== Parameters
|
64
|
+
#
|
65
|
+
# +url+ - URL to redirect to; it can be either a relative or
|
66
|
+
# fully-qualified URL.
|
67
|
+
#
|
227
68
|
def redirect(url)
|
228
69
|
MERB_LOGGER.info("Redirecting to: #{url}")
|
229
70
|
set_status(302)
|
230
|
-
headers
|
231
|
-
|
71
|
+
headers['Location'] = url
|
72
|
+
"<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>"
|
232
73
|
end
|
233
74
|
|
234
|
-
#
|
235
|
-
# right headers
|
236
|
-
#
|
75
|
+
# Sends a file over HTTP. When given a path to a file, it will set the
|
76
|
+
# right headers so that the static file is served directly.
|
77
|
+
#
|
78
|
+
# ==== Parameters
|
79
|
+
#
|
80
|
+
# +file+ - Path to file to send to the client.
|
81
|
+
#
|
237
82
|
def send_file(file, opts={})
|
238
83
|
opts.update(Merb::Const::DEFAULT_SEND_FILE_OPTIONS.merge(opts))
|
239
84
|
disposition = opts[:disposition].dup || 'attachment'
|
@@ -247,6 +92,10 @@ module Merb
|
|
247
92
|
return
|
248
93
|
end
|
249
94
|
|
95
|
+
# Streams a file over HTTP.
|
96
|
+
#
|
97
|
+
# ==== Example
|
98
|
+
#
|
250
99
|
# stream_file( { :filename => file_name,
|
251
100
|
# :type => content_type,
|
252
101
|
# :content_length => content_length }) do
|
@@ -270,15 +119,24 @@ module Merb
|
|
270
119
|
end
|
271
120
|
|
272
121
|
|
273
|
-
#
|
274
|
-
# a file directly from nginx.
|
122
|
+
# Uses the nginx specific +X-Accel-Redirect+ header to send
|
123
|
+
# a file directly from nginx. For more information, see the nginx wiki:
|
275
124
|
# http://wiki.codemongers.com/NginxXSendfile
|
125
|
+
#
|
126
|
+
# ==== Parameters
|
127
|
+
#
|
128
|
+
# +file+ - Path to file to send to the client.
|
129
|
+
#
|
276
130
|
def nginx_send_file(file)
|
277
131
|
headers['X-Accel-Redirect'] = File.expand_path(file)
|
278
132
|
return
|
279
133
|
end
|
280
134
|
|
281
|
-
# Sets a cookie to be included in the response.
|
135
|
+
# Sets a cookie to be included in the response. This method is used
|
136
|
+
# primarily internally in Merb.
|
137
|
+
#
|
138
|
+
# If you need to set a cookie, then use the +cookies+ hash.
|
139
|
+
#
|
282
140
|
def set_cookie(name, value, expires)
|
283
141
|
(headers['Set-Cookie'] ||='') << (Merb::Const::SET_COOKIE % [
|
284
142
|
name.to_s,
|
@@ -288,35 +146,13 @@ module Merb
|
|
288
146
|
])
|
289
147
|
end
|
290
148
|
|
291
|
-
# Marks a cookie as deleted
|
292
|
-
# the past.
|
149
|
+
# Marks a cookie as deleted and gives it an expires stamp in
|
150
|
+
# the past. This method is used primarily internally in Merb.
|
151
|
+
#
|
152
|
+
# Use the +cookies+ hash to manipulate cookies instead.
|
153
|
+
#
|
293
154
|
def delete_cookie(name)
|
294
155
|
set_cookie(name, nil, Merb::Const::COOKIE_EXPIRED_TIME)
|
295
156
|
end
|
296
|
-
|
297
|
-
# creates a random token like:
|
298
|
-
# "b9a82e011694cc13a4249731b9e83cea"
|
299
|
-
def make_token
|
300
|
-
require 'digest/md5'
|
301
|
-
Digest::MD5.hexdigest("#{inspect}#{Time.now}#{rand}")
|
302
|
-
end
|
303
|
-
|
304
|
-
|
305
|
-
def escape_xml(obj)
|
306
|
-
obj.to_s.gsub(/[&<>"']/) { |s| Merb::Const::ESCAPE_TABLE[s] }
|
307
|
-
end
|
308
|
-
alias h escape_xml
|
309
|
-
alias html_escape escape_xml
|
310
|
-
|
311
|
-
# does url escaping
|
312
|
-
def escape(s)
|
313
|
-
Mongrel::HttpRequest.escape(s)
|
314
|
-
end
|
315
|
-
|
316
|
-
# does url unescaping
|
317
|
-
def unescape(s)
|
318
|
-
Mongrel::HttpRequest.unescape(s)
|
319
|
-
end
|
320
|
-
|
321
157
|
end
|
322
158
|
end
|