sinatra 1.4.0.a → 1.4.0.b
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sinatra might be problematic. Click here for more details.
- data/CHANGES +2 -0
- data/Gemfile +5 -1
- data/README.es.rdoc +6 -0
- data/README.md +992 -827
- data/Rakefile +15 -0
- data/lib/sinatra/base.rb +5 -0
- data/lib/sinatra/version.rb +1 -1
- data/test/stylus_test.rb +90 -0
- data/test/views/hello.styl +2 -0
- metadata +5 -2
data/CHANGES
CHANGED
@@ -6,6 +6,8 @@
|
|
6
6
|
|
7
7
|
* Add support for Wlang templates. (Bernard Lambeau)
|
8
8
|
|
9
|
+
* Add support for Stylus templates. (Juan David Pastas, Konstantin Haase)
|
10
|
+
|
9
11
|
* You can now pass a block to ERb, Haml, Slim, Liquid and Wlang templates,
|
10
12
|
which will be used when calling `yield` in the template. (Alexey Muranov)
|
11
13
|
|
data/Gemfile
CHANGED
@@ -43,7 +43,11 @@ gem 'markaby'
|
|
43
43
|
gem 'radius'
|
44
44
|
gem 'rabl' unless RUBY_ENGINE =~ /jruby|maglev/
|
45
45
|
gem 'wlang', '>= 2.0.1' unless RUBY_ENGINE =~ /jruby|rbx/
|
46
|
-
|
46
|
+
|
47
|
+
if RUBY_ENGINE != 'rbx' or RUBY_VERSION < '1.9'
|
48
|
+
gem 'liquid'
|
49
|
+
gem 'stylus'
|
50
|
+
end
|
47
51
|
|
48
52
|
if RUBY_ENGINE == 'jruby'
|
49
53
|
gem 'nokogiri', '!= 1.5.0'
|
data/README.es.rdoc
CHANGED
@@ -537,6 +537,12 @@ Dependencias:: {coffee-script}[https://github.com/josh/ruby-coffee-s
|
|
537
537
|
Extensiones de Archivo:: <tt>.coffee</tt>
|
538
538
|
Ejemplo:: <tt>coffee :index</tt>
|
539
539
|
|
540
|
+
=== Plantillas Stylus
|
541
|
+
|
542
|
+
Dependencias:: {ruby-stylus}[https://github.com/lucasmazza/ruby-stylus]
|
543
|
+
Extensiones de Archivo:: <tt>.styl</tt>
|
544
|
+
Ejemplo:: <tt>stylus :index</tt>
|
545
|
+
|
540
546
|
=== Plantillas Yajl
|
541
547
|
|
542
548
|
Dependencias:: {yajl-ruby}[https://github.com/brianmario/yajl-ruby]
|
data/README.md
CHANGED
@@ -3,20 +3,20 @@
|
|
3
3
|
Sinatra is a [DSL](http://en.wikipedia.org/wiki/Domain-specific_language) for
|
4
4
|
quickly creating web applications in Ruby with minimal effort:
|
5
5
|
|
6
|
-
```ruby
|
7
|
-
|
8
|
-
|
6
|
+
``` ruby
|
7
|
+
# myapp.rb
|
8
|
+
require 'sinatra'
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
get '/' do
|
11
|
+
'Hello world!'
|
12
|
+
end
|
13
13
|
```
|
14
14
|
|
15
15
|
Install the gem and run with:
|
16
16
|
|
17
|
-
```
|
18
|
-
|
19
|
-
|
17
|
+
``` shell
|
18
|
+
gem install sinatra
|
19
|
+
ruby myapp.rb
|
20
20
|
```
|
21
21
|
|
22
22
|
View at: http://localhost:4567
|
@@ -24,35 +24,120 @@ View at: http://localhost:4567
|
|
24
24
|
It is recommended to also run `gem install thin`, which Sinatra will
|
25
25
|
pick up if available.
|
26
26
|
|
27
|
+
## Table of Contents
|
28
|
+
|
29
|
+
* [Sinatra](#sinatra)
|
30
|
+
* [Table of Contents](#table-of-contents)
|
31
|
+
* [Routes](#routes)
|
32
|
+
* [Conditions](#conditions)
|
33
|
+
* [Return Values](#return-values)
|
34
|
+
* [Custom Route Matchers](#custom-route-matchers)
|
35
|
+
* [Static Files](#static-files)
|
36
|
+
* [Views / Templates](#views--templates)
|
37
|
+
* [Literal Templates](#literal-templates)
|
38
|
+
* [Available Template Languages](#available-template-languages)
|
39
|
+
* [Haml Templates](#haml-templates)
|
40
|
+
* [Erb Templates](#erb-templates)
|
41
|
+
* [Builder Templates](#builder-templates)
|
42
|
+
* [Nokogiri Templates](#nokogiri-templates)
|
43
|
+
* [Sass Templates](#sass-templates)
|
44
|
+
* [SCSS Templates](#scss-templates)
|
45
|
+
* [Less Templates](#less-templates)
|
46
|
+
* [Liquid Templates](#liquid-templates)
|
47
|
+
* [Markdown Templates](#markdown-templates)
|
48
|
+
* [Textile Templates](#textile-templates)
|
49
|
+
* [RDoc Templates](#rdoc-templates)
|
50
|
+
* [Radius Templates](#radius-templates)
|
51
|
+
* [Markaby Templates](#markaby-templates)
|
52
|
+
* [RABL Templates](#rabl-templates)
|
53
|
+
* [Slim Templates](#slim-templates)
|
54
|
+
* [Creole Templates](#creole-templates)
|
55
|
+
* [CoffeeScript Templates](#coffeescript-templates)
|
56
|
+
* [Stylus Templates](#stylus-templates)
|
57
|
+
* [Yajl Templates](#yajl-templates)
|
58
|
+
* [WLang Templates](#wlang-templates)
|
59
|
+
* [Accessing Variables in Templates](#accessing-variables-in-templates)
|
60
|
+
* [Templates with `yield` and nested layouts](#templates-with-yield-and-nested-layouts)
|
61
|
+
* [Inline Templates](#inline-templates)
|
62
|
+
* [Named Templates](#named-templates)
|
63
|
+
* [Associating File Extensions](#associating-file-extensions)
|
64
|
+
* [Adding Your Own Template Engine](#adding-your-own-template-engine)
|
65
|
+
* [Filters](#filters)
|
66
|
+
* [Helpers](#helpers)
|
67
|
+
* [Using Sessions](#using-sessions)
|
68
|
+
* [Halting](#halting)
|
69
|
+
* [Passing](#passing)
|
70
|
+
* [Triggering Another Route](#triggering-another-route)
|
71
|
+
* [Setting Body, Status Code and Headers](#setting-body-status-code-and-headers)
|
72
|
+
* [Streaming Responses](#streaming-responses)
|
73
|
+
* [Logging](#logging)
|
74
|
+
* [Mime Types](#mime-types)
|
75
|
+
* [Generating URLs](#generating-urls)
|
76
|
+
* [Browser Redirect](#browser-redirect)
|
77
|
+
* [Cache Control](#cache-control)
|
78
|
+
* [Sending Files](#sending-files)
|
79
|
+
* [Accessing the Request Object](#accessing-the-request-object)
|
80
|
+
* [Attachments](#attachments)
|
81
|
+
* [Dealing with Date and Time](#dealing-with-date-and-time)
|
82
|
+
* [Looking Up Template Files](#looking-up-template-files)
|
83
|
+
* [Configuration](#configuration)
|
84
|
+
* [Configuring attack protection](#configuring-attack-protection)
|
85
|
+
* [Available Settings](#available-settings)
|
86
|
+
* [Environments](#environments)
|
87
|
+
* [Error Handling](#error-handling)
|
88
|
+
* [Not Found](#not-found)
|
89
|
+
* [Error](#error)
|
90
|
+
* [Rack Middleware](#rack-middleware)
|
91
|
+
* [Testing](#testing)
|
92
|
+
* [Sinatra::Base - Middleware, Libraries, and Modular Apps](#sinatrabase---middleware-libraries-and-modular-apps)
|
93
|
+
* [Modular vs. Classic Style](#modular-vs-classic-style)
|
94
|
+
* [Serving a Modular Application](#serving-a-modular-application)
|
95
|
+
* [Using a Classic Style Application with a config.ru](#using-a-classic-style-application-with-a-configru)
|
96
|
+
* [When to use a config.ru?](#when-to-use-a-configru)
|
97
|
+
* [Using Sinatra as Middleware](#using-sinatra-as-middleware)
|
98
|
+
* [Dynamic Application Creation](#dynamic-application-creation)
|
99
|
+
* [Scopes and Binding](#scopes-and-binding)
|
100
|
+
* [Application/Class Scope](#applicationclass-scope)
|
101
|
+
* [Request/Instance Scope](#requestinstance-scope)
|
102
|
+
* [Delegation Scope](#delegation-scope)
|
103
|
+
* [Command Line](#command-line)
|
104
|
+
* [Requirement](#requirement)
|
105
|
+
* [The Bleeding Edge](#the-bleeding-edge)
|
106
|
+
* [With Bundler](#with-bundler)
|
107
|
+
* [Roll Your Own](#roll-your-own)
|
108
|
+
* [Install Globally](#install-globally)
|
109
|
+
* [Versioning](#versioning)
|
110
|
+
* [Further Reading](#further-reading)
|
111
|
+
|
27
112
|
## Routes
|
28
113
|
|
29
114
|
In Sinatra, a route is an HTTP method paired with a URL-matching pattern.
|
30
115
|
Each route is associated with a block:
|
31
116
|
|
32
|
-
```ruby
|
33
|
-
|
34
|
-
|
35
|
-
|
117
|
+
``` ruby
|
118
|
+
get '/' do
|
119
|
+
.. show something ..
|
120
|
+
end
|
36
121
|
|
37
|
-
|
38
|
-
|
39
|
-
|
122
|
+
post '/' do
|
123
|
+
.. create something ..
|
124
|
+
end
|
40
125
|
|
41
|
-
|
42
|
-
|
43
|
-
|
126
|
+
put '/' do
|
127
|
+
.. replace something ..
|
128
|
+
end
|
44
129
|
|
45
|
-
|
46
|
-
|
47
|
-
|
130
|
+
patch '/' do
|
131
|
+
.. modify something ..
|
132
|
+
end
|
48
133
|
|
49
|
-
|
50
|
-
|
51
|
-
|
134
|
+
delete '/' do
|
135
|
+
.. annihilate something ..
|
136
|
+
end
|
52
137
|
|
53
|
-
|
54
|
-
|
55
|
-
|
138
|
+
options '/' do
|
139
|
+
.. appease something ..
|
140
|
+
end
|
56
141
|
```
|
57
142
|
|
58
143
|
Routes are matched in the order they are defined. The first route that
|
@@ -61,67 +146,67 @@ matches the request is invoked.
|
|
61
146
|
Route patterns may include named parameters, accessible via the
|
62
147
|
`params` hash:
|
63
148
|
|
64
|
-
```ruby
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
149
|
+
``` ruby
|
150
|
+
get '/hello/:name' do
|
151
|
+
# matches "GET /hello/foo" and "GET /hello/bar"
|
152
|
+
# params[:name] is 'foo' or 'bar'
|
153
|
+
"Hello #{params[:name]}!"
|
154
|
+
end
|
70
155
|
```
|
71
156
|
|
72
157
|
You can also access named parameters via block parameters:
|
73
158
|
|
74
|
-
```ruby
|
75
|
-
|
76
|
-
|
77
|
-
|
159
|
+
``` ruby
|
160
|
+
get '/hello/:name' do |n|
|
161
|
+
"Hello #{n}!"
|
162
|
+
end
|
78
163
|
```
|
79
164
|
|
80
165
|
Route patterns may also include splat (or wildcard) parameters, accessible
|
81
166
|
via the `params[:splat]` array:
|
82
167
|
|
83
|
-
```ruby
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
168
|
+
``` ruby
|
169
|
+
get '/say/*/to/*' do
|
170
|
+
# matches /say/hello/to/world
|
171
|
+
params[:splat] # => ["hello", "world"]
|
172
|
+
end
|
88
173
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
174
|
+
get '/download/*.*' do
|
175
|
+
# matches /download/path/to/file.xml
|
176
|
+
params[:splat] # => ["path/to/file", "xml"]
|
177
|
+
end
|
93
178
|
```
|
94
179
|
|
95
180
|
Or with block parameters:
|
96
181
|
|
97
|
-
```ruby
|
98
|
-
|
99
|
-
|
100
|
-
|
182
|
+
``` ruby
|
183
|
+
get '/download/*.*' do |path, ext|
|
184
|
+
[path, ext] # => ["path/to/file", "xml"]
|
185
|
+
end
|
101
186
|
```
|
102
187
|
|
103
188
|
Route matching with Regular Expressions:
|
104
189
|
|
105
|
-
```ruby
|
106
|
-
|
107
|
-
|
108
|
-
|
190
|
+
``` ruby
|
191
|
+
get %r{/hello/([\w]+)} do
|
192
|
+
"Hello, #{params[:captures].first}!"
|
193
|
+
end
|
109
194
|
```
|
110
195
|
|
111
196
|
Or with a block parameter:
|
112
197
|
|
113
|
-
```ruby
|
114
|
-
|
115
|
-
|
116
|
-
|
198
|
+
``` ruby
|
199
|
+
get %r{/hello/([\w]+)} do |c|
|
200
|
+
"Hello, #{c}!"
|
201
|
+
end
|
117
202
|
```
|
118
203
|
|
119
204
|
Route patterns may have optional parameters:
|
120
205
|
|
121
|
-
```ruby
|
122
|
-
|
123
|
-
|
124
|
-
|
206
|
+
``` ruby
|
207
|
+
get '/posts.?:format?' do
|
208
|
+
# matches "GET /posts" and any extension "GET /posts.json", "GET /posts.xml" etc.
|
209
|
+
end
|
125
210
|
```
|
126
211
|
|
127
212
|
By the way, unless you disable the path traversal attack protection (see below),
|
@@ -131,64 +216,64 @@ the request path might be modified before matching against your routes.
|
|
131
216
|
|
132
217
|
Routes may include a variety of matching conditions, such as the user agent:
|
133
218
|
|
134
|
-
```ruby
|
135
|
-
|
136
|
-
|
137
|
-
|
219
|
+
``` ruby
|
220
|
+
get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
|
221
|
+
"You're using Songbird version #{params[:agent][0]}"
|
222
|
+
end
|
138
223
|
|
139
|
-
|
140
|
-
|
141
|
-
|
224
|
+
get '/foo' do
|
225
|
+
# Matches non-songbird browsers
|
226
|
+
end
|
142
227
|
```
|
143
228
|
|
144
229
|
Other available conditions are `host_name` and `provides`:
|
145
230
|
|
146
|
-
```ruby
|
147
|
-
|
148
|
-
|
149
|
-
|
231
|
+
``` ruby
|
232
|
+
get '/', :host_name => /^admin\./ do
|
233
|
+
"Admin Area, Access denied!"
|
234
|
+
end
|
150
235
|
|
151
|
-
|
152
|
-
|
153
|
-
|
236
|
+
get '/', :provides => 'html' do
|
237
|
+
haml :index
|
238
|
+
end
|
154
239
|
|
155
|
-
|
156
|
-
|
157
|
-
|
240
|
+
get '/', :provides => ['rss', 'atom', 'xml'] do
|
241
|
+
builder :feed
|
242
|
+
end
|
158
243
|
```
|
159
244
|
|
160
245
|
You can easily define your own conditions:
|
161
246
|
|
162
|
-
```ruby
|
163
|
-
|
247
|
+
``` ruby
|
248
|
+
set(:probability) { |value| condition { rand <= value } }
|
164
249
|
|
165
|
-
|
166
|
-
|
167
|
-
|
250
|
+
get '/win_a_car', :probability => 0.1 do
|
251
|
+
"You won!"
|
252
|
+
end
|
168
253
|
|
169
|
-
|
170
|
-
|
171
|
-
|
254
|
+
get '/win_a_car' do
|
255
|
+
"Sorry, you lost."
|
256
|
+
end
|
172
257
|
```
|
173
258
|
|
174
259
|
For a condition that takes multiple values use a splat:
|
175
260
|
|
176
|
-
```ruby
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
end
|
182
|
-
end
|
261
|
+
``` ruby
|
262
|
+
set(:auth) do |*roles| # <- notice the splat here
|
263
|
+
condition do
|
264
|
+
unless logged_in? && roles.any? {|role| current_user.in_role? role }
|
265
|
+
redirect "/login/", 303
|
183
266
|
end
|
267
|
+
end
|
268
|
+
end
|
184
269
|
|
185
|
-
|
186
|
-
|
187
|
-
|
270
|
+
get "/my/account/", :auth => [:user, :admin] do
|
271
|
+
"Your Account Details"
|
272
|
+
end
|
188
273
|
|
189
|
-
|
190
|
-
|
191
|
-
|
274
|
+
get "/only/admin/", :auth => :admin do
|
275
|
+
"Only admins are allowed here!"
|
276
|
+
end
|
192
277
|
```
|
193
278
|
|
194
279
|
### Return Values
|
@@ -211,14 +296,14 @@ body object or HTTP status code:
|
|
211
296
|
|
212
297
|
That way we can, for instance, easily implement a streaming example:
|
213
298
|
|
214
|
-
```ruby
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
299
|
+
``` ruby
|
300
|
+
class Stream
|
301
|
+
def each
|
302
|
+
100.times { |i| yield "#{i}\n" }
|
303
|
+
end
|
304
|
+
end
|
220
305
|
|
221
|
-
|
306
|
+
get('/') { Stream.new }
|
222
307
|
```
|
223
308
|
|
224
309
|
You can also use the `stream` helper method (described below) to reduce boiler
|
@@ -230,45 +315,45 @@ As shown above, Sinatra ships with built-in support for using String patterns
|
|
230
315
|
and regular expressions as route matches. However, it does not stop there. You
|
231
316
|
can easily define your own matchers:
|
232
317
|
|
233
|
-
```ruby
|
234
|
-
|
235
|
-
|
318
|
+
``` ruby
|
319
|
+
class AllButPattern
|
320
|
+
Match = Struct.new(:captures)
|
236
321
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
322
|
+
def initialize(except)
|
323
|
+
@except = except
|
324
|
+
@captures = Match.new([])
|
325
|
+
end
|
241
326
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
327
|
+
def match(str)
|
328
|
+
@captures unless @except === str
|
329
|
+
end
|
330
|
+
end
|
246
331
|
|
247
|
-
|
248
|
-
|
249
|
-
|
332
|
+
def all_but(pattern)
|
333
|
+
AllButPattern.new(pattern)
|
334
|
+
end
|
250
335
|
|
251
|
-
|
252
|
-
|
253
|
-
|
336
|
+
get all_but("/index") do
|
337
|
+
# ...
|
338
|
+
end
|
254
339
|
```
|
255
340
|
|
256
341
|
Note that the above example might be over-engineered, as it can also be
|
257
342
|
expressed as:
|
258
343
|
|
259
|
-
```ruby
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
344
|
+
``` ruby
|
345
|
+
get // do
|
346
|
+
pass if request.path_info == "/index"
|
347
|
+
# ...
|
348
|
+
end
|
264
349
|
```
|
265
350
|
|
266
351
|
Or, using negative look ahead:
|
267
352
|
|
268
|
-
```ruby
|
269
|
-
|
270
|
-
|
271
|
-
|
353
|
+
``` ruby
|
354
|
+
get %r{^(?!/index$)} do
|
355
|
+
# ...
|
356
|
+
end
|
272
357
|
```
|
273
358
|
|
274
359
|
### Static Files
|
@@ -276,8 +361,8 @@ Or, using negative look ahead:
|
|
276
361
|
Static files are served from the `./public` directory. You can specify
|
277
362
|
a different location by setting the `:public_folder` option:
|
278
363
|
|
279
|
-
```ruby
|
280
|
-
|
364
|
+
``` ruby
|
365
|
+
set :public_folder, File.dirname(__FILE__) + '/static'
|
281
366
|
```
|
282
367
|
|
283
368
|
Note that the public directory name is not included in the URL. A file
|
@@ -292,10 +377,10 @@ Use the `:static_cache_control` setting (see below) to add
|
|
292
377
|
Each template language is exposed via its own rendering method. These
|
293
378
|
methods simply return a string:
|
294
379
|
|
295
|
-
```ruby
|
296
|
-
|
297
|
-
|
298
|
-
|
380
|
+
``` ruby
|
381
|
+
get '/' do
|
382
|
+
erb :index
|
383
|
+
end
|
299
384
|
```
|
300
385
|
|
301
386
|
This renders `views/index.erb`.
|
@@ -303,19 +388,19 @@ This renders `views/index.erb`.
|
|
303
388
|
Instead of a template name, you can also just pass in the template content
|
304
389
|
directly:
|
305
390
|
|
306
|
-
```ruby
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
391
|
+
``` ruby
|
392
|
+
get '/' do
|
393
|
+
code = "<%= Time.now %>"
|
394
|
+
erb code
|
395
|
+
end
|
311
396
|
```
|
312
397
|
|
313
398
|
Templates take a second argument, the options hash:
|
314
399
|
|
315
|
-
```ruby
|
316
|
-
|
317
|
-
|
318
|
-
|
400
|
+
``` ruby
|
401
|
+
get '/' do
|
402
|
+
erb :index, :layout => :post
|
403
|
+
end
|
319
404
|
```
|
320
405
|
|
321
406
|
This will render `views/index.erb` embedded in the
|
@@ -324,20 +409,20 @@ This will render `views/index.erb` embedded in the
|
|
324
409
|
Any options not understood by Sinatra will be passed on to the template
|
325
410
|
engine:
|
326
411
|
|
327
|
-
```ruby
|
328
|
-
|
329
|
-
|
330
|
-
|
412
|
+
``` ruby
|
413
|
+
get '/' do
|
414
|
+
haml :index, :format => :html5
|
415
|
+
end
|
331
416
|
```
|
332
417
|
|
333
418
|
You can also set options per template language in general:
|
334
419
|
|
335
|
-
```ruby
|
336
|
-
|
420
|
+
``` ruby
|
421
|
+
set :haml, :format => :html5
|
337
422
|
|
338
|
-
|
339
|
-
|
340
|
-
|
423
|
+
get '/' do
|
424
|
+
haml :index
|
425
|
+
end
|
341
426
|
```
|
342
427
|
|
343
428
|
Options passed to the render method override options set via `set`.
|
@@ -409,10 +494,10 @@ Available Options:
|
|
409
494
|
|
410
495
|
#### Literal Templates
|
411
496
|
|
412
|
-
```ruby
|
413
|
-
|
414
|
-
|
415
|
-
|
497
|
+
``` ruby
|
498
|
+
get '/' do
|
499
|
+
haml '%div.title Hello World'
|
500
|
+
end
|
416
501
|
```
|
417
502
|
|
418
503
|
Renders the template string.
|
@@ -422,9 +507,9 @@ Renders the template string.
|
|
422
507
|
Some languages have multiple implementations. To specify what implementation
|
423
508
|
to use (and to be thread-safe), you should simply require it first:
|
424
509
|
|
425
|
-
```ruby
|
426
|
-
|
427
|
-
|
510
|
+
``` ruby
|
511
|
+
require 'rdiscount' # or require 'bluecloth'
|
512
|
+
get('/') { markdown :index }
|
428
513
|
```
|
429
514
|
|
430
515
|
#### Haml Templates
|
@@ -603,15 +688,15 @@ It is not possible to call methods from markdown, nor to pass locals to it.
|
|
603
688
|
You therefore will usually use it in combination with another rendering
|
604
689
|
engine:
|
605
690
|
|
606
|
-
```ruby
|
607
|
-
|
691
|
+
``` ruby
|
692
|
+
erb :overview, :locals => { :text => markdown(:introduction) }
|
608
693
|
```
|
609
694
|
|
610
695
|
Note that you may also call the `markdown` method from within other templates:
|
611
696
|
|
612
|
-
```ruby
|
613
|
-
|
614
|
-
|
697
|
+
``` ruby
|
698
|
+
%h1 Hello From Haml!
|
699
|
+
%p= markdown(:greetings)
|
615
700
|
```
|
616
701
|
|
617
702
|
Since you cannot call Ruby from Markdown, you cannot use layouts written in
|
@@ -639,15 +724,15 @@ template than for the layout by passing the `:layout_engine` option.
|
|
639
724
|
It is not possible to call methods from textile, nor to pass locals to it. You
|
640
725
|
therefore will usually use it in combination with another rendering engine:
|
641
726
|
|
642
|
-
```ruby
|
643
|
-
|
727
|
+
``` ruby
|
728
|
+
erb :overview, :locals => { :text => textile(:introduction) }
|
644
729
|
```
|
645
730
|
|
646
731
|
Note that you may also call the `textile` method from within other templates:
|
647
732
|
|
648
|
-
```ruby
|
649
|
-
|
650
|
-
|
733
|
+
``` ruby
|
734
|
+
%h1 Hello From Haml!
|
735
|
+
%p= textile(:greetings)
|
651
736
|
```
|
652
737
|
|
653
738
|
Since you cannot call Ruby from Textile, you cannot use layouts written in
|
@@ -674,15 +759,15 @@ template than for the layout by passing the `:layout_engine` option.
|
|
674
759
|
It is not possible to call methods from rdoc, nor to pass locals to it. You
|
675
760
|
therefore will usually use it in combination with another rendering engine:
|
676
761
|
|
677
|
-
```ruby
|
678
|
-
|
762
|
+
``` ruby
|
763
|
+
erb :overview, :locals => { :text => rdoc(:introduction) }
|
679
764
|
```
|
680
765
|
|
681
766
|
Note that you may also call the `rdoc` method from within other templates:
|
682
767
|
|
683
|
-
```ruby
|
684
|
-
|
685
|
-
|
768
|
+
``` ruby
|
769
|
+
%h1 Hello From Haml!
|
770
|
+
%p= rdoc(:greetings)
|
686
771
|
```
|
687
772
|
|
688
773
|
Since you cannot call Ruby from RDoc, you cannot use layouts written in
|
@@ -782,15 +867,15 @@ It also takes a block for inline templates (see example).
|
|
782
867
|
It is not possible to call methods from creole, nor to pass locals to it. You
|
783
868
|
therefore will usually use it in combination with another rendering engine:
|
784
869
|
|
785
|
-
```ruby
|
786
|
-
|
870
|
+
``` ruby
|
871
|
+
erb :overview, :locals => { :text => creole(:introduction) }
|
787
872
|
```
|
788
873
|
|
789
874
|
Note that you may also call the `creole` method from within other templates:
|
790
875
|
|
791
|
-
```ruby
|
792
|
-
|
793
|
-
|
876
|
+
``` ruby
|
877
|
+
%h1 Hello From Haml!
|
878
|
+
%p= creole(:greetings)
|
794
879
|
```
|
795
880
|
|
796
881
|
Since you cannot call Ruby from Creole, you cannot use layouts written in
|
@@ -821,6 +906,43 @@ template than for the layout by passing the `:layout_engine` option.
|
|
821
906
|
</tr>
|
822
907
|
</table>
|
823
908
|
|
909
|
+
#### Stylus Templates
|
910
|
+
|
911
|
+
<table>
|
912
|
+
<tr>
|
913
|
+
<td>Dependency</td>
|
914
|
+
<td>
|
915
|
+
<a href="https://github.com/lucasmazza/ruby-stylus" title="Ruby Stylus">
|
916
|
+
Stylus
|
917
|
+
</a> and a
|
918
|
+
<a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
|
919
|
+
way to execute javascript
|
920
|
+
</a>
|
921
|
+
</td>
|
922
|
+
</tr>
|
923
|
+
<tr>
|
924
|
+
<td>File Extension</td>
|
925
|
+
<td><tt>.styl</tt></td>
|
926
|
+
</tr>
|
927
|
+
<tr>
|
928
|
+
<td>Example</td>
|
929
|
+
<td><tt>stylus :index</tt></td>
|
930
|
+
</tr>
|
931
|
+
</table>
|
932
|
+
|
933
|
+
Before being able to use Stylus templates, you need to load `stylus` and
|
934
|
+
`stylus/tilt` first:
|
935
|
+
|
936
|
+
``` ruby
|
937
|
+
require 'sinatra'
|
938
|
+
require 'stylus'
|
939
|
+
require 'stylus/tilt'
|
940
|
+
|
941
|
+
get '/' do
|
942
|
+
stylus :example
|
943
|
+
end
|
944
|
+
```
|
945
|
+
|
824
946
|
#### Yajl Templates
|
825
947
|
|
826
948
|
<table>
|
@@ -849,15 +971,15 @@ template than for the layout by passing the `:layout_engine` option.
|
|
849
971
|
The template source is evaluated as a Ruby string, and the
|
850
972
|
resulting json variable is converted using `#to_json`.
|
851
973
|
|
852
|
-
```ruby
|
853
|
-
|
854
|
-
|
974
|
+
``` ruby
|
975
|
+
json = { :foo => 'bar' }
|
976
|
+
json[:baz] = key
|
855
977
|
```
|
856
978
|
|
857
979
|
The `:callback` and `:variable` options can be used to decorate the rendered object.
|
858
980
|
|
859
|
-
```ruby
|
860
|
-
|
981
|
+
``` ruby
|
982
|
+
var resource = {"foo":"bar","baz":"qux"}; present(resource);
|
861
983
|
```
|
862
984
|
|
863
985
|
#### WLang Templates
|
@@ -885,20 +1007,20 @@ to it. Layouts written in wlang and `yield` are supported, though.
|
|
885
1007
|
Templates are evaluated within the same context as route handlers. Instance
|
886
1008
|
variables set in route handlers are directly accessible by templates:
|
887
1009
|
|
888
|
-
```ruby
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
1010
|
+
``` ruby
|
1011
|
+
get '/:id' do
|
1012
|
+
@foo = Foo.find(params[:id])
|
1013
|
+
haml '%h1= @foo.name'
|
1014
|
+
end
|
893
1015
|
```
|
894
1016
|
|
895
1017
|
Or, specify an explicit Hash of local variables:
|
896
1018
|
|
897
|
-
```ruby
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
1019
|
+
``` ruby
|
1020
|
+
get '/:id' do
|
1021
|
+
foo = Foo.find(params[:id])
|
1022
|
+
haml '%h1= bar.name', :locals => { :bar => foo }
|
1023
|
+
end
|
902
1024
|
```
|
903
1025
|
|
904
1026
|
This is typically used when rendering templates as partials from within
|
@@ -910,10 +1032,10 @@ A layout is usually just a template that calls `yield`.
|
|
910
1032
|
Such a template can by used either through the `:template` option as
|
911
1033
|
described above, or it can be rendered with a block as follows:
|
912
1034
|
|
913
|
-
```ruby
|
914
|
-
|
915
|
-
|
916
|
-
|
1035
|
+
``` ruby
|
1036
|
+
erb :post, :layout => false do
|
1037
|
+
erb :index
|
1038
|
+
end
|
917
1039
|
```
|
918
1040
|
|
919
1041
|
This code is mostly equivalent to `erb :index, :layout => :post`.
|
@@ -921,20 +1043,20 @@ This code is mostly equivalent to `erb :index, :layout => :post`.
|
|
921
1043
|
Passing blocks to rendering methods is most useful for creating nested
|
922
1044
|
layouts:
|
923
1045
|
|
924
|
-
```ruby
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
1046
|
+
``` ruby
|
1047
|
+
erb :main_layout, :layout => false do
|
1048
|
+
erb :admin_layout do
|
1049
|
+
erb :user
|
1050
|
+
end
|
1051
|
+
end
|
930
1052
|
```
|
931
1053
|
|
932
1054
|
This can also be done in fewer lines of code with:
|
933
1055
|
|
934
|
-
```ruby
|
935
|
-
|
936
|
-
|
937
|
-
|
1056
|
+
``` ruby
|
1057
|
+
erb :admin_layout, :layout => :main_layout do
|
1058
|
+
erb :user
|
1059
|
+
end
|
938
1060
|
```
|
939
1061
|
|
940
1062
|
Currently the following rendering method accept a block: `erb`, `haml`,
|
@@ -945,21 +1067,21 @@ Also the general `render` method accepts a block.
|
|
945
1067
|
|
946
1068
|
Templates may be defined at the end of the source file:
|
947
1069
|
|
948
|
-
```ruby
|
949
|
-
|
1070
|
+
``` ruby
|
1071
|
+
require 'sinatra'
|
950
1072
|
|
951
|
-
|
952
|
-
|
953
|
-
|
1073
|
+
get '/' do
|
1074
|
+
haml :index
|
1075
|
+
end
|
954
1076
|
|
955
|
-
|
1077
|
+
__END__
|
956
1078
|
|
957
|
-
|
958
|
-
|
959
|
-
|
1079
|
+
@@ layout
|
1080
|
+
%html
|
1081
|
+
= yield
|
960
1082
|
|
961
|
-
|
962
|
-
|
1083
|
+
@@ index
|
1084
|
+
%div.title Hello world.
|
963
1085
|
```
|
964
1086
|
|
965
1087
|
NOTE: Inline templates defined in the source file that requires sinatra are
|
@@ -970,18 +1092,18 @@ have inline templates in other source files.
|
|
970
1092
|
|
971
1093
|
Templates may also be defined using the top-level `template` method:
|
972
1094
|
|
973
|
-
```ruby
|
974
|
-
|
975
|
-
|
976
|
-
|
1095
|
+
``` ruby
|
1096
|
+
template :layout do
|
1097
|
+
"%html\n =yield\n"
|
1098
|
+
end
|
977
1099
|
|
978
|
-
|
979
|
-
|
980
|
-
|
1100
|
+
template :index do
|
1101
|
+
'%div.title Hello World!'
|
1102
|
+
end
|
981
1103
|
|
982
|
-
|
983
|
-
|
984
|
-
|
1104
|
+
get '/' do
|
1105
|
+
haml :index
|
1106
|
+
end
|
985
1107
|
```
|
986
1108
|
|
987
1109
|
If a template named "layout" exists, it will be used each time a template
|
@@ -989,10 +1111,10 @@ is rendered. You can individually disable layouts by passing
|
|
989
1111
|
`:layout => false` or disable them by default via
|
990
1112
|
`set :haml, :layout => false`:
|
991
1113
|
|
992
|
-
```ruby
|
993
|
-
|
994
|
-
|
995
|
-
|
1114
|
+
``` ruby
|
1115
|
+
get '/' do
|
1116
|
+
haml :index, :layout => !request.xhr?
|
1117
|
+
end
|
996
1118
|
```
|
997
1119
|
|
998
1120
|
### Associating File Extensions
|
@@ -1001,24 +1123,24 @@ To associate a file extension with a template engine, use
|
|
1001
1123
|
`Tilt.register`. For instance, if you like to use the file extension
|
1002
1124
|
`tt` for Textile templates, you can do the following:
|
1003
1125
|
|
1004
|
-
```ruby
|
1005
|
-
|
1126
|
+
``` ruby
|
1127
|
+
Tilt.register :tt, Tilt[:textile]
|
1006
1128
|
```
|
1007
1129
|
|
1008
1130
|
### Adding Your Own Template Engine
|
1009
1131
|
|
1010
1132
|
First, register your engine with Tilt, then create a rendering method:
|
1011
1133
|
|
1012
|
-
```ruby
|
1013
|
-
|
1134
|
+
``` ruby
|
1135
|
+
Tilt.register :myat, MyAwesomeTemplateEngine
|
1014
1136
|
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1137
|
+
helpers do
|
1138
|
+
def myat(*args) render(:myat, *args) end
|
1139
|
+
end
|
1018
1140
|
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1141
|
+
get '/' do
|
1142
|
+
myat :index
|
1143
|
+
end
|
1022
1144
|
```
|
1023
1145
|
|
1024
1146
|
Renders `./views/index.myat`. See https://github.com/rtomayko/tilt to
|
@@ -1030,26 +1152,26 @@ Before filters are evaluated before each request within the same
|
|
1030
1152
|
context as the routes will be and can modify the request and response. Instance
|
1031
1153
|
variables set in filters are accessible by routes and templates:
|
1032
1154
|
|
1033
|
-
```ruby
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1155
|
+
``` ruby
|
1156
|
+
before do
|
1157
|
+
@note = 'Hi!'
|
1158
|
+
request.path_info = '/foo/bar/baz'
|
1159
|
+
end
|
1038
1160
|
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1161
|
+
get '/foo/*' do
|
1162
|
+
@note #=> 'Hi!'
|
1163
|
+
params[:splat] #=> 'bar/baz'
|
1164
|
+
end
|
1043
1165
|
```
|
1044
1166
|
|
1045
1167
|
After filters are evaluated after each request within the same context and can
|
1046
1168
|
also modify the request and response. Instance variables set in before filters
|
1047
1169
|
and routes are accessible by after filters:
|
1048
1170
|
|
1049
|
-
```ruby
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1171
|
+
``` ruby
|
1172
|
+
after do
|
1173
|
+
puts response.status
|
1174
|
+
end
|
1053
1175
|
```
|
1054
1176
|
|
1055
1177
|
Note: Unless you use the `body` method rather than just returning a String from
|
@@ -1059,26 +1181,26 @@ generated later on.
|
|
1059
1181
|
Filters optionally take a pattern, causing them to be evaluated only if the
|
1060
1182
|
request path matches that pattern:
|
1061
1183
|
|
1062
|
-
```ruby
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1184
|
+
``` ruby
|
1185
|
+
before '/protected/*' do
|
1186
|
+
authenticate!
|
1187
|
+
end
|
1066
1188
|
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1189
|
+
after '/create/:slug' do |slug|
|
1190
|
+
session[:last_slug] = slug
|
1191
|
+
end
|
1070
1192
|
```
|
1071
1193
|
|
1072
1194
|
Like routes, filters also take conditions:
|
1073
1195
|
|
1074
|
-
```ruby
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1196
|
+
``` ruby
|
1197
|
+
before :agent => /Songbird/ do
|
1198
|
+
# ...
|
1199
|
+
end
|
1078
1200
|
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1201
|
+
after '/blog/*', :host_name => 'example.com' do
|
1202
|
+
# ...
|
1203
|
+
end
|
1082
1204
|
```
|
1083
1205
|
|
1084
1206
|
## Helpers
|
@@ -1086,30 +1208,30 @@ Like routes, filters also take conditions:
|
|
1086
1208
|
Use the top-level `helpers` method to define helper methods for use in
|
1087
1209
|
route handlers and templates:
|
1088
1210
|
|
1089
|
-
```ruby
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1211
|
+
``` ruby
|
1212
|
+
helpers do
|
1213
|
+
def bar(name)
|
1214
|
+
"#{name}bar"
|
1215
|
+
end
|
1216
|
+
end
|
1095
1217
|
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1218
|
+
get '/:name' do
|
1219
|
+
bar(params[:name])
|
1220
|
+
end
|
1099
1221
|
```
|
1100
1222
|
|
1101
1223
|
Alternatively, helper methods can be separately defined in a module:
|
1102
1224
|
|
1103
|
-
```ruby
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1225
|
+
``` ruby
|
1226
|
+
module FooUtils
|
1227
|
+
def foo(name) "#{name}foo" end
|
1228
|
+
end
|
1107
1229
|
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1230
|
+
module BarUtils
|
1231
|
+
def bar(name) "#{name}bar" end
|
1232
|
+
end
|
1111
1233
|
|
1112
|
-
|
1234
|
+
helpers FooUtils, BarUtils
|
1113
1235
|
```
|
1114
1236
|
|
1115
1237
|
The effect is the same as including the modules in the application class.
|
@@ -1119,16 +1241,16 @@ The effect is the same as including the modules in the application class.
|
|
1119
1241
|
A session is used to keep state during requests. If activated, you have one
|
1120
1242
|
session hash per user session:
|
1121
1243
|
|
1122
|
-
```ruby
|
1123
|
-
|
1244
|
+
``` ruby
|
1245
|
+
enable :sessions
|
1124
1246
|
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1247
|
+
get '/' do
|
1248
|
+
"value = " << session[:value].inspect
|
1249
|
+
end
|
1128
1250
|
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1251
|
+
get '/:value' do
|
1252
|
+
session[:value] = params[:value]
|
1253
|
+
end
|
1132
1254
|
```
|
1133
1255
|
|
1134
1256
|
Note that `enable :sessions` actually stores all data in a cookie. This
|
@@ -1137,16 +1259,16 @@ traffic, for instance). You can use any Rack session middleware: in order to
|
|
1137
1259
|
do so, do **not** call `enable :sessions`, but instead pull in your
|
1138
1260
|
middleware of choice as you would any other middleware:
|
1139
1261
|
|
1140
|
-
```ruby
|
1141
|
-
|
1262
|
+
``` ruby
|
1263
|
+
use Rack::Session::Pool, :expire_after => 2592000
|
1142
1264
|
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1265
|
+
get '/' do
|
1266
|
+
"value = " << session[:value].inspect
|
1267
|
+
end
|
1146
1268
|
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1269
|
+
get '/:value' do
|
1270
|
+
session[:value] = params[:value]
|
1271
|
+
end
|
1150
1272
|
```
|
1151
1273
|
|
1152
1274
|
To improve security, the session data in the cookie is signed with a session
|
@@ -1154,68 +1276,68 @@ secret. A random secret is generated for you by Sinatra. However, since this
|
|
1154
1276
|
secret will change with every start of your application, you might want to
|
1155
1277
|
set the secret yourself, so all your application instances share it:
|
1156
1278
|
|
1157
|
-
```ruby
|
1158
|
-
|
1279
|
+
``` ruby
|
1280
|
+
set :session_secret, 'super secret'
|
1159
1281
|
```
|
1160
1282
|
|
1161
1283
|
If you want to configure it further, you may also store a hash with options in
|
1162
1284
|
the `sessions` setting:
|
1163
1285
|
|
1164
|
-
```ruby
|
1165
|
-
|
1286
|
+
``` ruby
|
1287
|
+
set :sessions, :domain => 'foo.com'
|
1166
1288
|
```
|
1167
1289
|
|
1168
1290
|
### Halting
|
1169
1291
|
|
1170
1292
|
To immediately stop a request within a filter or route use:
|
1171
1293
|
|
1172
|
-
```ruby
|
1173
|
-
|
1294
|
+
``` ruby
|
1295
|
+
halt
|
1174
1296
|
```
|
1175
1297
|
|
1176
1298
|
You can also specify the status when halting:
|
1177
1299
|
|
1178
|
-
```ruby
|
1179
|
-
|
1300
|
+
``` ruby
|
1301
|
+
halt 410
|
1180
1302
|
```
|
1181
1303
|
|
1182
1304
|
Or the body:
|
1183
1305
|
|
1184
|
-
```ruby
|
1185
|
-
|
1306
|
+
``` ruby
|
1307
|
+
halt 'this will be the body'
|
1186
1308
|
```
|
1187
1309
|
|
1188
1310
|
Or both:
|
1189
1311
|
|
1190
|
-
```ruby
|
1191
|
-
|
1312
|
+
``` ruby
|
1313
|
+
halt 401, 'go away!'
|
1192
1314
|
```
|
1193
1315
|
|
1194
1316
|
With headers:
|
1195
1317
|
|
1196
|
-
```ruby
|
1197
|
-
|
1318
|
+
``` ruby
|
1319
|
+
halt 402, {'Content-Type' => 'text/plain'}, 'revenge'
|
1198
1320
|
```
|
1199
1321
|
|
1200
1322
|
It is of course possible to combine a template with `halt`:
|
1201
1323
|
|
1202
|
-
```ruby
|
1203
|
-
|
1324
|
+
``` ruby
|
1325
|
+
halt erb(:error)
|
1204
1326
|
```
|
1205
1327
|
|
1206
1328
|
### Passing
|
1207
1329
|
|
1208
1330
|
A route can punt processing to the next matching route using `pass`:
|
1209
1331
|
|
1210
|
-
```ruby
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1332
|
+
``` ruby
|
1333
|
+
get '/guess/:who' do
|
1334
|
+
pass unless params[:who] == 'Frank'
|
1335
|
+
'You got me!'
|
1336
|
+
end
|
1215
1337
|
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1338
|
+
get '/guess/*' do
|
1339
|
+
'You missed!'
|
1340
|
+
end
|
1219
1341
|
```
|
1220
1342
|
|
1221
1343
|
The route block is immediately exited and control continues with the next
|
@@ -1226,15 +1348,15 @@ matching route. If no matching route is found, a 404 is returned.
|
|
1226
1348
|
Sometimes `pass` is not what you want, instead you would like to get the result
|
1227
1349
|
of calling another route. Simply use `call` to achieve this:
|
1228
1350
|
|
1229
|
-
```ruby
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1351
|
+
``` ruby
|
1352
|
+
get '/foo' do
|
1353
|
+
status, headers, body = call env.merge("PATH_INFO" => '/bar')
|
1354
|
+
[status, headers, body.map(&:upcase)]
|
1355
|
+
end
|
1234
1356
|
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1357
|
+
get '/bar' do
|
1358
|
+
"bar"
|
1359
|
+
end
|
1238
1360
|
```
|
1239
1361
|
|
1240
1362
|
Note that in the example above, you would ease testing and increase performance
|
@@ -1254,14 +1376,14 @@ set the body at an arbitrary point in the execution flow. You can do so with the
|
|
1254
1376
|
`body` helper method. If you do so, you can use that method from there on to
|
1255
1377
|
access the body:
|
1256
1378
|
|
1257
|
-
```ruby
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1379
|
+
``` ruby
|
1380
|
+
get '/foo' do
|
1381
|
+
body "bar"
|
1382
|
+
end
|
1261
1383
|
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1384
|
+
after do
|
1385
|
+
puts body
|
1386
|
+
end
|
1265
1387
|
```
|
1266
1388
|
|
1267
1389
|
It is also possible to pass a block to `body`, which will be executed by the
|
@@ -1269,14 +1391,14 @@ Rack handler (this can be used to implement streaming, see "Return Values").
|
|
1269
1391
|
|
1270
1392
|
Similar to the body, you can also set the status code and headers:
|
1271
1393
|
|
1272
|
-
```ruby
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1394
|
+
``` ruby
|
1395
|
+
get '/foo' do
|
1396
|
+
status 418
|
1397
|
+
headers \
|
1398
|
+
"Allow" => "BREW, POST, GET, PROPFIND, WHEN",
|
1399
|
+
"Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
|
1400
|
+
body "I'm a tea pot!"
|
1401
|
+
end
|
1280
1402
|
```
|
1281
1403
|
|
1282
1404
|
Like `body`, `headers` and `status` with no arguments can be used to access
|
@@ -1289,16 +1411,16 @@ the response body. In extreme examples, you want to keep sending data until
|
|
1289
1411
|
the client closes the connection. You can use the `stream` helper to avoid
|
1290
1412
|
creating your own wrapper:
|
1291
1413
|
|
1292
|
-
```ruby
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1414
|
+
``` ruby
|
1415
|
+
get '/' do
|
1416
|
+
stream do |out|
|
1417
|
+
out << "It's gonna be legen -\n"
|
1418
|
+
sleep 0.5
|
1419
|
+
out << " (wait for it) \n"
|
1420
|
+
sleep 1
|
1421
|
+
out << "- dary!\n"
|
1422
|
+
end
|
1423
|
+
end
|
1302
1424
|
```
|
1303
1425
|
|
1304
1426
|
This allows you to implement streaming APIs,
|
@@ -1318,46 +1440,46 @@ the stream object, allowing you to close it at any later point in the
|
|
1318
1440
|
execution flow. This only works on evented servers, like Thin and Rainbows.
|
1319
1441
|
Other servers will still close the stream:
|
1320
1442
|
|
1321
|
-
```ruby
|
1322
|
-
|
1443
|
+
``` ruby
|
1444
|
+
# long polling
|
1323
1445
|
|
1324
|
-
|
1325
|
-
|
1446
|
+
set :server, :thin
|
1447
|
+
connections = []
|
1326
1448
|
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1449
|
+
get '/subscribe' do
|
1450
|
+
# register a client's interest in server events
|
1451
|
+
stream(:keep_open) { |out| connections << out }
|
1330
1452
|
|
1331
|
-
|
1332
|
-
|
1453
|
+
# purge dead connections
|
1454
|
+
connections.reject!(&:closed?)
|
1333
1455
|
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1456
|
+
# acknowledge
|
1457
|
+
"subscribed"
|
1458
|
+
end
|
1337
1459
|
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1460
|
+
post '/message' do
|
1461
|
+
connections.each do |out|
|
1462
|
+
# notify client that a new message has arrived
|
1463
|
+
out << params[:message] << "\n"
|
1342
1464
|
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1465
|
+
# indicate client to connect again
|
1466
|
+
out.close
|
1467
|
+
end
|
1346
1468
|
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1469
|
+
# acknowledge
|
1470
|
+
"message received"
|
1471
|
+
end
|
1350
1472
|
```
|
1351
1473
|
|
1352
1474
|
### Logging
|
1353
1475
|
|
1354
1476
|
In the request scope, the `logger` helper exposes a `Logger` instance:
|
1355
1477
|
|
1356
|
-
```ruby
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1478
|
+
``` ruby
|
1479
|
+
get '/' do
|
1480
|
+
logger.info "loading data"
|
1481
|
+
# ...
|
1482
|
+
end
|
1361
1483
|
```
|
1362
1484
|
|
1363
1485
|
This logger will automatically take your Rack handler's logging settings into
|
@@ -1368,12 +1490,12 @@ Note that logging is only enabled for `Sinatra::Application` by
|
|
1368
1490
|
default, so if you inherit from `Sinatra::Base`, you probably want to
|
1369
1491
|
enable it yourself:
|
1370
1492
|
|
1371
|
-
```ruby
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1493
|
+
``` ruby
|
1494
|
+
class MyApp < Sinatra::Base
|
1495
|
+
configure :production, :development do
|
1496
|
+
enable :logging
|
1497
|
+
end
|
1498
|
+
end
|
1377
1499
|
```
|
1378
1500
|
|
1379
1501
|
To avoid any logging middleware to be set up, set the `logging` setting to
|
@@ -1386,19 +1508,19 @@ whatever it will find in `env['rack.logger']`.
|
|
1386
1508
|
When using `send_file` or static files you may have mime types Sinatra
|
1387
1509
|
doesn't understand. Use `mime_type` to register them by file extension:
|
1388
1510
|
|
1389
|
-
```ruby
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1511
|
+
``` ruby
|
1512
|
+
configure do
|
1513
|
+
mime_type :foo, 'text/foo'
|
1514
|
+
end
|
1393
1515
|
```
|
1394
1516
|
|
1395
1517
|
You can also use it with the `content_type` helper:
|
1396
1518
|
|
1397
|
-
```ruby
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1519
|
+
``` ruby
|
1520
|
+
get '/' do
|
1521
|
+
content_type :foo
|
1522
|
+
"foo foo foo"
|
1523
|
+
end
|
1402
1524
|
```
|
1403
1525
|
|
1404
1526
|
### Generating URLs
|
@@ -1406,8 +1528,8 @@ You can also use it with the `content_type` helper:
|
|
1406
1528
|
For generating URLs you should use the `url` helper method, for instance, in
|
1407
1529
|
Haml:
|
1408
1530
|
|
1409
|
-
```
|
1410
|
-
|
1531
|
+
``` haml
|
1532
|
+
%a{:href => url('/foo')} foo
|
1411
1533
|
```
|
1412
1534
|
|
1413
1535
|
It takes reverse proxies and Rack routers into account, if present.
|
@@ -1418,52 +1540,52 @@ This method is also aliased to `to` (see below for an example).
|
|
1418
1540
|
|
1419
1541
|
You can trigger a browser redirect with the `redirect` helper method:
|
1420
1542
|
|
1421
|
-
```ruby
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1543
|
+
``` ruby
|
1544
|
+
get '/foo' do
|
1545
|
+
redirect to('/bar')
|
1546
|
+
end
|
1425
1547
|
```
|
1426
1548
|
|
1427
1549
|
Any additional parameters are handled like arguments passed to `halt`:
|
1428
1550
|
|
1429
|
-
```ruby
|
1430
|
-
|
1431
|
-
|
1551
|
+
``` ruby
|
1552
|
+
redirect to('/bar'), 303
|
1553
|
+
redirect 'http://google.com', 'wrong place, buddy'
|
1432
1554
|
```
|
1433
1555
|
|
1434
1556
|
You can also easily redirect back to the page the user came from with
|
1435
1557
|
`redirect back`:
|
1436
1558
|
|
1437
|
-
```ruby
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1559
|
+
``` ruby
|
1560
|
+
get '/foo' do
|
1561
|
+
"<a href='/bar'>do something</a>"
|
1562
|
+
end
|
1441
1563
|
|
1442
|
-
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1564
|
+
get '/bar' do
|
1565
|
+
do_something
|
1566
|
+
redirect back
|
1567
|
+
end
|
1446
1568
|
```
|
1447
1569
|
|
1448
1570
|
To pass arguments with a redirect, either add them to the query:
|
1449
1571
|
|
1450
|
-
```ruby
|
1451
|
-
|
1572
|
+
``` ruby
|
1573
|
+
redirect to('/bar?sum=42')
|
1452
1574
|
```
|
1453
1575
|
|
1454
1576
|
Or use a session:
|
1455
1577
|
|
1456
|
-
```ruby
|
1457
|
-
|
1578
|
+
``` ruby
|
1579
|
+
enable :sessions
|
1458
1580
|
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1581
|
+
get '/foo' do
|
1582
|
+
session[:secret] = 'foo'
|
1583
|
+
redirect to('/bar')
|
1584
|
+
end
|
1463
1585
|
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1586
|
+
get '/bar' do
|
1587
|
+
session[:secret]
|
1588
|
+
end
|
1467
1589
|
```
|
1468
1590
|
|
1469
1591
|
### Cache Control
|
@@ -1472,28 +1594,28 @@ Setting your headers correctly is the foundation for proper HTTP caching.
|
|
1472
1594
|
|
1473
1595
|
You can easily set the Cache-Control header like this:
|
1474
1596
|
|
1475
|
-
```ruby
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1597
|
+
``` ruby
|
1598
|
+
get '/' do
|
1599
|
+
cache_control :public
|
1600
|
+
"cache it!"
|
1601
|
+
end
|
1480
1602
|
```
|
1481
1603
|
|
1482
1604
|
Pro tip: Set up caching in a before filter:
|
1483
1605
|
|
1484
|
-
```ruby
|
1485
|
-
|
1486
|
-
|
1487
|
-
|
1606
|
+
``` ruby
|
1607
|
+
before do
|
1608
|
+
cache_control :public, :must_revalidate, :max_age => 60
|
1609
|
+
end
|
1488
1610
|
```
|
1489
1611
|
|
1490
1612
|
If you are using the `expires` helper to set the corresponding header,
|
1491
1613
|
`Cache-Control` will be set automatically for you:
|
1492
1614
|
|
1493
|
-
```ruby
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1615
|
+
``` ruby
|
1616
|
+
before do
|
1617
|
+
expires 500, :public, :must_revalidate
|
1618
|
+
end
|
1497
1619
|
```
|
1498
1620
|
|
1499
1621
|
To properly use caches, you should consider using `etag` or `last_modified`.
|
@@ -1501,37 +1623,37 @@ It is recommended to call those helpers *before* doing any heavy lifting, as the
|
|
1501
1623
|
will immediately flush a response if the client already has the current
|
1502
1624
|
version in its cache:
|
1503
1625
|
|
1504
|
-
```ruby
|
1505
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1626
|
+
``` ruby
|
1627
|
+
get '/article/:id' do
|
1628
|
+
@article = Article.find params[:id]
|
1629
|
+
last_modified @article.updated_at
|
1630
|
+
etag @article.sha1
|
1631
|
+
erb :article
|
1632
|
+
end
|
1511
1633
|
```
|
1512
1634
|
|
1513
1635
|
It is also possible to use a
|
1514
1636
|
[weak ETag](http://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation):
|
1515
1637
|
|
1516
|
-
```ruby
|
1517
|
-
|
1638
|
+
``` ruby
|
1639
|
+
etag @article.sha1, :weak
|
1518
1640
|
```
|
1519
1641
|
|
1520
1642
|
These helpers will not do any caching for you, but rather feed the necessary
|
1521
1643
|
information to your cache. If you are looking for a quick reverse-proxy caching
|
1522
1644
|
solution, try [rack-cache](https://github.com/rtomayko/rack-cache):
|
1523
1645
|
|
1524
|
-
```ruby
|
1525
|
-
|
1526
|
-
|
1646
|
+
``` ruby
|
1647
|
+
require "rack/cache"
|
1648
|
+
require "sinatra"
|
1527
1649
|
|
1528
|
-
|
1650
|
+
use Rack::Cache
|
1529
1651
|
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1652
|
+
get '/' do
|
1653
|
+
cache_control :public, :max_age => 36000
|
1654
|
+
sleep 5
|
1655
|
+
"hello"
|
1656
|
+
end
|
1535
1657
|
```
|
1536
1658
|
|
1537
1659
|
Use the `:static_cache_control` setting (see below) to add
|
@@ -1544,34 +1666,34 @@ and idempotent (like put) requests are already in existence, whereas other
|
|
1544
1666
|
resources (for instance for post requests), are treated as new resources. You
|
1545
1667
|
can change this behavior by passing in a `:new_resource` option:
|
1546
1668
|
|
1547
|
-
```ruby
|
1548
|
-
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
1552
|
-
|
1669
|
+
``` ruby
|
1670
|
+
get '/create' do
|
1671
|
+
etag '', :new_resource => true
|
1672
|
+
Article.create
|
1673
|
+
erb :new_article
|
1674
|
+
end
|
1553
1675
|
```
|
1554
1676
|
|
1555
1677
|
If you still want to use a weak ETag, pass in a `:kind` option:
|
1556
1678
|
|
1557
|
-
```ruby
|
1558
|
-
|
1679
|
+
``` ruby
|
1680
|
+
etag '', :new_resource => true, :kind => :weak
|
1559
1681
|
```
|
1560
1682
|
|
1561
1683
|
### Sending Files
|
1562
1684
|
|
1563
1685
|
For sending files, you can use the `send_file` helper method:
|
1564
1686
|
|
1565
|
-
```ruby
|
1566
|
-
|
1567
|
-
|
1568
|
-
|
1687
|
+
``` ruby
|
1688
|
+
get '/' do
|
1689
|
+
send_file 'foo.png'
|
1690
|
+
end
|
1569
1691
|
```
|
1570
1692
|
|
1571
1693
|
It also takes options:
|
1572
1694
|
|
1573
|
-
```ruby
|
1574
|
-
|
1695
|
+
``` ruby
|
1696
|
+
send_file 'foo.png', :type => :jpg
|
1575
1697
|
```
|
1576
1698
|
|
1577
1699
|
The options are:
|
@@ -1610,58 +1732,58 @@ The options are:
|
|
1610
1732
|
The incoming request object can be accessed from request level (filter, routes,
|
1611
1733
|
error handlers) through the `request` method:
|
1612
1734
|
|
1613
|
-
```ruby
|
1614
|
-
|
1615
|
-
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1620
|
-
|
1621
|
-
|
1622
|
-
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
|
1632
|
-
|
1633
|
-
|
1634
|
-
|
1635
|
-
|
1636
|
-
|
1637
|
-
|
1638
|
-
|
1639
|
-
|
1640
|
-
|
1641
|
-
|
1642
|
-
|
1643
|
-
|
1735
|
+
``` ruby
|
1736
|
+
# app running on http://example.com/example
|
1737
|
+
get '/foo' do
|
1738
|
+
t = %w[text/css text/html application/javascript]
|
1739
|
+
request.accept # ['text/html', '*/*']
|
1740
|
+
request.accept? 'text/xml' # true
|
1741
|
+
request.preferred_type(t) # 'text/html'
|
1742
|
+
request.body # request body sent by the client (see below)
|
1743
|
+
request.scheme # "http"
|
1744
|
+
request.script_name # "/example"
|
1745
|
+
request.path_info # "/foo"
|
1746
|
+
request.port # 80
|
1747
|
+
request.request_method # "GET"
|
1748
|
+
request.query_string # ""
|
1749
|
+
request.content_length # length of request.body
|
1750
|
+
request.media_type # media type of request.body
|
1751
|
+
request.host # "example.com"
|
1752
|
+
request.get? # true (similar methods for other verbs)
|
1753
|
+
request.form_data? # false
|
1754
|
+
request["some_param"] # value of some_param parameter. [] is a shortcut to the params hash.
|
1755
|
+
request.referrer # the referrer of the client or '/'
|
1756
|
+
request.user_agent # user agent (used by :agent condition)
|
1757
|
+
request.cookies # hash of browser cookies
|
1758
|
+
request.xhr? # is this an ajax request?
|
1759
|
+
request.url # "http://example.com/example/foo"
|
1760
|
+
request.path # "/example/foo"
|
1761
|
+
request.ip # client IP address
|
1762
|
+
request.secure? # false (would be true over ssl)
|
1763
|
+
request.forwarded? # true (if running behind a reverse proxy)
|
1764
|
+
request.env # raw env hash handed in by Rack
|
1765
|
+
end
|
1644
1766
|
```
|
1645
1767
|
|
1646
1768
|
Some options, like `script_name` or `path_info`, can also be
|
1647
1769
|
written:
|
1648
1770
|
|
1649
|
-
```ruby
|
1650
|
-
|
1771
|
+
``` ruby
|
1772
|
+
before { request.path_info = "/" }
|
1651
1773
|
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
1774
|
+
get "/" do
|
1775
|
+
"all requests end up here"
|
1776
|
+
end
|
1655
1777
|
```
|
1656
1778
|
|
1657
1779
|
The `request.body` is an IO or StringIO object:
|
1658
1780
|
|
1659
|
-
```ruby
|
1660
|
-
|
1661
|
-
|
1662
|
-
|
1663
|
-
|
1664
|
-
|
1781
|
+
``` ruby
|
1782
|
+
post "/api" do
|
1783
|
+
request.body.rewind # in case someone already read it
|
1784
|
+
data = JSON.parse request.body.read
|
1785
|
+
"Hello #{data['name']}!"
|
1786
|
+
end
|
1665
1787
|
```
|
1666
1788
|
|
1667
1789
|
### Attachments
|
@@ -1669,20 +1791,20 @@ The `request.body` is an IO or StringIO object:
|
|
1669
1791
|
You can use the `attachment` helper to tell the browser the response should be
|
1670
1792
|
stored on disk rather than displayed in the browser:
|
1671
1793
|
|
1672
|
-
```ruby
|
1673
|
-
|
1674
|
-
|
1675
|
-
|
1676
|
-
|
1794
|
+
``` ruby
|
1795
|
+
get '/' do
|
1796
|
+
attachment
|
1797
|
+
"store it!"
|
1798
|
+
end
|
1677
1799
|
```
|
1678
1800
|
|
1679
1801
|
You can also pass it a file name:
|
1680
1802
|
|
1681
|
-
```ruby
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1803
|
+
``` ruby
|
1804
|
+
get '/' do
|
1805
|
+
attachment "info.txt"
|
1806
|
+
"store it!"
|
1807
|
+
end
|
1686
1808
|
```
|
1687
1809
|
|
1688
1810
|
### Dealing with Date and Time
|
@@ -1691,71 +1813,71 @@ Sinatra offers a `time_for` helper method that generates a Time object
|
|
1691
1813
|
from the given value. It is also able to convert `DateTime`, `Date` and
|
1692
1814
|
similar classes:
|
1693
1815
|
|
1694
|
-
```ruby
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1816
|
+
``` ruby
|
1817
|
+
get '/' do
|
1818
|
+
pass if Time.now > time_for('Dec 23, 2012')
|
1819
|
+
"still time"
|
1820
|
+
end
|
1699
1821
|
```
|
1700
1822
|
|
1701
1823
|
This method is used internally by `expires`, `last_modified` and akin. You can
|
1702
1824
|
therefore easily extend the behavior of those methods by overriding `time_for`
|
1703
1825
|
in your application:
|
1704
1826
|
|
1705
|
-
```ruby
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
|
1712
|
-
end
|
1713
|
-
end
|
1827
|
+
``` ruby
|
1828
|
+
helpers do
|
1829
|
+
def time_for(value)
|
1830
|
+
case value
|
1831
|
+
when :yesterday then Time.now - 24*60*60
|
1832
|
+
when :tomorrow then Time.now + 24*60*60
|
1833
|
+
else super
|
1714
1834
|
end
|
1835
|
+
end
|
1836
|
+
end
|
1715
1837
|
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1838
|
+
get '/' do
|
1839
|
+
last_modified :yesterday
|
1840
|
+
expires :tomorrow
|
1841
|
+
"hello"
|
1842
|
+
end
|
1721
1843
|
```
|
1722
1844
|
|
1723
1845
|
### Looking Up Template Files
|
1724
1846
|
|
1725
1847
|
The `find_template` helper is used to find template files for rendering:
|
1726
1848
|
|
1727
|
-
```ruby
|
1728
|
-
|
1729
|
-
|
1730
|
-
|
1849
|
+
``` ruby
|
1850
|
+
find_template settings.views, 'foo', Tilt[:haml] do |file|
|
1851
|
+
puts "could be #{file}"
|
1852
|
+
end
|
1731
1853
|
```
|
1732
1854
|
|
1733
1855
|
This is not really useful. But it is useful that you can actually override this
|
1734
1856
|
method to hook in your own lookup mechanism. For instance, if you want to be
|
1735
1857
|
able to use more than one view directory:
|
1736
1858
|
|
1737
|
-
```ruby
|
1738
|
-
|
1859
|
+
``` ruby
|
1860
|
+
set :views, ['views', 'templates']
|
1739
1861
|
|
1740
|
-
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1862
|
+
helpers do
|
1863
|
+
def find_template(views, name, engine, &block)
|
1864
|
+
Array(views).each { |v| super(v, name, engine, &block) }
|
1865
|
+
end
|
1866
|
+
end
|
1745
1867
|
```
|
1746
1868
|
|
1747
1869
|
Another example would be using different directories for different engines:
|
1748
1870
|
|
1749
|
-
```ruby
|
1750
|
-
|
1751
|
-
|
1752
|
-
|
1753
|
-
|
1754
|
-
|
1755
|
-
|
1756
|
-
|
1757
|
-
|
1758
|
-
|
1871
|
+
``` ruby
|
1872
|
+
set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
|
1873
|
+
|
1874
|
+
helpers do
|
1875
|
+
def find_template(views, name, engine, &block)
|
1876
|
+
_, folder = views.detect { |k,v| engine == Tilt[k] }
|
1877
|
+
folder ||= views[:default]
|
1878
|
+
super(folder, name, engine, &block)
|
1879
|
+
end
|
1880
|
+
end
|
1759
1881
|
```
|
1760
1882
|
|
1761
1883
|
You can also easily wrap this up in an extension and share with others!
|
@@ -1771,55 +1893,55 @@ method.
|
|
1771
1893
|
|
1772
1894
|
Run once, at startup, in any environment:
|
1773
1895
|
|
1774
|
-
```ruby
|
1775
|
-
|
1776
|
-
|
1777
|
-
|
1896
|
+
``` ruby
|
1897
|
+
configure do
|
1898
|
+
# setting one option
|
1899
|
+
set :option, 'value'
|
1778
1900
|
|
1779
|
-
|
1780
|
-
|
1901
|
+
# setting multiple options
|
1902
|
+
set :a => 1, :b => 2
|
1781
1903
|
|
1782
|
-
|
1783
|
-
|
1904
|
+
# same as `set :option, true`
|
1905
|
+
enable :option
|
1784
1906
|
|
1785
|
-
|
1786
|
-
|
1907
|
+
# same as `set :option, false`
|
1908
|
+
disable :option
|
1787
1909
|
|
1788
|
-
|
1789
|
-
|
1790
|
-
|
1910
|
+
# you can also have dynamic settings with blocks
|
1911
|
+
set(:css_dir) { File.join(views, 'css') }
|
1912
|
+
end
|
1791
1913
|
```
|
1792
1914
|
|
1793
1915
|
Run only when the environment (`RACK_ENV` environment variable) is set to
|
1794
1916
|
`:production`:
|
1795
1917
|
|
1796
|
-
```ruby
|
1797
|
-
|
1798
|
-
|
1799
|
-
|
1918
|
+
``` ruby
|
1919
|
+
configure :production do
|
1920
|
+
...
|
1921
|
+
end
|
1800
1922
|
```
|
1801
1923
|
|
1802
1924
|
Run when the environment is set to either `:production` or
|
1803
1925
|
`:test`:
|
1804
1926
|
|
1805
1927
|
```ruby
|
1806
|
-
|
1807
|
-
|
1808
|
-
|
1928
|
+
configure :production, :test do
|
1929
|
+
...
|
1930
|
+
end
|
1809
1931
|
```
|
1810
1932
|
|
1811
1933
|
You can access those options via `settings`:
|
1812
1934
|
|
1813
|
-
```ruby
|
1814
|
-
|
1815
|
-
|
1816
|
-
|
1935
|
+
``` ruby
|
1936
|
+
configure do
|
1937
|
+
set :foo, 'bar'
|
1938
|
+
end
|
1817
1939
|
|
1818
|
-
|
1819
|
-
|
1820
|
-
|
1821
|
-
|
1822
|
-
|
1940
|
+
get '/' do
|
1941
|
+
settings.foo? # => true
|
1942
|
+
settings.foo # => 'bar'
|
1943
|
+
...
|
1944
|
+
end
|
1823
1945
|
```
|
1824
1946
|
|
1825
1947
|
### Configuring attack protection
|
@@ -1830,28 +1952,28 @@ your application against common, opportunistic attacks. You can easily disable
|
|
1830
1952
|
this behavior (which will open up your application to tons of common
|
1831
1953
|
vulnerabilities):
|
1832
1954
|
|
1833
|
-
```ruby
|
1834
|
-
|
1955
|
+
``` ruby
|
1956
|
+
disable :protection
|
1835
1957
|
```
|
1836
1958
|
|
1837
1959
|
To skip a single defense layer, set `protection` to an options hash:
|
1838
1960
|
|
1839
|
-
```ruby
|
1840
|
-
|
1961
|
+
``` ruby
|
1962
|
+
set :protection, :except => :path_traversal
|
1841
1963
|
```
|
1842
1964
|
You can also hand in an array in order to disable a list of protections:
|
1843
1965
|
|
1844
|
-
```ruby
|
1845
|
-
|
1966
|
+
``` ruby
|
1967
|
+
set :protection, :except => [:path_traversal, :session_hijacking]
|
1846
1968
|
```
|
1847
1969
|
|
1848
1970
|
By default, Sinatra will only set up session based protection if `:sessions`
|
1849
1971
|
has been enabled. Sometimes you want to set up sessions on your own, though. In
|
1850
1972
|
that case you can get it to set up session based protections by passing the `:session` option:
|
1851
1973
|
|
1852
|
-
```ruby
|
1853
|
-
|
1854
|
-
|
1974
|
+
``` ruby
|
1975
|
+
use Rack::Session::Pool
|
1976
|
+
set :protection, :session => true
|
1855
1977
|
```
|
1856
1978
|
|
1857
1979
|
### Available Settings
|
@@ -2034,14 +2156,24 @@ requests, and special `not_found` and `error` handlers
|
|
2034
2156
|
display stack traces in your browser.
|
2035
2157
|
In the `"production"` and `"test"` environments, templates are cached by default.
|
2036
2158
|
|
2037
|
-
To run different environments
|
2159
|
+
To run different environments, set the `RACK_ENV` environment variable:
|
2038
2160
|
|
2039
|
-
```
|
2040
|
-
|
2161
|
+
``` shell
|
2162
|
+
RACK_ENV=production ruby my_app.rb
|
2041
2163
|
```
|
2042
2164
|
|
2043
2165
|
You can use predefined methods: `development?`, `test?` and `production?` to
|
2044
|
-
check the current environment setting
|
2166
|
+
check the current environment setting:
|
2167
|
+
|
2168
|
+
``` ruby
|
2169
|
+
get '/' do
|
2170
|
+
if settings.development?
|
2171
|
+
"development!"
|
2172
|
+
else
|
2173
|
+
"not development!"
|
2174
|
+
end
|
2175
|
+
end
|
2176
|
+
```
|
2045
2177
|
|
2046
2178
|
## Error Handling
|
2047
2179
|
|
@@ -2054,10 +2186,10 @@ means you get all the goodies it has to offer, like `haml`,
|
|
2054
2186
|
When a `Sinatra::NotFound` exception is raised, or the response's status
|
2055
2187
|
code is 404, the `not_found` handler is invoked:
|
2056
2188
|
|
2057
|
-
```ruby
|
2058
|
-
|
2059
|
-
|
2060
|
-
|
2189
|
+
``` ruby
|
2190
|
+
not_found do
|
2191
|
+
'This is nowhere to be found.'
|
2192
|
+
end
|
2061
2193
|
```
|
2062
2194
|
|
2063
2195
|
### Error
|
@@ -2066,52 +2198,52 @@ The `error` handler is invoked any time an exception is raised from a route
|
|
2066
2198
|
block or a filter. The exception object can be obtained from the
|
2067
2199
|
`sinatra.error` Rack variable:
|
2068
2200
|
|
2069
|
-
```ruby
|
2070
|
-
|
2071
|
-
|
2072
|
-
|
2201
|
+
``` ruby
|
2202
|
+
error do
|
2203
|
+
'Sorry there was a nasty error - ' + env['sinatra.error'].name
|
2204
|
+
end
|
2073
2205
|
```
|
2074
2206
|
|
2075
2207
|
Custom errors:
|
2076
2208
|
|
2077
|
-
```ruby
|
2078
|
-
|
2079
|
-
|
2080
|
-
|
2209
|
+
``` ruby
|
2210
|
+
error MyCustomError do
|
2211
|
+
'So what happened was...' + env['sinatra.error'].message
|
2212
|
+
end
|
2081
2213
|
```
|
2082
2214
|
|
2083
2215
|
Then, if this happens:
|
2084
2216
|
|
2085
|
-
```ruby
|
2086
|
-
|
2087
|
-
|
2088
|
-
|
2217
|
+
``` ruby
|
2218
|
+
get '/' do
|
2219
|
+
raise MyCustomError, 'something bad'
|
2220
|
+
end
|
2089
2221
|
```
|
2090
2222
|
|
2091
2223
|
You get this:
|
2092
2224
|
|
2093
|
-
```
|
2094
|
-
|
2225
|
+
```
|
2226
|
+
So what happened was... something bad
|
2095
2227
|
```
|
2096
2228
|
|
2097
2229
|
Alternatively, you can install an error handler for a status code:
|
2098
2230
|
|
2099
|
-
```ruby
|
2100
|
-
|
2101
|
-
|
2102
|
-
|
2231
|
+
``` ruby
|
2232
|
+
error 403 do
|
2233
|
+
'Access forbidden'
|
2234
|
+
end
|
2103
2235
|
|
2104
|
-
|
2105
|
-
|
2106
|
-
|
2236
|
+
get '/secret' do
|
2237
|
+
403
|
2238
|
+
end
|
2107
2239
|
```
|
2108
2240
|
|
2109
2241
|
Or a range:
|
2110
2242
|
|
2111
|
-
```ruby
|
2112
|
-
|
2113
|
-
|
2114
|
-
|
2243
|
+
``` ruby
|
2244
|
+
error 400..510 do
|
2245
|
+
'Boom'
|
2246
|
+
end
|
2115
2247
|
```
|
2116
2248
|
|
2117
2249
|
Sinatra installs special `not_found` and `error` handlers when
|
@@ -2129,16 +2261,16 @@ HTTP request/response to provide various types of common functionality.
|
|
2129
2261
|
Sinatra makes building Rack middleware pipelines a cinch via a top-level
|
2130
2262
|
`use` method:
|
2131
2263
|
|
2132
|
-
```ruby
|
2133
|
-
|
2134
|
-
|
2264
|
+
``` ruby
|
2265
|
+
require 'sinatra'
|
2266
|
+
require 'my_custom_middleware'
|
2135
2267
|
|
2136
|
-
|
2137
|
-
|
2268
|
+
use Rack::Lint
|
2269
|
+
use MyCustomMiddleware
|
2138
2270
|
|
2139
|
-
|
2140
|
-
|
2141
|
-
|
2271
|
+
get '/hello' do
|
2272
|
+
'Hello World'
|
2273
|
+
end
|
2142
2274
|
```
|
2143
2275
|
|
2144
2276
|
The semantics of `use` are identical to those defined for the
|
@@ -2146,10 +2278,10 @@ The semantics of `use` are identical to those defined for the
|
|
2146
2278
|
(most frequently used from rackup files). For example, the `use` method
|
2147
2279
|
accepts multiple/variable args as well as blocks:
|
2148
2280
|
|
2149
|
-
```ruby
|
2150
|
-
|
2151
|
-
|
2152
|
-
|
2281
|
+
``` ruby
|
2282
|
+
use Rack::Auth::Basic do |username, password|
|
2283
|
+
username == 'admin' && password == 'secret'
|
2284
|
+
end
|
2153
2285
|
```
|
2154
2286
|
|
2155
2287
|
Rack is distributed with a variety of standard middleware for logging,
|
@@ -2169,33 +2301,33 @@ Sinatra tests can be written using any Rack-based testing library or framework.
|
|
2169
2301
|
[Rack::Test](http://rdoc.info/github/brynary/rack-test/master/frames)
|
2170
2302
|
is recommended:
|
2171
2303
|
|
2172
|
-
```ruby
|
2173
|
-
|
2174
|
-
|
2175
|
-
|
2176
|
-
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2180
|
-
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2186
|
-
|
2187
|
-
|
2188
|
-
|
2189
|
-
|
2190
|
-
|
2191
|
-
|
2192
|
-
|
2193
|
-
|
2194
|
-
|
2195
|
-
|
2196
|
-
|
2197
|
-
|
2198
|
-
|
2304
|
+
``` ruby
|
2305
|
+
require 'my_sinatra_app'
|
2306
|
+
require 'test/unit'
|
2307
|
+
require 'rack/test'
|
2308
|
+
|
2309
|
+
class MyAppTest < Test::Unit::TestCase
|
2310
|
+
include Rack::Test::Methods
|
2311
|
+
|
2312
|
+
def app
|
2313
|
+
Sinatra::Application
|
2314
|
+
end
|
2315
|
+
|
2316
|
+
def test_my_default
|
2317
|
+
get '/'
|
2318
|
+
assert_equal 'Hello World!', last_response.body
|
2319
|
+
end
|
2320
|
+
|
2321
|
+
def test_with_params
|
2322
|
+
get '/meet', :name => 'Frank'
|
2323
|
+
assert_equal 'Hello Frank!', last_response.body
|
2324
|
+
end
|
2325
|
+
|
2326
|
+
def test_with_rack_env
|
2327
|
+
get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
|
2328
|
+
assert_equal "You're using Songbird!", last_response.body
|
2329
|
+
end
|
2330
|
+
end
|
2199
2331
|
```
|
2200
2332
|
|
2201
2333
|
Note: If you are using Sinatra in the modular style, replace `Sinatra::Application`
|
@@ -2211,17 +2343,17 @@ Sinatra extensions. The top-level assumes a micro-app style configuration
|
|
2211
2343
|
directories, logging, exception detail page, etc.). That's where
|
2212
2344
|
`Sinatra::Base` comes into play:
|
2213
2345
|
|
2214
|
-
```ruby
|
2215
|
-
|
2346
|
+
``` ruby
|
2347
|
+
require 'sinatra/base'
|
2216
2348
|
|
2217
|
-
|
2218
|
-
|
2219
|
-
|
2349
|
+
class MyApp < Sinatra::Base
|
2350
|
+
set :sessions, true
|
2351
|
+
set :foo, 'bar'
|
2220
2352
|
|
2221
|
-
|
2222
|
-
|
2223
|
-
|
2224
|
-
|
2353
|
+
get '/' do
|
2354
|
+
'Hello world!'
|
2355
|
+
end
|
2356
|
+
end
|
2225
2357
|
```
|
2226
2358
|
|
2227
2359
|
The methods available to `Sinatra::Base` subclasses are exactly the same as those
|
@@ -2252,72 +2384,105 @@ the modular and the classic styles.
|
|
2252
2384
|
If switching from one style to the other, you should be aware of slightly
|
2253
2385
|
different default settings:
|
2254
2386
|
|
2255
|
-
|
2256
|
-
|
2387
|
+
<table>
|
2388
|
+
<tr>
|
2389
|
+
<th>Setting</th>
|
2390
|
+
<th>Classic</th>
|
2391
|
+
<th>Modular</th>
|
2392
|
+
</tr>
|
2257
2393
|
|
2258
|
-
|
2259
|
-
|
2260
|
-
|
2261
|
-
|
2262
|
-
|
2263
|
-
|
2264
|
-
|
2394
|
+
<tr>
|
2395
|
+
<td>app_file</td>
|
2396
|
+
<td>file loading sinatra</td>
|
2397
|
+
<td>file subclassing Sinatra::Base</td>
|
2398
|
+
</tr>
|
2399
|
+
|
2400
|
+
<tr>
|
2401
|
+
<td>run</td>
|
2402
|
+
<td>$0 == app_file</td>
|
2403
|
+
<td>false</td>
|
2404
|
+
</tr>
|
2405
|
+
|
2406
|
+
<tr>
|
2407
|
+
<td>logging</td>
|
2408
|
+
<td>true</td>
|
2409
|
+
<td>false</td>
|
2410
|
+
</tr>
|
2411
|
+
|
2412
|
+
<tr>
|
2413
|
+
<td>method_override</td>
|
2414
|
+
<td>true</td>
|
2415
|
+
<td>false</td>
|
2416
|
+
</tr>
|
2417
|
+
|
2418
|
+
<tr>
|
2419
|
+
<td>inline_templates</td>
|
2420
|
+
<td>true</td>
|
2421
|
+
<td>false</td>
|
2422
|
+
</tr>
|
2423
|
+
|
2424
|
+
<tr>
|
2425
|
+
<td>static</td>
|
2426
|
+
<td>true</td>
|
2427
|
+
<td>false</td>
|
2428
|
+
</tr>
|
2429
|
+
</table>
|
2265
2430
|
|
2266
2431
|
### Serving a Modular Application
|
2267
2432
|
|
2268
2433
|
There are two common options for starting a modular app, actively starting with
|
2269
2434
|
`run!`:
|
2270
2435
|
|
2271
|
-
```ruby
|
2272
|
-
|
2273
|
-
|
2436
|
+
``` ruby
|
2437
|
+
# my_app.rb
|
2438
|
+
require 'sinatra/base'
|
2274
2439
|
|
2275
|
-
|
2276
|
-
|
2440
|
+
class MyApp < Sinatra::Base
|
2441
|
+
# ... app code here ...
|
2277
2442
|
|
2278
|
-
|
2279
|
-
|
2280
|
-
|
2443
|
+
# start the server if ruby file executed directly
|
2444
|
+
run! if app_file == $0
|
2445
|
+
end
|
2281
2446
|
```
|
2282
2447
|
|
2283
2448
|
Start with:
|
2284
2449
|
|
2285
|
-
```ruby
|
2286
|
-
|
2450
|
+
``` ruby
|
2451
|
+
ruby my_app.rb
|
2287
2452
|
```
|
2288
2453
|
|
2289
2454
|
Or with a `config.ru` file, which allows using any Rack handler:
|
2290
2455
|
|
2291
|
-
```ruby
|
2292
|
-
|
2293
|
-
|
2294
|
-
|
2456
|
+
``` ruby
|
2457
|
+
# config.ru (run with rackup)
|
2458
|
+
require './my_app'
|
2459
|
+
run MyApp
|
2295
2460
|
```
|
2296
2461
|
|
2297
2462
|
Run:
|
2298
2463
|
|
2299
|
-
```ruby
|
2300
|
-
|
2464
|
+
``` ruby
|
2465
|
+
rackup -p 4567
|
2301
2466
|
```
|
2302
2467
|
|
2303
2468
|
### Using a Classic Style Application with a config.ru
|
2304
2469
|
|
2305
2470
|
Write your app file:
|
2306
2471
|
|
2307
|
-
```ruby
|
2308
|
-
|
2309
|
-
|
2472
|
+
``` ruby
|
2473
|
+
# app.rb
|
2474
|
+
require 'sinatra'
|
2310
2475
|
|
2311
|
-
|
2312
|
-
|
2313
|
-
|
2476
|
+
get '/' do
|
2477
|
+
'Hello world!'
|
2478
|
+
end
|
2314
2479
|
```
|
2315
2480
|
|
2316
2481
|
And a corresponding `config.ru`:
|
2317
2482
|
|
2318
|
-
```ruby
|
2319
|
-
|
2320
|
-
|
2483
|
+
``` ruby
|
2484
|
+
require './app'
|
2485
|
+
run Sinatra::Application
|
2321
2486
|
```
|
2322
2487
|
|
2323
2488
|
### When to use a config.ru?
|
@@ -2340,35 +2505,35 @@ can in turn be added in front of any Rack endpoint as middleware itself. This
|
|
2340
2505
|
endpoint could be another Sinatra application, or any other Rack-based
|
2341
2506
|
application (Rails/Ramaze/Camping/...):
|
2342
2507
|
|
2343
|
-
```ruby
|
2344
|
-
|
2508
|
+
``` ruby
|
2509
|
+
require 'sinatra/base'
|
2345
2510
|
|
2346
|
-
|
2347
|
-
|
2511
|
+
class LoginScreen < Sinatra::Base
|
2512
|
+
enable :sessions
|
2348
2513
|
|
2349
|
-
|
2514
|
+
get('/login') { haml :login }
|
2350
2515
|
|
2351
|
-
|
2352
|
-
|
2353
|
-
|
2354
|
-
|
2355
|
-
|
2356
|
-
end
|
2357
|
-
end
|
2516
|
+
post('/login') do
|
2517
|
+
if params[:name] == 'admin' && params[:password] == 'admin'
|
2518
|
+
session['user_name'] = params[:name]
|
2519
|
+
else
|
2520
|
+
redirect '/login'
|
2358
2521
|
end
|
2522
|
+
end
|
2523
|
+
end
|
2359
2524
|
|
2360
|
-
|
2361
|
-
|
2362
|
-
|
2363
|
-
|
2364
|
-
before do
|
2365
|
-
unless session['user_name']
|
2366
|
-
halt "Access denied, please <a href='/login'>login</a>."
|
2367
|
-
end
|
2368
|
-
end
|
2525
|
+
class MyApp < Sinatra::Base
|
2526
|
+
# middleware will run before filters
|
2527
|
+
use LoginScreen
|
2369
2528
|
|
2370
|
-
|
2529
|
+
before do
|
2530
|
+
unless session['user_name']
|
2531
|
+
halt "Access denied, please <a href='/login'>login</a>."
|
2371
2532
|
end
|
2533
|
+
end
|
2534
|
+
|
2535
|
+
get('/') { "Hello #{session['user_name']}." }
|
2536
|
+
end
|
2372
2537
|
```
|
2373
2538
|
|
2374
2539
|
### Dynamic Application Creation
|
@@ -2376,30 +2541,30 @@ application (Rails/Ramaze/Camping/...):
|
|
2376
2541
|
Sometimes you want to create new applications at runtime without having to
|
2377
2542
|
assign them to a constant, you can do this with `Sinatra.new`:
|
2378
2543
|
|
2379
|
-
```ruby
|
2380
|
-
|
2381
|
-
|
2382
|
-
|
2544
|
+
``` ruby
|
2545
|
+
require 'sinatra/base'
|
2546
|
+
my_app = Sinatra.new { get('/') { "hi" } }
|
2547
|
+
my_app.run!
|
2383
2548
|
```
|
2384
2549
|
|
2385
2550
|
It takes the application to inherit from as an optional argument:
|
2386
2551
|
|
2387
2552
|
```ruby
|
2388
|
-
|
2389
|
-
|
2553
|
+
# config.ru (run with rackup)
|
2554
|
+
require 'sinatra/base'
|
2390
2555
|
|
2391
|
-
|
2392
|
-
|
2393
|
-
|
2394
|
-
|
2556
|
+
controller = Sinatra.new do
|
2557
|
+
enable :logging
|
2558
|
+
helpers MyHelpers
|
2559
|
+
end
|
2395
2560
|
|
2396
|
-
|
2397
|
-
|
2398
|
-
|
2561
|
+
map('/a') do
|
2562
|
+
run Sinatra.new(controller) { get('/') { 'a' } }
|
2563
|
+
end
|
2399
2564
|
|
2400
|
-
|
2401
|
-
|
2402
|
-
|
2565
|
+
map('/b') do
|
2566
|
+
run Sinatra.new(controller) { get('/') { 'b' } }
|
2567
|
+
end
|
2403
2568
|
```
|
2404
2569
|
|
2405
2570
|
This is especially useful for testing Sinatra extensions or using Sinatra in
|
@@ -2407,14 +2572,14 @@ your own library.
|
|
2407
2572
|
|
2408
2573
|
This also makes using Sinatra as middleware extremely easy:
|
2409
2574
|
|
2410
|
-
```ruby
|
2411
|
-
|
2575
|
+
``` ruby
|
2576
|
+
require 'sinatra/base'
|
2412
2577
|
|
2413
|
-
|
2414
|
-
|
2415
|
-
|
2578
|
+
use Sinatra do
|
2579
|
+
get('/') { ... }
|
2580
|
+
end
|
2416
2581
|
|
2417
|
-
|
2582
|
+
run RailsProject::Application
|
2418
2583
|
```
|
2419
2584
|
|
2420
2585
|
## Scopes and Binding
|
@@ -2433,16 +2598,16 @@ single application class for all requests.
|
|
2433
2598
|
|
2434
2599
|
Options created via `set` are methods at class level:
|
2435
2600
|
|
2436
|
-
```ruby
|
2437
|
-
|
2438
|
-
|
2439
|
-
|
2440
|
-
|
2441
|
-
|
2442
|
-
|
2443
|
-
|
2444
|
-
|
2445
|
-
|
2601
|
+
``` ruby
|
2602
|
+
class MyApp < Sinatra::Base
|
2603
|
+
# Hey, I'm in the application scope!
|
2604
|
+
set :foo, 42
|
2605
|
+
foo # => 42
|
2606
|
+
|
2607
|
+
get '/foo' do
|
2608
|
+
# Hey, I'm no longer in the application scope!
|
2609
|
+
end
|
2610
|
+
end
|
2446
2611
|
```
|
2447
2612
|
|
2448
2613
|
You have the application scope binding inside:
|
@@ -2466,21 +2631,21 @@ can access the `request` and `session` objects or call rendering methods like
|
|
2466
2631
|
`erb` or `haml`. You can access the application scope from within the request
|
2467
2632
|
scope via the `settings` helper:
|
2468
2633
|
|
2469
|
-
```ruby
|
2470
|
-
|
2471
|
-
|
2472
|
-
|
2473
|
-
|
2474
|
-
|
2475
|
-
|
2476
|
-
|
2477
|
-
|
2478
|
-
|
2479
|
-
end
|
2480
|
-
|
2481
|
-
"Route defined!"
|
2482
|
-
end
|
2634
|
+
``` ruby
|
2635
|
+
class MyApp < Sinatra::Base
|
2636
|
+
# Hey, I'm in the application scope!
|
2637
|
+
get '/define_route/:name' do
|
2638
|
+
# Request scope for '/define_route/:name'
|
2639
|
+
@value = 42
|
2640
|
+
|
2641
|
+
settings.get("/#{params[:name]}") do
|
2642
|
+
# Request scope for "/#{params[:name]}"
|
2643
|
+
@value # => nil (not the same request)
|
2483
2644
|
end
|
2645
|
+
|
2646
|
+
"Route defined!"
|
2647
|
+
end
|
2648
|
+
end
|
2484
2649
|
```
|
2485
2650
|
|
2486
2651
|
You have the request scope binding inside:
|
@@ -2512,19 +2677,19 @@ being [extending the main object](https://github.com/sinatra/sinatra/blob/ca0636
|
|
2512
2677
|
|
2513
2678
|
Sinatra applications can be run directly:
|
2514
2679
|
|
2515
|
-
```ruby
|
2516
|
-
|
2680
|
+
``` ruby
|
2681
|
+
ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-o HOST] [-s HANDLER]
|
2517
2682
|
```
|
2518
2683
|
|
2519
2684
|
Options are:
|
2520
2685
|
|
2521
2686
|
```
|
2522
|
-
|
2523
|
-
|
2524
|
-
|
2525
|
-
|
2526
|
-
|
2527
|
-
|
2687
|
+
-h # help
|
2688
|
+
-p # set the port (default is 4567)
|
2689
|
+
-o # set the host (default is 0.0.0.0)
|
2690
|
+
-e # set the environment (default is development)
|
2691
|
+
-s # specify rack server/handler (default is thin)
|
2692
|
+
-x # turn on the mutex lock (default is off)
|
2528
2693
|
```
|
2529
2694
|
|
2530
2695
|
## Requirement
|
@@ -2603,8 +2768,8 @@ application against the master branch, it should be rather stable.
|
|
2603
2768
|
|
2604
2769
|
We also push out prerelease gems from time to time, so you can do a
|
2605
2770
|
|
2606
|
-
```
|
2607
|
-
|
2771
|
+
``` shell
|
2772
|
+
gem install sinatra --pre
|
2608
2773
|
```
|
2609
2774
|
|
2610
2775
|
To get some of the latest features.
|
@@ -2616,19 +2781,19 @@ If you want to run your application with the latest Sinatra, using
|
|
2616
2781
|
|
2617
2782
|
First, install bundler, if you haven't:
|
2618
2783
|
|
2619
|
-
```
|
2620
|
-
|
2784
|
+
``` shell
|
2785
|
+
gem install bundler
|
2621
2786
|
```
|
2622
2787
|
|
2623
2788
|
Then, in your project directory, create a `Gemfile`:
|
2624
2789
|
|
2625
2790
|
```ruby
|
2626
|
-
|
2627
|
-
|
2791
|
+
source 'https://rubygems.org'
|
2792
|
+
gem 'sinatra', :github => "sinatra/sinatra"
|
2628
2793
|
|
2629
|
-
|
2630
|
-
|
2631
|
-
|
2794
|
+
# other dependencies
|
2795
|
+
gem 'haml' # for instance, if you use haml
|
2796
|
+
gem 'activerecord', '~> 3.0' # maybe you also need ActiveRecord 3.x
|
2632
2797
|
```
|
2633
2798
|
|
2634
2799
|
Note that you will have to list all your application's dependencies in the `Gemfile`.
|
@@ -2637,8 +2802,8 @@ fetched and added by Bundler.
|
|
2637
2802
|
|
2638
2803
|
Now you can run your app like this:
|
2639
2804
|
|
2640
|
-
```
|
2641
|
-
|
2805
|
+
``` shell
|
2806
|
+
bundle exec ruby myapp.rb
|
2642
2807
|
```
|
2643
2808
|
|
2644
2809
|
### Roll Your Own
|
@@ -2646,33 +2811,33 @@ Now you can run your app like this:
|
|
2646
2811
|
Create a local clone and run your app with the `sinatra/lib` directory
|
2647
2812
|
on the `$LOAD_PATH`:
|
2648
2813
|
|
2649
|
-
```
|
2650
|
-
|
2651
|
-
|
2652
|
-
|
2814
|
+
``` shell
|
2815
|
+
cd myapp
|
2816
|
+
git clone git://github.com/sinatra/sinatra.git
|
2817
|
+
ruby -I sinatra/lib myapp.rb
|
2653
2818
|
```
|
2654
2819
|
|
2655
2820
|
To update the Sinatra sources in the future:
|
2656
2821
|
|
2657
|
-
```
|
2658
|
-
|
2659
|
-
|
2822
|
+
``` shell
|
2823
|
+
cd myapp/sinatra
|
2824
|
+
git pull
|
2660
2825
|
```
|
2661
2826
|
### Install Globally
|
2662
2827
|
|
2663
2828
|
You can build the gem on your own:
|
2664
2829
|
|
2665
|
-
```
|
2666
|
-
|
2667
|
-
|
2668
|
-
|
2669
|
-
|
2830
|
+
``` shell
|
2831
|
+
git clone git://github.com/sinatra/sinatra.git
|
2832
|
+
cd sinatra
|
2833
|
+
rake sinatra.gemspec
|
2834
|
+
rake install
|
2670
2835
|
```
|
2671
2836
|
|
2672
2837
|
If you install gems as root, the last step should be
|
2673
2838
|
|
2674
|
-
```
|
2675
|
-
|
2839
|
+
``` shell
|
2840
|
+
sudo rake install
|
2676
2841
|
```
|
2677
2842
|
|
2678
2843
|
## Versioning
|