sinatra-base 1.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/.yardopts +4 -0
  2. data/AUTHORS +15 -0
  3. data/CHANGES +524 -1
  4. data/Gemfile +82 -0
  5. data/LICENSE +1 -1
  6. data/README.de.rdoc +2093 -0
  7. data/README.es.rdoc +2091 -0
  8. data/README.fr.rdoc +2116 -0
  9. data/README.hu.rdoc +607 -0
  10. data/README.jp.rdoc +514 -23
  11. data/README.pt-br.rdoc +647 -0
  12. data/README.pt-pt.rdoc +646 -0
  13. data/README.rdoc +1580 -205
  14. data/README.ru.rdoc +2015 -0
  15. data/README.zh.rdoc +1816 -0
  16. data/Rakefile +110 -44
  17. data/examples/chat.rb +61 -0
  18. data/examples/simple.rb +3 -0
  19. data/examples/stream.ru +26 -0
  20. data/lib/sinatra.rb +0 -3
  21. data/lib/sinatra/base.rb +923 -393
  22. data/lib/sinatra/main.rb +9 -7
  23. data/lib/sinatra/showexceptions.rb +37 -4
  24. data/lib/sinatra/version.rb +3 -0
  25. data/sinatra-base.gemspec +15 -91
  26. data/test/base_test.rb +2 -2
  27. data/test/builder_test.rb +32 -2
  28. data/test/coffee_test.rb +92 -0
  29. data/test/contest.rb +62 -28
  30. data/test/creole_test.rb +65 -0
  31. data/test/delegator_test.rb +162 -0
  32. data/test/encoding_test.rb +20 -0
  33. data/test/erb_test.rb +25 -2
  34. data/test/extensions_test.rb +1 -1
  35. data/test/filter_test.rb +226 -8
  36. data/test/haml_test.rb +8 -2
  37. data/test/helper.rb +47 -0
  38. data/test/helpers_test.rb +1287 -80
  39. data/test/integration/app.rb +62 -0
  40. data/test/integration_helper.rb +208 -0
  41. data/test/integration_test.rb +82 -0
  42. data/test/less_test.rb +36 -6
  43. data/test/liquid_test.rb +59 -0
  44. data/test/mapped_error_test.rb +84 -7
  45. data/test/markaby_test.rb +80 -0
  46. data/test/markdown_test.rb +81 -0
  47. data/test/middleware_test.rb +1 -1
  48. data/test/nokogiri_test.rb +69 -0
  49. data/test/rack_test.rb +45 -0
  50. data/test/radius_test.rb +59 -0
  51. data/test/rdoc_test.rb +66 -0
  52. data/test/readme_test.rb +136 -0
  53. data/test/request_test.rb +13 -1
  54. data/test/response_test.rb +21 -2
  55. data/test/result_test.rb +5 -5
  56. data/test/route_added_hook_test.rb +1 -1
  57. data/test/routing_test.rb +328 -13
  58. data/test/sass_test.rb +48 -18
  59. data/test/scss_test.rb +88 -0
  60. data/test/server_test.rb +4 -3
  61. data/test/settings_test.rb +191 -21
  62. data/test/sinatra_test.rb +5 -1
  63. data/test/slim_test.rb +88 -0
  64. data/test/static_test.rb +89 -5
  65. data/test/streaming_test.rb +140 -0
  66. data/test/templates_test.rb +143 -4
  67. data/test/textile_test.rb +65 -0
  68. data/test/views/a/in_a.str +1 -0
  69. data/test/views/ascii.erb +2 -0
  70. data/test/views/b/in_b.str +1 -0
  71. data/test/views/calc.html.erb +1 -0
  72. data/test/views/explicitly_nested.str +1 -0
  73. data/test/views/hello.coffee +1 -0
  74. data/test/views/hello.creole +1 -0
  75. data/test/views/hello.liquid +1 -0
  76. data/test/views/hello.mab +1 -0
  77. data/test/views/hello.md +1 -0
  78. data/test/views/hello.nokogiri +1 -0
  79. data/test/views/hello.radius +1 -0
  80. data/test/views/hello.rdoc +1 -0
  81. data/test/views/hello.sass +1 -1
  82. data/test/views/hello.scss +3 -0
  83. data/test/views/hello.slim +1 -0
  84. data/test/views/hello.str +1 -0
  85. data/test/views/hello.textile +1 -0
  86. data/test/views/hello.yajl +1 -0
  87. data/test/views/layout2.liquid +2 -0
  88. data/test/views/layout2.mab +2 -0
  89. data/test/views/layout2.nokogiri +3 -0
  90. data/test/views/layout2.radius +2 -0
  91. data/test/views/layout2.slim +3 -0
  92. data/test/views/layout2.str +2 -0
  93. data/test/views/nested.str +1 -0
  94. data/test/views/utf8.erb +2 -0
  95. data/test/yajl_test.rb +80 -0
  96. metadata +126 -91
  97. data/lib/sinatra/tilt.rb +0 -746
  98. data/test/erubis_test.rb +0 -82
  99. data/test/views/error.erubis +0 -3
  100. data/test/views/hello.erubis +0 -1
  101. data/test/views/layout2.erubis +0 -2
@@ -4,22 +4,25 @@ Sinatra is a DSL for quickly creating web applications in Ruby with minimal
4
4
  effort:
5
5
 
6
6
  # myapp.rb
7
- require 'rubygems'
8
7
  require 'sinatra'
8
+
9
9
  get '/' do
10
10
  'Hello world!'
11
11
  end
12
12
 
13
13
  Install the gem and run with:
14
14
 
15
- sudo gem install sinatra
16
- ruby myapp.rb
15
+ gem install sinatra
16
+ ruby -rubygems myapp.rb
17
17
 
18
18
  View at: http://localhost:4567
19
19
 
20
+ It is recommended to also run <tt>gem install thin</tt>, which Sinatra will
21
+ pick up if available.
22
+
20
23
  == Routes
21
24
 
22
- In Sinatra, a route is an HTTP method paired with an URL matching pattern.
25
+ In Sinatra, a route is an HTTP method paired with a URL-matching pattern.
23
26
  Each route is associated with a block:
24
27
 
25
28
  get '/' do
@@ -31,13 +34,21 @@ Each route is associated with a block:
31
34
  end
32
35
 
33
36
  put '/' do
34
- .. update something ..
37
+ .. replace something ..
38
+ end
39
+
40
+ patch '/' do
41
+ .. modify something ..
35
42
  end
36
43
 
37
44
  delete '/' do
38
45
  .. annihilate something ..
39
46
  end
40
47
 
48
+ options '/' do
49
+ .. appease something ..
50
+ end
51
+
41
52
  Routes are matched in the order they are defined. The first route that
42
53
  matches the request is invoked.
43
54
 
@@ -57,7 +68,7 @@ You can also access named parameters via block parameters:
57
68
  end
58
69
 
59
70
  Route patterns may also include splat (or wildcard) parameters, accessible
60
- via the <tt>params[:splat]</tt> array.
71
+ via the <tt>params[:splat]</tt> array:
61
72
 
62
73
  get '/say/*/to/*' do
63
74
  # matches /say/hello/to/world
@@ -69,6 +80,12 @@ via the <tt>params[:splat]</tt> array.
69
80
  params[:splat] # => ["path/to/file", "xml"]
70
81
  end
71
82
 
83
+ Or with block parameters:
84
+
85
+ get '/download/*.*' do |path, ext|
86
+ [path, ext] # => ["path/to/file", "xml"]
87
+ end
88
+
72
89
  Route matching with Regular Expressions:
73
90
 
74
91
  get %r{/hello/([\w]+)} do
@@ -81,6 +98,17 @@ Or with a block parameter:
81
98
  "Hello, #{c}!"
82
99
  end
83
100
 
101
+ Route patterns may have optional parameters:
102
+
103
+ get '/posts.?:format?' do
104
+ # matches "GET /posts" and any extension "GET /posts.json", "GET /posts.xml" etc.
105
+ end
106
+
107
+ By the way, unless you disable the path traversal attack protection (see below),
108
+ the request path might be modified before matching against your routes.
109
+
110
+ === Conditions
111
+
84
112
  Routes may include a variety of matching conditions, such as the user agent:
85
113
 
86
114
  get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
@@ -91,144 +119,428 @@ Routes may include a variety of matching conditions, such as the user agent:
91
119
  # Matches non-songbird browsers
92
120
  end
93
121
 
