Module: Sinatra::Helpers
- Included in:
- Base
- Defined in:
- lib/sinatra/base.rb
Overview
Methods available to routes, before/after filters, and views.
Defined Under Namespace
Classes: Stream
Constant Summary collapse
- ETAG_KINDS =
[:strong, :weak]
Instance Method Summary collapse
-
#attachment(filename = nil, disposition = :attachment) ⇒ Object
Set the Content-Disposition to "attachment" with the specified filename, instructing the user agents to prompt to save.
-
#back ⇒ Object
Sugar for redirect (example: redirect back).
-
#bad_request? ⇒ Boolean
whether or not the status is set to 400.
-
#body(value = nil, &block) ⇒ Object
Set or retrieve the response body.
-
#cache_control(*values) ⇒ Object
Specify response freshness policy for HTTP caches (Cache-Control header).
-
#client_error? ⇒ Boolean
whether or not the status is set to 4xx.
-
#content_type(type = nil, params = {}) ⇒ Object
Set the Content-Type of the response body given a media type or file extension.
-
#error(code, body = nil) ⇒ Object
Halt processing and return the error status provided.
-
#etag(value, options = {}) ⇒ Object
Set the response entity tag (HTTP 'ETag' header) and halt if conditional GET matches.
-
#expires(amount, *values) ⇒ Object
Set the Expires header and Cache-Control/max-age directive.
-
#headers(hash = nil) ⇒ Object
Set multiple response headers with Hash.
-
#informational? ⇒ Boolean
whether or not the status is set to 1xx.
-
#last_modified(time) ⇒ Object
Set the last modified time of the resource (HTTP 'Last-Modified' header) and halt if conditional GET matches.
-
#logger ⇒ Object
Access shared logger object.
-
#mime_type(type) ⇒ Object
Look up a media type by file extension in Rack's mime registry.
-
#not_found(body = nil) ⇒ Object
Halt processing and return a 404 Not Found.
-
#not_found? ⇒ Boolean
whether or not the status is set to 404.
-
#redirect(uri, *args) ⇒ Object
Halt processing and redirect to the URI provided.
-
#redirect? ⇒ Boolean
whether or not the status is set to 3xx.
-
#send_file(path, opts = {}) ⇒ Object
Use the contents of the file at +path+ as the response body.
-
#server_error? ⇒ Boolean
whether or not the status is set to 5xx.
-
#session ⇒ Object
Access the underlying Rack session.
-
#status(value = nil) ⇒ Object
Set or retrieve the response status code.
-
#stream(keep_open = false) ⇒ Object
Allows to start sending data to the client even though later parts of the response body have not yet been generated.
-
#success? ⇒ Boolean
whether or not the status is set to 2xx.
-
#time_for(value) ⇒ Object
Generates a Time object from the given value.
-
#uri(addr = nil, absolute = true, add_script_name = true) ⇒ Object
(also: #url, #to)
Generates the absolute URI for a given path in the app.
Instance Method Details
#attachment(filename = nil, disposition = :attachment) ⇒ Object
Set the Content-Disposition to "attachment" with the specified filename, instructing the user agents to prompt to save.
362 363 364 365 366 367 368 369 370 |
# File 'lib/sinatra/base.rb', line 362 def (filename = nil, disposition = :attachment) response['Content-Disposition'] = disposition.to_s.dup if filename params = '; filename="%s"' % File.basename(filename) response['Content-Disposition'] << params ext = File.extname(filename) content_type(ext) unless response['Content-Type'] or ext.empty? end end |
#back ⇒ Object
Sugar for redirect (example: redirect back)
579 580 581 |
# File 'lib/sinatra/base.rb', line 579 def back request.referer end |
#bad_request? ⇒ Boolean
whether or not the status is set to 400
614 615 616 |
# File 'lib/sinatra/base.rb', line 614 def bad_request? status == 400 end |
#body(value = nil, &block) ⇒ Object
Set or retrieve the response body. When a block is given, evaluation is deferred until the body is read with #each.
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/sinatra/base.rb', line 254 def body(value = nil, &block) if block_given? def block.each; yield(call) end response.body = block elsif value # Rack 2.0 returns a Rack::File::Iterator here instead of # Rack::File as it was in the previous API. unless request.head? || value.is_a?(Rack::File::Iterator) || value.is_a?(Stream) headers.delete 'Content-Length' end response.body = value else response.body end end |
#cache_control(*values) ⇒ Object
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
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 |
# File 'lib/sinatra/base.rb', line 471 def cache_control(*values) if values.last.kind_of?(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 ['max-age', 's-maxage'].include? key values << "#{key}=#{value}" end response['Cache-Control'] = values.join(', ') if values.any? end |
#client_error? ⇒ Boolean
whether or not the status is set to 4xx
599 600 601 |
# File 'lib/sinatra/base.rb', line 599 def client_error? status.between? 400, 499 end |
#content_type(type = nil, params = {}) ⇒ Object
Set the Content-Type of the response body given a media type or file extension.
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 |
# File 'lib/sinatra/base.rb', line 340 def content_type(type = nil, params = {}) return response['Content-Type'] unless type default = params.delete :default mime_type = mime_type(type) || default fail "Unknown media type: %p" % type if mime_type.nil? mime_type = mime_type.dup unless params.include? :charset or settings.add_charset.all? { |p| not 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) ⇒ Object
Halt processing and return the error status provided.
306 307 308 309 310 |
# File 'lib/sinatra/base.rb', line 306 def error(code, body = nil) code, body = 500, code.to_str if code.respond_to? :to_str response.body = body unless body.nil? halt code end |
#etag(value, options = {}) ⇒ Object
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.
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 |
# File 'lib/sinatra/base.rb', line 553 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 = '"%s"' % value value = "W/#{value}" if kind == :weak response['ETag'] = value if success? or status == 304 if etag_matches? env['HTTP_IF_NONE_MATCH'], new_resource halt(request.safe? ? 304 : 412) end if env['HTTP_IF_MATCH'] halt 412 unless etag_matches? env['HTTP_IF_MATCH'], new_resource end end end |
#expires(amount, *values) ⇒ Object
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
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 |
# File 'lib/sinatra/base.rb', line 499 def expires(amount, *values) values << {} unless values.last.kind_of?(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) cache_control(*values) response['Expires'] = time.httpdate end |
#headers(hash = nil) ⇒ Object
Set multiple response headers with Hash.
318 319 320 321 |
# File 'lib/sinatra/base.rb', line 318 def headers(hash = nil) response.headers.merge! hash if hash response.headers end |
#informational? ⇒ Boolean
whether or not the status is set to 1xx
584 585 586 |
# File 'lib/sinatra/base.rb', line 584 def informational? status.between? 100, 199 end |
#last_modified(time) ⇒ Object
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.
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
# File 'lib/sinatra/base.rb', line 523 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 and 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? or status == 412) and 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 ⇒ Object
Access shared logger object.
329 330 331 |
# File 'lib/sinatra/base.rb', line 329 def logger request.logger end |
#mime_type(type) ⇒ Object
Look up a media type by file extension in Rack's mime registry.
334 335 336 |
# File 'lib/sinatra/base.rb', line 334 def mime_type(type) Base.mime_type(type) end |
#not_found(body = nil) ⇒ Object
Halt processing and return a 404 Not Found.
313 314 315 |
# File 'lib/sinatra/base.rb', line 313 def not_found(body = nil) error 404, body end |
#not_found? ⇒ Boolean
whether or not the status is set to 404
609 610 611 |
# File 'lib/sinatra/base.rb', line 609 def not_found? status == 404 end |
#redirect(uri, *args) ⇒ Object
Halt processing and redirect to the URI provided.
271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/sinatra/base.rb', line 271 def redirect(uri, *args) if env['HTTP_VERSION'] == 'HTTP/1.1' and 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 |
#redirect? ⇒ Boolean
whether or not the status is set to 3xx
594 595 596 |
# File 'lib/sinatra/base.rb', line 594 def redirect? status.between? 300, 399 end |
#send_file(path, opts = {}) ⇒ Object
Use the contents of the file at +path+ as the response body.
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
# File 'lib/sinatra/base.rb', line 373 def send_file(path, opts = {}) if opts[:type] or not response['Content-Type'] content_type opts[:type] || File.extname(path), :default => 'application/octet-stream' end disposition = opts[:disposition] filename = opts[:filename] disposition = :attachment if disposition.nil? and filename filename = path if filename.nil? (filename, disposition) if disposition last_modified opts[:last_modified] if opts[:last_modified] file = Rack::File.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 |
#server_error? ⇒ Boolean
whether or not the status is set to 5xx
604 605 606 |
# File 'lib/sinatra/base.rb', line 604 def server_error? status.between? 500, 599 end |
#session ⇒ Object
Access the underlying Rack session.
324 325 326 |
# File 'lib/sinatra/base.rb', line 324 def session request.session end |
#status(value = nil) ⇒ Object
Set or retrieve the response status code.
247 248 249 250 |
# File 'lib/sinatra/base.rb', line 247 def status(value = nil) response.status = Rack::Utils.status_code(value) if value response.status end |
#stream(keep_open = false) ⇒ Object
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. This is only relevant for evented servers like Thin or Rainbows.
455 456 457 458 459 |
# File 'lib/sinatra/base.rb', line 455 def stream(keep_open = false) scheduler = env['async.callback'] ? EventMachine : Stream current = @params.dup body Stream.new(scheduler, keep_open) { |out| with_params(current) { yield(out) } } end |
#success? ⇒ Boolean
whether or not the status is set to 2xx
589 590 591 |
# File 'lib/sinatra/base.rb', line 589 def success? status.between? 200, 299 end |
#time_for(value) ⇒ Object
Generates a Time object from the given value. Used by #expires and #last_modified.
620 621 622 623 624 625 626 627 628 629 630 631 632 |
# File 'lib/sinatra/base.rb', line 620 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 => boom raise boom rescue Exception raise ArgumentError, "unable to convert #{value.inspect} to a Time object" end |
#uri(addr = nil, absolute = true, add_script_name = true) ⇒ Object Also known as: url, to
Generates the absolute URI for a given path in the app. Takes Rack routers and reverse proxies into account.
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/sinatra/base.rb', line 286 def uri(addr = nil, absolute = true, add_script_name = true) return addr if addr =~ /\A[a-z][a-z0-9\+\.\-]*:/i uri = [host = String.new] if absolute host << "http#{'s' if request.secure?}://" if request.forwarded? or request.port != (request.secure? ? 443 : 80) host << request.host_with_port else host << request.host end end uri << request.script_name.to_s if add_script_name uri << (addr ? addr : request.path_info).to_s File.join uri end |