Module: Sinatra::Helpers
Relationships & Source Files | |
Namespace Children | |
Classes:
| |
Extension / Inclusion / Inheritance Descendants | |
Included In:
| |
Defined in: | lib/sinatra/base.rb |
Overview
Methods available to routes, before/after filters, and views.
Constant Summary
-
ETAG_KINDS =
# File 'lib/sinatra/base.rb', line 613%i[strong weak].freeze
-
MULTIPART_FORM_DATA_REPLACEMENT_TABLE =
# File 'lib/sinatra/base.rb', line 409
{ '"' => '%22', "\r" => '%0D', "\n" => '%0A' }.freeze
Instance Attribute Summary
-
#bad_request? ⇒ Boolean
readonly
whether or not the status is set to 400.
-
#client_error? ⇒ Boolean
readonly
whether or not the status is set to 4xx.
-
#informational? ⇒ Boolean
readonly
whether or not the status is set to 1xx.
-
#not_found? ⇒ Boolean
readonly
whether or not the status is set to 404.
-
#redirect? ⇒ Boolean
readonly
whether or not the status is set to 3xx.
-
#server_error? ⇒ Boolean
readonly
whether or not the status is set to 5xx.
-
#success? ⇒ Boolean
readonly
whether or not the status is set to 2xx.
Instance Method Summary
-
#attachment(filename = nil, disposition = :attachment)
Set the Content-Disposition to "attachment" with the specified filename, instructing the user agents to prompt to save.
-
#back
Sugar for redirect (example: redirect back).
-
#body(value = nil, &block)
Set or retrieve the response body.
-
#cache_control(*values)
Specify response freshness policy for HTTP caches (Cache-Control header).
-
#content_type(type = nil, params = {})
Set the content-type of the response body given a media type or file extension.
-
#error(code, body = nil)
Halt processing and return the error status provided.
-
#etag(value, options = {})
Set the response entity tag (HTTP 'ETag' header) and halt if conditional GET matches.
-
#expires(amount, *values)
Set the Expires header and Cache-Control/max-age directive.
-
#headers(hash = nil)
Set multiple response headers with Hash.
-
#last_modified(time)
Set the last modified time of the resource (HTTP 'Last-Modified' header) and halt if conditional GET matches.
-
#logger
Access shared logger object.
-
#mime_type(type)
Look up a media type by file extension in Rack's mime registry.
-
#not_found(body = nil)
readonly
Halt processing and return a 404 Not Found.
-
#redirect(uri, *args)
readonly
Halt processing and redirect to the URI provided.
-
#send_file(path, opts = {})
Use the contents of the file at
path
as the response body. -
#session
Access the underlying
::Rack
session. -
#status(value = nil)
Set or retrieve the response status code.
-
#stream(keep_open = false)
Allows to start sending data to the client even though later parts of the response body have not yet been generated.
-
#time_for(value)
Generates a Time object from the given value.
-
#to(addr = nil, absolute = true, add_script_name = true)
Alias for #uri.
-
#uri(addr = nil, absolute = true, add_script_name = true)
(also: #url, #to)
Generates the absolute URI for a given path in the app.
-
#url(addr = nil, absolute = true, add_script_name = true)
Alias for #uri.
-
#etag_matches?(list, new_resource = request.post?) ⇒ Boolean
private
Helper method checking if a ETag value list includes the current ETag.
- #with_params(temp_params) private
Instance Attribute Details
#bad_request? ⇒ Boolean
(readonly)
whether or not the status is set to 400
# File 'lib/sinatra/base.rb', line 688
def bad_request? status == 400 end
#client_error? ⇒ Boolean
(readonly)
whether or not the status is set to 4xx
# File 'lib/sinatra/base.rb', line 673
def client_error? status.between? 400, 499 end
#informational? ⇒ Boolean
(readonly)
whether or not the status is set to 1xx
# File 'lib/sinatra/base.rb', line 658
def informational? status.between? 100, 199 end
#not_found? ⇒ Boolean
(readonly)
whether or not the status is set to 404
# File 'lib/sinatra/base.rb', line 683
def not_found? status == 404 end
#redirect? ⇒ Boolean
(readonly)
whether or not the status is set to 3xx
# File 'lib/sinatra/base.rb', line 668
def redirect? status.between? 300, 399 end
#server_error? ⇒ Boolean
(readonly)
whether or not the status is set to 5xx
# File 'lib/sinatra/base.rb', line 678
def server_error? status.between? 500, 599 end
#success? ⇒ Boolean
(readonly)
whether or not the status is set to 2xx
# File 'lib/sinatra/base.rb', line 663
def success? status.between? 200, 299 end
Instance Method Details
#attachment(filename = nil, disposition = :attachment)
Set the Content-Disposition to "attachment" with the specified filename, instructing the user agents to prompt to save.
# File 'lib/sinatra/base.rb', line 417
def (filename = nil, disposition = : ) response['Content-Disposition'] = disposition.to_s.dup return unless filename params = format('; filename="%s"', File.basename(filename).gsub(/["\r\n]/, MULTIPART_FORM_DATA_REPLACEMENT_TABLE)) response['Content-Disposition'] << params ext = File.extname(filename) content_type(ext) unless response['content-type'] || ext.empty? end
#back
Sugar for redirect (example: redirect back)
# File 'lib/sinatra/base.rb', line 653
def back request.referer end
#body(value = nil, &block)
Set or retrieve the response body. When a block is given, evaluation is deferred until the body is read with #each.
# File 'lib/sinatra/base.rb', line 295
def body(value = nil, &block) if block_given? def block.each; yield(call) end response.body = block elsif value unless request.head? || value.is_a?(Rack::Files::BaseIterator) || value.is_a?(Stream) headers.delete 'content-length' end response.body = value else response.body end end
#cache_control(*values)
Specify response freshness policy for HTTP caches (Cache-Control header).
Any number of non-value directives (:public, :private
, :no_cache
,
:no_store
, :must_revalidate
, :proxy_revalidate
) may be passed along with
a Hash of value directives (:max_age, :s_maxage
).
cache_control :public, :must_revalidate, :max_age => 60 => Cache-Control: public, must-revalidate, max-age=60
See RFC 2616 / 14.9 for more on standard cache control directives: http://tools.ietf.org/html/rfc2616#section-14.9.1
# File 'lib/sinatra/base.rb', line 540
def cache_control(*values) if values.last.is_a?(Hash) hash = values.pop hash.reject! { |_k, v| v == false } hash.reject! { |k, v| values << k if v == true } else hash = {} end values.map! { |value| value.to_s.tr('_', '-') } hash.each do |key, value| key = key.to_s.tr('_', '-') value = value.to_i if %w[max-age s-maxage].include? key values << "#{key}=#{value}" end response['Cache-Control'] = values.join(', ') if values.any? end
#content_type(type = nil, params = {})
Set the content-type of the response body given a media type or file extension.
# File 'lib/sinatra/base.rb', line 386
def content_type(type = nil, params = {}) return response['content-type'] unless type default = params.delete :default mime_type = mime_type(type) || default raise format('Unknown media type: %p', type) if mime_type.nil? mime_type = mime_type.dup unless params.include?(:charset) || settings.add_charset.all? { |p| !(p === mime_type) } params[:charset] = params.delete('charset') || settings.default_encoding end params.delete :charset if mime_type.include? 'charset' unless params.empty? mime_type << (mime_type.include?(';') ? ', ' : ';') mime_type << params.map do |key, val| val = val.inspect if val =~ /[";,]/ "#{key}=#{val}" end.join(', ') end response['content-type'] = mime_type end
#error(code, body = nil)
Halt processing and return the error status provided.
#etag(value, options = {})
Set the response entity tag (HTTP 'ETag' header) and halt if conditional
GET matches. The value
argument is an identifier that uniquely
identifies the current version of the resource. The kind
argument
indicates whether the etag should be used as a :strong
(default) or :weak
cache validator.
When the current request includes an 'If-None-Match' header with a matching etag, execution is immediately halted. If the request method is GET or HEAD, a '304 Not Modified' response is sent.
# File 'lib/sinatra/base.rb', line 623
def etag(value, = {}) # Before touching this code, please double check RFC 2616 14.24 and 14.26. = { kind: } unless Hash === kind = [:kind] || :strong new_resource = .fetch(:new_resource) { request.post? } unless ETAG_KINDS.include?(kind) raise ArgumentError, ':strong or :weak expected' end value = format('"%s"', value) value = "W/#{value}" if kind == :weak response['ETag'] = value return unless success? || status == 304 if etag_matches?(env['HTTP_IF_NONE_MATCH'], new_resource) halt(request.safe? ? 304 : 412) end if env['HTTP_IF_MATCH'] return if etag_matches?(env['HTTP_IF_MATCH'], new_resource) halt 412 end nil end
#etag_matches?(list, new_resource = request.post?) ⇒ Boolean
(private)
Helper method checking if a ETag value list includes the current ETag.
# File 'lib/sinatra/base.rb', line 711
def etag_matches?(list, new_resource = request.post?) return !new_resource if list == '*' list.to_s.split(/\s*,\s*/).include? response['ETag'] end
#expires(amount, *values)
Set the Expires header and Cache-Control/max-age directive. Amount can be an integer number of seconds in the future or a Time object indicating when the response should be considered "stale". The remaining "values" arguments are passed to the #cache_control helper:
expires 500, :public, :must_revalidate => Cache-Control: public, must-revalidate, max-age=500 => Expires: Mon, 08 Jun 2009 08:50:17 GMT
# File 'lib/sinatra/base.rb', line 568
def expires(amount, *values) values << {} unless values.last.is_a?(Hash) if amount.is_a? Integer time = Time.now + amount.to_i max_age = amount else time = time_for amount max_age = time - Time.now end values.last.merge!(max_age: max_age) { |_key, v1, v2| v1 || v2 } cache_control(*values) response['Expires'] = time.httpdate end
#headers(hash = nil)
Set multiple response headers with Hash.
# File 'lib/sinatra/base.rb', line 364
def headers(hash = nil) response.headers.merge! hash if hash response.headers end
#last_modified(time)
Set the last modified time of the resource (HTTP 'Last-Modified' header)
and halt if conditional GET matches. The time
argument is a Time,
DateTime, or other object that responds to to_time
.
When the current request includes an 'If-Modified-Since' header that is equal or later than the time specified, execution is immediately halted with a '304 Not Modified' response.
# File 'lib/sinatra/base.rb', line 592
def last_modified(time) return unless time time = time_for time response['Last-Modified'] = time.httpdate return if env['HTTP_IF_NONE_MATCH'] if (status == 200) && env['HTTP_IF_MODIFIED_SINCE'] # compare based on seconds since epoch since = Time.httpdate(env['HTTP_IF_MODIFIED_SINCE']).to_i halt 304 if since >= time.to_i end if (success? || (status == 412)) && env['HTTP_IF_UNMODIFIED_SINCE'] # compare based on seconds since epoch since = Time.httpdate(env['HTTP_IF_UNMODIFIED_SINCE']).to_i halt 412 if since < time.to_i end rescue ArgumentError end
#logger
Access shared logger object.
# File 'lib/sinatra/base.rb', line 375
def logger request.logger end
#mime_type(type)
Look up a media type by file extension in Rack's mime registry.
#not_found(body = nil) (readonly)
Halt processing and return a 404 Not Found.
#redirect(uri, *args) (readonly)
Halt processing and redirect to the URI provided.
# File 'lib/sinatra/base.rb', line 310
def redirect(uri, *args) # SERVER_PROTOCOL is required in Rack 3, fall back to HTTP_VERSION # for servers not updated for Rack 3 (like Puma 5) http_version = env['SERVER_PROTOCOL'] || env['HTTP_VERSION'] if (http_version == 'HTTP/1.1') && (env['REQUEST_METHOD'] != 'GET') status 303 else status 302 end # According to RFC 2616 section 14.30, "the field value consists of a # single absolute URI" response['Location'] = uri(uri.to_s, settings.absolute_redirects?, settings.prefixed_redirects?) halt(*args) end
#send_file(path, opts = {})
Use the contents of the file at path
as the response body.
# File 'lib/sinatra/base.rb', line 428
def send_file(path, opts = {}) if opts[:type] || !response['content-type'] content_type opts[:type] || File.extname(path), default: 'application/octet-stream' end disposition = opts[:disposition] filename = opts[:filename] disposition = : if disposition.nil? && filename filename = path if filename.nil? (filename, disposition) if disposition last_modified opts[:last_modified] if opts[:last_modified] file = Rack::Files.new(File.dirname(settings.app_file)) result = file.serving(request, path) result[1].each { |k, v| headers[k] ||= v } headers['content-length'] = result[1]['content-length'] opts[:status] &&= Integer(opts[:status]) halt (opts[:status] || result[0]), result[2] rescue Errno::ENOENT not_found end
#session
Access the underlying ::Rack
session.
# File 'lib/sinatra/base.rb', line 370
def session request.session end
#status(value = nil)
Set or retrieve the response status code.
# File 'lib/sinatra/base.rb', line 288
def status(value = nil) response.status = Rack::Utils.status_code(value) if value response.status end
#stream(keep_open = false)
Allows to start sending data to the client even though later parts of the response body have not yet been generated.
The close parameter specifies whether Stream#close should be called after the block has been executed.
# File 'lib/sinatra/base.rb', line 515
def stream(keep_open = false) scheduler = env['async.callback'] ? EventMachine : Stream current = @params.dup stream = if scheduler == Stream && keep_open Stream.new(scheduler, false) do |out| until out.closed? with_params(current) { yield(out) } end end else Stream.new(scheduler, keep_open) { |out| with_params(current) { yield(out) } } end body stream end
#time_for(value)
Generates a Time object from the given value. Used by #expires and #last_modified.
# File 'lib/sinatra/base.rb', line 694
def time_for(value) if value.is_a? Numeric Time.at value elsif value.respond_to? :to_s Time.parse value.to_s else value.to_time end rescue ArgumentError => e raise e rescue Exception raise ArgumentError, "unable to convert #{value.inspect} to a Time object" end
#to(addr = nil, absolute = true, add_script_name = true)
Alias for #uri.
# File 'lib/sinatra/base.rb', line 346
alias to uri
#uri(addr = nil, absolute = true, add_script_name = true) Also known as: #url, #to
Generates the absolute URI for a given path in the app. Takes Rack routers and reverse proxies into account.
# File 'lib/sinatra/base.rb', line 328
def uri(addr = nil, absolute = true, add_script_name = true) return addr if addr.to_s =~ /\A[a-z][a-z0-9+.\-]*:/i uri = [host = String.new] if absolute host << "http#{'s' if request.secure?}://" host << if request.forwarded? || (request.port != (request.secure? ? 443 : 80)) request.host_with_port else request.host end end uri << request.script_name.to_s if add_script_name uri << (addr || request.path_info).to_s File.join uri end
#url(addr = nil, absolute = true, add_script_name = true)
Alias for #uri.
# File 'lib/sinatra/base.rb', line 345
alias url uri
#with_params(temp_params) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 717
def with_params(temp_params) original = @params @params = temp_params yield ensure @params = original if original end