Sinatra includes an API for extension authors to help ensure that consistent behavior is provided for application developers.
Some knowledge of Sinatra’s internal design is required to write good extensions. This section provides a high level overview of the classes and idioms at the core of Sinatra’s design.
Sinatra has two distinct modes of use that extensions should be aware of:
The “Classic” style, where applications are defined on main / the top-level – most of the examples and documentation target this usage. Classic applications are often single-file, standalone apps that are run directly from the command line or with a minimal rackup file. When an extension is required in a classic application, the expectation is that all extension functionality should be present without additional setup on the application developers part (like included/extending modules).
The “Modular” style, where
Sinatra::Baseis subclassed explicitly and the application is defined within the subclass’s scope. These applications are often bundled as libraries and used as components within a larger Rack-based system. Modular applications must include any desired extensions explicitly by calling
register ExtensionModulewithin the application’s class scope.
Most extensions are relevant to both styles but care must be taken by
extension authors to ensure that extensions do the right thing under each
style. The extension API (
provided to help extension authors with this task.
Important: The following notes on
Sinatra::Application are provided for background only - extension
authors should not need to modify these classes directly.
Sinatra::Base class provides the context for all evaluation in a
Sinatra application. The top-level DSLish stuff exists in class scope
while request-level stuff exists at instance scope.
Applications are defined within the class scope of a
subclass. The “DSL” (e.g.,
etc.) is simply a set of class methods defined on
the DSL is achieved by adding class methods to
Sinatra::Base or one of its
subclasses. However, Base classes should not be extended with
Sinatra.register method (described below) is provided
for this task.
Requests are evaluated within a new
Sinatra::Base instance – routes,
before filters, views, helpers, and error pages all share this same context.
The default set of request-level helper methods (e.g,
content_type, etc.) are simple instance methods defined on
or within modules that are included in
Sinatra::Base. Providing new
functionality at the request level is achieved by adding instance methods to
As with DSL extensions, helper modules should not be added directly to
Sinatra::Base by extension authors with
Sinatra.helpers method (described below) is provided for this task.
Sinatra::Application class provides the default execution context
for classic style applications. It is a simple subclass of
Sinatra::Base that provides default option values and other behavior
tailored for top-level apps. When a classic style application is run,
Sinatra::Application public class methods are exported to the
Rules for Extensions
Sinatra::Basedirectly. You should not include or extend, change option values, or modify its behavior elsewise. Modular style applications will include your extension in their subclass explicitly using the
require 'sinatra'in your extension. You should only ever need to
require 'sinatra/base'. The reason for this is that
require 'sinatra'is what triggers the classic style – extensions should never trigger the classic style.
Use the APIs described below where possible. You should not need to include or extend modules directly or define methods directly on a core Sinatra class. The specialized methods below handle all of that for you.
Extensions should be defined in separate modules under the
Sinatramodule. For example, an extension that added basic authentication primitives might be named
Extending The Request Context with
The most common type of extension is one that adds methods for use in routes, views, and helper methods.
For example, suppose you wanted to write an extension that added an
method that escaped reserved HTML characters (such as those found in other
popular Ruby web frameworks).
The call to
Sinatra.helpers includes the module in
Sinatra::Application, making all methods defined in the module
available to classic style applications. Using this extension in classic
style apps is as simple as requiring the extension and using the new
Sinatra::Base subclasses, on the other hand, must require and include
the module explicitly using the
Extending The DSL (class) Context with
Extensions can also extend Sinatra’s class level DSL using the
Sinatra.register method. Here’s an extension that adds a
block_links_from macro that checks the referer on each request for
a app provided pattern and sends back a
403 Forbidden response when
a match is detected:
Sinatra.register adds all public methods in the module(s) given as class
Sinatra::Application. It also handles exporting public methods to
the top-level when classic style apps are executed.
A classic style application would use this extension as follows:
Modular style applications must register the extension explicitly in their
Setting Options and Other Extension Setup
Extensions can define options, routes, before filters, and error handlers by
registered method on the extension module. The
method is called immediately after the extension module is added to the
Sinatra::Base subclass and is passed the class that the module was
The following example creates a very simple extension that adds basic session auth support. Options are added for the username and password, routes are defined for logging in, and helper methods are provided for determining whether a user has been authorized:
A classic application would use this extension by requiring the extension library, overriding options, and using the helpers provided:
A modular application is different only in that it must register the extension module explicitly:
Building and Packaging Extensions
Sinatra extensions should be built as separate libraries and packaged as
gems or as single files that can be included within an application’s
directory. The ideal process for using an extensions is installing a gem
and requiring a single file.
The following is an example file layout for a typical extension packaged as a gem:
sinatra-fu |-- README |-- LICENSE |-- Rakefile |-- lib | `-- sinatra | `-- fu.rb |-- test | `-- spec_sinatra_fu.rb `-- sinatra-fu.gemspec