Class: Sinatra::Base
Relationships & Source Files | |
Extension / Inclusion / Inheritance Descendants | |
Subclasses:
|
|
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
|
|
Inherits: | Object |
Defined in: | lib/sinatra/base.rb |
Overview
Base
class for all ::Sinatra
applications and middleware.
Constant Summary
-
CALLERS_TO_IGNORE =
Internal use only
# File 'lib/sinatra/base.rb', line 1286[ # :nodoc: %r{/sinatra(/(base|main|show_exceptions))?\.rb$}, # all sinatra code %r{lib/tilt.*\.rb$}, # all tilt code /^\(.*\)$/, # generated code /\/bundled_gems.rb$/, # ruby >= 3.3 with bundler >= 2.5 %r{rubygems/(custom|core_ext/kernel)_require\.rb$}, # rubygems require hacks /active_support/, # active_support require hacks %r{bundler(/(?:runtime|inline))?\.rb}, # bundler require hacks /<internal:/, # internal in ruby >= 1.9.2 %r{zeitwerk/kernel\.rb} # Zeitwerk kernel#require decorator ].freeze
-
URI_INSTANCE =
# File 'lib/sinatra/base.rb', line 975URI::Parser.new
Helpers
- Included
Class Attribute Summary
- .development? ⇒ Boolean readonly
- .errors readonly
- .filters readonly
- .on_start_callback readonly
- .on_stop_callback readonly
- .production? ⇒ Boolean readonly
- .public=(value) writeonly
- .public_dir rw
- .public_dir=(value) rw
- .routes readonly
-
.running? ⇒ Boolean
readonly
Check whether the self-hosted server is running or not.
- .templates readonly
- .test? ⇒ Boolean readonly
- .suppress_messages? ⇒ Boolean readonly private
Class Method Summary
-
.add_filter(type, path = /.*/, **options, &block)
add a filter.
-
.after(path = /.*/, **options, &block)
Define an after filter; runs after all requests within the same context as route handlers and may access/modify the request and response.
-
.before(path = /.*/, **options, &block)
Define a before filter; runs before all requests within the same context as route handlers and may access/modify the request and response.
-
.build(app)
Creates a
::Rack::Builder
instance with all the middleware set up and the given #app as end point. - .call(env)
-
.caller_files
Like Kernel#caller but excluding certain magic entries and without line / method information; the resulting array contains filenames only.
- .callers_to_ignore
-
.condition(name = "#{caller.first[/`.*'/]} condition", &block)
Add a route condition.
-
.configure(*envs) {|_self| ... }
Set configuration options for
::Sinatra
and/or the app. - .delete(path, opts = {}, &block)
-
.disable(*opts)
Same as calling
set <code>:option</code>, false
for each of the given options. -
.enable(*opts)
Same as calling
set <code>:option</code>, true
for each of the given options. -
.error(*codes, &block)
Define a custom error handler.
-
.extensions
Extension
modules registered on this class and all superclasses. -
.get(path, opts = {}, &block)
Defining a
GET
handler also automatically defines aHEAD
handler. - .head(path, opts = {}, &block)
-
.helpers(*extensions, &block)
Makes the methods defined in the block and in the Modules given in
extensions
available to the handlers and templates. -
.inline_templates=(file = nil)
Load embedded templates from the file; uses the caller's FILE when no file is specified.
-
.layout(name = :layout, &block)
Define the layout template.
- .link(path, opts = {}, &block)
- .methodoverride=
- .methodoverride?
-
.middleware
Middleware used in this class and all superclasses.
-
.mime_type(type, value = nil)
Lookup or register a mime type in Rack's mime registry.
-
.mime_types(type)
provides all mime types matching type, including deprecated types:
-
.new(*args, &block) ⇒ Base
(also: .new!, .new!)
constructor
Create a new instance of the class fronted by its middleware pipeline.
-
.new!(app = nil, **_kwargs)
Alias for .new.
-
.not_found(&block)
Sugar for `error(404) { ...
- .on_start(&on_start_callback)
- .on_stop(&on_stop_callback)
- .options(path, opts = {}, &block)
- .patch(path, opts = {}, &block)
- .post(path, opts = {}, &block)
-
.prototype
The prototype instance used to process requests.
- .put(path, opts = {}, &block)
-
.quit!
(also: .stop!)
Stop the self-hosted server if running.
-
.register(*extensions, &block)
Register an extension.
-
.reset!
Removes all routes, filters, middleware and extension hooks from the current class (not routes/filters/...
-
.run!(options = {}, &block)
(also: .start!)
Run the
::Sinatra
app as a self-hosted server using Puma, Falcon, or WEBrick (in that order). -
.set(option, value = (not_set = true), ignore_setter = false, &block)
Sets an option to the given value.
-
.settings
Access settings defined with
Base
.set. -
.start!(options = {}, &block)
Alias for .run!.
-
.stop!
Alias for .quit!.
-
.template(name, &block)
Define a named template.
- .unlink(path, opts = {}, &block)
-
.use(middleware, *args, &block)
Use the specified
::Rack
middleware. -
.agent(pattern)
private
Alias for .user_agent.
-
.cleaned_caller(keep = 3)
private
Like Kernel#caller but excluding certain magic entries.
- .compile(path, route_mustermann_opts = {}) private
- .compile!(verb, path, block, **options) private
-
.define_singleton(name, content = Proc.new)
private
Dynamically defines a method on settings.
-
.force_encoding(data, encoding = default_encoding)
private
Force data to specified encoding.
- .generate_method(method_name, &block) private
-
.host_name(pattern)
private
Condition for matching host name.
- .inherited(subclass) private
- .invoke_hook(name, *args) private
-
.provides(*types)
private
Condition for matching mimetypes.
- .route(verb, path, options = {}, &block) private
- .setup_common_logger(builder) private
- .setup_custom_logger(builder) private
- .setup_default_middleware(builder) private
- .setup_logging(builder) private
- .setup_middleware(builder) private
- .setup_null_logger(builder) private
- .setup_protection(builder) private
- .setup_sessions(builder) private
- .setup_traps private
-
.start_server(handler, server_settings, handler_name)
private
Starts the server by running the
::Rack
Handler. - .synchronize(&block) private
-
.user_agent(pattern)
(also: .agent)
private
Condition for matching user agent.
-
.warn_for_deprecation(message)
private
used for deprecation warnings.
Instance Attribute Summary
Helpers
- Included
#bad_request? | whether or not the status is set to 400. |
#client_error? | whether or not the status is set to 4xx. |
#informational? | whether or not the status is set to 1xx. |
#not_found? | whether or not the status is set to 404. |
#redirect? | whether or not the status is set to 3xx. |
#server_error? | whether or not the status is set to 5xx. |
#success? | whether or not the status is set to 2xx. |
Instance Method Summary
-
#call(env)
::Rack
call interface. - #call!(env) Internal use only
-
#forward
Forward the request to the downstream app -- middleware only.
-
#halt(*response)
Exit the current block, halts any further processing of the request, and returns the specified response.
-
#pass(&block)
Pass control to the next matching route.
-
#settings
Access settings defined with
Base
.set. -
#dispatch!
private
Dispatch a request with error handling.
- #dump_errors!(boom) private
-
#error_block!(key, *block_params)
private
Find an custom error block for the key(s) specified.
-
#filter!(type, base = settings, &block)
private
Run filters defined on the class and all superclasses.
- #force_encoding(*args) private
-
#handle_exception!(boom)
private
Error
handling during requests. -
#invoke(&block)
private
Run the block with 'throw :halt' support and apply result to the response.
-
#process_route(pattern, conditions, block = nil, values = [])
private
If the current request matches pattern and conditions, fill params with keys and call the given block.
-
#route!(base = settings, pass_block = nil)
private
Run routes defined on the class and all superclasses.
-
#route_eval
private
Run a route block and throw
:halt
with the result. -
#route_missing
private
No matching route was found or all routes passed.
-
#static!(options = {})
private
Attempt to serve static files from public directory.
Templates
- Included
#asciidoc, #builder, #erb, | |
#find_template | Calls the given block for every possible template file in views, named name.ext, where ext is registered on engine. |
#haml, #initialize, #liquid, #markaby, #markdown, #nokogiri, #rabl, #rdoc, #sass, #scss, #slim, #yajl, #compile_block_template, #compile_template, #render, | |
#render_ruby | logic shared between builder and nokogiri. |
Helpers
- Included
#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 | Set or retrieve the response body. |
#cache_control | Specify response freshness policy for HTTP caches (Cache-Control header). |
#content_type | Set the content-type of the response body given a media type or file extension. |
#error | Halt processing and return the error status provided. |
#etag | Set the response entity tag (HTTP 'ETag' header) and halt if conditional GET matches. |
#expires | Set the Expires header and Cache-Control/max-age directive. |
#headers | Set multiple response headers with Hash. |
#last_modified | 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 | Look up a media type by file extension in Rack's mime registry. |
#not_found | Halt processing and return a 404 Not Found. |
#redirect | Halt processing and redirect to the URI provided. |
#send_file | Use the contents of the file at |
#session | Access the underlying |
#status | Set or retrieve the response status code. |
#stream | Allows to start sending data to the client even though later parts of the response body have not yet been generated. |
#time_for | Generates a Time object from the given value. |
#to | Alias for Helpers#uri. |
#uri | Generates the absolute URI for a given path in the app. |
#url | Alias for Helpers#uri. |
#etag_matches? | Helper method checking if a ETag value list includes the current ETag. |
#with_params |
Constructor Details
.new(*args, &block) ⇒ Base
Also known as: .new!, .new!
Create a new instance of the class fronted by its middleware pipeline. The object is guaranteed to respond to #call but may not be an instance of the class new was called on.
# File 'lib/sinatra/base.rb', line 1657
def initialize(app = nil, **_kwargs) super() @app = app @template_cache = TemplateCache.new @pinned_response = nil # whether a before! filter pinned the content-type yield self if block_given? end
Class Attribute Details
.development? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/sinatra/base.rb', line 1568
def development?; environment == :development end
.errors (readonly)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1298
attr_reader :routes, :filters, :templates, :errors, :on_start_callback, :on_stop_callback
.filters (readonly)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1298
attr_reader :routes, :filters, :templates, :errors, :on_start_callback, :on_stop_callback
.on_start_callback (readonly)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1298
attr_reader :routes, :filters, :templates, :errors, :on_start_callback, :on_stop_callback
.on_stop_callback (readonly)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1298
attr_reader :routes, :filters, :templates, :errors, :on_start_callback, :on_stop_callback
.production? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/sinatra/base.rb', line 1569
def production?; environment == :production end
.public=(value) (writeonly)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1511
def public=(value) warn_for_deprecation ':public is no longer used to avoid overloading Module#public, use :public_folder or :public_dir instead' set(:public_folder, value) end
.public_dir (rw)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1520
def public_dir public_folder end
.public_dir=(value) (rw)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1516
def public_dir=(value) self.public_folder = value end
.routes (readonly)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1298
attr_reader :routes, :filters, :templates, :errors, :on_start_callback, :on_stop_callback
.running? ⇒ Boolean
(readonly)
Check whether the self-hosted server is running or not.
# File 'lib/sinatra/base.rb', line 1642
def running? running_server? end
.suppress_messages? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/sinatra/base.rb', line 1705
def handler_name =~ /cgi/i || quiet end
.templates (readonly)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1298
attr_reader :routes, :filters, :templates, :errors, :on_start_callback, :on_stop_callback
.test? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/sinatra/base.rb', line 1570
def test?; environment == :test end
Class Method Details
.add_filter(type, path = /.*/, **options, &block)
add a filter
.after(path = /.*/, **options, &block)
Define an after filter; runs after all requests within the same context as route handlers and may access/modify the request and response.
# File 'lib/sinatra/base.rb', line 1488
def after(path = /.*/, **, &block) add_filter(:after, path, **, &block) end
.agent(pattern) (private)
Alias for .user_agent.
# File 'lib/sinatra/base.rb', line 1749
alias agent user_agent
.before(path = /.*/, **options, &block)
Define a before filter; runs before all requests within the same context as route handlers and may access/modify the request and response.
# File 'lib/sinatra/base.rb', line 1481
def before(path = /.*/, **, &block) add_filter(:before, path, **, &block) end
.build(app)
Creates a ::Rack::Builder
instance with all the middleware set up and
the given #app as end point.
# File 'lib/sinatra/base.rb', line 1665
def build(app) builder = Rack::Builder.new setup_default_middleware builder setup_middleware builder builder.run app builder end
.call(env)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1673
def call(env) synchronize { prototype.call(env) } end
.caller_files
Like Kernel#caller but excluding certain magic entries and without line / method information; the resulting array contains filenames only.
# File 'lib/sinatra/base.rb', line 1679
def caller_files cleaned_caller(1).flatten end
.callers_to_ignore
[ GitHub ]# File 'lib/sinatra/base.rb', line 1300
def callers_to_ignore CALLERS_TO_IGNORE end
.cleaned_caller(keep = 3) (private)
Like Kernel#caller but excluding certain magic entries
# File 'lib/sinatra/base.rb', line 1900
def cleaned_caller(keep = 3) caller(1) .map! { |line| line.split(/:(?=\d|in )/, 3)[0, keep] } .reject { |file, *_| callers_to_ignore.any? { |pattern| file =~ pattern } } end
.compile(path, route_mustermann_opts = {}) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1810
def compile(path, route_mustermann_opts = {}) Mustermann.new(path, **mustermann_opts.merge(route_mustermann_opts)) end
.compile!(verb, path, block, **options) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1790
def compile!(verb, path, block, ** ) # Because of self.options.host host_name( .delete(:host)) if .key?(:host) # Pass Mustermann opts to compile() route_mustermann_opts = .key?(:mustermann_opts) ? .delete(:mustermann_opts) : {}.freeze .each_pair { |option, args| send(option, *args) } pattern = compile(path, route_mustermann_opts) method_name = "#{verb} #{path}" unbound_method = generate_method(method_name, &block) conditions = @conditions @conditions = [] wrapper = block.arity.zero? ? proc { |a, _p| unbound_method.bind(a).call } : proc { |a, p| unbound_method.bind(a).call(*p) } [pattern, conditions, wrapper] end
.condition(name = "#{caller.first[/`.*'/]} condition", &block)
Add a route condition. The route is considered non-matching when the block returns false.
# File 'lib/sinatra/base.rb', line 1507
def condition(name = "#{caller.first[/`.*'/]} condition", &block) @conditions << generate_method(name, &block) end
.configure(*envs) {|_self| ... }
Set configuration options for ::Sinatra
and/or the app.
Allows scoping of settings for certain environments.
# File 'lib/sinatra/base.rb', line 1574
def configure(*envs) yield self if envs.empty? || envs.include?(environment.to_sym) end
.define_singleton(name, content = Proc.new) (private)
Dynamically defines a method on settings.
# File 'lib/sinatra/base.rb', line 1725
def define_singleton(name, content = Proc.new) singleton_class.class_eval do undef_method(name) if method_defined? name String === content ? class_eval("def #{name}() #{content}; end") : define_method(name, &content) end end
.delete(path, opts = {}, &block)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1538
def delete(path, opts = {}, &block) route 'DELETE', path, opts, &block end
.disable(*opts)
Same as calling set <code>:option</code>, false
for each of the given options.
# File 'lib/sinatra/base.rb', line 1388
def disable(*opts) opts.each { |key| set(key, false) } end
.enable(*opts)
Same as calling set <code>:option</code>, true
for each of the given options.
# File 'lib/sinatra/base.rb', line 1383
def enable(*opts) opts.each { |key| set(key, true) } end
.error(*codes, &block)
Define a custom error handler. Optionally takes either an Exception class, or an HTTP status code to specify which errors should be handled.
.extensions
Extension
modules registered on this class and all superclasses.
# File 'lib/sinatra/base.rb', line 1323
def extensions if superclass.respond_to?(:extensions) (@extensions + superclass.extensions).uniq else @extensions end end
.force_encoding(data, encoding = default_encoding) (private)
Force data to specified encoding. It defaults to settings.default_encoding which is UTF-8 by default
# File 'lib/sinatra/base.rb', line 1909
def self.force_encoding(data, encoding = default_encoding) return if data == settings || data.is_a?(Tempfile) if data.respond_to? :force_encoding data.force_encoding(encoding).encode! elsif data.respond_to? :each_value data.each_value { |v| force_encoding(v, encoding) } elsif data.respond_to? :each data.each { |v| force_encoding(v, encoding) } end data end
.generate_method(method_name, &block) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1783
def generate_method(method_name, &block) define_method(method_name, &block) method = instance_method method_name remove_method method_name method end
.get(path, opts = {}, &block)
Defining a GET
handler also automatically defines
a HEAD
handler.
.head(path, opts = {}, &block)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1540
def head(path, opts = {}, &block) route 'HEAD', path, opts, &block end
.helpers(*extensions, &block)
Makes the methods defined in the block and in the Modules given
in extensions
available to the handlers and templates
# File 'lib/sinatra/base.rb', line 1552
def helpers(*extensions, &block) class_eval(&block) if block_given? include(*extensions) if extensions.any? end
.host_name(pattern) (private)
Condition for matching host name. Parameter might be String or Regexp.
.inherited(subclass) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1879
def inherited(subclass) subclass.reset! subclass.set :app_file, caller_files.first unless subclass.app_file? super end
.inline_templates=(file = nil)
Load embedded templates from the file; uses the caller's FILE when no file is specified.
# File 'lib/sinatra/base.rb', line 1421
def inline_templates=(file = nil) file = (caller_files.first || File. ($0)) if file.nil? || file == true begin io = ::IO.respond_to?(:binread) ? ::IO.binread(file) : ::IO.read(file) app, data = io.gsub("\r\n", "\n").split(/^__END__$/, 2) rescue Errno::ENOENT app, data = nil end return unless data encoding = if app && app =~ /([^\n]*\n)?#[^\n]*coding: *(\S+)/m $2 else settings.default_encoding end lines = app.count("\n") + 1 template = nil force_encoding data, encoding data.each_line do |line| lines += 1 if line =~ /^@@\s*(.*\S)\s*$/ template = force_encoding(String.new, encoding) templates[$1.to_sym] = [template, file, lines] elsif template template << line end end end
.invoke_hook(name, *args) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1779
def invoke_hook(name, *args) extensions.each { |e| e.send(name, *args) if e.respond_to?(name) } end
.layout(name = :layout, &block)
Define the layout template. The block must return the template source.
# File 'lib/sinatra/base.rb', line 1415
def layout(name = :layout, &block) template name, &block end
.link(path, opts = {}, &block)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1546
def link(path, opts = {}, &block) route 'LINK', path, opts, &block end
.methodoverride=
[ GitHub ]# File 'lib/sinatra/base.rb', line 1957
alias methodoverride= method_override=
.methodoverride?
[ GitHub ]# File 'lib/sinatra/base.rb', line 1956
alias methodoverride? method_override?
.middleware
Middleware used in this class and all superclasses.
# File 'lib/sinatra/base.rb', line 1332
def middleware if superclass.respond_to?(:middleware) superclass.middleware + @middleware else @middleware end end
.mime_type(type, value = nil)
Lookup or register a mime type in Rack's mime registry.
.mime_types(type)
provides all mime types matching type, including deprecated types: mime_types :html # => ['text/html'] mime_types :js # => ['application/javascript', 'text/javascript']
# File 'lib/sinatra/base.rb', line 1467
def mime_types(type) type = mime_type type if type =~ %r{^application/(xml|javascript)$} [type, "text/#{$1}"] elsif type =~ %r{^text/(xml|javascript)$} [type, "application/#{$1}"] else [type] end end
.new!(app = nil, **_kwargs)
Alias for .new.
# File 'lib/sinatra/base.rb', line 1652
alias new! new unless method_defined? :new!
.not_found(&block)
Sugar for error(404) { ... }
# File 'lib/sinatra/base.rb', line 1404
def not_found(&block) error(404, &block) end
.on_start(&on_start_callback)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1497
def on_start(&on_start_callback) @on_start_callback = on_start_callback end
.on_stop(&on_stop_callback)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1501
def on_stop(&on_stop_callback) @on_stop_callback = on_stop_callback end
.options(path, opts = {}, &block)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1542
def (path, opts = {}, &block) route 'OPTIONS', path, opts, &block end
.patch(path, opts = {}, &block)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1544
def patch(path, opts = {}, &block) route 'PATCH', path, opts, &block end
.post(path, opts = {}, &block)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1536
def post(path, opts = {}, &block) route 'POST', path, opts, &block end
.prototype
The prototype instance used to process requests.
# File 'lib/sinatra/base.rb', line 1647
def prototype @prototype ||= new end
.provides(*types) (private)
Condition for matching mimetypes. Accepts file extensions.
# File 'lib/sinatra/base.rb', line 1752
def provides(*types) types.map! { |t| mime_types(t) } types.flatten! condition do response_content_type = response['content-type'] preferred_type = request.preferred_type(types) if response_content_type types.include?(response_content_type) || types.include?(response_content_type[/^[^;]+/]) elsif preferred_type params = (preferred_type.respond_to?(:params) ? preferred_type.params : {}) content_type(preferred_type, params) true else false end end end
.put(path, opts = {}, &block)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1534
def put(path, opts = {}, &block) route 'PUT', path, opts, &block end
.quit! Also known as: .stop!
Stop the self-hosted server if running.
# File 'lib/sinatra/base.rb', line 1586
def quit! return unless running? # Use Thin's hard #stop! if available, otherwise just #stop. running_server.respond_to?(:stop!) ? running_server.stop! : running_server.stop warn '== Sinatra has ended his set (crowd applauds)' unless set :running_server, nil set :handler_name, nil on_stop_callback.call unless on_stop_callback.nil? end
.register(*extensions, &block)
Register an extension. Alternatively take a block from which an extension will be created and registered on the fly.
# File 'lib/sinatra/base.rb', line 1559
def register(*extensions, &block) extensions << Module.new(&block) if block_given? @extensions += extensions extensions.each do |extension| extend extension extension.registered(self) if extension.respond_to?(:registered) end end
.reset!
Removes all routes, filters, middleware and extension hooks from the current class (not routes/filters/... defined by its superclass).
# File 'lib/sinatra/base.rb', line 1306
def reset! @conditions = [] @routes = {} @filters = { before: [], after: [] } @errors = {} @middleware = [] @prototype = nil @extensions = [] @templates = if superclass.respond_to?(:templates) Hash.new { |_hash, key| superclass.templates[key] } else {} end end
.route(verb, path, options = {}, &block) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1771
def route(verb, path, = {}, &block) enable :empty_path_info if path == '' && empty_path_info.nil? signature = compile!(verb, path, block, ** ) (@routes[verb] ||= []) << signature invoke_hook(:route_added, verb, path, block) signature end
.run!(options = {}, &block) Also known as: .start!
Run the ::Sinatra
app as a self-hosted server using
Puma, Falcon, or WEBrick (in that order). If given a block, will call
with the constructed handler once we have taken the stage.
# File 'lib/sinatra/base.rb', line 1603
def run!( = {}, &block) unless defined?(Rackup::Handler) rackup_warning = <<~MISSING_RACKUP Sinatra could not start, the "rackup" gem was not found! Add it to your bundle with: bundle add rackup or install it with: gem install rackup MISSING_RACKUP warn rackup_warning exit 1 end return if running? set handler = Rackup::Handler.pick(server) handler_name = handler.name.gsub(/.*::/, '') server_settings = settings.respond_to?(:server_settings) ? settings.server_settings : {} server_settings.merge!(Port: port, Host: bind) begin start_server(handler, server_settings, handler_name, &block) rescue Errno::EADDRINUSE warn "== Someone is already performing on port #{port}!" raise ensure quit! end end
.set(option, value = (not_set = true), ignore_setter = false, &block)
Sets an option to the given value. If the value is a proc, the proc will be called every time the option is accessed.
# File 'lib/sinatra/base.rb', line 1342
def set(option, value = (not_set = true), ignore_setter = false, &block) raise ArgumentError if block && !not_set if block value = block not_set = false end if not_set raise ArgumentError unless option.respond_to?(:each) option.each { |k, v| set(k, v) } return self end if respond_to?("#{option}=") && !ignore_setter return __send__("#{option}=", value) end setter = proc { |val| set option, val, true } getter = proc { value } case value when Proc getter = value when Symbol, Integer, FalseClass, TrueClass, NilClass getter = value.inspect when Hash setter = proc do |val| val = value.merge val if Hash === val set option, val, true end end define_singleton("#{option}=", setter) define_singleton(option, getter) define_singleton("#{option}?", "!!#{option}") unless method_defined? "#{option}?" self end
.settings
Access settings defined with Base
.set.
# File 'lib/sinatra/base.rb', line 1016
def self.settings self end
.setup_common_logger(builder) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1841
def setup_common_logger(builder) builder.use Sinatra::CommonLogger end
.setup_custom_logger(builder) (private)
[ GitHub ].setup_default_middleware(builder) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1814
def setup_default_middleware(builder) builder.use ExtendedRack builder.use ShowExceptions if show_exceptions? builder.use Rack::MethodOverride if method_override? builder.use Rack::Head setup_logging builder setup_sessions builder setup_protection builder end
.setup_logging(builder) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1828
def setup_logging(builder) if logging? setup_common_logger(builder) setup_custom_logger(builder) elsif logging == false setup_null_logger(builder) end end
.setup_middleware(builder) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1824
def setup_middleware(builder) middleware.each { |c, a, b| builder.use(c, *a, &b) } end
.setup_null_logger(builder) (private)
[ GitHub ].setup_protection(builder) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1853
def setup_protection(builder) return unless protection? = Hash === protection ? protection.dup : {} = { img_src: "'self' data:", font_src: "'self'" }.merge protect_session = .fetch(:session) { sessions? } [:without_session] = !protect_session [:reaction] ||= :drop_session builder.use Rack::Protection, end
.setup_sessions(builder) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1870
def setup_sessions(builder) return unless sessions? = {} [:secret] = session_secret if session_secret? .merge! sessions.to_hash if sessions.respond_to? :to_hash builder.use session_store, end
.setup_traps (private)
[ GitHub ].start!(options = {}, &block)
Alias for .run!.
# File 'lib/sinatra/base.rb', line 1639
alias start! run!
.start_server(handler, server_settings, handler_name) (private)
Starts the server by running the ::Rack
Handler.
# File 'lib/sinatra/base.rb', line 1686
def start_server(handler, server_settings, handler_name) # Ensure we initialize middleware before startup, to match standard Rack # behavior, by ensuring an instance exists: prototype # Run the instance we created: handler.run(self, **server_settings) do |server| unless warn "== Sinatra (v#{Sinatra::VERSION}) has taken the stage on #{port} for #{environment} with backup from #{handler_name}" end setup_traps set :running_server, server set :handler_name, handler_name server.threaded = settings.threaded if server.respond_to? :threaded= on_start_callback.call unless on_start_callback.nil? yield server if block_given? end end
.stop!
Alias for .quit!.
# File 'lib/sinatra/base.rb', line 1598
alias stop! quit!
.synchronize(&block) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1886
def synchronize(&block) if lock? @@mutex.synchronize(&block) else yield end end
.template(name, &block)
Define a named template. The block must return the template source.
# File 'lib/sinatra/base.rb', line 1409
def template(name, &block) filename, line = caller_locations.first templates[name] = [block, filename, line.to_i] end
.unlink(path, opts = {}, &block)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1548
def unlink(path, opts = {}, &block) route 'UNLINK', path, opts, &block end
.use(middleware, *args, &block)
Use the specified ::Rack
middleware
# File 'lib/sinatra/base.rb', line 1579
def use(middleware, *args, &block) @prototype = nil @middleware << [middleware, args, block] end
.user_agent(pattern) (private) Also known as: .agent
Condition for matching user agent. Parameter should be Regexp. Will set params[:agent].
.warn_for_deprecation(message) (private)
used for deprecation warnings
# File 'lib/sinatra/base.rb', line 1895
def warn_for_deprecation( ) warn + "\n\tfrom #{cleaned_caller.first.join(':')}" end
Instance Attribute Details
#app (rw)
[ GitHub ]#env (rw)
[ GitHub ]#params (rw)
[ GitHub ]#request (rw)
[ GitHub ]#response (rw)
[ GitHub ]#template_cache (readonly)
[ GitHub ]# File 'lib/sinatra/base.rb', line 978
attr_reader :template_cache
Instance Method Details
#call(env)
::Rack
call interface.
#call!(env)
# File 'lib/sinatra/base.rb', line 993
def call!(env) # :nodoc: @env = env @params = IndifferentHash.new @request = Request.new(env) @response = Response.new @pinned_response = nil template_cache.clear if settings.reload_templates invoke { dispatch! } invoke { error_block!(response.status) } unless @env['sinatra.error'] unless @response['content-type'] if Array === body && body[0].respond_to?(:content_type) content_type body[0].content_type elsif (default = settings.default_content_type) content_type default end end @response.finish end
#dispatch! (private)
Dispatch a request with error handling.
# File 'lib/sinatra/base.rb', line 1176
def dispatch! # Avoid passing frozen string in force_encoding @params.merge!(@request.params).each do |key, val| next unless val.respond_to?(:force_encoding) val = val.dup if val.frozen? @params[key] = force_encoding(val) end invoke do static! if settings.static? && (request.get? || request.head?) filter! :before do @pinned_response = !response['content-type'].nil? end route! end rescue ::Exception => e invoke { handle_exception!(e) } ensure begin filter! :after unless env['sinatra.static_file'] rescue ::Exception => e invoke { handle_exception!(e) } unless @env['sinatra.error'] end end
#dump_errors!(boom) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1268
def dump_errors!(boom) if boom.respond_to?(: ) msg = boom. (highlight: false) if msg =~ /\A(.*?)(?: \(#{ Regexp.quote(boom.class.to_s) }\))?\n/ msg = $1 additional_msg = $'.lines(chomp: true) else additional_msg = [] end else msg = boom. additional_msg = [] end msg = ["#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} - #{boom.class} - #{msg}:", *additional_msg, *boom.backtrace].join("\n\t") @env['rack.errors'].puts(msg) end
#error_block!(key, *block_params) (private)
Find an custom error block for the key(s) specified.
# File 'lib/sinatra/base.rb', line 1249
def error_block!(key, *block_params) base = settings while base.respond_to?(:errors) args_array = base.errors[key] next base = base.superclass unless args_array args_array.reverse_each do |args| first = args == args_array.first args += [block_params] resp = process_route(*args) return resp unless resp.nil? && !first end end return false unless key.respond_to?(:superclass) && (key.superclass < Exception) error_block!(key.superclass, *block_params) end
#filter!(type, base = settings, &block) (private)
Run filters defined on the class and all superclasses. Accepts an optional block to call after each filter is applied.
# File 'lib/sinatra/base.rb', line 1054
def filter!(type, base = settings, &block) filter!(type, base.superclass, &block) if base.superclass.respond_to?(:filters) base.filters[type].each do |args| result = process_route(*args) block.call(result) if block_given? end end
#force_encoding(*args) (private)
[ GitHub ]# File 'lib/sinatra/base.rb', line 1922
def force_encoding(*args) settings.force_encoding(*args) end
#forward
Forward the request to the downstream app -- middleware only.
#halt(*response)
Exit the current block, halts any further processing of the request, and returns the specified response.
#handle_exception!(boom) (private)
Error
handling during requests.
# File 'lib/sinatra/base.rb', line 1203
def handle_exception!(boom) error_params = @env['sinatra.error.params'] @params = @params.merge(error_params) if error_params @env['sinatra.error'] = boom http_status = if boom.is_a? Sinatra::Error if boom.respond_to? :http_status boom.http_status elsif settings.use_code? && boom.respond_to?(:code) boom.code end end http_status = 500 unless http_status&.between?(400, 599) status(http_status) if server_error? dump_errors! boom if settings.dump_errors? raise boom if settings.show_exceptions? && (settings.show_exceptions != :after_handler) elsif not_found? headers['X-Cascade'] = 'pass' if settings.x_cascade? end if (res = error_block!(boom.class, boom) || error_block!(status, boom)) return res end if not_found? || bad_request? if boom. && boom. != boom.class.name body Rack::Utils.escape_html(boom. ) else content_type 'text/html' body "<h1>#{not_found? ? 'Not Found' : 'Bad Request'}</h1>" end end return unless server_error? raise boom if settings.raise_errors? || settings.show_exceptions? error_block! Exception, boom end
#invoke(&block) (private)
Run the block with 'throw :halt' support and apply result to the response.
# File 'lib/sinatra/base.rb', line 1160
def invoke(&block) res = catch(:halt, &block) res = [res] if (Integer === res) || (String === res) if (Array === res) && (Integer === res.first) res = res.dup status(res.shift) body(res.pop) headers(*res) elsif res.respond_to? :each body res end nil # avoid double setting the same response tuple twice end
#pass(&block)
Pass control to the next matching route.
If there are no more matching routes, ::Sinatra
will
return a 404 response.
# File 'lib/sinatra/base.rb', line 1035
def pass(&block) throw :pass, block end
#process_route(pattern, conditions, block = nil, values = []) (private)
If the current request matches pattern and conditions, fill params with keys and call the given block. Revert params afterwards.
Returns pass block.
# File 'lib/sinatra/base.rb', line 1097
def process_route(pattern, conditions, block = nil, values = []) route = @request.path_info route = '/' if route.empty? && !settings.empty_path_info? route = route[0..-2] if !settings.strict_paths? && route != '/' && route.end_with?('/') params = pattern.params(route) return unless params params.delete('ignore') # TODO: better params handling, maybe turn it into "smart" object or detect changes force_encoding(params) @params = @params.merge(params) { |_k, v1, v2| v2 || v1 } if params.any? regexp_exists = pattern.is_a?(Mustermann::Regular) || (pattern.respond_to?(:patterns) && pattern.patterns.any? { |subpattern| subpattern.is_a?(Mustermann::Regular) }) if regexp_exists captures = pattern.match(route).captures.map { |c| URI_INSTANCE.unescape(c) if c } values += captures @params[:captures] = force_encoding(captures) unless captures.nil? || captures.empty? else values += params.values.flatten end catch(:pass) do conditions.each { |c| throw :pass if c.bind(self).call == false } block ? block[self, values] : yield(self, values) end rescue StandardError @env['sinatra.error.params'] = @params raise ensure params ||= {} params.each { |k, _| @params.delete(k) } unless @env['sinatra.error.params'] end
#route!(base = settings, pass_block = nil) (private)
Run routes defined on the class and all superclasses.
# File 'lib/sinatra/base.rb', line 1063
def route!(base = settings, pass_block = nil) routes = base.routes[@request.request_method] routes&.each do |pattern, conditions, block| response.delete_header('content-type') unless @pinned_response returned_pass_block = process_route(pattern, conditions) do |*args| env['sinatra.route'] = "#{@request.request_method} #{pattern}" route_eval { block[*args] } end # don't wipe out pass_block in superclass pass_block = returned_pass_block if returned_pass_block end # Run routes defined in superclass. if base.superclass.respond_to?(:routes) return route!(base.superclass, pass_block) end route_eval(&pass_block) if pass_block route_missing end
#route_eval (private)
Run a route block and throw :halt
with the result.
# File 'lib/sinatra/base.rb', line 1088
def route_eval throw :halt, yield end
#route_missing (private)
No matching route was found or all routes passed. The default
implementation is to forward the request downstream when running
as middleware (@app is non-nil); when no downstream app is set, raise
a NotFound
exception. Subclasses can override this method to perform
custom route miss logic.
#settings
Access settings defined with Base
.set.
# File 'lib/sinatra/base.rb', line 1021
def settings self.class.settings end
#static!(options = {}) (private)
Attempt to serve static files from public directory. Throws :halt
when
a matching file is found, returns nil otherwise.
# File 'lib/sinatra/base.rb', line 1143
def static!( = {}) return if (public_dir = settings.public_folder).nil? path = "#{public_dir}#{URI_INSTANCE.unescape(request.path_info)}" return unless valid_path?(path) path = File. (path) return unless path.start_with?("#{File. (public_dir)}/") return unless File.file?(path) env['sinatra.static_file'] = path cache_control(*settings.static_cache_control) if settings.static_cache_control? send_file path, .merge(disposition: nil) end