sinatra 1.3.6 → 1.4.0.a

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.

Files changed (71) hide show
  1. data/CHANGES +96 -22
  2. data/Gemfile +11 -3
  3. data/README.de.md +2590 -0
  4. data/README.es.rdoc +66 -38
  5. data/README.fr.md +2630 -0
  6. data/README.hu.rdoc +3 -2
  7. data/README.jp.rdoc +16 -3
  8. data/README.ko.rdoc +11 -5
  9. data/README.md +2699 -0
  10. data/README.pt-br.rdoc +152 -21
  11. data/README.pt-pt.rdoc +3 -2
  12. data/README.ru.md +2724 -0
  13. data/README.zh.rdoc +3 -3
  14. data/Rakefile +3 -4
  15. data/examples/chat.rb +3 -3
  16. data/lib/sinatra/base.rb +433 -247
  17. data/lib/sinatra/main.rb +4 -2
  18. data/lib/sinatra/showexceptions.rb +6 -1
  19. data/lib/sinatra/version.rb +1 -1
  20. data/test/base_test.rb +21 -9
  21. data/test/builder_test.rb +15 -19
  22. data/test/coffee_test.rb +4 -6
  23. data/test/compile_test.rb +154 -0
  24. data/test/contest.rb +4 -6
  25. data/test/creole_test.rb +5 -5
  26. data/test/delegator_test.rb +1 -3
  27. data/test/erb_test.rb +32 -20
  28. data/test/extensions_test.rb +1 -3
  29. data/test/filter_test.rb +65 -56
  30. data/test/haml_test.rb +34 -26
  31. data/test/helpers_test.rb +331 -221
  32. data/test/integration_helper.rb +8 -0
  33. data/test/integration_test.rb +3 -1
  34. data/test/less_test.rb +10 -8
  35. data/test/liquid_test.rb +22 -4
  36. data/test/mapped_error_test.rb +122 -96
  37. data/test/markaby_test.rb +5 -5
  38. data/test/markdown_test.rb +5 -5
  39. data/test/middleware_test.rb +3 -3
  40. data/test/nokogiri_test.rb +4 -6
  41. data/test/rabl_test.rb +89 -0
  42. data/test/radius_test.rb +4 -4
  43. data/test/rdoc_test.rb +7 -7
  44. data/test/readme_test.rb +14 -30
  45. data/test/request_test.rb +15 -0
  46. data/test/response_test.rb +3 -4
  47. data/test/result_test.rb +11 -33
  48. data/test/route_added_hook_test.rb +10 -10
  49. data/test/routing_test.rb +123 -1
  50. data/test/sass_test.rb +26 -26
  51. data/test/scss_test.rb +16 -16
  52. data/test/server_test.rb +2 -2
  53. data/test/settings_test.rb +48 -4
  54. data/test/sinatra_test.rb +2 -7
  55. data/test/slim_test.rb +37 -23
  56. data/test/static_test.rb +56 -15
  57. data/test/streaming_test.rb +11 -2
  58. data/test/templates_test.rb +117 -45
  59. data/test/textile_test.rb +9 -9
  60. data/test/views/hello.rabl +2 -0
  61. data/test/views/hello.wlang +1 -0
  62. data/test/views/hello.yajl +1 -0
  63. data/test/views/layout2.rabl +3 -0
  64. data/test/views/layout2.wlang +2 -0
  65. data/test/wlang_test.rb +87 -0
  66. data/test/yajl_test.rb +86 -0
  67. metadata +27 -17
  68. data/README.de.rdoc +0 -2097
  69. data/README.fr.rdoc +0 -2036
  70. data/README.rdoc +0 -2017
  71. data/README.ru.rdoc +0 -1785