122
+ Other available conditions are +host_name+ and +provides+:
123
+
124
+ get '/', :host_name => /^admin\./ do
125
+ "Admin Area, Access denied!"
126
+ end
127
+
128
+ get '/', :provides => 'html' do
129
+ haml :index
130
+ end
131
+
132
+ get '/', :provides => ['rss', 'atom', 'xml'] do
133
+ builder :feed
134
+ end
135
+
136
+ You can easily define your own conditions:
137
+
138
+ set(:probability) { |value| condition { rand <= value } }
139
+
140
+ get '/win_a_car', :probability => 0.1 do
141
+ "You won!"
142
+ end
143
+
144
+ get '/win_a_car' do
145
+ "Sorry, you lost."
146
+ end
147
+
148
+ For a condition that takes multiple values use a splat:
149
+
150
+ set(:auth) do |*roles| # <- notice the splat here
151
+ condition do
152
+ unless logged_in? && roles.any? {|role| current_user.in_role? role }
153
+ redirect "/login/", 303
154
+ end
155
+ end
156
+ end
157
+
158
+ get "/my/account/", :auth => [:user, :admin] do
159
+ "Your Account Details"
160
+ end
161
+
162
+ get "/only/admin/", :auth => :admin do
163
+ "Only admins are allowed here!"
164
+ end
165
+
166
+ === Return Values
167
+
168
+ The return value of a route block determines at least the response body passed
169
+ on to the HTTP client, or at least the next middleware in the Rack stack.
170
+ Most commonly, this is a string, as in the above examples. But other values are
171
+ also accepted.
172
+
173
+ You can return any object that would either be a valid Rack response, Rack
174
+ body object or HTTP status code:
175
+
176
+ * An Array with three elements: <tt>[status (Fixnum), headers (Hash), response
177
+ body (responds to #each)]</tt>
178
+ * An Array with two elements: <tt>[status (Fixnum), response body (responds to
179
+ #each)]</tt>
180
+ * An object that responds to <tt>#each</tt> and passes nothing but strings to
181
+ the given block
182
+ * A Fixnum representing the status code
183
+
184
+ That way we can, for instance, easily implement a streaming example:
185
+
186
+ class Stream
187
+ def each
188
+ 100.times { |i| yield "#{i}\n" }
189
+ end
190
+ end
191
+
192
+ get('/') { Stream.new }
193
+
194
+ You can also use the +stream+ helper method (described below) to reduce boiler
195
+ plate and embed the streaming logic in the route.
196
+
197
+ === Custom Route Matchers
198
+
199
+ As shown above, Sinatra ships with built-in support for using String patterns
200
+ and regular expressions as route matches. However, it does not stop there. You
201
+ can easily define your own matchers:
202
+
203
+ class AllButPattern
204
+ Match = Struct.new(:captures)
205
+
206
+ def initialize(except)
207
+ @except = except
208
+ @captures = Match.new([])
209
+ end
210
+
211
+ def match(str)
212
+ @captures unless @except === str
213
+ end
214
+ end
215
+
216
+ def all_but(pattern)
217
+ AllButPattern.new(pattern)
218
+ end
219
+
220
+ get all_but("/index") do
221
+ # ...
222
+ end
223
+
224
+ Note that the above example might be over-engineered, as it can also be
225
+ expressed as:
226
+
227
+ get // do
228
+ pass if request.path_info == "/index"
229
+ # ...
230
+ end
231
+
232
+ Or, using negative look ahead:
233
+
234
+ get %r{^(?!/index$)} do
235
+ # ...
236
+ end
237
+
94
238
  == Static Files
95
239
 
96
240
  Static files are served from the <tt>./public</tt> directory. You can specify
97
- a different location by setting the <tt>:public</tt> option:
241
+ a different location by setting the <tt>:public_folder</tt> option:
98
242
 
99
- set :public, File.dirname(__FILE__) + '/static'
243
+ set :public_folder, File.dirname(__FILE__) + '/static'
100
244
 
101
245
  Note that the public directory name is not included in the URL. A file
102
246
  <tt>./public/css/style.css</tt> is made available as
103
247
  <tt>http://example.com/css/style.css</tt>.
104
248
 
249
+ Use the <tt>:static_cache_control</tt> setting (see below) to add
250
+ <tt>Cache-Control</tt> header info.
251
+
105
252
  == Views / Templates
106
253
 
107
- Templates are assumed to be located directly under the <tt>./views</tt>
108
- directory. To use a different views directory:
254
+ Each template language is exposed as via its own rendering method. These
255
+ methods simply return a string:
109
256
 
110
- set :views, File.dirname(__FILE__) + '/templates'
257
+ get '/' do
258
+ erb :index
259
+ end
111
260
 
112
- One important thing to remember is that you always have to reference
113
- templates with symbols, even if they're in a subdirectory (in this
114
- case use <tt>:'subdir/template'</tt>). Rendering methods will render
115
- any strings passed to them directly.
261
+ This renders <tt>views/index.erb</tt>.
116
262
 
117
- === Haml Templates
263
+ Instead of a template name, you can also just pass in the template content
264
+ directly:
118
265
 
119
- The haml gem/library is required to render HAML templates:
266
+ get '/' do
267
+ code = "<%= Time.now %>"
268
+ erb code
269
+ end
120
270
 
121
- ## You'll need to require haml in your app
122
- require 'haml'
271
+ Templates take a second argument, the options hash:
123
272
 
124
273
  get '/' do
125
- haml :index
274
+ erb :index, :layout => :post
126
275
  end
127
276
 
128
- Renders <tt>./views/index.haml</tt>.
129
-
130
- {Haml's options}[http://haml.hamptoncatlin.com/docs/rdoc/classes/Haml.html]
131
- can be set globally through Sinatra's configurations,
132
- see {Options and Configurations}[http://www.sinatrarb.com/configuration.html],
133
- and overridden on an individual basis.
277
+ This will render <tt>views/index.erb</tt> embedded in the
278
+ <tt>views/post.erb</tt> (default is <tt>views/layout.erb</tt>, if it exists).
134
279
 
135
- set :haml, {:format => :html5 } # default Haml format is :xhtml
280
+ Any options not understood by Sinatra will be passed on to the template
281
+ engine:
136
282
 
137
283
  get '/' do
138
- haml :index, :haml_options => {:format => :html4 } # overridden
284
+ haml :index, :format => :html5
139
285
  end
140
286
 
287
+ You can also set options per template language in general:
141
288
 
142
- === Erb Templates
143
-
144
- ## You'll need to require erb in your app
145
- require 'erb'
289
+ set :haml, :format => :html5
146
290
 
147
291
  get '/' do
148
- erb :index
292
+ haml :index
149
293
  end
150
294
 
151
- Renders <tt>./views/index.erb</tt>
295
+ Options passed to the render method override options set via +set+.
152
296
 
153
- === Erubis
297
+ Available Options:
154
298
 
155
- The erubis gem/library is required to render builder templates:
299
+ [locals]
300
+ List of locals passed to the document. Handy with partials.
301
+ Example: <tt>erb "<%= foo %>", :locals => {:foo => "bar"}</tt>
156
302
 
157
- ## You'll need to require erubis in your app
158
- require 'erubis'
303
+ [default_encoding]
304
+ String encoding to use if uncertain. Defaults to
305
+ <tt>settings.default_encoding</tt>.
159
306
 
160
- get '/' do
161
- erubis :index
162
- end
307
+ [views]
308
+ Views folder to load templates from. Defaults to <tt>settings.views</tt>.
309
+
310
+ [layout]
311
+ Whether to use a layout (+true+ or +false+), if it's a Symbol, specifies
312
+ what template to use. Example: <tt>erb :index, :layout => !request.xhr?</tt>
313
+
314
+ [content_type]
315
+ Content-Type the template produces, default depends on template language.
316
+
317
+ [scope]
318
+ Scope to render template under. Defaults to the application instance. If you
319
+ change this, instance variables and helper methods will not be available.
320
+
321
+ [layout_engine]
322
+ Template engine to use for rendering the layout. Useful for languages that
323
+ do not support layouts otherwise. Defaults to the engine used for the
324
+ template. Example: <tt>set :rdoc, :layout_engine => :erb</tt>
325
+
326
+ Templates are assumed to be located directly under the <tt>./views</tt>
327
+ directory. To use a different views directory:
328
+
329
+ set :views, settings.root + '/templates'
330
+
331
+ One important thing to remember is that you always have to reference
332
+ templates with symbols, even if they're in a subdirectory (in this
333
+ case, use <tt>:'subdir/template'</tt>). You must use a symbol because
334
+ otherwise rendering methods will render any strings passed to them
335
+ directly.
336
+
337
+ === Available Template Languages
338
+
339
+ Some languages have multiple implementations. To specify what implementation
340
+ to use (and to be thread-safe), you should simply require it first:
341
+
342
+ require 'rdiscount' # or require 'bluecloth'
343
+ get('/') { markdown :index }
163
344
 
164
- Renders <tt>./views/index.erubis</tt>
345
+ === Haml Templates
346
+
347
+ Dependency:: {haml}[http://haml-lang.com/]
348
+ File Extensions:: <tt>.haml</tt>
349
+ Example:: <tt>haml :index, :format => :html5</tt>
350
+
351
+ === Erb Templates
352
+
353
+ Dependency:: {erubis}[http://www.kuwata-lab.com/erubis/] or
354
+ erb (included in Ruby)
355
+ File Extensions:: <tt>.erb</tt>, <tt>.rhtml</tt> or <tt>.erubis</tt> (Erubis
356
+ only)
357
+ Example:: <tt>erb :index</tt>
165
358
 
166
359
  === Builder Templates
167
360
 
168
- The builder gem/library is required to render builder templates:
361
+ Dependency:: {builder}[http://builder.rubyforge.org/]
362
+ File Extensions:: <tt>.builder</tt>
363
+ Example:: <tt>builder { |xml| xml.em "hi" }</tt>
169
364
 
170
- ## You'll need to require builder in your app
171
- require 'builder'
365
+ It also takes a block for inline templates (see example).
172
366
 
173
- get '/' do
174
- content_type 'application/xml', :charset => 'utf-8'
175
- builder :index
176
- end
367
+ === Nokogiri Templates
368
+
369
+ Dependency:: {nokogiri}[http://nokogiri.org/]
370
+ File Extensions:: <tt>.nokogiri</tt>
371
+ Example:: <tt>nokogiri { |xml| xml.em "hi" }</tt>
177
372
 
178
- Renders <tt>./views/index.builder</tt>.
373
+ It also takes a block for inline templates (see example).
179
374
 
180
375
  === Sass Templates
181
376
 
182
- The sass gem/library is required to render Sass templates:
377
+ Dependency:: {sass}[http://sass-lang.com/]
378
+ File Extensions:: <tt>.sass</tt>
379
+ Example:: <tt>sass :stylesheet, :style => :expanded</tt>
183
380
 
184
- ## You'll need to require haml or sass in your app
185
- require 'sass'
381
+ === SCSS Templates
186
382
 
187
- get '/stylesheet.css' do
188
- content_type 'text/css', :charset => 'utf-8'
189
- sass :stylesheet
190
- end
383
+ Dependency:: {sass}[http://sass-lang.com/]
384
+ File Extensions:: <tt>.scss</tt>
385
+ Example:: <tt>scss :stylesheet, :style => :expanded</tt>
191
386
 
192
- Renders <tt>./views/stylesheet.sass</tt>.
387
+ === Less Templates
193
388
 
194
- {Sass' options}[http://haml.hamptoncatlin.com/docs/rdoc/classes/Sass.html]
195
- can be set globally through Sinatra's configurations,
196
- see {Options and Configurations}[http://www.sinatrarb.com/configuration.html],
197
- and overridden on an individual basis.
389
+ Dependency:: {less}[http://www.lesscss.org/]
390
+ File Extensions:: <tt>.less</tt>
391
+ Example:: <tt>less :stylesheet</tt>
198
392
 
199
- set :sass, {:style => :compact } # default Sass style is :nested
393
+ === Liquid Templates
200
394
 
201
- get '/stylesheet.css' do
202
- content_type 'text/css', :charset => 'utf-8'
203
- sass :stylesheet, :style => :expanded # overridden
204
- end
395
+ Dependency:: {liquid}[http://www.liquidmarkup.org/]
396
+ File Extensions:: <tt>.liquid</tt>
397
+ Example:: <tt>liquid :index, :locals => { :key => 'value' }</tt>
205
398
 
206
- === Less Templates
399
+ Since you cannot call Ruby methods (except for +yield+) from a Liquid
400
+ template, you almost always want to pass locals to it.
207
401
 
208
- The less gem/library is required to render Less templates:
402
+ === Markdown Templates
209
403
 
210
- ## You'll need to require less in your app
211
- require 'less'
404
+ Dependency:: {rdiscount}[https://github.com/rtomayko/rdiscount],
405
+ {redcarpet}[https://github.com/tanoku/redcarpet],
406
+ {bluecloth}[http://deveiate.org/projects/BlueCloth],
407
+ {kramdown}[http://kramdown.rubyforge.org/] *or*
408
+ {maruku}[http://maruku.rubyforge.org/]
409
+ File Extensions:: <tt>.markdown</tt>, <tt>.mkd</tt> and <tt>.md</tt>
410
+ Example:: <tt>markdown :index, :layout_engine => :erb</tt>
212
411
 
213
- get '/stylesheet.css' do
214
- content_type 'text/css', :charset => 'utf-8'
215
- less :stylesheet
216
- end
412
+ It is not possible to call methods from markdown, nor to pass locals to it.
413
+ You therefore will usually use it in combination with another rendering
414
+ engine:
217
415
 
218
- Renders <tt>./views/stylesheet.less</tt>.
416
+ erb :overview, :locals => { :text => markdown(:introduction) }
219
417
 
220
- === Inline Templates
418
+ Note that you may also call the +markdown+ method from within other templates:
419
+
420
+ %h1 Hello From Haml!
421
+ %p= markdown(:greetings)
422
+
423
+ Since you cannot call Ruby from Markdown, you cannot use layouts written in
424
+ Markdown. However, it is possible to use another rendering engine for the
425
+ template than for the layout by passing the <tt>:layout_engine</tt> option.
426
+
427
+ === Textile Templates
428
+
429
+ Dependency:: {RedCloth}[http://redcloth.org/]
430
+ File Extensions:: <tt>.textile</tt>
431
+ Example:: <tt>textile :index, :layout_engine => :erb</tt>
432
+
433
+ It is not possible to call methods from textile, nor to pass locals to it. You
434
+ therefore will usually use it in combination with another rendering engine:
435
+
436
+ erb :overview, :locals => { :text => textile(:introduction) }
437
+
438
+ Note that you may also call the +textile+ method from within other templates:
439
+
440
+ %h1 Hello From Haml!
441
+ %p= textile(:greetings)
442
+
443
+ Since you cannot call Ruby from Textile, you cannot use layouts written in
444
+ Textile. However, it is possible to use another rendering engine for the
445
+ template than for the layout by passing the <tt>:layout_engine</tt> option.
446
+
447
+ === RDoc Templates
448
+
449
+ Dependency:: {rdoc}[http://rdoc.rubyforge.org/]
450
+ File Extensions:: <tt>.rdoc</tt>
451
+ Example:: <tt>rdoc :README, :layout_engine => :erb</tt>
452
+
453
+ It is not possible to call methods from rdoc, nor to pass locals to it. You
454
+ therefore will usually use it in combination with another rendering engine:
455
+
456
+ erb :overview, :locals => { :text => rdoc(:introduction) }
457
+
458
+ Note that you may also call the +rdoc+ method from within other templates:
459
+
460
+ %h1 Hello From Haml!
461
+ %p= rdoc(:greetings)
462
+
463
+ Since you cannot call Ruby from RDoc, you cannot use layouts written in
464
+ RDoc. However, it is possible to use another rendering engine for the
465
+ template than for the layout by passing the <tt>:layout_engine</tt> option.
466
+
467
+ === Radius Templates
468
+
469
+ Dependency:: {radius}[http://radius.rubyforge.org/]
470
+ File Extensions:: <tt>.radius</tt>
471
+ Example:: <tt>radius :index, :locals => { :key => 'value' }</tt>
472
+
473
+ Since you cannot call Ruby methods directly from a Radius template, you almost
474
+ always want to pass locals to it.
475
+
476
+ === Markaby Templates
477
+
478
+ Dependency:: {markaby}[http://markaby.github.com/]
479
+ File Extensions:: <tt>.mab</tt>
480
+ Example:: <tt>markaby { h1 "Welcome!" }</tt>
481
+
482
+ It also takes a block for inline templates (see example).
483
+
484
+ === Slim Templates
485
+
486
+ Dependency:: {slim}[http://slim-lang.com/]
487
+ File Extensions:: <tt>.slim</tt>
488
+ Example:: <tt>slim :index</tt>
489
+
490
+ === Creole Templates
491
+
492
+ Dependency:: {creole}[https://github.com/minad/creole]
493
+ File Extensions:: <tt>.creole</tt>
494
+ Example:: <tt>creole :wiki, :layout_engine => :erb</tt>
495
+
496
+ It is not possible to call methods from creole, nor to pass locals to it. You
497
+ therefore will usually use it in combination with another rendering engine:
498
+
499
+ erb :overview, :locals => { :text => creole(:introduction) }
500
+
501
+ Note that you may also call the +creole+ method from within other templates:
502
+
503
+ %h1 Hello From Haml!
504
+ %p= creole(:greetings)
505
+
506
+ Since you cannot call Ruby from Creole, you cannot use layouts written in
507
+ Creole. However, it is possible to use another rendering engine for the
508
+ template than for the layout by passing the <tt>:layout_engine</tt> option.
509
+
510
+ === CoffeeScript Templates
511
+
512
+ Dependency:: {coffee-script}[https://github.com/josh/ruby-coffee-script]
513
+ and a {way to execute javascript}[https://github.com/sstephenson/execjs/blob/master/README.md#readme]
514
+ File Extensions:: <tt>.coffee</tt>
515
+ Example:: <tt>coffee :index</tt>
516
+
517
+ === Yajl Templates
518
+
519
+ Dependency:: {yajl-ruby}[https://github.com/brianmario/yajl-ruby]
520
+ File Extensions:: <tt>.yajl</tt>
521
+ Example:: <tt>yajl :index, :locals => { :key => 'qux' }, :callback => 'present', :variable => 'resource' </tt>
522
+
523
+ The template source is evaluated as a Ruby string, and the resulting json variable is converted #to_json.
524
+
525
+ json = { :foo => 'bar' }
526
+ json[:baz] = key
527
+
528
+ The <tt>:callback</tt> and <tt>:variable</tt> options can be used to decorate the rendered object.
529
+
530
+ var resource = {"foo":"bar","baz":"qux"}; present(resource);
531
+
532
+ === Embedded Templates
221
533
 
222
534
  get '/' do
223
535
  haml '%div.title Hello World'
224
536
  end
225
537
 
226
- Renders the inlined template string.
538
+ Renders the embedded template string.
227
539
 
228
540
  === Accessing Variables in Templates
229
541
 
230
542
  Templates are evaluated within the same context as route handlers. Instance
231
- variables set in route handlers are direcly accessible by templates:
543
+ variables set in route handlers are directly accessible by templates:
232
544
 
233
545
  get '/:id' do
234
546
  @foo = Foo.find(params[:id])
@@ -239,7 +551,7 @@ Or, specify an explicit Hash of local variables:
239
551
 
240
552
  get '/:id' do
241
553
  foo = Foo.find(params[:id])
242
- haml '%h1= foo.name', :locals => { :foo => foo }
554
+ haml '%h1= bar.name', :locals => { :bar => foo }
243
555
  end
244
556
 
245
557
  This is typically used when rendering templates as partials from within
@@ -249,7 +561,6 @@ other templates.
249
561
 
250
562
  Templates may be defined at the end of the source file:
251
563
 
252
- require 'rubygems'
253
564
  require 'sinatra'
254
565
 
255
566
  get '/' do
@@ -263,10 +574,10 @@ Templates may be defined at the end of the source file:
263
574
  = yield
264
575
 
265
576
  @@ index
266
- %div.title Hello world!!!!!
577
+ %div.title Hello world.
267
578
 
268
- NOTE: Inline templates defined in the source file that requires sinatra
269
- are automatically loaded. Call `enable :inline_templates` explicitly if you
579
+ NOTE: Inline templates defined in the source file that requires sinatra are
580
+ automatically loaded. Call <tt>enable :inline_templates</tt> explicitly if you
270
581
  have inline templates in other source files.
271
582
 
272
583
  === Named Templates
@@ -286,32 +597,44 @@ Templates may also be defined using the top-level <tt>template</tt> method:
286
597
  end
287
598
 
288
599
  If a template named "layout" exists, it will be used each time a template
289
- is rendered. You can disable layouts by passing <tt>:layout => false</tt>.
600
+ is rendered. You can individually disable layouts by passing
601
+ <tt>:layout => false</tt> or disable them by default via
602
+ <tt>set :haml, :layout => false</tt>:
290
603
 
291
604
  get '/' do
292
605
  haml :index, :layout => !request.xhr?
293
606
  end
294
607
 
295
- == Helpers
608
+ === Associating File Extensions
296
609
 
297
- Use the top-level <tt>helpers</tt> method to define helper methods for use in
298
- route handlers and templates:
610
+ To associate a file extension with a template engine, use
611
+ <tt>Tilt.register</tt>. For instance, if you like to use the file extension
612
+ +tt+ for Textile templates, you can do the following:
613
+
614
+ Tilt.register :tt, Tilt[:textile]
615
+
616
+ === Adding Your Own Template Engine
617
+
618
+ First, register your engine with Tilt, then create a rendering method:
619
+
620
+ Tilt.register :myat, MyAwesomeTemplateEngine
299
621
 
300
622
  helpers do
301
- def bar(name)
302
- "#{name}bar"
303
- end
623
+ def myat(*args) render(:myat, *args) end
304
624
  end
305
625
 
306
- get '/:name' do
307
- bar(params[:name])
626
+ get '/' do
627
+ myat :index
308
628
  end
309
629
 
630
+ Renders <tt>./views/index.myat</tt>. See https://github.com/rtomayko/tilt to
631
+ learn more about Tilt.
632
+
310
633
  == Filters
311
634
 
312
- Before filters are evaluated before each request within the context of the
313
- request and can modify the request and response. Instance variables set in
314
- filters are accessible by routes and templates:
635
+ Before filters are evaluated before each request within the same
636
+ context as the routes will be and can modify the request and response. Instance
637
+ variables set in filters are accessible by routes and templates:
315
638
 
316
639
  before do
317
640
  @note = 'Hi!'
@@ -323,37 +646,138 @@ filters are accessible by routes and templates:
323
646
  params[:splat] #=> 'bar/baz'
324
647
  end
325
648
 
326
- After filter are evaluated after each request within the context of the
327
- request and can also modify the request and response. Instance variables
328
- set in before filters and routes are accessible by after filters:
649
+ After filters are evaluated after each request within the same context and can
650
+ also modify the request and response. Instance variables set in before filters
651
+ and routes are accessible by after filters:
329
652
 
330
653
  after do
331
654
  puts response.status
332
655
  end
333
656
 
334
- == Halting
657
+ Note: Unless you use the +body+ method rather than just returning a String from
658
+ the routes, the body will not yet be available in the after filter, since it is
659
+ generated later on.
660
+
661
+ Filters optionally take a pattern, causing them to be evaluated only if the
662
+ request path matches that pattern:
663
+
664
+ before '/protected/*' do
665
+ authenticate!
666
+ end
667
+
668
+ after '/create/:slug' do |slug|
669
+ session[:last_slug] = slug
670
+ end
671
+
672
+ Like routes, filters also take conditions:
673
+
674
+ before :agent => /Songbird/ do
675
+ # ...
676
+ end
677
+
678
+ after '/blog/*', :host_name => 'example.com' do
679
+ # ...
680
+ end
681
+
682
+ == Helpers
683
+
684
+ Use the top-level <tt>helpers</tt> method to define helper methods for use in
685
+ route handlers and templates:
686
+
687
+ helpers do
688
+ def bar(name)
689
+ "#{name}bar"
690
+ end
691
+ end
692
+
693
+ get '/:name' do
694
+ bar(params[:name])
695
+ end
696
+
697
+ Alternatively, helper methods can be separately defined in a module:
698
+
699
+ module FooUtils
700
+ def foo(name) "#{name}foo" end
701
+ end
702
+
703
+ module BarUtils
704
+ def bar(name) "#{name}bar" end
705
+ end
706
+
707
+ helpers FooUtils, BarUtils
708
+
709
+ The effect is the same as including the modules in the application class.
710
+
711
+ === Using Sessions
712
+
713
+ A session is used to keep state during requests. If activated, you have one
714
+ session hash per user session:
715
+
716
+ enable :sessions
717
+
718
+ get '/' do
719
+ "value = " << session[:value].inspect
720
+ end
721
+
722
+ get '/:value' do
723
+ session[:value] = params[:value]
724
+ end
725
+
726
+ Note that <tt>enable :sessions</tt> actually stores all data in a cookie. This
727
+ might not always be what you want (storing lots of data will increase your
728
+ traffic, for instance). You can use any Rack session middleware: in order to
729
+ do so, do *not* call <tt>enable :sessions</tt>, but instead pull in your
730
+ middleware of choice as you would any other middleware:
731
+
732
+ use Rack::Session::Pool, :expire_after => 2592000
733
+
734
+ get '/' do
735
+ "value = " << session[:value].inspect
736
+ end
737
+
738
+ get '/:value' do
739
+ session[:value] = params[:value]
740
+ end
741
+
742
+ To improve security, the session data in the cookie is signed with a session
743
+ secret. A random secret is generate for you by Sinatra. However, since this
744
+ secret will change with every start of your application, you might want to
745
+ set the secret yourself, so all your application instances share it:
746
+
747
+ set :session_secret, 'super secret'
748
+
749
+ If you want to configure it further, you may also store a hash with options in
750
+ the +sessions+ setting:
751
+
752
+ set :sessions, :domain => 'foo.com'
753
+
754
+ === Halting
335
755
 
336
756
  To immediately stop a request within a filter or route use:
337
757
 
338
758
  halt
339
759
 
340
- You can also specify the status when halting ...
760
+ You can also specify the status when halting:
341
761
 
342
762
  halt 410
343
763
 
344
- Or the body ...
764
+ Or the body:
345
765
 
346
766
  halt 'this will be the body'
347
767
 
348
- Or both ...
768
+ Or both:
349
769
 
350
770
  halt 401, 'go away!'
351
771
 
352
- With headers ...
772
+ With headers:
353
773
 
354
774
  halt 402, {'Content-Type' => 'text/plain'}, 'revenge'
355
775
 
356
- == Passing
776
+ It is of course possible to combine a template with +halt+:
777
+
778
+ halt erb(:error)
779
+
780
+ === Passing
357
781
 
358
782
  A route can punt processing to the next matching route using <tt>pass</tt>:
359
783
 
@@ -369,70 +793,690 @@ A route can punt processing to the next matching route using <tt>pass</tt>:
369
793
  The route block is immediately exited and control continues with the next
370
794
  matching route. If no matching route is found, a 404 is returned.
371
795
 
372
- == Configuration
796
+ === Triggering Another Route
373
797
 
374
- Run once, at startup, in any environment:
798
+ Sometimes +pass+ is not what you want, instead you would like to get the result
799
+ of calling another route. Simply use +call+ to achieve this:
375
800
 
376
- configure do
377
- ...
801
+ get '/foo' do
802
+ status, headers, body = call env.merge("PATH_INFO" => '/bar')
803
+ [status, headers, body.map(&:upcase)]
378
804
  end
379
805
 
380
- Run only when the environment (RACK_ENV environment variable) is set to
381
- <tt>:production</tt>:
382
-
383
- configure :production do
384
- ...
806
+ get '/bar' do
807
+ "bar"
385
808
  end
386
809
 
387
- Run when the environment is set to either <tt>:production</tt> or
388
- <tt>:test</tt>:
810
+ Note that in the example above, you would ease testing and increase performance
811
+ by simply moving <tt>"bar"</tt> into a helper used by both <tt>/foo</tt>
812
+ and <tt>/bar</tt>.
389
813
 
390
- configure :production, :test do
391
- ...
392
- end
814
+ If you want the request to be sent to the same application instance rather than
815
+ a duplicate, use <tt>call!</tt> instead of <tt>call</tt>.
393
816
 
394
- == Error handling
817
+ Check out the Rack specification if you want to learn more about <tt>call</tt>.
395
818
 
396
- Error handlers run within the same context as routes and before filters, which
397
- means you get all the goodies it has to offer, like <tt>haml</tt>, <tt>erb</tt>,
398
- <tt>halt</tt>, etc.
819
+ === Setting Body, Status Code and Headers
399
820
 
400
- === Not Found
821
+ It is possible and recommended to set the status code and response body with the
822
+ return value of the route block. However, in some scenarios you might want to
823
+ set the body at an arbitrary point in the execution flow. You can do so with the
824
+ +body+ helper method. If you do so, you can use that method from there on to
825
+ access the body:
401
826
 
402
- When a <tt>Sinatra::NotFound</tt> exception is raised, or the response's status
403
- code is 404, the <tt>not_found</tt> handler is invoked:
827
+ get '/foo' do
828
+ body "bar"
829
+ end
404
830
 
405
- not_found do
406
- 'This is nowhere to be found'
831
+ after do
832
+ puts body
407
833
  end
408
834
 
409
- === Error
835
+ It is also possible to pass a block to +body+, which will be executed by the
836
+ Rack handler (this can be used to implement streaming, see "Return Values").
410
837
 
411
- The +error+ handler is invoked any time an exception is raised from a route
412
- block or a filter. The exception object can be obtained from the
413
- <tt>sinatra.error</tt> Rack variable:
838
+ Similar to the body, you can also set the status code and headers:
414
839
 
415
- error do
416
- 'Sorry there was a nasty error - ' + env['sinatra.error'].name
840
+ get '/foo' do
841
+ status 418
842
+ headers \
843
+ "Allow" => "BREW, POST, GET, PROPFIND, WHEN",
844
+ "Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
845
+ body "I'm a tea pot!"
417
846
  end
418
847
 
419
- Custom errors:
848
+ Like +body+, +headers+ and +status+ with no arguments can be used to access
849
+ their current values.
420
850
 
421
- error MyCustomError do
422
- 'So what happened was...' + request.env['sinatra.error'].message
423
- end
851
+ === Streaming Responses
424
852
 
425
- Then, if this happens:
853
+ Sometimes you want to start sending out data while still generating parts of
854
+ the response body. In extreme examples, you want to keep sending data until
855
+ the client closes the connection. You can use the +stream+ helper to avoid
856
+ creating your own wrapper:
426
857
 
427
858
  get '/' do
428
- raise MyCustomError, 'something bad'
859
+ stream do |out|
860
+ out << "It's gonna be legen -\n"
861
+ sleep 0.5
862
+ out << " (wait for it) \n"
863
+ sleep 1
864
+ out << "- dary!\n"
865
+ end
429
866
  end
430
867
 
431
- You get this:
868
+ This allows you to implement streaming APIs,
869
+ {Server Sent Events}[http://dev.w3.org/html5/eventsource/] and can be used as
870
+ basis for {WebSockets}[http://en.wikipedia.org/wiki/WebSocket]. It can also be
871
+ used to increase throughput if some but not all content depends on a slow
872
+ resource.
432
873
 
433
- So what happened was... something bad
874
+ Note that the streaming behavior, especially the number of concurrent request,
875
+ highly depends on the web server used to serve the application. Some servers,
876
+ like WEBRick, might not even support streaming at all. If the server does not
877
+ support streaming, the body will be sent all at once after the block passed to
878
+ +stream+ finished executing. Streaming does not work at all with Shotgun.
434
879
 
435
- Alternatively, you can install error handler for a status code:
880
+ If the optional parameter is set to +keep_open+, it will not call +close+ on
881
+ the stream object, allowing you to close it at any later point in the
882
+ execution flow. This only works on evented servers, like Thin and Rainbows.
883
+ Other servers will still close the stream:
884
+
885
+ set :server, :thin
886
+ connections = []
887
+
888
+ get '/' do
889
+ # keep stream open
890
+ stream(:keep_open) { |out| connections << out }
891
+ end
892
+
893
+ post '/' do
894
+ # write to all open streams
895
+ connections.each { |out| out << params[:message] << "\n" }
896
+ "message sent"
897
+ end
898
+
899
+ === Logging
900
+
901
+ In the request scope, the +logger+ helper exposes a +Logger+ instance:
902
+
903
+ get '/' do
904
+ logger.info "loading data"
905
+ # ...
906
+ end
907
+
908
+ This logger will automatically take your Rack handler's logging settings into
909
+ account. If logging is disabled, this method will return a dummy object, so
910
+ you do not have to worry in your routes and filters about it.
911
+
912
+ Note that logging is only enabled for <tt>Sinatra::Application</tt> by
913
+ default, so if you inherit from <tt>Sinatra::Base</tt>, you probably want to
914
+ enable it yourself:
915
+
916
+ class MyApp < Sinatra::Base
917
+ configure :production, :development do
918
+ enable :logging
919
+ end
920
+ end
921
+
922
+ To avoid any logging middleware to be set up, set the +logging+ setting to
923
+ +nil+. However, keep in mind that +logger+ will in that case return +nil+. A
924
+ common use case is when you want to set your own logger. Sinatra will use
925
+ whatever it will find in <tt>env['rack.logger']</tt>.
926
+
927
+ === Mime Types
928
+
929
+ When using <tt>send_file</tt> or static files you may have mime types Sinatra
930
+ doesn't understand. Use +mime_type+ to register them by file extension:
931
+
932
+ configure do
933
+ mime_type :foo, 'text/foo'
934
+ end
935
+
936
+ You can also use it with the +content_type+ helper:
937
+
938
+ get '/' do
939
+ content_type :foo
940
+ "foo foo foo"
941
+ end
942
+
943
+ === Generating URLs
944
+
945
+ For generating URLs you should use the +url+ helper method, for instance, in
946
+ Haml:
947
+
948
+ %a{:href => url('/foo')} foo
949
+
950
+ It takes reverse proxies and Rack routers into account, if present.
951
+
952
+ This method is also aliased to +to+ (see below for an example).
953
+
954
+ === Browser Redirect
955
+
956
+ You can trigger a browser redirect with the +redirect+ helper method:
957
+
958
+ get '/foo' do
959
+ redirect to('/bar')
960
+ end
961
+
962
+ Any additional parameters are handled like arguments passed to +halt+:
963
+
964
+ redirect to('/bar'), 303
965
+ redirect 'http://google.com', 'wrong place, buddy'
966
+
967
+ You can also easily redirect back to the page the user came from with
968
+ <tt>redirect back</tt>:
969
+
970
+ get '/foo' do
971
+ "<a href='/bar'>do something</a>"
972
+ end
973
+
974
+ get '/bar' do
975
+ do_something
976
+ redirect back
977
+ end
978
+
979
+ To pass arguments with a redirect, either add them to the query:
980
+
981
+ redirect to('/bar?sum=42')
982
+
983
+ Or use a session:
984
+
985
+ enable :sessions
986
+
987
+ get '/foo' do
988
+ session[:secret] = 'foo'
989
+ redirect to('/bar')
990
+ end
991
+
992
+ get '/bar' do
993
+ session[:secret]
994
+ end
995
+
996
+ === Cache Control
997
+
998
+ Setting your headers correctly is the foundation for proper HTTP caching.
999
+
1000
+ You can easily set the Cache-Control header with like this:
1001
+
1002
+ get '/' do
1003
+ cache_control :public
1004
+ "cache it!"
1005
+ end
1006
+
1007
+ Pro tip: Set up caching in a before filter:
1008
+
1009
+ before do
1010
+ cache_control :public, :must_revalidate, :max_age => 60
1011
+ end
1012
+
1013
+ If you are using the +expires+ helper to set the corresponding header,
1014
+ <tt>Cache-Control</tt> will be set automatically for you:
1015
+
1016
+ before do
1017
+ expires 500, :public, :must_revalidate
1018
+ end
1019
+
1020
+ To properly use caches, you should consider using +etag+ or +last_modified+.
1021
+ It is recommended to call those helpers *before* doing heavy lifting, as they
1022
+ will immediately flush a response if the client already has the current
1023
+ version in its cache:
1024
+
1025
+ get '/article/:id' do
1026
+ @article = Article.find params[:id]
1027
+ last_modified @article.updated_at
1028
+ etag @article.sha1
1029
+ erb :article
1030
+ end
1031
+
1032
+ It is also possible to use a
1033
+ {weak ETag}[http://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation]:
1034
+
1035
+ etag @article.sha1, :weak
1036
+
1037
+ These helpers will not do any caching for you, but rather feed the necessary
1038
+ information to your cache. If you are looking for a quick reverse-proxy caching
1039
+ solution, try {rack-cache}[http://rtomayko.github.com/rack-cache/]:
1040
+
1041
+ require "rack/cache"
1042
+ require "sinatra"
1043
+
1044
+ use Rack::Cache
1045
+
1046
+ get '/' do
1047
+ cache_control :public, :max_age => 36000
1048
+ sleep 5
1049
+ "hello"
1050
+ end
1051
+
1052
+ Use the <tt>:static_cache_control</tt> setting (see below) to add
1053
+ <tt>Cache-Control</tt> header info to static files.
1054
+
1055
+ According to RFC 2616 your application should behave differently if the If-Match
1056
+ or If-None-Match header is set to <tt>*</tt> depending on whether the resource
1057
+ requested is already in existence. Sinatra assumes resources for safe (like get)
1058
+ and idempotent (like put) requests are already in existence, whereas other
1059
+ resources (for instance for post requests), are treated as new resources. You
1060
+ can change this behavior by passing in a <tt>:new_resource</tt> option:
1061
+
1062
+ get '/create' do
1063
+ etag '', :new_resource => true
1064
+ Article.create
1065
+ erb :new_article
1066
+ end
1067
+
1068
+ If you still want to use a weak ETag, pass in a <tt>:kind</tt> option:
1069
+
1070
+ etag '', :new_resource => true, :kind => :weak
1071
+
1072
+ === Sending Files
1073
+
1074
+ For sending files, you can use the <tt>send_file</tt> helper method:
1075
+
1076
+ get '/' do
1077
+ send_file 'foo.png'
1078
+ end
1079
+
1080
+ It also takes a couple of options:
1081
+
1082
+ send_file 'foo.png', :type => :jpg
1083
+
1084
+ The options are:
1085
+
1086
+ [filename]
1087
+ file name, in response, defaults to the real file name.
1088
+
1089
+ [last_modified]
1090
+ value for Last-Modified header, defaults to the file's mtime.
1091
+
1092
+ [type]
1093
+ content type to use, guessed from the file extension if missing.
1094
+
1095
+ [disposition]
1096
+ used for Content-Disposition, possible values: +nil+ (default),
1097
+ <tt>:attachment</tt> and <tt>:inline</tt>
1098
+
1099
+ [length]
1100
+ Content-Length header, defaults to file size.
1101
+
1102
+ [status]
1103
+ Status code to be send. Useful when sending a static file as an error page.
1104
+
1105
+ If supported by the Rack handler, other means than streaming from the Ruby
1106
+ process will be used. If you use this helper method, Sinatra will automatically
1107
+ handle range requests.
1108
+
1109
+ === Accessing the Request Object
1110
+
1111
+ The incoming request object can be accessed from request level (filter, routes,
1112
+ error handlers) through the <tt>request</tt> method:
1113
+
1114
+ # app running on http://example.com/example
1115
+ get '/foo' do
1116
+ t = %w[text/css text/html application/javascript]
1117
+ request.accept # ['text/html', '*/*']
1118
+ request.accept? 'text/xml' # true
1119
+ request.preferred_type(t) # 'text/html'
1120
+ request.body # request body sent by the client (see below)
1121
+ request.scheme # "http"
1122
+ request.script_name # "/example"
1123
+ request.path_info # "/foo"
1124
+ request.port # 80
1125
+ request.request_method # "GET"
1126
+ request.query_string # ""
1127
+ request.content_length # length of request.body
1128
+ request.media_type # media type of request.body
1129
+ request.host # "example.com"
1130
+ request.get? # true (similar methods for other verbs)
1131
+ request.form_data? # false
1132
+ request["SOME_HEADER"] # value of SOME_HEADER header
1133
+ request.referrer # the referrer of the client or '/'
1134
+ request.user_agent # user agent (used by :agent condition)
1135
+ request.cookies # hash of browser cookies
1136
+ request.xhr? # is this an ajax request?
1137
+ request.url # "http://example.com/example/foo"
1138
+ request.path # "/example/foo"
1139
+ request.ip # client IP address
1140
+ request.secure? # false (would be true over ssl)
1141
+ request.forwarded? # true (if running behind a reverse proxy)
1142
+ request.env # raw env hash handed in by Rack
1143
+ end
1144
+
1145
+ Some options, like <tt>script_name</tt> or <tt>path_info</tt>, can also be
1146
+ written:
1147
+
1148
+ before { request.path_info = "/" }
1149
+
1150
+ get "/" do
1151
+ "all requests end up here"
1152
+ end
1153
+
1154
+ The <tt>request.body</tt> is an IO or StringIO object:
1155
+
1156
+ post "/api" do
1157
+ request.body.rewind # in case someone already read it
1158
+ data = JSON.parse request.body.read
1159
+ "Hello #{data['name']}!"
1160
+ end
1161
+
1162
+ === Attachments
1163
+
1164
+ You can use the +attachment+ helper to tell the browser the response should be
1165
+ stored on disk rather than displayed in the browser:
1166
+
1167
+ get '/' do
1168
+ attachment
1169
+ "store it!"
1170
+ end
1171
+
1172
+ You can also pass it a file name:
1173
+
1174
+ get '/' do
1175
+ attachment "info.txt"
1176
+ "store it!"
1177
+ end
1178
+
1179
+ === Dealing with Date and Time
1180
+
1181
+ Sinatra offers a +time_for+ helper method, which, from the given value
1182
+ generates a Time object. It is also able to convert +DateTime+, +Date+ and
1183
+ similar classes:
1184
+
1185
+ get '/' do
1186
+ pass if Time.now > time_for('Dec 23, 2012')
1187
+ "still time"
1188
+ end
1189
+
1190
+ This method is used internally by +expires+, +last_modified+ and akin. You can
1191
+ therefore easily extend the behavior of those methods by overriding +time_for+
1192
+ in your application:
1193
+
1194
+ helpers do
1195
+ def time_for(value)
1196
+ case value
1197
+ when :yesterday then Time.now - 24*60*60
1198
+ when :tomorrow then Time.now + 24*60*60
1199
+ else super
1200
+ end
1201
+ end
1202
+ end
1203
+
1204
+ get '/' do
1205
+ last_modified :yesterday
1206
+ expires :tomorrow
1207
+ "hello"
1208
+ end
1209
+
1210
+ === Looking Up Template Files
1211
+
1212
+ The <tt>find_template</tt> helper is used to find template files for rendering:
1213
+
1214
+ find_template settings.views, 'foo', Tilt[:haml] do |file|
1215
+ puts "could be #{file}"
1216
+ end
1217
+
1218
+ This is not really useful. But it is useful that you can actually override this
1219
+ method to hook in your own lookup mechanism. For instance, if you want to be
1220
+ able to use more than one view directory:
1221
+
1222
+ set :views, ['views', 'templates']
1223
+
1224
+ helpers do
1225
+ def find_template(views, name, engine, &block)
1226
+ Array(views).each { |v| super(v, name, engine, &block) }
1227
+ end
1228
+ end
1229
+
1230
+ Another example would be using different directories for different engines:
1231
+
1232
+ set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
1233
+
1234
+ helpers do
1235
+ def find_template(views, name, engine, &block)
1236
+ _, folder = views.detect { |k,v| engine == Tilt[k] }
1237
+ folder ||= views[:default]
1238
+ super(folder, name, engine, &block)
1239
+ end
1240
+ end
1241
+
1242
+ You can also easily wrap this up in an extension and share with others!
1243
+
1244
+ Note that <tt>find_template</tt> does not check if the file really exists but
1245
+ rather calls the given block for all possible paths. This is not a performance
1246
+ issue, since +render+ will use +break+ as soon as a file is found. Also,
1247
+ template locations (and content) will be cached if you are not running in
1248
+ development mode. You should keep that in mind if you write a really crazy
1249
+ method.
1250
+
1251
+ == Configuration
1252
+
1253
+ Run once, at startup, in any environment:
1254
+
1255
+ configure do
1256
+ # setting one option
1257
+ set :option, 'value'
1258
+
1259
+ # setting multiple options
1260
+ set :a => 1, :b => 2
1261
+
1262
+ # same as `set :option, true`
1263
+ enable :option
1264
+
1265
+ # same as `set :option, false`
1266
+ disable :option
1267
+
1268
+ # you can also have dynamic settings with blocks
1269
+ set(:css_dir) { File.join(views, 'css') }
1270
+ end
1271
+
1272
+ Run only when the environment (RACK_ENV environment variable) is set to
1273
+ <tt>:production</tt>:
1274
+
1275
+ configure :production do
1276
+ ...
1277
+ end
1278
+
1279
+ Run when the environment is set to either <tt>:production</tt> or
1280
+ <tt>:test</tt>:
1281
+
1282
+ configure :production, :test do
1283
+ ...
1284
+ end
1285
+
1286
+ You can access those options via <tt>settings</tt>:
1287
+
1288
+ configure do
1289
+ set :foo, 'bar'
1290
+ end
1291
+
1292
+ get '/' do
1293
+ settings.foo? # => true
1294
+ settings.foo # => 'bar'
1295
+ ...
1296
+ end
1297
+
1298
+ === Configuring attack protection
1299
+
1300
+ Sinatra is using
1301
+ {Rack::Protection}[https://github.com/rkh/rack-protection#readme] to defend
1302
+ you application against common, opportunistic attacks. You can easily disable
1303
+ this behavior (which should result in performance gains):
1304
+
1305
+ disable :protection
1306
+
1307
+ To skip a single defense layer, set +protection+ to an options hash:
1308
+
1309
+ set :protection, :except => :path_traversal
1310
+
1311
+ You can also hand in an array in order to disable a list of protections:
1312
+
1313
+ set :protection, :except => [:path_traversal, :session_hijacking]
1314
+
1315
+ === Available Settings
1316
+
1317
+ [absolute_redirects] If disabled, Sinatra will allow relative redirects,
1318
+ however, Sinatra will no longer conform with RFC 2616
1319
+ (HTTP 1.1), which only allows absolute redirects.
1320
+
1321
+ Enable if your app is running behind a reverse proxy that
1322
+ has not been set up properly. Note that the +url+ helper
1323
+ will still produce absolute URLs, unless you pass in
1324
+ +false+ as second parameter.
1325
+
1326
+ Disabled per default.
1327
+
1328
+ [add_charsets] mime types the <tt>content_type</tt> helper will
1329
+ automatically add the charset info to.
1330
+
1331
+ You should add to it rather than overriding this option:
1332
+
1333
+ settings.add_charsets << "application/foobar"
1334
+
1335
+ [app_file] Path to the main application file, used to detect project
1336
+ root, views and public folder and inline templates.
1337
+
1338
+ [bind] IP address to bind to (default: 0.0.0.0).
1339
+ Only used for built-in server.
1340
+
1341
+ [default_encoding] encoding to assume if unknown
1342
+ (defaults to <tt>"utf-8"</tt>).
1343
+
1344
+ [dump_errors] display errors in the log.
1345
+
1346
+ [environment] current environment, defaults to <tt>ENV['RACK_ENV']</tt>,
1347
+ or <tt>"development"</tt> if not available.
1348
+
1349
+ [logging] use the logger.
1350
+
1351
+ [lock] Places a lock around every request, only running
1352
+ processing on request per Ruby process concurrently.
1353
+
1354
+ Enabled if your app is not thread-safe.
1355
+ Disabled per default.
1356
+
1357
+ [method_override] use <tt>_method</tt> magic to allow put/delete forms in
1358
+ browsers that don't support it.
1359
+
1360
+ [port] Port to listen on. Only used for built-in server.
1361
+
1362
+ [prefixed_redirects] Whether or not to insert <tt>request.script_name</tt>
1363
+ into redirects if no absolute path is given. That way
1364
+ <tt>redirect '/foo'</tt> would behave like
1365
+ <tt>redirect to('/foo')</tt>. Disabled per default.
1366
+
1367
+ [protection] Whether or not to enable web attack protections. See
1368
+ protection section above.
1369
+
1370
+ [public_folder] Path to the folder public files are served from. Only
1371
+ used if static file serving is enabled (see
1372
+ <tt>static</tt> setting below). Inferred from
1373
+ <tt>app_file</tt> setting if not set.
1374
+
1375
+ [reload_templates] whether or not to reload templates between requests.
1376
+ Enabled in development mode.
1377
+
1378
+ [root] Path to project root folder. Inferred from +app_file+
1379
+ setting if not set.
1380
+
1381
+ [raise_errors] raise exceptions (will stop application). Enabled
1382
+ by default when <tt>environment</tt> is set to
1383
+ <tt>"test"</tt>, disabled otherwise.
1384
+
1385
+ [run] if enabled, Sinatra will handle starting the web server,
1386
+ do not enable if using rackup or other means.
1387
+
1388
+ [running] is the built-in server running now?
1389
+ do not change this setting!
1390
+
1391
+ [server] server or list of servers to use for built-in server.
1392
+ defaults to ['thin', 'mongrel', 'webrick'], order
1393
+ indicates priority.
1394
+
1395
+ [sessions] enable cookie based sessions support using
1396
+ <tt>Rack::Session::Cookie</tt>. See 'Using Sessions'
1397
+ section for more information.
1398
+
1399
+ [show_exceptions] show a stack trace in the browser when an exception
1400
+ happens. Enabled by default when <tt>environment</tt>
1401
+ is set to <tt>"development"</tt>, disabled otherwise.
1402
+
1403
+ [static] Whether Sinatra should handle serving static files.
1404
+ Disable when using a Server able to do this on its own.
1405
+ Disabling will boost performance.
1406
+ Enabled per default in classic style, disabled for
1407
+ modular apps.
1408
+
1409
+ [static_cache_control] When Sinatra is serving static files, set this to add
1410
+ <tt>Cache-Control</tt> headers to the responses. Uses the
1411
+ +cache_control+ helper. Disabled by default.
1412
+ Use an explicit array when setting multiple values:
1413
+ <tt>set :static_cache_control, [:public, :max_age => 300]</tt>
1414
+
1415
+ [threaded] If set to +true+, will tell Thin to use
1416
+ <tt>EventMachine.defer</tt> for processing the request.
1417
+
1418
+ [views] Path to the views folder. Inferred from <tt>app_file</tt>
1419
+ setting if not set.
1420
+
1421
+ == Environments
1422
+
1423
+ There are three predefined +environments+: <tt>"development"</tt>,
1424
+ <tt>"production"</tt> and <tt>"test"</tt>. Environments can be set
1425
+ through the +RACK_ENV+ environment variable. The default value is
1426
+ <tt>"development"</tt>. In this mode, all templates are reloaded between
1427
+ requests. Special <tt>not_found</tt> and <tt>error</tt> handlers are installed
1428
+ for this environment so you will see a stack trace in your browser.
1429
+ In <tt>"production"</tt> and <tt>"test"</tt> templates are cached by default.
1430
+
1431
+ To run different environments use the <tt>-e</tt> option:
1432
+
1433
+ ruby my_app.rb -e [ENVIRONMENT]
1434
+
1435
+ You can use predefined methods: +development?+, +test?+ and +production?+ to
1436
+ check which enviroment is currently set.
1437
+
1438
+ == Error Handling
1439
+
1440
+ Error handlers run within the same context as routes and before filters, which
1441
+ means you get all the goodies it has to offer, like <tt>haml</tt>,
1442
+ <tt>erb</tt>, <tt>halt</tt>, etc.
1443
+
1444
+ === Not Found
1445
+
1446
+ When a <tt>Sinatra::NotFound</tt> exception is raised, or the response's status
1447
+ code is 404, the <tt>not_found</tt> handler is invoked:
1448
+
1449
+ not_found do
1450
+ 'This is nowhere to be found.'
1451
+ end
1452
+
1453
+ === Error
1454
+
1455
+ The +error+ handler is invoked any time an exception is raised from a route
1456
+ block or a filter. The exception object can be obtained from the
1457
+ <tt>sinatra.error</tt> Rack variable:
1458
+
1459
+ error do
1460
+ 'Sorry there was a nasty error - ' + env['sinatra.error'].name
1461
+ end
1462
+
1463
+ Custom errors:
1464
+
1465
+ error MyCustomError do
1466
+ 'So what happened was...' + env['sinatra.error'].message
1467
+ end
1468
+
1469
+ Then, if this happens:
1470
+
1471
+ get '/' do
1472
+ raise MyCustomError, 'something bad'
1473
+ end
1474
+
1475
+ You get this:
1476
+
1477
+ So what happened was... something bad
1478
+
1479
+ Alternatively, you can install an error handler for a status code:
436
1480
 
437
1481
  error 403 do
438
1482
  'Access forbidden'
@@ -451,17 +1495,6 @@ Or a range:
451
1495
  Sinatra installs special <tt>not_found</tt> and <tt>error</tt> handlers when
452
1496
  running under the development environment.
453
1497
 
454
- == Mime types
455
-
456
- When using <tt>send_file</tt> or static files you may have mime types Sinatra
457
- doesn't understand. Use +mime_type+ to register them by file extension:
458
-
459
- mime_type :foo, 'text/foo'
460
-
461
- You can also use it with the +content_type+ helper:
462
-
463
- content_type :foo
464
-
465
1498
  == Rack Middleware
466
1499
 
467
1500
  Sinatra rides on Rack[http://rack.rubyforge.org/], a minimal standard
@@ -494,16 +1527,23 @@ accepts multiple/variable args as well as blocks:
494
1527
 
495
1528
  Rack is distributed with a variety of standard middleware for logging,
496
1529
  debugging, URL routing, authentication, and session handling. Sinatra uses
497
- many of of these components automatically based on configuration so you
1530
+ many of these components automatically based on configuration so you
498
1531
  typically don't have to +use+ them explicitly.
499
1532
 
1533
+ You can find useful middleware in
1534
+ {rack}[https://github.com/rack/rack/tree/master/lib/rack],
1535
+ {rack-contrib}[https://github.com/rack/rack-contrib#readme],
1536
+ with {CodeRack}[http://coderack.org/] or in the
1537
+ {Rack wiki}[https://github.com/rack/rack/wiki/List-of-Middleware].
1538
+
500
1539
  == Testing
501
1540
 
502
- Sinatra tests can be written using any Rack-based testing library
503
- or framework. {Rack::Test}[http://gitrdoc.com/brynary/rack-test] is
504
- recommended:
1541
+ Sinatra tests can be written using any Rack-based testing library or framework.
1542
+ {Rack::Test}[http://rdoc.info/github/brynary/rack-test/master/frames]
1543
+ is recommended:
505
1544
 
506
1545
  require 'my_sinatra_app'
1546
+ require 'test/unit'
507
1547
  require 'rack/test'
508
1548
 
509
1549
  class MyAppTest < Test::Unit::TestCase
@@ -529,18 +1569,15 @@ recommended:
529
1569
  end
530
1570
  end
531
1571
 
532
- NOTE: The built-in Sinatra::Test module and Sinatra::TestHarness class
533
- are deprecated as of the 0.9.2 release.
534
-
535
1572
  == Sinatra::Base - Middleware, Libraries, and Modular Apps
536
1573
 
537
1574
  Defining your app at the top-level works well for micro-apps but has
538
- considerable drawbacks when building reuseable components such as Rack
539
- middleware, Rails metal, simple libraries with a server component, or
540
- even Sinatra extensions. The top-level DSL pollutes the Object namespace
541
- and assumes a micro-app style configuration (e.g., a single application
542
- file, ./public and ./views directories, logging, exception detail page,
543
- etc.). That's where Sinatra::Base comes into play:
1575
+ considerable drawbacks when building reusable components such as Rack
1576
+ middleware, Rails metal, simple libraries with a server component, or even
1577
+ Sinatra extensions. The top-level assumes a micro-app style configuration
1578
+ (e.g., a single application file, <tt>./public</tt> and <tt>./views</tt>
1579
+ directories, logging, exception detail page, etc.). That's where
1580
+ <tt>Sinatra::Base</tt> comes into play:
544
1581
 
545
1582
  require 'sinatra/base'
546
1583
 
@@ -553,36 +1590,266 @@ etc.). That's where Sinatra::Base comes into play:
553
1590
  end
554
1591
  end
555
1592
 
556
- The MyApp class is an independent Rack component that can act as
557
- Rack middleware, a Rack application, or Rails metal. You can +use+ or
558
- +run+ this class from a rackup +config.ru+ file; or, control a server
559
- component shipped as a library:
560
-
561
- MyApp.run! :host => 'localhost', :port => 9090
562
-
563
- The methods available to Sinatra::Base subclasses are exactly as those
1593
+ The methods available to <tt>Sinatra::Base</tt> subclasses are exactly as those
564
1594
  available via the top-level DSL. Most top-level apps can be converted to
565
- Sinatra::Base components with two modifications:
1595
+ <tt>Sinatra::Base</tt> components with two modifications:
566
1596
 
567
- * Your file should require +sinatra/base+ instead of +sinatra+;
1597
+ * Your file should require <tt>sinatra/base</tt> instead of +sinatra+;
568
1598
  otherwise, all of Sinatra's DSL methods are imported into the main
569
1599
  namespace.
570
1600
  * Put your app's routes, error handlers, filters, and options in a subclass
571
- of Sinatra::Base.
1601
+ of <tt>Sinatra::Base</tt>.
572
1602
 
573
- +Sinatra::Base+ is a blank slate. Most options are disabled by default,
574
- including the built-in server. See {Options and Configuration}[http://sinatra.github.com/configuration.html]
1603
+ <tt>Sinatra::Base</tt> is a blank slate. Most options are disabled by default,
1604
+ including the built-in server. See
1605
+ {Options and Configuration}[http://sinatra.github.com/configuration.html]
575
1606
  for details on available options and their behavior.
576
1607
 
577
- SIDEBAR: Sinatra's top-level DSL is implemented using a simple delegation
578
- system. The +Sinatra::Application+ class -- a special subclass of
579
- Sinatra::Base -- receives all :get, :put, :post, :delete, :before,
580
- :error, :not_found, :configure, and :set messages sent to the
581
- top-level. Have a look at the code for yourself: here's the
582
- {Sinatra::Delegator mixin}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/base.rb#L1128]
583
- being {included into the main namespace}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/main.rb#L28]
1608
+ === Modular vs. Classic Style
1609
+
1610
+ Contrary to common belief, there is nothing wrong with classic style. If it
1611
+ suits your application, you do not have to switch to a modular application.
1612
+
1613
+ The main downsides of using classic style rather than modular style is that
1614
+ you may only have one Sinatra application per Ruby process. If you plan to use
1615
+ more than one, switch to modular style. There is no reason you cannot mix
1616
+ modular and classic style.
1617
+
1618
+ If switching from one style to the other, you should be aware of slightly
1619
+ different default settings:
1620
+
1621
+ Setting Classic Modular
1622
+
1623
+ app_file file loading sinatra file subclassing Sinatra::Base
1624
+ run $0 == app_file false
1625
+ logging true false
1626
+ method_override true false
1627
+ inline_templates true false
1628
+ static true false
1629
+
1630
+
1631
+ === Serving a Modular Application
1632
+
1633
+ There are two common options for starting a modular app, actively starting with
1634
+ <tt>run!</tt>:
1635
+
1636
+ # my_app.rb
1637
+ require 'sinatra/base'
1638
+
1639
+ class MyApp < Sinatra::Base
1640
+ # ... app code here ...
1641
+
1642
+ # start the server if ruby file executed directly
1643
+ run! if app_file == $0
1644
+ end
1645
+
1646
+ Start with:
1647
+
1648
+ ruby my_app.rb
1649
+
1650
+ Or with a <tt>config.ru</tt>, which allows using any Rack handler:
1651
+
1652
+ # config.ru
1653
+ require './my_app'
1654
+ run MyApp
1655
+
1656
+ Run:
1657
+
1658
+ rackup -p 4567
1659
+
1660
+ === Using a Classic Style Application with a config.ru
1661
+
1662
+ Write your app file:
1663
+
1664
+ # app.rb
1665
+ require 'sinatra'
1666
+
1667
+ get '/' do
1668
+ 'Hello world!'
1669
+ end
1670
+
1671
+ And a corresponding <tt>config.ru</tt>:
1672
+
1673
+ require './app'
1674
+ run Sinatra::Application
1675
+
1676
+ === When to use a config.ru?
1677
+
1678
+ Good signs you probably want to use a <tt>config.ru</tt>:
584
1679
 
585
- == Command line
1680
+ * You want to deploy with a different Rack handler (Passenger, Unicorn,
1681
+ Heroku, ...).
1682
+ * You want to use more than one subclass of <tt>Sinatra::Base</tt>.
1683
+ * You want to use Sinatra only for middleware, but not as endpoint.
1684
+
1685
+ <b>There is no need to switch to a <tt>config.ru</tt> only because you
1686
+ switched to modular style, and you don't have to use modular style for running
1687
+ with a <tt>config.ru</tt>.</b>
1688
+
1689
+ === Using Sinatra as Middleware
1690
+
1691
+ Not only is Sinatra able to use other Rack middleware, any Sinatra application
1692
+ can in turn be added in front of any Rack endpoint as middleware itself. This
1693
+ endpoint could be another Sinatra application, or any other Rack-based
1694
+ application (Rails/Ramaze/Camping/...):
1695
+
1696
+ require 'sinatra/base'
1697
+
1698
+ class LoginScreen < Sinatra::Base
1699
+ enable :sessions
1700
+
1701
+ get('/login') { haml :login }
1702
+
1703
+ post('/login') do
1704
+ if params[:name] == 'admin' && params[:password] == 'admin'
1705
+ session['user_name'] = params[:name]
1706
+ else
1707
+ redirect '/login'
1708
+ end
1709
+ end
1710
+ end
1711
+
1712
+ class MyApp < Sinatra::Base
1713
+ # middleware will run before filters
1714
+ use LoginScreen
1715
+
1716
+ before do
1717
+ unless session['user_name']
1718
+ halt "Access denied, please <a href='/login'>login</a>."
1719
+ end
1720
+ end
1721
+
1722
+ get('/') { "Hello #{session['user_name']}." }
1723
+ end
1724
+
1725
+ === Dynamic Application Creation
1726
+
1727
+ Sometimes you want to create new applications at runtime without having to
1728
+ assign them to a constant, you can do this with <tt>Sinatra.new</tt>:
1729
+
1730
+ require 'sinatra/base'
1731
+ my_app = Sinatra.new { get('/') { "hi" } }
1732
+ my_app.run!
1733
+
1734
+ It takes the application to inherit from as optional argument:
1735
+
1736
+ # config.ru
1737
+ require 'sinatra/base'
1738
+
1739
+ controller = Sinatra.new do
1740
+ enable :logging
1741
+ helpers MyHelpers
1742
+ end
1743
+
1744
+ map('/a') do
1745
+ run Sinatra.new(controller) { get('/') { 'a' } }
1746
+ end
1747
+
1748
+ map('/b') do
1749
+ run Sinatra.new(controller) { get('/') { 'b' } }
1750
+ end
1751
+
1752
+ This is especially useful for testing Sinatra extensions or using Sinatra in
1753
+ your own library.
1754
+
1755
+ This also makes using Sinatra as middleware extremely easy:
1756
+
1757
+ require 'sinatra/base'
1758
+
1759
+ use Sinatra do
1760
+ get('/') { ... }
1761
+ end
1762
+
1763
+ run RailsProject::Application
1764
+
1765
+ == Scopes and Binding
1766
+
1767
+ The scope you are currently in determines what methods and variables are
1768
+ available.
1769
+
1770
+ === Application/Class Scope
1771
+
1772
+ Every Sinatra application corresponds to a subclass of <tt>Sinatra::Base</tt>.
1773
+ If you are using the top-level DSL (<tt>require 'sinatra'</tt>), then this
1774
+ class is <tt>Sinatra::Application</tt>, otherwise it is the subclass you
1775
+ created explicitly. At class level you have methods like +get+ or +before+, but
1776
+ you cannot access the +request+ object or the +session+, as there only is a
1777
+ single application class for all requests.
1778
+
1779
+ Options created via +set+ are methods at class level:
1780
+
1781
+ class MyApp < Sinatra::Base
1782
+ # Hey, I'm in the application scope!
1783
+ set :foo, 42
1784
+ foo # => 42
1785
+
1786
+ get '/foo' do
1787
+ # Hey, I'm no longer in the application scope!
1788
+ end
1789
+ end
1790
+
1791
+ You have the application scope binding inside:
1792
+
1793
+ * Your application class body
1794
+ * Methods defined by extensions
1795
+ * The block passed to +helpers+
1796
+ * Procs/blocks used as value for +set+
1797
+ * The block passed to <tt>Sinatra.new</tt>
1798
+
1799
+ You can reach the scope object (the class) like this:
1800
+
1801
+ * Via the object passed to configure blocks (<tt>configure { |c| ... }</tt>)
1802
+ * +settings+ from within request scope
1803
+
1804
+ === Request/Instance Scope
1805
+
1806
+ For every incoming request, a new instance of your application class is
1807
+ created and all handler blocks run in that scope. From within this scope you
1808
+ can access the +request+ and +session+ object or call rendering methods like
1809
+ +erb+ or +haml+. You can access the application scope from within the request
1810
+ scope via the +settings+ helper:
1811
+
1812
+ class MyApp < Sinatra::Base
1813
+ # Hey, I'm in the application scope!
1814
+ get '/define_route/:name' do
1815
+ # Request scope for '/define_route/:name'
1816
+ @value = 42
1817
+
1818
+ settings.get("/#{params[:name]}") do
1819
+ # Request scope for "/#{params[:name]}"
1820
+ @value # => nil (not the same request)
1821
+ end
1822
+
1823
+ "Route defined!"
1824
+ end
1825
+ end
1826
+
1827
+ You have the request scope binding inside:
1828
+
1829
+ * get/head/post/put/delete/options blocks
1830
+ * before/after filters
1831
+ * helper methods
1832
+ * templates/views
1833
+
1834
+ === Delegation Scope
1835
+
1836
+ The delegation scope just forwards methods to the class scope. However, it
1837
+ does not behave 100% like the class scope, as you do not have the class
1838
+ binding. Only methods explicitly marked for delegation are available and you
1839
+ do not share variables/state with the class scope (read: you have a different
1840
+ +self+). You can explicitly add method delegations by calling
1841
+ <tt>Sinatra::Delegator.delegate :method_name</tt>.
1842
+
1843
+ You have the delegate scope binding inside:
1844
+
1845
+ * The top level binding, if you did <tt>require "sinatra"</tt>
1846
+ * An object extended with the <tt>Sinatra::Delegator</tt> mixin
1847
+
1848
+ Have a look at the code for yourself: here's the
1849
+ {Sinatra::Delegator mixin}[https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/base.rb#L1609-1633]
1850
+ being {extending the main object}[https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/main.rb#L28-30].
1851
+
1852
+ == Command Line
586
1853
 
587
1854
  Sinatra applications can be run directly:
588
1855
 
@@ -597,40 +1864,148 @@ Options are:
597
1864
  -s # specify rack server/handler (default is thin)
598
1865
  -x # turn on the mutex lock (default is off)
599
1866
 
1867
+ == Requirement
1868
+
1869
+ The following Ruby versions are officially supported:
1870
+
1871
+ [ Ruby 1.8.7 ]
1872
+ 1.8.7 is fully supported, however, if nothing is keeping you from it, we
1873
+ recommend upgrading to 1.9.2 or switching to JRuby or Rubinius. Support for
1874
+ 1.8.7 will not be dropped before Sinatra 2.0 and Ruby 2.0 except maybe for
1875
+ the unlikely event of 1.8.8 being released. Even then, we might continue
1876
+ supporting it. <b>Ruby 1.8.6 is no longer supported.</b> If you want to run
1877
+ with 1.8.6, downgrade to Sinatra 1.2, which will receive bug fixes until
1878
+ Sinatra 1.4.0 is released.
1879
+
1880
+ [ Ruby 1.9.2 ]
1881
+ 1.9.2 is fully supported and recommended. Do not use 1.9.2p0, it is known to
1882
+ cause segmentation faults when running Sinatra. Support will continue at least
1883
+ until the release of Ruby 1.9.4/2.0 and support for the latest 1.9 release
1884
+ will continue as long as it is still supported by the Ruby core team.
1885
+
1886
+ [ Ruby 1.9.3 ]
1887
+ 1.9.3 is fully supported and recommended. Please note that switching to 1.9.3
1888
+ from an earlier version will invalidate all sessions.
1889
+
1890
+ [ Rubinius ]
1891
+ Rubinius is officially supported (Rubinius >= 1.2.4), everything, including
1892
+ all template languages, works. The upcoming 2.0 release is supported as
1893
+ well, including 1.9 mode.
1894
+
1895
+ [ JRuby ]
1896
+ JRuby is officially supported (JRuby >= 1.6.7). No issues with third party
1897
+ template libraries are known, however, if you choose to use JRuby, please
1898
+ look into JRuby rack handlers, as the Thin web server is not fully supported
1899
+ on JRuby. JRuby's support for C extensions is still experimental, which only
1900
+ affects RDiscount, Redcarpet, RedCloth and Yajl templates as well as Thin
1901
+ and Mongrel at the moment.
1902
+
1903
+ We also keep an eye on upcoming Ruby versions.
1904
+
1905
+ The following Ruby implementations are not officially supported but still are
1906
+ known to run Sinatra:
1907
+
1908
+ * Older versions of JRuby and Rubinius
1909
+ * Ruby Enterprise Edition
1910
+ * MacRuby, Maglev, IronRuby
1911
+ * Ruby 1.9.0 and 1.9.1 (but we do recommend against using those)
1912
+
1913
+ Not being officially supported means if things only break there and not on a
1914
+ supported platform, we assume it's not our issue but theirs.
1915
+
1916
+ We also run our CI against ruby-head (the upcoming 2.0.0) and the 1.9.4
1917
+ branch, but we can't guarantee anything, since it is constantly moving. Expect
1918
+ both 1.9.4p0 and 2.0.0p0 to be supported.
1919
+
1920
+ Sinatra should work on any operating system supported by the chosen Ruby
1921
+ implementation.
1922
+
1923
+ You will not be able to run Sinatra on Cardinal, SmallRuby, BlueRuby or any
1924
+ Ruby version prior to 1.8.7 as of the time being.
1925
+
600
1926
  == The Bleeding Edge
601
1927
 
602
- If you would like to use Sinatra's latest bleeding code, create a local
603
- clone and run your app with the <tt>sinatra/lib</tt> directory on the
604
- <tt>LOAD_PATH</tt>:
1928
+ If you would like to use Sinatra's latest bleeding code, feel free to run your
1929
+ application against the master branch, it should be rather stable.
1930
+
1931
+ We also push out prerelease gems from time to time, so you can do a
1932
+
1933
+ gem install sinatra --pre
1934
+
1935
+ To get some of the latest features.
1936
+
1937
+ === With Bundler
1938
+
1939
+ If you want to run your application with the latest Sinatra, using
1940
+ {Bundler}[http://gembundler.com/] is the recommended way.
1941
+
1942
+ First, install bundler, if you haven't:
1943
+
1944
+ gem install bundler
1945
+
1946
+ Then, in your project directory, create a +Gemfile+:
1947
+
1948
+ source :rubygems
1949
+ gem 'sinatra', :git => "git://github.com/sinatra/sinatra.git"
1950
+
1951
+ # other dependencies
1952
+ gem 'haml' # for instance, if you use haml
1953
+ gem 'activerecord', '~> 3.0' # maybe you also need ActiveRecord 3.x
1954
+
1955
+ Note that you will have to list all your applications dependencies in there.
1956
+ Sinatra's direct dependencies (Rack and Tilt) will, however, be automatically
1957
+ fetched and added by Bundler.
1958
+
1959
+ Now you can run your app like this:
1960
+
1961
+ bundle exec ruby myapp.rb
1962
+
1963
+ === Roll Your Own
1964
+
1965
+ Create a local clone and run your app with the <tt>sinatra/lib</tt> directory
1966
+ on the <tt>$LOAD_PATH</tt>:
605
1967
 
606
1968
  cd myapp
607
1969
  git clone git://github.com/sinatra/sinatra.git
608
1970
  ruby -Isinatra/lib myapp.rb
609
1971
 
610
- Alternatively, you can add the <tt>sinatra/lib</tt> directory to the
611
- <tt>LOAD_PATH</tt> in your application:
1972
+ To update the Sinatra sources in the future:
612
1973
 
613
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
614
- require 'rubygems'
615
- require 'sinatra'
1974
+ cd myapp/sinatra
1975
+ git pull
616
1976
 
617
- get '/about' do
618
- "I'm running version " + Sinatra::VERSION
619
- end
1977
+ === Install Globally
620
1978
 
621
- To update the Sinatra sources in the future:
1979
+ You can build the gem on your own:
622
1980
 
623
- cd myproject/sinatra
624
- git pull
1981
+ git clone git://github.com/sinatra/sinatra.git
1982
+ cd sinatra
1983
+ rake sinatra.gemspec
1984
+ rake install
1985
+
1986
+ If you install gems as root, the last step should be
1987
+
1988
+ sudo rake install
1989
+
1990
+ == Versioning
1991
+
1992
+ Sinatra follows {Semantic Versioning}[http://semver.org/], both SemVer and
1993
+ SemVerTag.
625
1994
 
626
- == More
1995
+ == Further Reading
627
1996
 
628
1997
  * {Project Website}[http://www.sinatrarb.com/] - Additional documentation,
629
1998
  news, and links to other resources.
630
1999
  * {Contributing}[http://www.sinatrarb.com/contributing] - Find a bug? Need
631
2000
  help? Have a patch?
632
- * {Lighthouse}[http://sinatra.lighthouseapp.com] - Issue tracking and release
633
- planning.
2001
+ * {Issue tracker}[http://github.com/sinatra/sinatra/issues]
634
2002
  * {Twitter}[http://twitter.com/sinatra]
635
2003
  * {Mailing List}[http://groups.google.com/group/sinatrarb/topics]
636
2004
  * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] on http://freenode.net
2005
+ * {Sinatra Book}[http://sinatra-book.gittr.com] Cookbook Tutorial
2006
+ * {Sinatra Recipes}[http://recipes.sinatrarb.com/] Community
2007
+ contributed recipes
2008
+ * API documentation for the {latest release}[http://rubydoc.info/gems/sinatra]
2009
+ or the {current HEAD}[http://rubydoc.info/github/sinatra/sinatra] on
2010
+ http://rubydoc.info
2011
+ * {CI server}[http://ci.rkh.im/view/Sinatra/]