2008-03-24 20:20:58 -04:00
|
|
|
= Sinatra
|
|
|
|
|
2009-04-19 12:34:41 -04:00
|
|
|
Sinatra is a DSL for quickly creating web applications in Ruby with minimal
|
2009-01-11 10:59:34 -05:00
|
|
|
effort:
|
2008-03-24 20:20:58 -04:00
|
|
|
|
|
|
|
# myapp.rb
|
|
|
|
require 'sinatra'
|
2010-09-07 12:18:35 -04:00
|
|
|
|
2008-03-24 20:20:58 -04:00
|
|
|
get '/' do
|
|
|
|
'Hello world!'
|
|
|
|
end
|
|
|
|
|
2009-01-24 02:19:56 -05:00
|
|
|
Install the gem and run with:
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2010-09-07 04:23:28 -04:00
|
|
|
gem install sinatra
|
|
|
|
ruby -rubygems myapp.rb
|
2009-01-24 02:19:56 -05:00
|
|
|
|
|
|
|
View at: http://localhost:4567
|
|
|
|
|
|
|
|
== Routes
|
|
|
|
|
|
|
|
In Sinatra, a route is an HTTP method paired with an URL matching pattern.
|
|
|
|
Each route is associated with a block:
|
2008-03-24 20:20:58 -04:00
|
|
|
|
|
|
|
get '/' do
|
2009-01-24 02:19:56 -05:00
|
|
|
.. show something ..
|
2008-03-24 20:20:58 -04:00
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2008-03-24 20:20:58 -04:00
|
|
|
post '/' do
|
|
|
|
.. create something ..
|
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2008-03-24 20:20:58 -04:00
|
|
|
put '/' do
|
|
|
|
.. update something ..
|
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2008-03-24 20:20:58 -04:00
|
|
|
delete '/' do
|
|
|
|
.. annihilate something ..
|
|
|
|
end
|
2010-11-29 15:08:44 -05:00
|
|
|
|
|
|
|
options '/' do
|
|
|
|
.. appease something ..
|
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2009-01-24 02:19:56 -05:00
|
|
|
Routes are matched in the order they are defined. The first route that
|
2008-08-31 03:53:21 -04:00
|
|
|
matches the request is invoked.
|
2008-03-24 21:28:24 -04:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
Route patterns may include named parameters, accessible via the
|
|
|
|
<tt>params</tt> hash:
|
2008-03-24 21:28:24 -04:00
|
|
|
|
2009-01-24 02:19:56 -05:00
|
|
|
get '/hello/:name' do
|
2009-05-20 13:56:58 -04:00
|
|
|
# matches "GET /hello/foo" and "GET /hello/bar"
|
2008-12-13 16:06:02 -05:00
|
|
|
# params[:name] is 'foo' or 'bar'
|
2009-01-11 10:59:34 -05:00
|
|
|
"Hello #{params[:name]}!"
|
2008-03-24 21:28:24 -04:00
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2009-01-28 15:27:32 -05:00
|
|
|
You can also access named parameters via block parameters:
|
|
|
|
|
|
|
|
get '/hello/:name' do |n|
|
|
|
|
"Hello #{n}!"
|
|
|
|
end
|
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
Route patterns may also include splat (or wildcard) parameters, accessible
|
|
|
|
via the <tt>params[:splat]</tt> array.
|
2008-03-24 21:28:24 -04:00
|
|
|
|
2008-04-24 22:24:31 -04:00
|
|
|
get '/say/*/to/*' do
|
|
|
|
# matches /say/hello/to/world
|
2008-12-13 16:06:02 -05:00
|
|
|
params[:splat] # => ["hello", "world"]
|
2008-04-24 22:24:31 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
get '/download/*.*' do
|
|
|
|
# matches /download/path/to/file.xml
|
2008-12-13 16:06:02 -05:00
|
|
|
params[:splat] # => ["path/to/file", "xml"]
|
2008-03-24 21:28:24 -04:00
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
Route matching with Regular Expressions:
|
|
|
|
|
|
|
|
get %r{/hello/([\w]+)} do
|
|
|
|
"Hello, #{params[:captures].first}!"
|
|
|
|
end
|
|
|
|
|
2009-01-28 15:27:32 -05:00
|
|
|
Or with a block parameter:
|
|
|
|
|
|
|
|
get %r{/hello/([\w]+)} do |c|
|
|
|
|
"Hello, #{c}!"
|
|
|
|
end
|
|
|
|
|
2010-09-02 08:13:36 -04:00
|
|
|
=== Conditions
|
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
Routes may include a variety of matching conditions, such as the user agent:
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2008-03-24 21:28:24 -04:00
|
|
|
get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
|
|
|
|
"You're using Songbird version #{params[:agent][0]}"
|
|
|
|
end
|
|
|
|
|
|
|
|
get '/foo' do
|
2008-12-13 16:06:02 -05:00
|
|
|
# Matches non-songbird browsers
|
2008-03-24 21:28:24 -04:00
|
|
|
end
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2010-09-03 01:57:49 -04:00
|
|
|
Other available conditions are +host_name+ and +provides+:
|
2010-09-02 08:13:36 -04:00
|
|
|
|
|
|
|
get '/', :host_name => /^admin\./ do
|
|
|
|
"Admin Area, Access denied!"
|
|
|
|
end
|
|
|
|
|
|
|
|
get '/', :provides => 'html' do
|
|
|
|
haml :index
|
|
|
|
end
|
|
|
|
|
|
|
|
get '/', :provides => ['rss', 'atom', 'xml'] do
|
|
|
|
builder :feed
|
|
|
|
end
|
|
|
|
|
|
|
|
You can easily define your own conditions:
|
|
|
|
|
|
|
|
set(:probability) { |value| condition { rand <= value } }
|
|
|
|
|
|
|
|
get '/win_a_car', :probability => 0.1 do
|
|
|
|
"You won!"
|
|
|
|
end
|
|
|
|
|
|
|
|
get '/win_a_car' do
|
|
|
|
"Sorry, you lost."
|
|
|
|
end
|
|
|
|
|
2010-09-02 15:37:07 -04:00
|
|
|
=== Return values
|
|
|
|
|
|
|
|
The return value of a route block determines at least the response body passed
|
|
|
|
on to the HTTP client, or at least the next middleware in the Rack stack.
|
|
|
|
Most commonly this is a string, as in the above examples. But other values are
|
|
|
|
also accepted.
|
|
|
|
|
2010-09-10 10:33:45 -04:00
|
|
|
You can return any object that would either be a valid Rack response, Rack
|
|
|
|
body object or HTTP status code:
|
2010-09-02 15:37:07 -04:00
|
|
|
|
2010-09-03 02:00:27 -04:00
|
|
|
* An Array with three elements: <tt>[status (Fixnum), headers (Hash), response body (responds to #each)]</tt>
|
|
|
|
* An Array with two elements: <tt>[status (Fixnum), response body (responds to #each)]</tt>
|
2010-09-03 02:01:23 -04:00
|
|
|
* An object that responds to <tt>#each</tt> and passes nothing but strings to the given block
|
2010-09-02 15:37:07 -04:00
|
|
|
* A Fixnum representing the status code
|
|
|
|
|
|
|
|
That way we can for instance easily implement a streaming example:
|
|
|
|
|
|
|
|
class Stream
|
|
|
|
def each
|
|
|
|
100.times { |i| yield "#{i}\n" }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-09-07 08:53:43 -04:00
|
|
|
get('/') { Stream.new }
|
2010-09-02 15:37:07 -04:00
|
|
|
|
2008-12-13 16:06:02 -05:00
|
|
|
== Static Files
|
2008-03-26 22:02:28 -04:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
Static files are served from the <tt>./public</tt> directory. You can specify
|
|
|
|
a different location by setting the <tt>:public</tt> option:
|
2008-12-13 16:06:02 -05:00
|
|
|
|
|
|
|
set :public, File.dirname(__FILE__) + '/static'
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2009-01-24 02:19:56 -05:00
|
|
|
Note that the public directory name is not included in the URL. A file
|
2009-01-24 16:31:51 -05:00
|
|
|
<tt>./public/css/style.css</tt> is made available as
|
|
|
|
<tt>http://example.com/css/style.css</tt>.
|
2009-01-24 02:19:56 -05:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
== Views / Templates
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2009-01-24 02:19:56 -05:00
|
|
|
Templates are assumed to be located directly under the <tt>./views</tt>
|
2009-01-11 10:59:34 -05:00
|
|
|
directory. To use a different views directory:
|
2008-12-13 16:06:02 -05:00
|
|
|
|
|
|
|
set :views, File.dirname(__FILE__) + '/templates'
|
|
|
|
|
2009-03-25 12:45:48 -04:00
|
|
|
One important thing to remember is that you always have to reference
|
|
|
|
templates with symbols, even if they're in a subdirectory (in this
|
2010-09-23 07:46:03 -04:00
|
|
|
case use <tt>:'subdir/template'</tt>). You must use a symbol because
|
|
|
|
otherwise rendering methods will render any strings passed to them
|
|
|
|
directly.
|
2009-03-25 12:45:48 -04:00
|
|
|
|
2008-08-31 03:53:21 -04:00
|
|
|
=== Haml Templates
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
The <tt>haml</tt> gem/library is required to render HAML templates:
|
2009-01-11 10:59:34 -05:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require haml in your app
|
2009-04-24 20:10:46 -04:00
|
|
|
require 'haml'
|
|
|
|
|
2008-03-24 20:20:58 -04:00
|
|
|
get '/' do
|
|
|
|
haml :index
|
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
|
|
|
Renders <tt>./views/index.haml</tt>.
|
|
|
|
|
2010-05-26 14:15:45 -04:00
|
|
|
{Haml's options}[http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#options]
|
2009-03-14 22:10:55 -04:00
|
|
|
can be set globally through Sinatra's configurations,
|
|
|
|
see {Options and Configurations}[http://www.sinatrarb.com/configuration.html],
|
|
|
|
and overridden on an individual basis.
|
|
|
|
|
2010-09-07 12:18:35 -04:00
|
|
|
set :haml, :format => :html5 # default Haml format is :xhtml
|
2009-03-14 22:10:55 -04:00
|
|
|
|
|
|
|
get '/' do
|
2010-09-07 12:18:35 -04:00
|
|
|
haml :index, :format => :html4 # overridden
|
2009-03-14 22:10:55 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
=== Erb Templates
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require erb in your app
|
2009-04-24 20:10:46 -04:00
|
|
|
require 'erb'
|
|
|
|
|
2008-08-31 03:53:21 -04:00
|
|
|
get '/' do
|
|
|
|
erb :index
|
|
|
|
end
|
|
|
|
|
2011-01-10 18:30:17 -05:00
|
|
|
Renders <tt>./views/index.erb</tt>.
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2011-01-10 18:30:17 -05:00
|
|
|
=== Erubis Templates
|
2009-12-22 21:11:09 -05:00
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
The <tt>erubis</tt> gem/library is required to render Erubis templates:
|
2009-12-22 21:11:09 -05:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require erubis in your app
|
2009-12-22 21:11:09 -05:00
|
|
|
require 'erubis'
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
erubis :index
|
|
|
|
end
|
|
|
|
|
2011-01-10 18:30:17 -05:00
|
|
|
Renders <tt>./views/index.erubis</tt>.
|
|
|
|
|
|
|
|
It is also possible to replace Erb with Erubis:
|
|
|
|
|
|
|
|
require 'erubis'
|
|
|
|
Tilt.register :erb, Tilt[:erubis]
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
erb :index
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/index.erb</tt> with Erubis.
|
2009-12-22 21:11:09 -05:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
=== Builder Templates
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
The <tt>builder</tt> gem/library is required to render builder templates:
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require builder in your app
|
2009-04-24 20:10:46 -04:00
|
|
|
require 'builder'
|
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
get '/' do
|
|
|
|
builder :index
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/index.builder</tt>.
|
|
|
|
|
2010-10-10 07:53:43 -04:00
|
|
|
=== Nokogiri Templates
|
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
The <tt>nokogiri</tt> gem/library is required to render nokogiri templates:
|
2010-10-10 07:53:43 -04:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require nokogiri in your app
|
2010-10-10 07:53:43 -04:00
|
|
|
require 'nokogiri'
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
nokogiri :index
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/index.nokogiri</tt>.
|
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
=== Sass Templates
|
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
The <tt>haml</tt> or <tt>sass</tt> gem/library is required to render Sass templates:
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require haml or sass in your app
|
2009-04-24 20:10:46 -04:00
|
|
|
require 'sass'
|
|
|
|
|
2008-04-08 16:51:28 -04:00
|
|
|
get '/stylesheet.css' do
|
|
|
|
sass :stylesheet
|
|
|
|
end
|
|
|
|
|
2008-08-31 03:53:21 -04:00
|
|
|
Renders <tt>./views/stylesheet.sass</tt>.
|
|
|
|
|
2010-05-26 14:15:45 -04:00
|
|
|
{Sass' options}[http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options]
|
2009-03-14 22:10:55 -04:00
|
|
|
can be set globally through Sinatra's configurations,
|
|
|
|
see {Options and Configurations}[http://www.sinatrarb.com/configuration.html],
|
|
|
|
and overridden on an individual basis.
|
|
|
|
|
2010-09-07 12:18:35 -04:00
|
|
|
set :sass, :style => :compact # default Sass style is :nested
|
2009-03-14 22:10:55 -04:00
|
|
|
|
|
|
|
get '/stylesheet.css' do
|
2009-12-19 03:06:28 -05:00
|
|
|
sass :stylesheet, :style => :expanded # overridden
|
2009-03-14 22:10:55 -04:00
|
|
|
end
|
|
|
|
|
2010-08-29 20:56:44 -04:00
|
|
|
=== Scss Templates
|
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
The <tt>haml</tt> or <tt>sass</tt> gem/library is required to render Scss templates:
|
2010-08-29 20:56:44 -04:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require haml or sass in your app
|
2010-08-29 20:56:44 -04:00
|
|
|
require 'sass'
|
|
|
|
|
|
|
|
get '/stylesheet.css' do
|
|
|
|
scss :stylesheet
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/stylesheet.scss</tt>.
|
|
|
|
|
|
|
|
{Scss' options}[http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options]
|
|
|
|
can be set globally through Sinatra's configurations,
|
|
|
|
see {Options and Configurations}[http://www.sinatrarb.com/configuration.html],
|
|
|
|
and overridden on an individual basis.
|
|
|
|
|
2010-09-07 12:18:35 -04:00
|
|
|
set :scss, :style => :compact # default Scss style is :nested
|
2010-08-29 20:56:44 -04:00
|
|
|
|
|
|
|
get '/stylesheet.css' do
|
|
|
|
scss :stylesheet, :style => :expanded # overridden
|
|
|
|
end
|
|
|
|
|
2010-03-01 07:13:10 -05:00
|
|
|
=== Less Templates
|
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
The <tt>less</tt> gem/library is required to render Less templates:
|
2010-03-01 07:13:10 -05:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require less in your app
|
2010-03-01 07:13:10 -05:00
|
|
|
require 'less'
|
|
|
|
|
|
|
|
get '/stylesheet.css' do
|
|
|
|
less :stylesheet
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/stylesheet.less</tt>.
|
|
|
|
|
2010-09-11 07:53:49 -04:00
|
|
|
=== Liquid Templates
|
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
The <tt>liquid</tt> gem/library is required to render Liquid templates:
|
2010-09-11 07:53:49 -04:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require liquid in your app
|
2010-09-11 07:53:49 -04:00
|
|
|
require 'liquid'
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
liquid :index
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/index.liquid</tt>.
|
|
|
|
|
|
|
|
Since you cannot call Ruby methods (except for +yield+) from a Liquid
|
|
|
|
template, you almost always want to pass locals to it:
|
|
|
|
|
|
|
|
liquid :index, :locals => { :key => 'value' }
|
|
|
|
|
2010-09-11 08:34:41 -04:00
|
|
|
=== Markdown Templates
|
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
The <tt>rdiscount</tt> gem/library is required to render Markdown templates:
|
2010-09-11 08:34:41 -04:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require rdiscount in your app
|
2010-09-11 08:34:41 -04:00
|
|
|
require "rdiscount"
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
markdown :index
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/index.markdown</tt> (+md+ and +mkd+ are also valid file
|
|
|
|
extensions).
|
|
|
|
|
2011-01-11 03:13:18 -05:00
|
|
|
It is not possible to call methods from markdown, nor to pass locals to it.
|
|
|
|
You therefore will usually use it in combination with another rendering
|
|
|
|
engine:
|
2010-09-11 08:34:41 -04:00
|
|
|
|
|
|
|
erb :overview, :locals => { :text => markdown(:introduction) }
|
|
|
|
|
2011-01-11 03:13:18 -05:00
|
|
|
Note that you may also call the +markdown+ method from within other templates:
|
2010-09-11 08:34:41 -04:00
|
|
|
|
|
|
|
%h1 Hello From Haml!
|
|
|
|
%p= markdown(:greetings)
|
|
|
|
|
2011-01-11 04:30:46 -05:00
|
|
|
Since you cannot call Ruby from Markdown, you cannot use layouts written in
|
|
|
|
Markdown. However, it is possible to use another rendering engine for the
|
|
|
|
template than for the layout by passing the `:layout_engine` option:
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
markdown :index, :layout_engine => :erb
|
|
|
|
end
|
|
|
|
|
|
|
|
This will render <tt>./views/index.md</tt> with <tt>./views/layout.erb</tt> as
|
|
|
|
layout.
|
|
|
|
|
|
|
|
Remember that you can set such rendering options globally:
|
|
|
|
|
|
|
|
set :markdown, :layout_engine => :haml, :layout => :post
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
markdown :index
|
|
|
|
end
|
|
|
|
|
|
|
|
This will render <tt>./views/index.md</tt> (and any other Markdown template)
|
|
|
|
with <tt>./views/post.haml</tt> as layout.
|
|
|
|
|
2011-01-11 03:13:18 -05:00
|
|
|
It is also possible to parse Markdown with BlueCloth rather than RDiscount:
|
|
|
|
|
|
|
|
require 'bluecloth'
|
|
|
|
|
|
|
|
Tilt.register 'markdown', BlueClothTemplate
|
|
|
|
Tilt.register 'mkd', BlueClothTemplate
|
|
|
|
Tilt.register 'md', BlueClothTemplate
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
markdown :index
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/index.md</tt> with BlueCloth.
|
|
|
|
|
2010-09-11 08:52:55 -04:00
|
|
|
=== Textile Templates
|
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
The <tt>RedCloth</tt> gem/library is required to render Textile templates:
|
2010-09-11 08:52:55 -04:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require redcloth in your app
|
2010-09-11 08:52:55 -04:00
|
|
|
require "redcloth"
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
textile :index
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/index.textile</tt>.
|
|
|
|
|
2011-01-11 03:13:18 -05:00
|
|
|
It is not possible to call methods from textile, nor to pass locals to it. You
|
|
|
|
therefore will usually use it in combination with another rendering engine:
|
2010-09-11 08:52:55 -04:00
|
|
|
|
|
|
|
erb :overview, :locals => { :text => textile(:introduction) }
|
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
Note that you may also call the +textile+ method from within other templates:
|
2010-09-11 08:52:55 -04:00
|
|
|
|
|
|
|
%h1 Hello From Haml!
|
|
|
|
%p= textile(:greetings)
|
|
|
|
|
2011-01-11 04:30:46 -05:00
|
|
|
Since you cannot call Ruby from Textile, you cannot use layouts written in
|
|
|
|
Textile. However, it is possible to use another rendering engine for the
|
|
|
|
template than for the layout by passing the `:layout_engine` option:
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
textile :index, :layout_engine => :erb
|
|
|
|
end
|
|
|
|
|
|
|
|
This will render <tt>./views/index.textile</tt> with
|
|
|
|
<tt>./views/layout.erb</tt> as layout.
|
|
|
|
|
|
|
|
Remember that you can set such rendering options globally:
|
|
|
|
|
|
|
|
set :textile, :layout_engine => :haml, :layout => :post
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
textile :index
|
|
|
|
end
|
|
|
|
|
|
|
|
This will render <tt>./views/index.textile</tt> (and any other Textile
|
|
|
|
template) with <tt>./views/post.haml</tt> as layout.
|
|
|
|
|
2010-09-12 07:59:00 -04:00
|
|
|
=== RDoc Templates
|
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
The <tt>rdoc</tt> gem/library is required to render RDoc templates:
|
2010-09-12 07:59:00 -04:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require rdoc in your app
|
2010-09-12 07:59:00 -04:00
|
|
|
require "rdoc"
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
rdoc :index
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/index.rdoc</tt>.
|
|
|
|
|
2011-01-11 03:13:18 -05:00
|
|
|
It is not possible to call methods from rdoc, nor to pass locals to it. You
|
|
|
|
therefore will usually use it in combination with another rendering engine:
|
2010-09-12 07:59:00 -04:00
|
|
|
|
|
|
|
erb :overview, :locals => { :text => rdoc(:introduction) }
|
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
Note that you may also call the +rdoc+ method from within other templates:
|
2010-09-12 07:59:00 -04:00
|
|
|
|
|
|
|
%h1 Hello From Haml!
|
|
|
|
%p= rdoc(:greetings)
|
|
|
|
|
2011-01-11 04:30:46 -05:00
|
|
|
Since you cannot call Ruby from RDoc, you cannot use layouts written in
|
|
|
|
RDoc. However, it is possible to use another rendering engine for the
|
|
|
|
template than for the layout by passing the `:layout_engine` option:
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
rdoc :index, :layout_engine => :erb
|
|
|
|
end
|
|
|
|
|
|
|
|
This will render <tt>./views/index.rdoc</tt> with <tt>./views/layout.erb</tt> as
|
|
|
|
layout.
|
|
|
|
|
|
|
|
Remember that you can set such rendering options globally:
|
|
|
|
|
|
|
|
set :rdoc, :layout_engine => :haml, :layout => :post
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
rdoc :index
|
|
|
|
end
|
|
|
|
|
|
|
|
This will render <tt>./views/index.rdoc</tt> (and any other RDoc template)
|
|
|
|
with <tt>./views/post.haml</tt> as layout.
|
|
|
|
|
2010-09-12 09:14:45 -04:00
|
|
|
=== Radius Templates
|
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
The <tt>radius</tt> gem/library is required to render Radius templates:
|
2010-09-12 09:14:45 -04:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require radius in your app
|
2010-09-12 09:14:45 -04:00
|
|
|
require 'radius'
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
radius :index
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/index.radius</tt>.
|
|
|
|
|
|
|
|
Since you cannot call Ruby methods (except for +yield+) from a Radius
|
|
|
|
template, you almost always want to pass locals to it:
|
|
|
|
|
|
|
|
radius :index, :locals => { :key => 'value' }
|
|
|
|
|
2010-09-12 11:00:33 -04:00
|
|
|
=== Markaby Templates
|
|
|
|
|
2011-01-11 03:31:11 -05:00
|
|
|
The <tt>markaby</tt> gem/library is required to render Markaby templates:
|
2010-09-12 11:00:33 -04:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require markaby in your app
|
2010-09-12 11:00:33 -04:00
|
|
|
require 'markaby'
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
markaby :index
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/index.mab</tt>.
|
|
|
|
|
2011-01-11 03:33:26 -05:00
|
|
|
You may also use inline Markaby:
|
2010-11-12 15:18:52 -05:00
|
|
|
|
|
|
|
get '/' do
|
|
|
|
markaby { h1 "Welcome!" }
|
|
|
|
end
|
|
|
|
|
2010-11-05 08:59:49 -04:00
|
|
|
=== Slim Templates
|
|
|
|
|
2011-01-11 03:32:25 -05:00
|
|
|
The <tt>slim</tt> gem/library is required to render Slim templates:
|
2010-11-05 08:59:49 -04:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require slim in your app
|
2010-11-05 08:59:49 -04:00
|
|
|
require 'slim'
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
slim :index
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/index.slim</tt>.
|
|
|
|
|
2010-09-12 17:09:10 -04:00
|
|
|
=== CoffeeScript Templates
|
|
|
|
|
2011-01-11 03:34:26 -05:00
|
|
|
The <tt>coffee-script</tt> gem/library and at least <b>one</b> of the
|
|
|
|
following options to execute JavaScript:
|
|
|
|
|
|
|
|
* +node+ (from Node.js) in your path
|
|
|
|
* you must be running on OSX
|
|
|
|
* +therubyracer+ gem/library
|
|
|
|
|
|
|
|
See http://github.com/josh/ruby-coffee-script for an updated list of options.
|
|
|
|
|
|
|
|
Now you can render CoffeeScript templates:
|
2010-09-12 17:09:10 -04:00
|
|
|
|
2011-01-11 03:15:31 -05:00
|
|
|
# You'll need to require coffee-script in your app
|
2010-09-12 17:09:10 -04:00
|
|
|
require 'coffee-script'
|
|
|
|
|
|
|
|
get '/application.js' do
|
|
|
|
coffee :application
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/application.coffee</tt>.
|
|
|
|
|
2011-01-11 04:33:40 -05:00
|
|
|
=== Embedded Templates
|
2008-03-24 20:20:58 -04:00
|
|
|
|
|
|
|
get '/' do
|
|
|
|
haml '%div.title Hello World'
|
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2011-01-11 04:33:40 -05:00
|
|
|
Renders the embedded template string.
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2009-01-24 02:19:56 -05:00
|
|
|
=== Accessing Variables in Templates
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2009-03-01 21:17:47 -05:00
|
|
|
Templates are evaluated within the same context as route handlers. Instance
|
|
|
|
variables set in route handlers are direcly accessible by templates:
|
2008-03-24 20:20:58 -04:00
|
|
|
|
|
|
|
get '/:id' do
|
|
|
|
@foo = Foo.find(params[:id])
|
2008-11-30 12:21:32 -05:00
|
|
|
haml '%h1= @foo.name'
|
2008-03-24 20:20:58 -04:00
|
|
|
end
|
|
|
|
|
2008-08-31 03:53:21 -04:00
|
|
|
Or, specify an explicit Hash of local variables:
|
2008-03-24 20:20:58 -04:00
|
|
|
|
|
|
|
get '/:id' do
|
2008-08-31 03:53:21 -04:00
|
|
|
foo = Foo.find(params[:id])
|
2008-11-30 12:21:32 -05:00
|
|
|
haml '%h1= foo.name', :locals => { :foo => foo }
|
2008-03-24 20:20:58 -04:00
|
|
|
end
|
|
|
|
|
2008-08-31 03:53:21 -04:00
|
|
|
This is typically used when rendering templates as partials from within
|
|
|
|
other templates.
|
|
|
|
|
2009-12-18 20:07:01 -05:00
|
|
|
=== Inline Templates
|
2008-03-29 19:59:45 -04:00
|
|
|
|
2008-08-31 03:53:21 -04:00
|
|
|
Templates may be defined at the end of the source file:
|
2008-03-29 19:59:45 -04:00
|
|
|
|
2009-01-16 20:01:41 -05:00
|
|
|
require 'sinatra'
|
|
|
|
|
2008-03-29 19:59:45 -04:00
|
|
|
get '/' do
|
|
|
|
haml :index
|
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2008-03-29 19:59:45 -04:00
|
|
|
__END__
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2008-05-07 17:18:43 -04:00
|
|
|
@@ layout
|
2009-01-11 10:59:34 -05:00
|
|
|
%html
|
|
|
|
= yield
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2008-05-07 17:18:43 -04:00
|
|
|
@@ index
|
2008-03-29 19:59:45 -04:00
|
|
|
%div.title Hello world!!!!!
|
|
|
|
|
2010-10-12 11:16:29 -04:00
|
|
|
NOTE: Inline templates defined in the source file that requires sinatra are
|
2010-10-12 11:27:25 -04:00
|
|
|
automatically loaded. Call <tt>enable :inline_templates</tt> explicitly if you
|
2009-12-18 20:07:01 -05:00
|
|
|
have inline templates in other source files.
|
2009-01-16 20:01:41 -05:00
|
|
|
|
2009-01-24 02:19:56 -05:00
|
|
|
=== Named Templates
|
|
|
|
|
2009-03-01 21:17:47 -05:00
|
|
|
Templates may also be defined using the top-level <tt>template</tt> method:
|
2008-03-29 19:59:45 -04:00
|
|
|
|
|
|
|
template :layout do
|
2009-01-11 10:59:34 -05:00
|
|
|
"%html\n =yield\n"
|
2008-03-29 19:59:45 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
template :index do
|
|
|
|
'%div.title Hello World!'
|
|
|
|
end
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
haml :index
|
|
|
|
end
|
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
If a template named "layout" exists, it will be used each time a template
|
2011-01-07 20:13:06 -05:00
|
|
|
is rendered. You can individually disable layouts by passing <tt>:layout => false</tt>
|
|
|
|
or disable them by default via <tt>set :haml, :layout => false</tt>.
|
2009-01-09 07:26:10 -05:00
|
|
|
|
|
|
|
get '/' do
|
|
|
|
haml :index, :layout => !request.xhr?
|
|
|
|
end
|
|
|
|
|
2011-01-11 04:37:25 -05:00
|
|
|
=== Associating File Extensions
|
|
|
|
|
|
|
|
To associate a file extension with a template engine, use
|
|
|
|
<tt>Tilt.register</tt>. For instance, if you like to use the file extension
|
|
|
|
+tt+ for Textile templates, you can do the following:
|
|
|
|
|
|
|
|
Tilt.register :tt, Tilt[:textile]
|
|
|
|
|
2011-01-11 05:02:29 -05:00
|
|
|
=== Adding You Own Template Engine
|
|
|
|
|
|
|
|
First, register your engine with Tilt, then create a rendering method:
|
|
|
|
|
|
|
|
Tilt.register :myat, MyAwesomeTemplateEngine
|
|
|
|
|
|
|
|
helpers do
|
|
|
|
def myat(*args) render(:myat, *args) end
|
|
|
|
end
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
myat :index
|
|
|
|
end
|
|
|
|
|
|
|
|
Renders <tt>./views/index.myat</tt>. See https://github.com/rtomayko/tilt to
|
|
|
|
learn more about Tilt.
|
|
|
|
|
2008-08-31 03:53:21 -04:00
|
|
|
== Filters
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2010-09-10 10:33:45 -04:00
|
|
|
Before filters are evaluated before each request within the same context as
|
|
|
|
the routes will be and can modify the request and response. Instance variables
|
|
|
|
set in filters are accessible by routes and templates:
|
2008-03-24 21:28:24 -04:00
|
|
|
|
2008-03-24 20:20:58 -04:00
|
|
|
before do
|
2008-12-13 16:06:02 -05:00
|
|
|
@note = 'Hi!'
|
|
|
|
request.path_info = '/foo/bar/baz'
|
|
|
|
end
|
|
|
|
|
|
|
|
get '/foo/*' do
|
|
|
|
@note #=> 'Hi!'
|
|
|
|
params[:splat] #=> 'bar/baz'
|
2008-03-24 20:20:58 -04:00
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2010-09-10 10:33:45 -04:00
|
|
|
After filter are evaluated after each request within the same context and can
|
|
|
|
also modify the request and response. Instance variables set in before filters
|
|
|
|
and routes are accessible by after filters:
|
2008-12-21 21:36:14 -05:00
|
|
|
|
|
|
|
after do
|
|
|
|
puts response.status
|
|
|
|
end
|
|
|
|
|
2011-02-17 10:14:56 -05:00
|
|
|
Note: Unless you use the `body` method rather than just returning a String from
|
|
|
|
the routes, the body will not yet be available in the after filter, since it is
|
|
|
|
generated later on.
|
|
|
|
|
2010-09-10 10:33:45 -04:00
|
|
|
Filters optionally taking a pattern, causing them to be evaluated only if the
|
|
|
|
request path matches that pattern:
|
2010-04-27 17:11:43 -04:00
|
|
|
|
|
|
|
before '/protected/*' do
|
|
|
|
authenticate!
|
|
|
|
end
|
|
|
|
|
|
|
|
after '/create/:slug' do |slug|
|
|
|
|
session[:last_slug] = slug
|
|
|
|
end
|
|
|
|
|
2010-11-03 08:51:52 -04:00
|
|
|
Like routes, filters also take conditions:
|
|
|
|
|
|
|
|
before :agent => /Songbird/ do
|
|
|
|
# ...
|
|
|
|
end
|
|
|
|
|
|
|
|
after '/blog/*', :host_name => 'example.com' do
|
|
|
|
# ...
|
|
|
|
end
|
|
|
|
|
2011-02-18 04:34:00 -05:00
|
|
|
== Helpers
|
|
|
|
|
|
|
|
Use the top-level <tt>helpers</tt> method to define helper methods for use in
|
|
|
|
route handlers and templates:
|
|
|
|
|
|
|
|
helpers do
|
|
|
|
def bar(name)
|
|
|
|
"#{name}bar"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
get '/:name' do
|
|
|
|
bar(params[:name])
|
|
|
|
end
|
|
|
|
|
|
|
|
=== Halting
|
2008-12-13 16:06:02 -05:00
|
|
|
|
2008-12-21 21:36:14 -05:00
|
|
|
To immediately stop a request within a filter or route use:
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
halt
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2010-09-10 10:33:45 -04:00
|
|
|
You can also specify the status when halting:
|
2009-12-19 03:16:31 -05:00
|
|
|
|
|
|
|
halt 410
|
|
|
|
|
2010-09-10 10:33:45 -04:00
|
|
|
Or the body:
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
halt 'this will be the body'
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2010-09-10 10:33:45 -04:00
|
|
|
Or both:
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
halt 401, 'go away!'
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2010-09-10 10:33:45 -04:00
|
|
|
With headers:
|
2009-12-19 03:16:31 -05:00
|
|
|
|
|
|
|
halt 402, {'Content-Type' => 'text/plain'}, 'revenge'
|
|
|
|
|
2011-02-18 04:34:00 -05:00
|
|
|
=== Passing
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2009-03-01 21:17:47 -05:00
|
|
|
A route can punt processing to the next matching route using <tt>pass</tt>:
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
get '/guess/:who' do
|
|
|
|
pass unless params[:who] == 'Frank'
|
2009-12-22 21:13:35 -05:00
|
|
|
'You got me!'
|
2009-01-11 10:59:34 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
get '/guess/*' do
|
2009-12-22 21:13:35 -05:00
|
|
|
'You missed!'
|
2009-01-11 10:59:34 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
The route block is immediately exited and control continues with the next
|
|
|
|
matching route. If no matching route is found, a 404 is returned.
|
2008-03-24 20:20:58 -04:00
|
|
|
|
2011-02-18 05:06:00 -05:00
|
|
|
=== Setting Body and Status Code
|
2011-02-18 04:58:34 -05:00
|
|
|
|
|
|
|
It is possible and recommended to set the status code and response body with the
|
|
|
|
return value of the route block. However, in some scenarios you might want to
|
|
|
|
set the body at an arbritary point in the execution flow. You can do so with the
|
|
|
|
`body` helper method. If you do so, you can use that method from there on to
|
|
|
|
access the body:
|
|
|
|
|
2011-02-18 05:10:43 -05:00
|
|
|
get '/foo' do
|
|
|
|
body "bar"
|
|
|
|
end
|
|
|
|
|
|
|
|
after do
|
|
|
|
puts body
|
|
|
|
end
|
2011-02-18 04:58:34 -05:00
|
|
|
|
|
|
|
It is also possible to pass a block to body, that will be executed by the rack
|
|
|
|
handler (this can be used to implement streaming, see
|
|
|
|
[Return values](#Return%20values)).
|
|
|
|
|
|
|
|
Similar to the body, you can also set the status code:
|
|
|
|
|
|
|
|
get '/foo' do
|
|
|
|
status 418
|
|
|
|
halt "I'm a tea pot!"
|
|
|
|
end
|
|
|
|
|
2011-02-18 05:06:00 -05:00
|
|
|
=== Browser Redirect
|
|
|
|
|
|
|
|
You can trigger a browser redirect with the `redirect` helper method:
|
|
|
|
|
|
|
|
get '/foo' do
|
2011-02-19 05:28:06 -05:00
|
|
|
redirect to('/bar')
|
2011-02-18 05:06:00 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
Any additional parameters are handled like arguments passed to `halt`:
|
|
|
|
|
2011-02-19 05:28:06 -05:00
|
|
|
redirect to('/bar'), 303
|
|
|
|
redirect 'http://google.com', 'wrong place, buddy'
|
2011-02-18 05:06:00 -05:00
|
|
|
|
2011-02-19 05:28:33 -05:00
|
|
|
You can also easily redirect back to the page the user came from with
|
|
|
|
`redirect back`:
|
|
|
|
|
|
|
|
get '/foo' do
|
|
|
|
"<a href='/bar'>do something</a>"
|
|
|
|
end
|
|
|
|
|
|
|
|
get '/bar' do
|
|
|
|
do_something
|
|
|
|
redirect back
|
|
|
|
end
|
|
|
|
|
2011-02-18 05:06:00 -05:00
|
|
|
To pass arguments with a redirect, either add them to the query:
|
|
|
|
|
2011-02-19 05:28:06 -05:00
|
|
|
redirect to('/bar?sum=42')
|
2011-02-18 05:06:00 -05:00
|
|
|
|
|
|
|
Or use a session:
|
|
|
|
|
|
|
|
enable :session
|
|
|
|
|
|
|
|
get '/foo' do
|
|
|
|
session[:secret] = 'foo'
|
2011-02-19 05:28:06 -05:00
|
|
|
redirect to('/bar')
|
2011-02-18 05:06:00 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
get '/bar' do
|
|
|
|
session[:secret]
|
|
|
|
end
|
|
|
|
|
2011-02-18 04:34:00 -05:00
|
|
|
=== Accessing the Request Object
|
2010-10-11 03:50:42 -04:00
|
|
|
|
2010-10-11 08:18:37 -04:00
|
|
|
The incoming request object can be accessed from request level (filter, routes, error handlers) through the `request` method:
|
2010-10-11 03:50:42 -04:00
|
|
|
|
|
|
|
# app running on http://example.com/example
|
|
|
|
get '/foo' do
|
|
|
|
request.body # request body sent by the client (see below)
|
|
|
|
request.scheme # "http"
|
|
|
|
request.script_name # "/example"
|
|
|
|
request.path_info # "/foo"
|
|
|
|
request.port # 80
|
|
|
|
request.request_method # "GET"
|
|
|
|
request.query_string # ""
|
|
|
|
request.content_length # length of request.body
|
|
|
|
request.media_type # media type of request.body
|
|
|
|
request.host # "example.com"
|
|
|
|
request.get? # true (similar methods for other verbs)
|
|
|
|
request.form_data? # false
|
|
|
|
request["SOME_HEADER"] # value of SOME_HEADER header
|
|
|
|
request.referer # the referer of the client or '/'
|
|
|
|
request.user_agent # user agent (used by :agent condition)
|
|
|
|
request.cookies # hash of browser cookies
|
|
|
|
request.xhr? # is this an ajax request?
|
|
|
|
request.url # "http://example.com/example/foo"
|
|
|
|
request.path # "/example/foo"
|
|
|
|
request.ip # client IP address
|
|
|
|
request.secure? # false
|
2010-10-24 00:39:35 -04:00
|
|
|
request.env # raw env hash handed in by Rack
|
2010-10-11 03:50:42 -04:00
|
|
|
end
|
|
|
|
|
2010-10-11 04:49:38 -04:00
|
|
|
Some options, like <tt>script_name</tt> or <tt>path_info</tt> can also be
|
|
|
|
written:
|
2010-10-11 03:50:42 -04:00
|
|
|
|
|
|
|
before { request.path_info = "/" }
|
|
|
|
|
|
|
|
get "/" do
|
|
|
|
"all requests end up here"
|
|
|
|
end
|
|
|
|
|
|
|
|
The <tt>request.body</tt> is an IO or StringIO object:
|
|
|
|
|
|
|
|
post "/api" do
|
|
|
|
request.body.rewind # in case someone already read it
|
|
|
|
data = JSON.parse request.body.read
|
|
|
|
"Hello #{data['name']}!"
|
|
|
|
end
|
|
|
|
|
2009-03-24 04:24:01 -04:00
|
|
|
== Configuration
|
2008-03-24 21:28:24 -04:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
Run once, at startup, in any environment:
|
2008-03-24 21:28:24 -04:00
|
|
|
|
|
|
|
configure do
|
2008-09-09 04:17:13 -04:00
|
|
|
...
|
2008-03-24 21:28:24 -04:00
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
Run only when the environment (RACK_ENV environment variable) is set to
|
2009-03-24 04:24:01 -04:00
|
|
|
<tt>:production</tt>:
|
2008-03-24 21:28:24 -04:00
|
|
|
|
|
|
|
configure :production do
|
2008-09-09 04:17:13 -04:00
|
|
|
...
|
2008-03-24 21:28:24 -04:00
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2009-03-24 04:24:01 -04:00
|
|
|
Run when the environment is set to either <tt>:production</tt> or
|
|
|
|
<tt>:test</tt>:
|
2008-03-24 21:28:24 -04:00
|
|
|
|
|
|
|
configure :production, :test do
|
2008-09-09 04:17:13 -04:00
|
|
|
...
|
2008-03-24 21:28:24 -04:00
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2011-01-11 05:05:28 -05:00
|
|
|
== Error Handling
|
2008-03-24 21:28:24 -04:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
Error handlers run within the same context as routes and before filters, which
|
2010-09-10 10:33:45 -04:00
|
|
|
means you get all the goodies it has to offer, like <tt>haml</tt>,
|
|
|
|
<tt>erb</tt>, <tt>halt</tt>, etc.
|
2008-03-24 21:28:24 -04:00
|
|
|
|
2008-09-09 04:17:13 -04:00
|
|
|
=== Not Found
|
2008-03-24 21:28:24 -04:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
When a <tt>Sinatra::NotFound</tt> exception is raised, or the response's status
|
|
|
|
code is 404, the <tt>not_found</tt> handler is invoked:
|
2008-03-24 21:28:24 -04:00
|
|
|
|
|
|
|
not_found do
|
2010-09-10 10:33:45 -04:00
|
|
|
'This is nowhere to be found.'
|
2008-03-24 21:28:24 -04:00
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2008-09-09 04:17:13 -04:00
|
|
|
=== Error
|
2008-03-29 19:59:45 -04:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
The +error+ handler is invoked any time an exception is raised from a route
|
2009-12-19 16:03:37 -05:00
|
|
|
block or a filter. The exception object can be obtained from the
|
2009-01-24 02:19:56 -05:00
|
|
|
<tt>sinatra.error</tt> Rack variable:
|
2008-03-29 19:59:45 -04:00
|
|
|
|
2008-03-24 21:28:24 -04:00
|
|
|
error do
|
2009-01-11 10:59:34 -05:00
|
|
|
'Sorry there was a nasty error - ' + env['sinatra.error'].name
|
2008-03-29 19:59:45 -04:00
|
|
|
end
|
|
|
|
|
2008-09-09 04:17:13 -04:00
|
|
|
Custom errors:
|
2008-03-29 19:59:45 -04:00
|
|
|
|
|
|
|
error MyCustomError do
|
2008-04-14 16:31:52 -04:00
|
|
|
'So what happened was...' + request.env['sinatra.error'].message
|
2008-03-24 21:28:24 -04:00
|
|
|
end
|
2008-03-29 19:59:45 -04:00
|
|
|
|
2008-09-09 04:17:13 -04:00
|
|
|
Then, if this happens:
|
2008-03-29 19:59:45 -04:00
|
|
|
|
|
|
|
get '/' do
|
|
|
|
raise MyCustomError, 'something bad'
|
|
|
|
end
|
|
|
|
|
2008-09-09 04:17:13 -04:00
|
|
|
You get this:
|
2008-03-29 19:59:45 -04:00
|
|
|
|
|
|
|
So what happened was... something bad
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2009-12-22 21:10:14 -05:00
|
|
|
Alternatively, you can install error handler for a status code:
|
|
|
|
|
|
|
|
error 403 do
|
|
|
|
'Access forbidden'
|
|
|
|
end
|
|
|
|
|
|
|
|
get '/secret' do
|
|
|
|
403
|
|
|
|
end
|
|
|
|
|
|
|
|
Or a range:
|
|
|
|
|
|
|
|
error 400..510 do
|
|
|
|
'Boom'
|
|
|
|
end
|
|
|
|
|
2009-01-24 02:19:56 -05:00
|
|
|
Sinatra installs special <tt>not_found</tt> and <tt>error</tt> handlers when
|
|
|
|
running under the development environment.
|
2008-03-29 19:59:45 -04:00
|
|
|
|
2011-01-11 05:05:28 -05:00
|
|
|
== Mime Types
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2009-01-11 10:59:34 -05:00
|
|
|
When using <tt>send_file</tt> or static files you may have mime types Sinatra
|
2009-10-17 19:17:37 -04:00
|
|
|
doesn't understand. Use +mime_type+ to register them by file extension:
|
2008-03-29 19:59:45 -04:00
|
|
|
|
2009-10-17 19:17:37 -04:00
|
|
|
mime_type :foo, 'text/foo'
|
2008-03-24 21:28:24 -04:00
|
|
|
|
2009-12-22 21:12:23 -05:00
|
|
|
You can also use it with the +content_type+ helper:
|
|
|
|
|
|
|
|
content_type :foo
|
|
|
|
|
2008-08-31 03:53:21 -04:00
|
|
|
== Rack Middleware
|
2008-05-19 17:25:09 -04:00
|
|
|
|
2008-08-31 03:53:21 -04:00
|
|
|
Sinatra rides on Rack[http://rack.rubyforge.org/], a minimal standard
|
|
|
|
interface for Ruby web frameworks. One of Rack's most interesting capabilities
|
|
|
|
for application developers is support for "middleware" -- components that sit
|
|
|
|
between the server and your application monitoring and/or manipulating the
|
|
|
|
HTTP request/response to provide various types of common functionality.
|
2008-05-19 17:25:09 -04:00
|
|
|
|
2008-09-09 04:17:13 -04:00
|
|
|
Sinatra makes building Rack middleware pipelines a cinch via a top-level
|
|
|
|
+use+ method:
|
2008-05-19 17:25:09 -04:00
|
|
|
|
|
|
|
require 'sinatra'
|
|
|
|
require 'my_custom_middleware'
|
|
|
|
|
|
|
|
use Rack::Lint
|
|
|
|
use MyCustomMiddleware
|
|
|
|
|
|
|
|
get '/hello' do
|
|
|
|
'Hello World'
|
|
|
|
end
|
|
|
|
|
2008-08-31 03:53:21 -04:00
|
|
|
The semantics of +use+ are identical to those defined for the
|
|
|
|
Rack::Builder[http://rack.rubyforge.org/doc/classes/Rack/Builder.html] DSL
|
|
|
|
(most frequently used from rackup files). For example, the +use+ method
|
|
|
|
accepts multiple/variable args as well as blocks:
|
2008-05-19 17:25:09 -04:00
|
|
|
|
|
|
|
use Rack::Auth::Basic do |username, password|
|
|
|
|
username == 'admin' && password == 'secret'
|
|
|
|
end
|
|
|
|
|
2008-08-31 03:53:21 -04:00
|
|
|
Rack is distributed with a variety of standard middleware for logging,
|
|
|
|
debugging, URL routing, authentication, and session handling. Sinatra uses
|
|
|
|
many of of these components automatically based on configuration so you
|
|
|
|
typically don't have to +use+ them explicitly.
|
2008-05-19 17:25:09 -04:00
|
|
|
|
2008-08-31 03:53:21 -04:00
|
|
|
== Testing
|
2008-03-24 21:28:24 -04:00
|
|
|
|
2009-05-18 08:17:00 -04:00
|
|
|
Sinatra tests can be written using any Rack-based testing library
|
|
|
|
or framework. {Rack::Test}[http://gitrdoc.com/brynary/rack-test] is
|
|
|
|
recommended:
|
2009-01-13 12:53:53 -05:00
|
|
|
|
2008-09-24 21:48:33 -04:00
|
|
|
require 'my_sinatra_app'
|
2010-07-27 00:32:00 -04:00
|
|
|
require 'test/unit'
|
2009-05-18 08:17:00 -04:00
|
|
|
require 'rack/test'
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2008-03-24 21:28:24 -04:00
|
|
|
class MyAppTest < Test::Unit::TestCase
|
2009-05-18 08:17:00 -04:00
|
|
|
include Rack::Test::Methods
|
|
|
|
|
|
|
|
def app
|
|
|
|
Sinatra::Application
|
|
|
|
end
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2009-03-01 21:04:42 -05:00
|
|
|
def test_my_default
|
2009-01-13 12:53:53 -05:00
|
|
|
get '/'
|
2009-05-18 08:17:00 -04:00
|
|
|
assert_equal 'Hello World!', last_response.body
|
2008-03-24 21:28:24 -04:00
|
|
|
end
|
2008-09-27 06:29:27 -04:00
|
|
|
|
2009-03-01 21:04:42 -05:00
|
|
|
def test_with_params
|
2009-05-18 08:17:00 -04:00
|
|
|
get '/meet', :name => 'Frank'
|
|
|
|
assert_equal 'Hello Frank!', last_response.body
|
2008-09-27 06:29:27 -04:00
|
|
|
end
|
|
|
|
|
2009-03-01 21:04:42 -05:00
|
|
|
def test_with_rack_env
|
2009-05-18 08:17:00 -04:00
|
|
|
get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
|
|
|
|
assert_equal "You're using Songbird!", last_response.body
|
2009-01-09 01:37:26 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-05-18 08:17:00 -04:00
|
|
|
NOTE: The built-in Sinatra::Test module and Sinatra::TestHarness class
|
|
|
|
are deprecated as of the 0.9.2 release.
|
2008-03-24 21:28:24 -04:00
|
|
|
|
2009-06-06 06:06:45 -04:00
|
|
|
== Sinatra::Base - Middleware, Libraries, and Modular Apps
|
|
|
|
|
|
|
|
Defining your app at the top-level works well for micro-apps but has
|
2010-09-24 13:33:51 -04:00
|
|
|
considerable drawbacks when building reusable components such as Rack
|
2009-06-06 06:06:45 -04:00
|
|
|
middleware, Rails metal, simple libraries with a server component, or
|
|
|
|
even Sinatra extensions. The top-level DSL pollutes the Object namespace
|
|
|
|
and assumes a micro-app style configuration (e.g., a single application
|
|
|
|
file, ./public and ./views directories, logging, exception detail page,
|
|
|
|
etc.). That's where Sinatra::Base comes into play:
|
|
|
|
|
|
|
|
require 'sinatra/base'
|
|
|
|
|
|
|
|
class MyApp < Sinatra::Base
|
|
|
|
set :sessions, true
|
|
|
|
set :foo, 'bar'
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
'Hello world!'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
The methods available to Sinatra::Base subclasses are exactly as those
|
|
|
|
available via the top-level DSL. Most top-level apps can be converted to
|
|
|
|
Sinatra::Base components with two modifications:
|
|
|
|
|
|
|
|
* Your file should require +sinatra/base+ instead of +sinatra+;
|
|
|
|
otherwise, all of Sinatra's DSL methods are imported into the main
|
|
|
|
namespace.
|
|
|
|
* Put your app's routes, error handlers, filters, and options in a subclass
|
|
|
|
of Sinatra::Base.
|
|
|
|
|
2010-10-12 11:31:59 -04:00
|
|
|
<tt>Sinatra::Base</tt> is a blank slate. Most options are disabled by default,
|
2009-06-06 06:06:45 -04:00
|
|
|
including the built-in server. See {Options and Configuration}[http://sinatra.github.com/configuration.html]
|
|
|
|
for details on available options and their behavior.
|
|
|
|
|
2011-01-11 05:05:28 -05:00
|
|
|
=== Serving a Modular Application
|
2011-01-10 07:37:03 -05:00
|
|
|
|
|
|
|
There are two common options for starting a modular app, activly starting with
|
|
|
|
<tt>run!</tt>:
|
|
|
|
|
|
|
|
# my_app.rb
|
|
|
|
require 'sinatra/base'
|
|
|
|
|
|
|
|
class MyApp < Sinatra::Base
|
|
|
|
# ... app code here ...
|
|
|
|
|
|
|
|
# start the server if ruby file executed directly
|
|
|
|
run! if app_file == $0
|
|
|
|
end
|
|
|
|
|
|
|
|
Start with:
|
|
|
|
|
|
|
|
ruby my_app.rb
|
|
|
|
|
|
|
|
Or with a <tt>config.ru</tt>, which allows using any Rack handler:
|
|
|
|
|
|
|
|
# config.ru
|
|
|
|
require 'my_app'
|
|
|
|
run MyApp
|
|
|
|
|
|
|
|
Run:
|
|
|
|
|
|
|
|
rackup -p 4567
|
|
|
|
|
2011-01-11 05:05:28 -05:00
|
|
|
=== Using a Classic Style Application with a config.ru
|
2011-01-10 07:37:03 -05:00
|
|
|
|
|
|
|
Write your app file:
|
|
|
|
|
|
|
|
# app.rb
|
|
|
|
require 'sinatra'
|
|
|
|
|
|
|
|
get '/' do
|
|
|
|
'Hello world!'
|
|
|
|
end
|
|
|
|
|
|
|
|
And a corresponding <tt>config.ru</tt>:
|
|
|
|
|
|
|
|
require 'app'
|
|
|
|
run Sinatra::Application
|
|
|
|
|
|
|
|
=== When to use a config.ru?
|
|
|
|
|
|
|
|
Good signs you probably want to use a <tt>config.ru</tt>:
|
|
|
|
|
|
|
|
* You want to deploy with a different Rack handler (Passenger, Unicorn,
|
|
|
|
Heroku, ...).
|
|
|
|
* You want to use more than one subclass of <tt>Sinatra::Base</tt>.
|
|
|
|
* You want to use Sinatra only for middleware, but not as endpoint.
|
|
|
|
|
|
|
|
<b>There is no need to switch to a <tt>config.ru</tt> only because you
|
|
|
|
switched to modular style, and you don't have to use modular style for running
|
|
|
|
with a <tt>config.ru</tt>.</b>
|
|
|
|
|
2010-09-24 13:33:51 -04:00
|
|
|
=== Using Sinatra as Middleware
|
2010-09-24 04:37:53 -04:00
|
|
|
|
|
|
|
Not only is Sinatra able to use other Rack middleware, any Sinatra application
|
|
|
|
can in turn be added in front of any Rack endpoint as middleware itself. This
|
|
|
|
endpoint could be another Sinatra application, or any other Rack-based
|
|
|
|
application (Rails/Ramaze/Camping/...).
|
|
|
|
|
|
|
|
require 'sinatra/base'
|
|
|
|
|
|
|
|
class LoginScreen < Sinatra::Base
|
2010-11-07 03:49:23 -05:00
|
|
|
enable :sessions
|
2010-09-24 04:37:53 -04:00
|
|
|
|
|
|
|
get('/login') { haml :login }
|
|
|
|
|
|
|
|
post('/login') do
|
|
|
|
if params[:name] = 'admin' and params[:password] = 'admin'
|
|
|
|
session['user_name'] = params[:name]
|
|
|
|
else
|
|
|
|
redirect '/login'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class MyApp < Sinatra::Base
|
|
|
|
# middleware will run before filters
|
|
|
|
use LoginScreen
|
|
|
|
|
|
|
|
before do
|
|
|
|
unless session['user_name']
|
|
|
|
halt "Access denied, please <a href='/login'>login</a>."
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
get('/') { "Hello #{session['user_name']}." }
|
|
|
|
end
|
|
|
|
|
2010-09-23 19:28:03 -04:00
|
|
|
== Scopes and Binding
|
|
|
|
|
2010-09-24 04:15:53 -04:00
|
|
|
The scope you are currently in determines what methods and variables are
|
|
|
|
available.
|
2010-09-23 19:28:03 -04:00
|
|
|
|
|
|
|
=== Application/Class Scope
|
|
|
|
|
|
|
|
Every Sinatra application corresponds to a subclass of Sinatra::Base. If you
|
|
|
|
are using the top level DSL (<tt>require 'sinatra'</tt>), then this class is
|
|
|
|
Sinatra::Application, otherwise it is the subclass you created explicitly. At
|
|
|
|
class level you have methods like `get` or `before`, but you cannot access the
|
|
|
|
`request` object or the `session`, as there only is a single application class
|
|
|
|
for all requests.
|
|
|
|
|
|
|
|
Options created via `set` are methods at class level:
|
|
|
|
|
2010-11-10 14:15:51 -05:00
|
|
|
class MyApp < Sinatra::Base
|
2010-09-23 19:28:03 -04:00
|
|
|
# Hey, I'm in the application scope!
|
|
|
|
set :foo, 42
|
|
|
|
foo # => 42
|
|
|
|
|
|
|
|
get '/foo' do
|
|
|
|
# Hey, I'm no longer in the application scope!
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-09-24 04:15:53 -04:00
|
|
|
You have the application scope binding inside:
|
2010-09-23 19:28:03 -04:00
|
|
|
|
|
|
|
* Your application class body
|
|
|
|
* Methods defined by extensions
|
|
|
|
* The block passed to `helpers`
|
|
|
|
* Procs/blocks used as value for `set`
|
|
|
|
|
|
|
|
You can reach the scope object (the class) like this:
|
|
|
|
|
2010-09-24 04:15:53 -04:00
|
|
|
* Via the object passed to configure blocks (<tt>configure { |c| ... }</tt>)
|
2010-09-23 19:28:03 -04:00
|
|
|
* `settings` from within request scope
|
|
|
|
|
|
|
|
=== Request/Instance Scope
|
|
|
|
|
2010-09-24 04:15:53 -04:00
|
|
|
For every incoming request, a new instance of your application class is
|
|
|
|
created and all handler blocks run in that scope. From within this scope you
|
|
|
|
can access the `request` and `session` object or call rendering methods like
|
|
|
|
`erb` or `haml`. You can access the application scope from within the request
|
|
|
|
scope via the `settings` helper:
|
2010-09-23 19:28:03 -04:00
|
|
|
|
2010-11-10 14:15:51 -05:00
|
|
|
class MyApp < Sinatra::Base
|
2010-09-23 19:28:03 -04:00
|
|
|
# Hey, I'm in the application scope!
|
|
|
|
get '/define_route/:name' do
|
|
|
|
# Request scope for '/define_route/:name'
|
|
|
|
@value = 42
|
|
|
|
|
|
|
|
settings.get("/#{params[:name]}") do
|
|
|
|
# Request scope for "/#{params[:name]}"
|
|
|
|
@value # => nil (not the same request)
|
|
|
|
end
|
|
|
|
|
|
|
|
"Route defined!"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-09-24 04:15:53 -04:00
|
|
|
You have the request scope binding inside:
|
2010-09-23 19:28:03 -04:00
|
|
|
|
2010-11-29 15:08:44 -05:00
|
|
|
* get/head/post/put/delete/options blocks
|
2010-09-23 19:28:03 -04:00
|
|
|
* before/after filters
|
|
|
|
* helper methods
|
|
|
|
* templates/views
|
|
|
|
|
|
|
|
=== Delegation Scope
|
|
|
|
|
|
|
|
The delegation scope just forwards methods to the class scope. However, it
|
2010-09-24 04:15:53 -04:00
|
|
|
does not behave 100% like the class scope, as you do not have the class'
|
|
|
|
binding: Only methods explicitly marked for delegation are available and you
|
|
|
|
do not share variables/state with the class scope (read: you have a different
|
|
|
|
`self`). You can explicitly add method delegations by calling
|
|
|
|
<tt>Sinatra::Delegator.delegate :method_name</tt>.
|
2010-09-23 19:28:03 -04:00
|
|
|
|
2010-09-24 04:15:53 -04:00
|
|
|
You have the delegate scope binding inside:
|
2010-09-23 19:28:03 -04:00
|
|
|
|
|
|
|
* The top level binding, if you did <tt>require "sinatra"</tt>
|
2010-09-24 04:15:53 -04:00
|
|
|
* An object extended with the `Sinatra::Delegator` mixin
|
2010-09-23 19:28:03 -04:00
|
|
|
|
2010-09-24 04:21:40 -04:00
|
|
|
Have a look at the code for yourself: here's the
|
|
|
|
{Sinatra::Delegator mixin}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/base.rb#L1128]
|
2010-09-24 13:33:51 -04:00
|
|
|
being {included into the main namespace}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/main.rb#L28].
|
2010-09-24 04:21:40 -04:00
|
|
|
|
2011-01-11 05:05:28 -05:00
|
|
|
== Command Line
|
2008-03-24 21:28:24 -04:00
|
|
|
|
2008-09-09 04:17:13 -04:00
|
|
|
Sinatra applications can be run directly:
|
2008-08-31 03:53:21 -04:00
|
|
|
|
2010-03-01 18:59:03 -05:00
|
|
|
ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-o HOST] [-s HANDLER]
|
2008-03-24 21:28:24 -04:00
|
|
|
|
|
|
|
Options are:
|
|
|
|
|
|
|
|
-h # help
|
|
|
|
-p # set the port (default is 4567)
|
2010-03-01 18:59:03 -05:00
|
|
|
-o # set the host (default is 0.0.0.0)
|
2008-03-24 21:28:24 -04:00
|
|
|
-e # set the environment (default is development)
|
2009-01-15 09:08:40 -05:00
|
|
|
-s # specify rack server/handler (default is thin)
|
2008-04-14 16:31:52 -04:00
|
|
|
-x # turn on the mutex lock (default is off)
|
2008-03-24 21:28:24 -04:00
|
|
|
|
2009-01-24 02:19:56 -05:00
|
|
|
== The Bleeding Edge
|
2011-01-11 05:26:20 -05:00
|
|
|
If you would like to use Sinatra's latest bleeding code, feel free to run your
|
|
|
|
application against the master branch, it should be rather stable.
|
|
|
|
|
|
|
|
We also push out prerelease gems from time to time, so you can do a
|
|
|
|
|
|
|
|
gem install sinatra --pre
|
|
|
|
|
|
|
|
To get some of the latest features.
|
|
|
|
|
2011-01-11 05:19:29 -05:00
|
|
|
=== With Bundler
|
|
|
|
If you want to run your application with the latest Sinatra, using
|
|
|
|
{Bundler}[http://gembundler.com/] is the recommend way.
|
2008-08-31 08:41:20 -04:00
|
|
|
|
2011-01-11 05:19:29 -05:00
|
|
|
First, install bundler, if you haven't:
|
|
|
|
|
|
|
|
gem install bundler
|
|
|
|
|
|
|
|
Then, in you project directory, create a +Gemfile+:
|
|
|
|
|
|
|
|
source :rubygems
|
|
|
|
gem 'sinatra', :git => "git://github.com/sinatra/sinatra.git"
|
|
|
|
|
|
|
|
# other dependencies
|
|
|
|
gem 'haml' # for instance, if you use haml
|
|
|
|
gem 'activerecord', '~> 3.0' # maybe you also need ActiveRecord 3.x
|
|
|
|
|
|
|
|
Note that you will have to list all your applications dependencies in there.
|
|
|
|
Sinatra's direct dependencies (Rack and Tilt) will however be automatically
|
|
|
|
fetched and added by Bundler.
|
|
|
|
|
|
|
|
Now you can run your app like this:
|
|
|
|
|
|
|
|
bundle exec ruby myapp.rb
|
|
|
|
|
|
|
|
=== Roll Your Own
|
2011-01-11 05:26:20 -05:00
|
|
|
Create a local clone and run your app with the <tt>sinatra/lib</tt> directory
|
|
|
|
on the <tt>LOAD_PATH</tt>:
|
2008-08-31 08:41:20 -04:00
|
|
|
|
2009-01-24 02:19:56 -05:00
|
|
|
cd myapp
|
2009-01-18 18:22:10 -05:00
|
|
|
git clone git://github.com/sinatra/sinatra.git
|
2009-01-24 02:19:56 -05:00
|
|
|
ruby -Isinatra/lib myapp.rb
|
2008-08-31 15:09:10 -04:00
|
|
|
|
2009-01-24 02:19:56 -05:00
|
|
|
To update the Sinatra sources in the future:
|
2008-08-31 08:46:39 -04:00
|
|
|
|
2011-01-11 05:21:29 -05:00
|
|
|
cd myapp/sinatra
|
2009-01-24 02:19:56 -05:00
|
|
|
git pull
|
2008-08-31 08:37:58 -04:00
|
|
|
|
2011-01-11 05:26:20 -05:00
|
|
|
=== Install Globally
|
|
|
|
|
|
|
|
You can build the gem on your own:
|
|
|
|
|
|
|
|
git clone git://github.com/sinatra/sinatra.git
|
|
|
|
cd sinatra
|
|
|
|
rake sinatra.gemspec
|
|
|
|
rake install
|
|
|
|
|
|
|
|
If you install gems as root, the last step should be
|
|
|
|
|
|
|
|
sudo rake install
|
|
|
|
|
2011-01-11 05:05:28 -05:00
|
|
|
== Further Reading
|
2008-08-31 08:37:58 -04:00
|
|
|
|
2010-03-07 05:50:27 -05:00
|
|
|
* {Project Website}[http://www.sinatrarb.com/] - Additional documentation,
|
2009-01-24 02:19:56 -05:00
|
|
|
news, and links to other resources.
|
2010-03-07 05:50:27 -05:00
|
|
|
* {Contributing}[http://www.sinatrarb.com/contributing] - Find a bug? Need
|
2009-01-24 02:19:56 -05:00
|
|
|
help? Have a patch?
|
2010-07-01 01:32:11 -04:00
|
|
|
* {Issue tracker}[http://github.com/sinatra/sinatra/issues]
|
2009-03-01 21:17:47 -05:00
|
|
|
* {Twitter}[http://twitter.com/sinatra]
|
2010-03-07 05:50:27 -05:00
|
|
|
* {Mailing List}[http://groups.google.com/group/sinatrarb/topics]
|
2009-01-24 02:19:56 -05:00
|
|
|
* {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] on http://freenode.net
|