@@ -1,2017 +0,0 @@
1
- = Sinatra
2
-
3
- Sinatra is a DSL for quickly creating web applications in Ruby with minimal
4
- effort:
5
-
6
- # myapp.rb
7
- require 'sinatra'
8
-
9
- get '/' do
10
- 'Hello world!'
11
- end
12
-
13
- Install the gem and run with:
14
-
15
- gem install sinatra
16
- ruby -rubygems myapp.rb
17
-
18
- View at: http://localhost:4567
19
-
20
- It is recommended to also run <tt>gem install thin</tt>, which Sinatra will
21
- pick up if available.
22
-
23
- == Routes
24
-
25
- In Sinatra, a route is an HTTP method paired with a URL-matching pattern.
26
- Each route is associated with a block:
27
-
28
- get '/' do
29
- .. show something ..
30
- end
31
-
32
- post '/' do
33
- .. create something ..
34
- end
35
-
36
- put '/' do
37
- .. replace something ..
38
- end
39
-
40
- patch '/' do
41
- .. modify something ..
42
- end
43
-
44
- delete '/' do
45
- .. annihilate something ..
46
- end
47
-
48
- options '/' do
49
- .. appease something ..
50
- end
51
-
52
- Routes are matched in the order they are defined. The first route that
53
- matches the request is invoked.
54
-
55
- Route patterns may include named parameters, accessible via the
56
- <tt>params</tt> hash:
57
-
58
- get '/hello/:name' do
59
- # matches "GET /hello/foo" and "GET /hello/bar"
60
- # params[:name] is 'foo' or 'bar'
61
- "Hello #{params[:name]}!"
62
- end
63
-
64
- You can also access named parameters via block parameters:
65
-
66
- get '/hello/:name' do |n|
67
- "Hello #{n}!"
68
- end
69
-
70
- Route patterns may also include splat (or wildcard) parameters, accessible
71
- via the <tt>params[:splat]</tt> array:
72
-
73
- get '/say/*/to/*' do
74
- # matches /say/hello/to/world
75
- params[:splat] # => ["hello", "world"]
76
- end
77
-
78
- get '/download/*.*' do
79
- # matches /download/path/to/file.xml
80
- params[:splat] # => ["path/to/file", "xml"]
81
- end
82
-
83
- Or with block parameters:
84
-
85
- get '/download/*.*' do |path, ext|
86
- [path, ext] # => ["path/to/file", "xml"]
87
- end
88
-
89
- Route matching with Regular Expressions:
90
-
91
- get %r{/hello/([\w]+)} do
92
- "Hello, #{params[:captures].first}!"
93
- end
94
-
95
- Or with a block parameter:
96
-
97
- get %r{/hello/([\w]+)} do |c|
98
- "Hello, #{c}!"
99
- end
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
-
112
- Routes may include a variety of matching conditions, such as the user agent:
113
-
114
- get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
115
- "You're using Songbird version #{params[:agent][0]}"
116
- end
117
-
118
- get '/foo' do
119
- # Matches non-songbird browsers
120
- end
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
-
238
- == Static Files
239
-
240
- Static files are served from the <tt>./public</tt> directory. You can specify
241
- a different location by setting the <tt>:public_folder</tt> option:
242
-
243
- set :public_folder, File.dirname(__FILE__) + '/static'
244
-
245
- Note that the public directory name is not included in the URL. A file
246
- <tt>./public/css/style.css</tt> is made available as
247
- <tt>http://example.com/css/style.css</tt>.
248
-
249
- Use the <tt>:static_cache_control</tt> setting (see below) to add
250
- <tt>Cache-Control</tt> header info.
251
-
252
- == Views / Templates
253
-
254
- Each template language is exposed via its own rendering method. These
255
- methods simply return a string:
256
-
257
- get '/' do
258
- erb :index
259
- end
260
-
261
- This renders <tt>views/index.erb</tt>.
262
-
263
- Instead of a template name, you can also just pass in the template content
264
- directly:
265
-
266
- get '/' do
267
- code = "<%= Time.now %>"
268
- erb code
269
- end
270
-
271
- Templates take a second argument, the options hash:
272
-
273
- get '/' do
274
- erb :index, :layout => :post
275
- end
276
-
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).
279
-
280
- Any options not understood by Sinatra will be passed on to the template
281
- engine:
282
-
283
- get '/' do
284
- haml :index, :format => :html5
285
- end
286
-
287
- You can also set options per template language in general:
288
-
289
- set :haml, :format => :html5
290
-
291
- get '/' do
292
- haml :index
293
- end
294
-
295
- Options passed to the render method override options set via +set+.
296
-
297
- Available Options:
298
-
299
- [locals]
300
- List of locals passed to the document. Handy with partials.
301
- Example: <tt>erb "<%= foo %>", :locals => {:foo => "bar"}</tt>
302
-
303
- [default_encoding]
304
- String encoding to use if uncertain. Defaults to
305
- <tt>settings.default_encoding</tt>.
306
-
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 }
344
-
345
- === Haml Templates
346
-
347
- Dependency:: {haml}[http://haml.info/]
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>
358
-
359
- === Builder Templates
360
-
361
- Dependency:: {builder}[http://builder.rubyforge.org/]
362
- File Extensions:: <tt>.builder</tt>
363
- Example:: <tt>builder { |xml| xml.em "hi" }</tt>
364
-
365
- It also takes a block for inline templates (see example).
366
-
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>
372
-
373
- It also takes a block for inline templates (see example).
374
-
375
- === Sass Templates
376
-
377
- Dependency:: {sass}[http://sass-lang.com/]
378
- File Extensions:: <tt>.sass</tt>
379
- Example:: <tt>sass :stylesheet, :style => :expanded</tt>
380
-
381
- === SCSS Templates
382
-
383
- Dependency:: {sass}[http://sass-lang.com/]
384
- File Extensions:: <tt>.scss</tt>
385
- Example:: <tt>scss :stylesheet, :style => :expanded</tt>
386
-
387
- === Less Templates
388
-
389
- Dependency:: {less}[http://www.lesscss.org/]
390
- File Extensions:: <tt>.less</tt>
391
- Example:: <tt>less :stylesheet</tt>
392
-
393
- === Liquid Templates
394
-
395
- Dependency:: {liquid}[http://www.liquidmarkup.org/]
396
- File Extensions:: <tt>.liquid</tt>
397
- Example:: <tt>liquid :index, :locals => { :key => 'value' }</tt>
398
-
399
- Since you cannot call Ruby methods (except for +yield+) from a Liquid
400
- template, you almost always want to pass locals to it.
401
-
402
- === Markdown Templates
403
-
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>
411
-
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:
415
-
416
- erb :overview, :locals => { :text => markdown(:introduction) }
417
-
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
- === Embedded Templates
518
-
519
- get '/' do
520
- haml '%div.title Hello World'
521
- end
522
-
523
- Renders the embedded template string.
524
-
525
- === Accessing Variables in Templates
526
-
527
- Templates are evaluated within the same context as route handlers. Instance
528
- variables set in route handlers are directly accessible by templates:
529
-
530
- get '/:id' do
531
- @foo = Foo.find(params[:id])
532
- haml '%h1= @foo.name'
533
- end
534
-
535
- Or, specify an explicit Hash of local variables:
536
-
537
- get '/:id' do
538
- foo = Foo.find(params[:id])
539
- haml '%h1= bar.name', :locals => { :bar => foo }
540
- end
541
-
542
- This is typically used when rendering templates as partials from within
543
- other templates.
544
-
545
- === Inline Templates
546
-
547
- Templates may be defined at the end of the source file:
548
-
549
- require 'sinatra'
550
-
551
- get '/' do
552
- haml :index
553
- end
554
-
555
- __END__
556
-
557
- @@ layout
558
- %html
559
- = yield
560
-
561
- @@ index
562
- %div.title Hello world.
563
-
564
- NOTE: Inline templates defined in the source file that requires sinatra are
565
- automatically loaded. Call <tt>enable :inline_templates</tt> explicitly if you
566
- have inline templates in other source files.
567
-
568
- === Named Templates
569
-
570
- Templates may also be defined using the top-level <tt>template</tt> method:
571
-
572
- template :layout do
573
- "%html\n =yield\n"
574
- end
575
-
576
- template :index do
577
- '%div.title Hello World!'
578
- end
579
-
580
- get '/' do
581
- haml :index
582
- end
583
-
584
- If a template named "layout" exists, it will be used each time a template
585
- is rendered. You can individually disable layouts by passing
586
- <tt>:layout => false</tt> or disable them by default via
587
- <tt>set :haml, :layout => false</tt>:
588
-
589
- get '/' do
590
- haml :index, :layout => !request.xhr?
591
- end
592
-
593
- === Associating File Extensions
594
-
595
- To associate a file extension with a template engine, use
596
- <tt>Tilt.register</tt>. For instance, if you like to use the file extension
597
- +tt+ for Textile templates, you can do the following:
598
-
599
- Tilt.register :tt, Tilt[:textile]
600
-
601
- === Adding Your Own Template Engine
602
-
603
- First, register your engine with Tilt, then create a rendering method:
604
-
605
- Tilt.register :myat, MyAwesomeTemplateEngine
606
-
607
- helpers do
608
- def myat(*args) render(:myat, *args) end
609
- end
610
-
611
- get '/' do
612
- myat :index
613
- end
614
-
615
- Renders <tt>./views/index.myat</tt>. See https://github.com/rtomayko/tilt to
616
- learn more about Tilt.
617
-
618
- == Filters
619
-
620
- Before filters are evaluated before each request within the same
621
- context as the routes will be and can modify the request and response. Instance
622
- variables set in filters are accessible by routes and templates:
623
-
624
- before do
625
- @note = 'Hi!'
626
- request.path_info = '/foo/bar/baz'
627
- end
628
-
629
- get '/foo/*' do
630
- @note #=> 'Hi!'
631
- params[:splat] #=> 'bar/baz'
632
- end
633
-
634
- After filters are evaluated after each request within the same context and can
635
- also modify the request and response. Instance variables set in before filters
636
- and routes are accessible by after filters:
637
-
638
- after do
639
- puts response.status
640
- end
641
-
642
- Note: Unless you use the +body+ method rather than just returning a String from
643
- the routes, the body will not yet be available in the after filter, since it is
644
- generated later on.
645
-
646
- Filters optionally take a pattern, causing them to be evaluated only if the
647
- request path matches that pattern:
648
-
649
- before '/protected/*' do
650
- authenticate!
651
- end
652
-
653
- after '/create/:slug' do |slug|
654
- session[:last_slug] = slug
655
- end
656
-
657
- Like routes, filters also take conditions:
658
-
659
- before :agent => /Songbird/ do
660
- # ...
661
- end
662
-
663
- after '/blog/*', :host_name => 'example.com' do
664
- # ...
665
- end
666
-
667
- == Helpers
668
-
669
- Use the top-level <tt>helpers</tt> method to define helper methods for use in
670
- route handlers and templates:
671
-
672
- helpers do
673
- def bar(name)
674
- "#{name}bar"
675
- end
676
- end
677
-
678
- get '/:name' do
679
- bar(params[:name])
680
- end
681
-
682
- Alternatively, helper methods can be separately defined in a module:
683
-
684
- module FooUtils
685
- def foo(name) "#{name}foo" end
686
- end
687
-
688
- module BarUtils
689
- def bar(name) "#{name}bar" end
690
- end
691
-
692
- helpers FooUtils, BarUtils
693
-
694
- The effect is the same as including the modules in the application class.
695
-
696
- === Using Sessions
697
-
698
- A session is used to keep state during requests. If activated, you have one
699
- session hash per user session:
700
-
701
- enable :sessions
702
-
703
- get '/' do
704
- "value = " << session[:value].inspect
705
- end
706
-
707
- get '/:value' do
708
- session[:value] = params[:value]
709
- end
710
-
711
- Note that <tt>enable :sessions</tt> actually stores all data in a cookie. This
712
- might not always be what you want (storing lots of data will increase your
713
- traffic, for instance). You can use any Rack session middleware: in order to
714
- do so, do *not* call <tt>enable :sessions</tt>, but instead pull in your
715
- middleware of choice as you would any other middleware:
716
-
717
- use Rack::Session::Pool, :expire_after => 2592000
718
-
719
- get '/' do
720
- "value = " << session[:value].inspect
721
- end
722
-
723
- get '/:value' do
724
- session[:value] = params[:value]
725
- end
726
-
727
- To improve security, the session data in the cookie is signed with a session
728
- secret. A random secret is generated for you by Sinatra. However, since this
729
- secret will change with every start of your application, you might want to
730
- set the secret yourself, so all your application instances share it:
731
-
732
- set :session_secret, 'super secret'
733
-
734
- If you want to configure it further, you may also store a hash with options in
735
- the +sessions+ setting:
736
-
737
- set :sessions, :domain => 'foo.com'
738
-
739
- === Halting
740
-
741
- To immediately stop a request within a filter or route use:
742
-
743
- halt
744
-
745
- You can also specify the status when halting:
746
-
747
- halt 410
748
-
749
- Or the body:
750
-
751
- halt 'this will be the body'
752
-
753
- Or both:
754
-
755
- halt 401, 'go away!'
756
-
757
- With headers:
758
-
759
- halt 402, {'Content-Type' => 'text/plain'}, 'revenge'
760
-
761
- It is of course possible to combine a template with +halt+:
762
-
763
- halt erb(:error)
764
-
765
- === Passing
766
-
767
- A route can punt processing to the next matching route using <tt>pass</tt>:
768
-
769
- get '/guess/:who' do
770
- pass unless params[:who] == 'Frank'
771
- 'You got me!'
772
- end
773
-
774
- get '/guess/*' do
775
- 'You missed!'
776
- end
777
-
778
- The route block is immediately exited and control continues with the next
779
- matching route. If no matching route is found, a 404 is returned.
780
-
781
- === Triggering Another Route
782
-
783
- Sometimes +pass+ is not what you want, instead you would like to get the result
784
- of calling another route. Simply use +call+ to achieve this:
785
-
786
- get '/foo' do
787
- status, headers, body = call env.merge("PATH_INFO" => '/bar')
788
- [status, headers, body.map(&:upcase)]
789
- end
790
-
791
- get '/bar' do
792
- "bar"
793
- end
794
-
795
- Note that in the example above, you would ease testing and increase performance
796
- by simply moving <tt>"bar"</tt> into a helper used by both <tt>/foo</tt>
797
- and <tt>/bar</tt>.
798
-
799
- If you want the request to be sent to the same application instance rather than
800
- a duplicate, use <tt>call!</tt> instead of <tt>call</tt>.
801
-
802
- Check out the Rack specification if you want to learn more about <tt>call</tt>.
803
-
804
- === Setting Body, Status Code and Headers
805
-
806
- It is possible and recommended to set the status code and response body with the
807
- return value of the route block. However, in some scenarios you might want to
808
- set the body at an arbitrary point in the execution flow. You can do so with the
809
- +body+ helper method. If you do so, you can use that method from there on to
810
- access the body:
811
-
812
- get '/foo' do
813
- body "bar"
814
- end
815
-
816
- after do
817
- puts body
818
- end
819
-
820
- It is also possible to pass a block to +body+, which will be executed by the
821
- Rack handler (this can be used to implement streaming, see "Return Values").
822
-
823
- Similar to the body, you can also set the status code and headers:
824
-
825
- get '/foo' do
826
- status 418
827
- headers \
828
- "Allow" => "BREW, POST, GET, PROPFIND, WHEN",
829
- "Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
830
- body "I'm a tea pot!"
831
- end
832
-
833
- Like +body+, +headers+ and +status+ with no arguments can be used to access
834
- their current values.
835
-
836
- === Streaming Responses
837
-
838
- Sometimes you want to start sending out data while still generating parts of
839
- the response body. In extreme examples, you want to keep sending data until
840
- the client closes the connection. You can use the +stream+ helper to avoid
841
- creating your own wrapper:
842
-
843
- get '/' do
844
- stream do |out|
845
- out << "It's gonna be legen -\n"
846
- sleep 0.5
847
- out << " (wait for it) \n"
848
- sleep 1
849
- out << "- dary!\n"
850
- end
851
- end
852
-
853
- This allows you to implement streaming APIs,
854
- {Server Sent Events}[http://dev.w3.org/html5/eventsource/] and can be used as
855
- the basis for {WebSockets}[http://en.wikipedia.org/wiki/WebSocket]. It can also be
856
- used to increase throughput if some but not all content depends on a slow
857
- resource.
858
-
859
- Note that the streaming behavior, especially the number of concurrent requests,
860
- highly depends on the web server used to serve the application. Some servers,
861
- like WEBRick, might not even support streaming at all. If the server does not
862
- support streaming, the body will be sent all at once after the block passed to
863
- +stream+ finishes executing. Streaming does not work at all with Shotgun.
864
-
865
- If the optional parameter is set to +keep_open+, it will not call +close+ on
866
- the stream object, allowing you to close it at any later point in the
867
- execution flow. This only works on evented servers, like Thin and Rainbows.
868
- Other servers will still close the stream:
869
-
870
- # long polling
871
-
872
- set :server, :thin
873
- connections = []
874
-
875
- get '/subscribe' do
876
- # register a client's interest in server events
877
- stream(:keep_open) { |out| connections << out }
878
-
879
- # purge dead connections
880
- connections.reject!(&:closed?)
881
-
882
- # acknowledge
883
- "subscribed"
884
- end
885
-
886
- post '/message' do
887
- connections.each do |out|
888
- # notify client that a new message has arrived
889
- out << params[:message] << "\n"
890
-
891
- # indicate client to connect again
892
- out.close
893
- end
894
-
895
- # acknowledge
896
- "message received"
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
- If supported by the Rack handler, other means than streaming from the Ruby
1103
- process will be used. If you use this helper method, Sinatra will automatically
1104
- handle range requests.
1105
-
1106
- === Accessing the Request Object
1107
-
1108
- The incoming request object can be accessed from request level (filter, routes,
1109
- error handlers) through the <tt>request</tt> method:
1110
-
1111
- # app running on http://example.com/example
1112
- get '/foo' do
1113
- t = %w[text/css text/html application/javascript]
1114
- request.accept # ['text/html', '*/*']
1115
- request.accept? 'text/xml' # true
1116
- request.preferred_type(t) # 'text/html'
1117
- request.body # request body sent by the client (see below)
1118
- request.scheme # "http"
1119
- request.script_name # "/example"
1120
- request.path_info # "/foo"
1121
- request.port # 80
1122
- request.request_method # "GET"
1123
- request.query_string # ""
1124
- request.content_length # length of request.body
1125
- request.media_type # media type of request.body
1126
- request.host # "example.com"
1127
- request.get? # true (similar methods for other verbs)
1128
- request.form_data? # false
1129
- request["some_param"] # value of some_param parameter. [] is a shortcut to the params hash.
1130
- request.referrer # the referrer of the client or '/'
1131
- request.user_agent # user agent (used by :agent condition)
1132
- request.cookies # hash of browser cookies
1133
- request.xhr? # is this an ajax request?
1134
- request.url # "http://example.com/example/foo"
1135
- request.path # "/example/foo"
1136
- request.ip # client IP address
1137
- request.secure? # false (would be true over ssl)
1138
- request.forwarded? # true (if running behind a reverse proxy)
1139
- request.env # raw env hash handed in by Rack
1140
- end
1141
-
1142
- Some options, like <tt>script_name</tt> or <tt>path_info</tt>, can also be
1143
- written:
1144
-
1145
- before { request.path_info = "/" }
1146
-
1147
- get "/" do
1148
- "all requests end up here"
1149
- end
1150
-
1151
- The <tt>request.body</tt> is an IO or StringIO object:
1152
-
1153
- post "/api" do
1154
- request.body.rewind # in case someone already read it
1155
- data = JSON.parse request.body.read
1156
- "Hello #{data['name']}!"
1157
- end
1158
-
1159
- === Attachments
1160
-
1161
- You can use the +attachment+ helper to tell the browser the response should be
1162
- stored on disk rather than displayed in the browser:
1163
-
1164
- get '/' do
1165
- attachment
1166
- "store it!"
1167
- end
1168
-
1169
- You can also pass it a file name:
1170
-
1171
- get '/' do
1172
- attachment "info.txt"
1173
- "store it!"
1174
- end
1175
-
1176
- === Dealing with Date and Time
1177
-
1178
- Sinatra offers a +time_for+ helper method, which, from the given value
1179
- generates a Time object. It is also able to convert +DateTime+, +Date+ and
1180
- similar classes:
1181
-
1182
- get '/' do
1183
- pass if Time.now > time_for('Dec 23, 2012')
1184
- "still time"
1185
- end
1186
-
1187
- This method is used internally by +expires+, +last_modified+ and akin. You can
1188
- therefore easily extend the behavior of those methods by overriding +time_for+
1189
- in your application:
1190
-
1191
- helpers do
1192
- def time_for(value)
1193
- case value
1194
- when :yesterday then Time.now - 24*60*60
1195
- when :tomorrow then Time.now + 24*60*60
1196
- else super
1197
- end
1198
- end
1199
- end
1200
-
1201
- get '/' do
1202
- last_modified :yesterday
1203
- expires :tomorrow
1204
- "hello"
1205
- end
1206
-
1207
- === Looking Up Template Files
1208
-
1209
- The <tt>find_template</tt> helper is used to find template files for rendering:
1210
-
1211
- find_template settings.views, 'foo', Tilt[:haml] do |file|
1212
- puts "could be #{file}"
1213
- end
1214
-
1215
- This is not really useful. But it is useful that you can actually override this
1216
- method to hook in your own lookup mechanism. For instance, if you want to be
1217
- able to use more than one view directory:
1218
-
1219
- set :views, ['views', 'templates']
1220
-
1221
- helpers do
1222
- def find_template(views, name, engine, &block)
1223
- Array(views).each { |v| super(v, name, engine, &block) }
1224
- end
1225
- end
1226
-
1227
- Another example would be using different directories for different engines:
1228
-
1229
- set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
1230
-
1231
- helpers do
1232
- def find_template(views, name, engine, &block)
1233
- _, folder = views.detect { |k,v| engine == Tilt[k] }
1234
- folder ||= views[:default]
1235
- super(folder, name, engine, &block)
1236
- end
1237
- end
1238
-
1239
- You can also easily wrap this up in an extension and share with others!
1240
-
1241
- Note that <tt>find_template</tt> does not check if the file really exists but
1242
- rather calls the given block for all possible paths. This is not a performance
1243
- issue, since +render+ will use +break+ as soon as a file is found. Also,
1244
- template locations (and content) will be cached if you are not running in
1245
- development mode. You should keep that in mind if you write a really crazy
1246
- method.
1247
-
1248
- == Configuration
1249
-
1250
- Run once, at startup, in any environment:
1251
-
1252
- configure do
1253
- # setting one option
1254
- set :option, 'value'
1255
-
1256
- # setting multiple options
1257
- set :a => 1, :b => 2
1258
-
1259
- # same as `set :option, true`
1260
- enable :option
1261
-
1262
- # same as `set :option, false`
1263
- disable :option
1264
-
1265
- # you can also have dynamic settings with blocks
1266
- set(:css_dir) { File.join(views, 'css') }
1267
- end
1268
-
1269
- Run only when the environment (RACK_ENV environment variable) is set to
1270
- <tt>:production</tt>:
1271
-
1272
- configure :production do
1273
- ...
1274
- end
1275
-
1276
- Run when the environment is set to either <tt>:production</tt> or
1277
- <tt>:test</tt>:
1278
-
1279
- configure :production, :test do
1280
- ...
1281
- end
1282
-
1283
- You can access those options via <tt>settings</tt>:
1284
-
1285
- configure do
1286
- set :foo, 'bar'
1287
- end
1288
-
1289
- get '/' do
1290
- settings.foo? # => true
1291
- settings.foo # => 'bar'
1292
- ...
1293
- end
1294
-
1295
- === Configuring attack protection
1296
-
1297
- Sinatra is using
1298
- {Rack::Protection}[https://github.com/rkh/rack-protection#readme] to defend
1299
- your application against common, opportunistic attacks. You can easily disable
1300
- this behavior (which will open up your application to tons of common
1301
- vulnerabilities):
1302
-
1303
- disable :protection
1304
-
1305
- To skip a single defense layer, set +protection+ to an options hash:
1306
-
1307
- set :protection, :except => :path_traversal
1308
-
1309
- You can also hand in an array in order to disable a list of protections:
1310
-
1311
- set :protection, :except => [:path_traversal, :session_hijacking]
1312
-
1313
- === Available Settings
1314
-
1315
- [absolute_redirects] If disabled, Sinatra will allow relative redirects,
1316
- however, Sinatra will no longer conform with RFC 2616
1317
- (HTTP 1.1), which only allows absolute redirects.
1318
-
1319
- Enable if your app is running behind a reverse proxy that
1320
- has not been set up properly. Note that the +url+ helper
1321
- will still produce absolute URLs, unless you pass in
1322
- +false+ as second parameter.
1323
-
1324
- Disabled per default.
1325
-
1326
- [add_charsets] mime types the <tt>content_type</tt> helper will
1327
- automatically add the charset info to.
1328
-
1329
- You should add to it rather than overriding this option:
1330
-
1331
- settings.add_charsets << "application/foobar"
1332
-
1333
- [app_file] Path to the main application file, used to detect project
1334
- root, views and public folder and inline templates.
1335
-
1336
- [bind] IP address to bind to (default: 0.0.0.0).
1337
- Only used for built-in server.
1338
-
1339
- [default_encoding] encoding to assume if unknown
1340
- (defaults to <tt>"utf-8"</tt>).
1341
-
1342
- [dump_errors] display errors in the log.
1343
-
1344
- [environment] current environment, defaults to <tt>ENV['RACK_ENV']</tt>,
1345
- or <tt>"development"</tt> if not available.
1346
-
1347
- [logging] use the logger.
1348
-
1349
- [lock] Places a lock around every request, only running
1350
- processing on request per Ruby process concurrently.
1351
-
1352
- Enabled if your app is not thread-safe.
1353
- Disabled per default.
1354
-
1355
- [method_override] use <tt>_method</tt> magic to allow put/delete forms in
1356
- browsers that don't support it.
1357
-
1358
- [port] Port to listen on. Only used for built-in server.
1359
-
1360
- [prefixed_redirects] Whether or not to insert <tt>request.script_name</tt>
1361
- into redirects if no absolute path is given. That way
1362
- <tt>redirect '/foo'</tt> would behave like
1363
- <tt>redirect to('/foo')</tt>. Disabled per default.
1364
-
1365
- [protection] Whether or not to enable web attack protections. See
1366
- protection section above.
1367
-
1368
- [public_folder] Path to the folder public files are served from. Only
1369
- used if static file serving is enabled (see
1370
- <tt>static</tt> setting below). Inferred from
1371
- <tt>app_file</tt> setting if not set.
1372
-
1373
- [reload_templates] whether or not to reload templates between requests.
1374
- Enabled in development mode.
1375
-
1376
- [root] Path to project root folder. Inferred from +app_file+
1377
- setting if not set.
1378
-
1379
- [raise_errors] raise exceptions (will stop application). Enabled
1380
- by default when <tt>environment</tt> is set to
1381
- <tt>"test"</tt>, disabled otherwise.
1382
-
1383
- [run] if enabled, Sinatra will handle starting the web server,
1384
- do not enable if using rackup or other means.
1385
-
1386
- [running] is the built-in server running now?
1387
- do not change this setting!
1388
-
1389
- [server] server or list of servers to use for built-in server.
1390
- defaults to ['thin', 'mongrel', 'webrick'], order
1391
- indicates priority.
1392
-
1393
- [sessions] enable cookie based sessions support using
1394
- <tt>Rack::Session::Cookie</tt>. See 'Using Sessions'
1395
- section for more information.
1396
-
1397
- [show_exceptions] show a stack trace in the browser when an exception
1398
- happens. Enabled by default when <tt>environment</tt>
1399
- is set to <tt>"development"</tt>, disabled otherwise.
1400
- Can also be set to <tt>:after_handler</tt> to trigger
1401
- app-specified error handling before showing a stack
1402
- trace in the browser.
1403
-
1404
- [static] Whether Sinatra should handle serving static files.
1405
- Disable when using a Server able to do this on its own.
1406
- Disabling will boost performance.
1407
- Enabled per default in classic style, disabled for
1408
- modular apps.
1409
-
1410
- [static_cache_control] When Sinatra is serving static files, set this to add
1411
- <tt>Cache-Control</tt> headers to the responses. Uses the
1412
- +cache_control+ helper. Disabled by default.
1413
- Use an explicit array when setting multiple values:
1414
- <tt>set :static_cache_control, [:public, :max_age => 300]</tt>
1415
-
1416
- [threaded] If set to +true+, will tell Thin to use
1417
- <tt>EventMachine.defer</tt> for processing the request.
1418
-
1419
- [views] Path to the views folder. Inferred from <tt>app_file</tt>
1420
- setting if not set.
1421
-
1422
- == Environments
1423
-
1424
- There are three predefined +environments+: <tt>"development"</tt>,
1425
- <tt>"production"</tt> and <tt>"test"</tt>. Environments can be set
1426
- through the +RACK_ENV+ environment variable. The default value is
1427
- <tt>"development"</tt>. In this mode, all templates are reloaded between
1428
- requests. Special <tt>not_found</tt> and <tt>error</tt> handlers are installed
1429
- for this environment so you will see a stack trace in your browser.
1430
- In <tt>"production"</tt> and <tt>"test"</tt> templates are cached by default.
1431
-
1432
- To run different environments use the <tt>-e</tt> option:
1433
-
1434
- ruby my_app.rb -e [ENVIRONMENT]
1435
-
1436
- You can use predefined methods: +development?+, +test?+ and +production?+ to
1437
- check which enviroment is currently set.
1438
-
1439
- == Error Handling
1440
-
1441
- Error handlers run within the same context as routes and before filters, which
1442
- means you get all the goodies it has to offer, like <tt>haml</tt>,
1443
- <tt>erb</tt>, <tt>halt</tt>, etc.
1444
-
1445
- === Not Found
1446
-
1447
- When a <tt>Sinatra::NotFound</tt> exception is raised, or the response's status
1448
- code is 404, the <tt>not_found</tt> handler is invoked:
1449
-
1450
- not_found do
1451
- 'This is nowhere to be found.'
1452
- end
1453
-
1454
- === Error
1455
-
1456
- The +error+ handler is invoked any time an exception is raised from a route
1457
- block or a filter. The exception object can be obtained from the
1458
- <tt>sinatra.error</tt> Rack variable:
1459
-
1460
- error do
1461
- 'Sorry there was a nasty error - ' + env['sinatra.error'].name
1462
- end
1463
-
1464
- Custom errors:
1465
-
1466
- error MyCustomError do
1467
- 'So what happened was...' + env['sinatra.error'].message
1468
- end
1469
-
1470
- Then, if this happens:
1471
-
1472
- get '/' do
1473
- raise MyCustomError, 'something bad'
1474
- end
1475
-
1476
- You get this:
1477
-
1478
- So what happened was... something bad
1479
-
1480
- Alternatively, you can install an error handler for a status code:
1481
-
1482
- error 403 do
1483
- 'Access forbidden'
1484
- end
1485
-
1486
- get '/secret' do
1487
- 403
1488
- end
1489
-
1490
- Or a range:
1491
-
1492
- error 400..510 do
1493
- 'Boom'
1494
- end
1495
-
1496
- Sinatra installs special <tt>not_found</tt> and <tt>error</tt> handlers when
1497
- running under the development environment.
1498
-
1499
- == Rack Middleware
1500
-
1501
- Sinatra rides on Rack[http://rack.rubyforge.org/], a minimal standard
1502
- interface for Ruby web frameworks. One of Rack's most interesting capabilities
1503
- for application developers is support for "middleware" -- components that sit
1504
- between the server and your application monitoring and/or manipulating the
1505
- HTTP request/response to provide various types of common functionality.
1506
-
1507
- Sinatra makes building Rack middleware pipelines a cinch via a top-level
1508
- +use+ method:
1509
-
1510
- require 'sinatra'
1511
- require 'my_custom_middleware'
1512
-
1513
- use Rack::Lint
1514
- use MyCustomMiddleware
1515
-
1516
- get '/hello' do
1517
- 'Hello World'
1518
- end
1519
-
1520
- The semantics of +use+ are identical to those defined for the
1521
- Rack::Builder[http://rack.rubyforge.org/doc/classes/Rack/Builder.html] DSL
1522
- (most frequently used from rackup files). For example, the +use+ method
1523
- accepts multiple/variable args as well as blocks:
1524
-
1525
- use Rack::Auth::Basic do |username, password|
1526
- username == 'admin' && password == 'secret'
1527
- end
1528
-
1529
- Rack is distributed with a variety of standard middleware for logging,
1530
- debugging, URL routing, authentication, and session handling. Sinatra uses
1531
- many of these components automatically based on configuration so you
1532
- typically don't have to +use+ them explicitly.
1533
-
1534
- You can find useful middleware in
1535
- {rack}[https://github.com/rack/rack/tree/master/lib/rack],
1536
- {rack-contrib}[https://github.com/rack/rack-contrib#readme],
1537
- with {CodeRack}[http://coderack.org/] or in the
1538
- {Rack wiki}[https://github.com/rack/rack/wiki/List-of-Middleware].
1539
-
1540
- == Testing
1541
-
1542
- Sinatra tests can be written using any Rack-based testing library or framework.
1543
- {Rack::Test}[http://rdoc.info/github/brynary/rack-test/master/frames]
1544
- is recommended:
1545
-
1546
- require 'my_sinatra_app'
1547
- require 'test/unit'
1548
- require 'rack/test'
1549
-
1550
- class MyAppTest < Test::Unit::TestCase
1551
- include Rack::Test::Methods
1552
-
1553
- def app
1554
- Sinatra::Application
1555
- end
1556
-
1557
- def test_my_default
1558
- get '/'
1559
- assert_equal 'Hello World!', last_response.body
1560
- end
1561
-
1562
- def test_with_params
1563
- get '/meet', :name => 'Frank'
1564
- assert_equal 'Hello Frank!', last_response.body
1565
- end
1566
-
1567
- def test_with_rack_env
1568
- get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
1569
- assert_equal "You're using Songbird!", last_response.body
1570
- end
1571
- end
1572
-
1573
- == Sinatra::Base - Middleware, Libraries, and Modular Apps
1574
-
1575
- Defining your app at the top-level works well for micro-apps but has
1576
- considerable drawbacks when building reusable components such as Rack
1577
- middleware, Rails metal, simple libraries with a server component, or
1578
- even Sinatra extensions. The top-level DSL pollutes the Object namespace
1579
- and assumes a micro-app style configuration (e.g., a single application
1580
- file, <tt>./public</tt> and <tt>./views</tt> directories, logging, exception
1581
- detail page, etc.). That's where <tt>Sinatra::Base</tt> comes into play:
1582
-
1583
- require 'sinatra/base'
1584
-
1585
- class MyApp < Sinatra::Base
1586
- set :sessions, true
1587
- set :foo, 'bar'
1588
-
1589
- get '/' do
1590
- 'Hello world!'
1591
- end
1592
- end
1593
-
1594
- The methods available to <tt>Sinatra::Base</tt> subclasses are exactly as those
1595
- available via the top-level DSL. Most top-level apps can be converted to
1596
- <tt>Sinatra::Base</tt> components with two modifications:
1597
-
1598
- * Your file should require <tt>sinatra/base</tt> instead of +sinatra+;
1599
- otherwise, all of Sinatra's DSL methods are imported into the main
1600
- namespace.
1601
- * Put your app's routes, error handlers, filters, and options in a subclass
1602
- of <tt>Sinatra::Base</tt>.
1603
-
1604
- <tt>Sinatra::Base</tt> is a blank slate. Most options are disabled by default,
1605
- including the built-in server. See
1606
- {Options and Configuration}[http://sinatra.github.com/configuration.html]
1607
- for details on available options and their behavior.
1608
-
1609
- === Modular vs. Classic Style
1610
-
1611
- Contrary to common belief, there is nothing wrong with classic style. If it
1612
- suits your application, you do not have to switch to a modular application.
1613
-
1614
- There are only two downsides compared with modular style:
1615
-
1616
- * You may only have one Sinatra application per Ruby process. If you plan to
1617
- use more, switch to modular style.
1618
-
1619
- * Classic style pollutes Object with delegator methods. If you plan to ship
1620
- your application in a library/gem, switch to modular style.
1621
-
1622
- There is no reason you cannot mix modular and classic style.
1623
-
1624
- If switching from one style to the other, you should be aware of slightly
1625
- different default settings:
1626
-
1627
- Setting Classic Modular
1628
-
1629
- app_file file loading sinatra file subclassing Sinatra::Base
1630
- run $0 == app_file false
1631
- logging true false
1632
- method_override true false
1633
- inline_templates true false
1634
- static true false
1635
-
1636
-
1637
- === Serving a Modular Application
1638
-
1639
- There are two common options for starting a modular app, actively starting with
1640
- <tt>run!</tt>:
1641
-
1642
- # my_app.rb
1643
- require 'sinatra/base'
1644
-
1645
- class MyApp < Sinatra::Base
1646
- # ... app code here ...
1647
-
1648
- # start the server if ruby file executed directly
1649
- run! if app_file == $0
1650
- end
1651
-
1652
- Start with:
1653
-
1654
- ruby my_app.rb
1655
-
1656
- Or with a <tt>config.ru</tt>, which allows using any Rack handler:
1657
-
1658
- # config.ru (run with rackup)
1659
- require './my_app'
1660
- run MyApp
1661
-
1662
- Run:
1663
-
1664
- rackup -p 4567
1665
-
1666
- === Using a Classic Style Application with a config.ru
1667
-
1668
- Write your app file:
1669
-
1670
- # app.rb
1671
- require 'sinatra'
1672
-
1673
- get '/' do
1674
- 'Hello world!'
1675
- end
1676
-
1677
- And a corresponding <tt>config.ru</tt>:
1678
-
1679
- require './app'
1680
- run Sinatra::Application
1681
-
1682
- === When to use a config.ru?
1683
-
1684
- Good signs you probably want to use a <tt>config.ru</tt>:
1685
-
1686
- * You want to deploy with a different Rack handler (Passenger, Unicorn,
1687
- Heroku, ...).
1688
- * You want to use more than one subclass of <tt>Sinatra::Base</tt>.
1689
- * You want to use Sinatra only for middleware, but not as endpoint.
1690
-
1691
- <b>There is no need to switch to a <tt>config.ru</tt> only because you
1692
- switched to modular style, and you don't have to use modular style for running
1693
- with a <tt>config.ru</tt>.</b>
1694
-
1695
- === Using Sinatra as Middleware
1696
-
1697
- Not only is Sinatra able to use other Rack middleware, any Sinatra application
1698
- can in turn be added in front of any Rack endpoint as middleware itself. This
1699
- endpoint could be another Sinatra application, or any other Rack-based
1700
- application (Rails/Ramaze/Camping/...):
1701
-
1702
- require 'sinatra/base'
1703
-
1704
- class LoginScreen < Sinatra::Base
1705
- enable :sessions
1706
-
1707
- get('/login') { haml :login }
1708
-
1709
- post('/login') do
1710
- if params[:name] == 'admin' && params[:password] == 'admin'
1711
- session['user_name'] = params[:name]
1712
- else
1713
- redirect '/login'
1714
- end
1715
- end
1716
- end
1717
-
1718
- class MyApp < Sinatra::Base
1719
- # middleware will run before filters
1720
- use LoginScreen
1721
-
1722
- before do
1723
- unless session['user_name']
1724
- halt "Access denied, please <a href='/login'>login</a>."
1725
- end
1726
- end
1727
-
1728
- get('/') { "Hello #{session['user_name']}." }
1729
- end
1730
-
1731
- === Dynamic Application Creation
1732
-
1733
- Sometimes you want to create new applications at runtime without having to
1734
- assign them to a constant, you can do this with <tt>Sinatra.new</tt>:
1735
-
1736
- require 'sinatra/base'
1737
- my_app = Sinatra.new { get('/') { "hi" } }
1738
- my_app.run!
1739
-
1740
- It takes the application to inherit from as optional argument:
1741
-
1742
- # config.ru (run with rackup)
1743
- require 'sinatra/base'
1744
-
1745
- controller = Sinatra.new do
1746
- enable :logging
1747
- helpers MyHelpers
1748
- end
1749
-
1750
- map('/a') do
1751
- run Sinatra.new(controller) { get('/') { 'a' } }
1752
- end
1753
-
1754
- map('/b') do
1755
- run Sinatra.new(controller) { get('/') { 'b' } }
1756
- end
1757
-
1758
- This is especially useful for testing Sinatra extensions or using Sinatra in
1759
- your own library.
1760
-
1761
- This also makes using Sinatra as middleware extremely easy:
1762
-
1763
- require 'sinatra/base'
1764
-
1765
- use Sinatra do
1766
- get('/') { ... }
1767
- end
1768
-
1769
- run RailsProject::Application
1770
-
1771
- == Scopes and Binding
1772
-
1773
- The scope you are currently in determines what methods and variables are
1774
- available.
1775
-
1776
- === Application/Class Scope
1777
-
1778
- Every Sinatra application corresponds to a subclass of <tt>Sinatra::Base</tt>.
1779
- If you are using the top-level DSL (<tt>require 'sinatra'</tt>), then this
1780
- class is <tt>Sinatra::Application</tt>, otherwise it is the subclass you
1781
- created explicitly. At class level you have methods like +get+ or +before+, but
1782
- you cannot access the +request+ object or the +session+, as there only is a
1783
- single application class for all requests.
1784
-
1785
- Options created via +set+ are methods at class level:
1786
-
1787
- class MyApp < Sinatra::Base
1788
- # Hey, I'm in the application scope!
1789
- set :foo, 42
1790
- foo # => 42
1791
-
1792
- get '/foo' do
1793
- # Hey, I'm no longer in the application scope!
1794
- end
1795
- end
1796
-
1797
- You have the application scope binding inside:
1798
-
1799
- * Your application class body
1800
- * Methods defined by extensions
1801
- * The block passed to +helpers+
1802
- * Procs/blocks used as value for +set+
1803
- * The block passed to <tt>Sinatra.new</tt>
1804
-
1805
- You can reach the scope object (the class) like this:
1806
-
1807
- * Via the object passed to configure blocks (<tt>configure { |c| ... }</tt>)
1808
- * +settings+ from within request scope
1809
-
1810
- === Request/Instance Scope
1811
-
1812
- For every incoming request, a new instance of your application class is
1813
- created and all handler blocks run in that scope. From within this scope you
1814
- can access the +request+ and +session+ object or call rendering methods like
1815
- +erb+ or +haml+. You can access the application scope from within the request
1816
- scope via the +settings+ helper:
1817
-
1818
- class MyApp < Sinatra::Base
1819
- # Hey, I'm in the application scope!
1820
- get '/define_route/:name' do
1821
- # Request scope for '/define_route/:name'
1822
- @value = 42
1823
-
1824
- settings.get("/#{params[:name]}") do
1825
- # Request scope for "/#{params[:name]}"
1826
- @value # => nil (not the same request)
1827
- end
1828
-
1829
- "Route defined!"
1830
- end
1831
- end
1832
-
1833
- You have the request scope binding inside:
1834
-
1835
- * get/head/post/put/delete/options blocks
1836
- * before/after filters
1837
- * helper methods
1838
- * templates/views
1839
-
1840
- === Delegation Scope
1841
-
1842
- The delegation scope just forwards methods to the class scope. However, it
1843
- does not behave 100% like the class scope, as you do not have the class
1844
- binding. Only methods explicitly marked for delegation are available and you
1845
- do not share variables/state with the class scope (read: you have a different
1846
- +self+). You can explicitly add method delegations by calling
1847
- <tt>Sinatra::Delegator.delegate :method_name</tt>.
1848
-
1849
- You have the delegate scope binding inside:
1850
-
1851
- * The top level binding, if you did <tt>require "sinatra"</tt>
1852
- * An object extended with the <tt>Sinatra::Delegator</tt> mixin
1853
-
1854
- Have a look at the code for yourself: here's the
1855
- {Sinatra::Delegator mixin}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/base.rb#L1128]
1856
- being {included into the main namespace}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/main.rb#L28].
1857
-
1858
- == Command Line
1859
-
1860
- Sinatra applications can be run directly:
1861
-
1862
- ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-o HOST] [-s HANDLER]
1863
-
1864
- Options are:
1865
-
1866
- -h # help
1867
- -p # set the port (default is 4567)
1868
- -o # set the host (default is 0.0.0.0)
1869
- -e # set the environment (default is development)
1870
- -s # specify rack server/handler (default is thin)
1871
- -x # turn on the mutex lock (default is off)
1872
-
1873
- == Requirement
1874
-
1875
- The following Ruby versions are officially supported:
1876
-
1877
- [ Ruby 1.8.7 ]
1878
- 1.8.7 is fully supported, however, if nothing is keeping you from it, we
1879
- recommend upgrading to 1.9.2 or switching to JRuby or Rubinius. Support for
1880
- 1.8.7 will not be dropped before Sinatra 2.0 and Ruby 2.0 except maybe for
1881
- the unlikely event of 1.8.8 being released. Even then, we might continue
1882
- supporting it. <b>Ruby 1.8.6 is no longer supported.</b> If you want to run
1883
- with 1.8.6, downgrade to Sinatra 1.2, which will receive bug fixes until
1884
- Sinatra 1.4.0 is released.
1885
-
1886
- [ Ruby 1.9.2 ]
1887
- 1.9.2 is fully supported and recommended. Do not use 1.9.2p0, it is known to
1888
- cause segmentation faults when running Sinatra. Support will continue at least
1889
- until the release of Ruby 1.9.4/2.0 and support for the latest 1.9 release
1890
- will continue as long as it is still supported by the Ruby core team.
1891
-
1892
- [ Ruby 1.9.3 ]
1893
- 1.9.3 is fully supported and recommended. Please note that switching to 1.9.3
1894
- from an earlier version will invalidate all sessions.
1895
-
1896
- [ Rubinius ]
1897
- Rubinius is officially supported (Rubinius >= 1.2.4), everything, including
1898
- all template languages, works. The upcoming 2.0 release is supported as
1899
- well, including 1.9 mode.
1900
-
1901
- [ JRuby ]
1902
- JRuby is officially supported (JRuby >= 1.6.7). No issues with third party
1903
- template libraries are known, however, if you choose to use JRuby, please
1904
- look into JRuby rack handlers, as the Thin web server is not fully supported
1905
- on JRuby. JRuby's support for C extensions is still experimental, which only
1906
- affects RDiscount, Redcarpet, RedCloth and Yajl templates as well as Thin
1907
- and Mongrel at the moment.
1908
-
1909
- We also keep an eye on upcoming Ruby versions.
1910
-
1911
- The following Ruby implementations are not officially supported but still are
1912
- known to run Sinatra:
1913
-
1914
- * Older versions of JRuby and Rubinius
1915
- * Ruby Enterprise Edition
1916
- * MacRuby, Maglev, IronRuby
1917
- * Ruby 1.9.0 and 1.9.1 (but we do recommend against using those)
1918
-
1919
- Not being officially supported means if things only break there and not on a
1920
- supported platform, we assume it's not our issue but theirs.
1921
-
1922
- We also run our CI against ruby-head (the upcoming 2.0.0) and the 1.9.4
1923
- branch, but we can't guarantee anything, since it is constantly moving. Expect
1924
- both 1.9.4p0 and 2.0.0p0 to be supported.
1925
-
1926
- Sinatra should work on any operating system supported by the chosen Ruby
1927
- implementation.
1928
-
1929
- You will not be able to run Sinatra on Cardinal, SmallRuby, BlueRuby or any
1930
- Ruby version prior to 1.8.7 as of the time being.
1931
-
1932
- == The Bleeding Edge
1933
-
1934
- If you would like to use Sinatra's latest bleeding code, feel free to run your
1935
- application against the master branch, it should be rather stable.
1936
-
1937
- We also push out prerelease gems from time to time, so you can do a
1938
-
1939
- gem install sinatra --pre
1940
-
1941
- To get some of the latest features.
1942
-
1943
- === With Bundler
1944
-
1945
- If you want to run your application with the latest Sinatra, using
1946
- {Bundler}[http://gembundler.com/] is the recommended way.
1947
-
1948
- First, install bundler, if you haven't:
1949
-
1950
- gem install bundler
1951
-
1952
- Then, in your project directory, create a +Gemfile+:
1953
-
1954
- source :rubygems
1955
- gem 'sinatra', :git => "git://github.com/sinatra/sinatra.git"
1956
-
1957
- # other dependencies
1958
- gem 'haml' # for instance, if you use haml
1959
- gem 'activerecord', '~> 3.0' # maybe you also need ActiveRecord 3.x
1960
-
1961
- Note that you will have to list all your applications dependencies in there.
1962
- Sinatra's direct dependencies (Rack and Tilt) will, however, be automatically
1963
- fetched and added by Bundler.
1964
-
1965
- Now you can run your app like this:
1966
-
1967
- bundle exec ruby myapp.rb
1968
-
1969
- === Roll Your Own
1970
-
1971
- Create a local clone and run your app with the <tt>sinatra/lib</tt> directory
1972
- on the <tt>$LOAD_PATH</tt>:
1973
-
1974
- cd myapp
1975
- git clone git://github.com/sinatra/sinatra.git
1976
- ruby -Isinatra/lib myapp.rb
1977
-
1978
- To update the Sinatra sources in the future:
1979
-
1980
- cd myapp/sinatra
1981
- git pull
1982
-
1983
- === Install Globally
1984
-
1985
- You can build the gem on your own:
1986
-
1987
- git clone git://github.com/sinatra/sinatra.git
1988
- cd sinatra
1989
- rake sinatra.gemspec
1990
- rake install
1991
-
1992
- If you install gems as root, the last step should be
1993
-
1994
- sudo rake install
1995
-
1996
- == Versioning
1997
-
1998
- Sinatra follows {Semantic Versioning}[http://semver.org/], both SemVer and
1999
- SemVerTag.
2000
-
2001
- == Further Reading
2002
-
2003
- * {Project Website}[http://www.sinatrarb.com/] - Additional documentation,
2004
- news, and links to other resources.
2005
- * {Contributing}[http://www.sinatrarb.com/contributing] - Find a bug? Need
2006
- help? Have a patch?
2007
- * {Issue tracker}[http://github.com/sinatra/sinatra/issues]
2008
- * {Twitter}[http://twitter.com/sinatra]
2009
- * {Mailing List}[http://groups.google.com/group/sinatrarb/topics]
2010
- * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] on http://freenode.net
2011
- * {Sinatra Book}[http://sinatra-book.gittr.com] Cookbook Tutorial
2012
- * {Sinatra Recipes}[http://recipes.sinatrarb.com/] Community
2013
- contributed recipes
2014
- * API documentation for the {latest release}[http://rubydoc.info/gems/sinatra]
2015
- or the {current HEAD}[http://rubydoc.info/github/sinatra/sinatra] on
2016
- http://rubydoc.info
2017
- * {CI server}[http://ci.rkh.im/view/Sinatra/]