sinatra-acd 1.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +5 -0
  3. data/AUTHORS +61 -0
  4. data/CHANGES +1293 -0
  5. data/Gemfile +76 -0
  6. data/LICENSE +23 -0
  7. data/README.de.md +2864 -0
  8. data/README.es.md +2786 -0
  9. data/README.fr.md +2924 -0
  10. data/README.hu.md +694 -0
  11. data/README.ja.md +2726 -0
  12. data/README.ko.md +2832 -0
  13. data/README.md +2980 -0
  14. data/README.pt-br.md +965 -0
  15. data/README.pt-pt.md +791 -0
  16. data/README.ru.md +2799 -0
  17. data/README.zh.md +2158 -0
  18. data/Rakefile +199 -0
  19. data/examples/chat.rb +61 -0
  20. data/examples/simple.rb +3 -0
  21. data/examples/stream.ru +26 -0
  22. data/lib/sinatra.rb +4 -0
  23. data/lib/sinatra/base.rb +2044 -0
  24. data/lib/sinatra/images/404.png +0 -0
  25. data/lib/sinatra/images/500.png +0 -0
  26. data/lib/sinatra/main.rb +34 -0
  27. data/lib/sinatra/show_exceptions.rb +345 -0
  28. data/lib/sinatra/version.rb +3 -0
  29. data/sinatra.gemspec +19 -0
  30. data/test/asciidoctor_test.rb +72 -0
  31. data/test/base_test.rb +171 -0
  32. data/test/builder_test.rb +91 -0
  33. data/test/coffee_test.rb +90 -0
  34. data/test/compile_test.rb +183 -0
  35. data/test/contest.rb +100 -0
  36. data/test/creole_test.rb +65 -0
  37. data/test/delegator_test.rb +160 -0
  38. data/test/encoding_test.rb +20 -0
  39. data/test/erb_test.rb +116 -0
  40. data/test/extensions_test.rb +98 -0
  41. data/test/filter_test.rb +487 -0
  42. data/test/haml_test.rb +109 -0
  43. data/test/helper.rb +131 -0
  44. data/test/helpers_test.rb +1917 -0
  45. data/test/integration/app.rb +79 -0
  46. data/test/integration_helper.rb +236 -0
  47. data/test/integration_test.rb +104 -0
  48. data/test/less_test.rb +69 -0
  49. data/test/liquid_test.rb +77 -0
  50. data/test/mapped_error_test.rb +285 -0
  51. data/test/markaby_test.rb +80 -0
  52. data/test/markdown_test.rb +82 -0
  53. data/test/mediawiki_test.rb +68 -0
  54. data/test/middleware_test.rb +68 -0
  55. data/test/nokogiri_test.rb +67 -0
  56. data/test/public/favicon.ico +0 -0
  57. data/test/rabl_test.rb +89 -0
  58. data/test/rack_test.rb +45 -0
  59. data/test/radius_test.rb +59 -0
  60. data/test/rdoc_test.rb +66 -0
  61. data/test/readme_test.rb +130 -0
  62. data/test/request_test.rb +97 -0
  63. data/test/response_test.rb +63 -0
  64. data/test/result_test.rb +76 -0
  65. data/test/route_added_hook_test.rb +59 -0
  66. data/test/routing_test.rb +1412 -0
  67. data/test/sass_test.rb +115 -0
  68. data/test/scss_test.rb +88 -0
  69. data/test/server_test.rb +48 -0
  70. data/test/settings_test.rb +582 -0
  71. data/test/sinatra_test.rb +12 -0
  72. data/test/slim_test.rb +102 -0
  73. data/test/static_test.rb +236 -0
  74. data/test/streaming_test.rb +149 -0
  75. data/test/stylus_test.rb +90 -0
  76. data/test/templates_test.rb +382 -0
  77. data/test/textile_test.rb +65 -0
  78. data/test/views/a/in_a.str +1 -0
  79. data/test/views/ascii.erb +2 -0
  80. data/test/views/b/in_b.str +1 -0
  81. data/test/views/calc.html.erb +1 -0
  82. data/test/views/error.builder +3 -0
  83. data/test/views/error.erb +3 -0
  84. data/test/views/error.haml +3 -0
  85. data/test/views/error.sass +2 -0
  86. data/test/views/explicitly_nested.str +1 -0
  87. data/test/views/foo/hello.test +1 -0
  88. data/test/views/hello.asciidoc +1 -0
  89. data/test/views/hello.builder +1 -0
  90. data/test/views/hello.coffee +1 -0
  91. data/test/views/hello.creole +1 -0
  92. data/test/views/hello.erb +1 -0
  93. data/test/views/hello.haml +1 -0
  94. data/test/views/hello.less +5 -0
  95. data/test/views/hello.liquid +1 -0
  96. data/test/views/hello.mab +1 -0
  97. data/test/views/hello.md +1 -0
  98. data/test/views/hello.mediawiki +1 -0
  99. data/test/views/hello.nokogiri +1 -0
  100. data/test/views/hello.rabl +2 -0
  101. data/test/views/hello.radius +1 -0
  102. data/test/views/hello.rdoc +1 -0
  103. data/test/views/hello.sass +2 -0
  104. data/test/views/hello.scss +3 -0
  105. data/test/views/hello.slim +1 -0
  106. data/test/views/hello.str +1 -0
  107. data/test/views/hello.styl +2 -0
  108. data/test/views/hello.test +1 -0
  109. data/test/views/hello.textile +1 -0
  110. data/test/views/hello.wlang +1 -0
  111. data/test/views/hello.yajl +1 -0
  112. data/test/views/layout2.builder +3 -0
  113. data/test/views/layout2.erb +2 -0
  114. data/test/views/layout2.haml +2 -0
  115. data/test/views/layout2.liquid +2 -0
  116. data/test/views/layout2.mab +2 -0
  117. data/test/views/layout2.nokogiri +3 -0
  118. data/test/views/layout2.rabl +3 -0
  119. data/test/views/layout2.radius +2 -0
  120. data/test/views/layout2.slim +3 -0
  121. data/test/views/layout2.str +2 -0
  122. data/test/views/layout2.test +1 -0
  123. data/test/views/layout2.wlang +2 -0
  124. data/test/views/nested.str +1 -0
  125. data/test/views/utf8.erb +2 -0
  126. data/test/wlang_test.rb +87 -0
  127. data/test/yajl_test.rb +86 -0
  128. metadata +280 -0
@@ -0,0 +1,2924 @@
1
+ # Sinatra
2
+ *Attention : Ce document correspond à la traduction de la version anglaise et
3
+ il n'est peut être plus à jour.*
4
+
5
+ Sinatra est un [DSL](http://fr.wikipedia.org/wiki/Langage_dédié) pour
6
+ créer rapidement et facilement des applications web en Ruby :
7
+
8
+ ``` ruby
9
+ # mon_application.rb
10
+ require 'sinatra'
11
+
12
+ get '/' do
13
+ 'Bonjour le monde !'
14
+ end
15
+ ```
16
+
17
+ Installez la gem Sinatra :
18
+
19
+ ``` shell
20
+ gem install sinatra
21
+ ```
22
+
23
+ Puis lancez votre programme :
24
+
25
+ ``` shell
26
+ ruby mon_application.rb
27
+ ```
28
+
29
+ Le résultat est visible sur : http://localhost:4567
30
+
31
+ Il est recommandé d'exécuter également `gem install thin`, pour que
32
+ Sinatra utilise le server Thin quand il est disponible.
33
+
34
+ ## Table des matières
35
+
36
+ * [Sinatra](#sinatra)
37
+ * [Table des matières](#table-des-matières)
38
+ * [Routes](#routes)
39
+ * [Conditions](#conditions)
40
+ * [Valeurs de retour](#valeurs-de-retour)
41
+ * [Masques de route spécifiques](#masques-de-route-spécifiques)
42
+ * [Fichiers statiques](#fichiers-statiques)
43
+ * [Vues / Templates](#vues--templates)
44
+ * [Templates littéraux](#templates-littéraux)
45
+ * [Langages de template disponibles](#langages-de-template-disponibles)
46
+ * [Templates Haml](#templates-haml)
47
+ * [Templates Erb](#templates-erb)
48
+ * [Templates Builder](#templates-builder)
49
+ * [Templates Nokogiri](#templates-nokogiri)
50
+ * [Templates Sass](#templates-sass)
51
+ * [Templates SCSS](#templates-scss)
52
+ * [Templates Less](#templates-less)
53
+ * [Templates Liquid](#templates-liquid)
54
+ * [Templates Markdown](#templates-markdown)
55
+ * [Templates Textile](#templates-textile)
56
+ * [Templates RDoc](#templates-rdoc)
57
+ * [Templates Radius](#templates-radius)
58
+ * [Templates Markaby](#templates-markaby)
59
+ * [Templates RABL](#templates-rabl)
60
+ * [Templates Slim](#templates-slim)
61
+ * [Templates Creole](#templates-creole)
62
+ * [Templates CoffeeScript](#templates-coffeescript)
63
+ * [Templates Stylus](#templates-stylus)
64
+ * [Templates Yajl](#templates-yajl)
65
+ * [Templates WLang](#templates-wlang)
66
+ * [Accéder aux variables dans un Template](#accéder-aux-variables-dans-un-template)
67
+ * [Templates avec `yield` et layouts imbriqués](#templates-avec-yield-et-layouts-imbriqués)
68
+ * [Templates dans le fichier source](#templates-dans-le-fichier-source)
69
+ * [Templates nommés](#templates-nommés)
70
+ * [Associer des extensions de fichier](#associer-des-extensions-de-fichier)
71
+ * [Ajouter son propre moteur de rendu](#ajouter-son-propre-moteur-de-rendu)
72
+ * [Filtres](#filtres)
73
+ * [Helpers](#helpers)
74
+ * [Utiliser les sessions](#utiliser-les-sessions)
75
+ * [Halt](#halt)
76
+ * [Passer](#passer)
77
+ * [Déclencher une autre route](#déclencher-une-autre-route)
78
+ * [Définir le corps, le code retour et les entêtes](#définir-le-corps-le-code-retour-et-les-entêtes)
79
+ * [Faire du streaming](#faire-du-streaming)
80
+ * [Journalisation (Logging)](#journalisation-logging)
81
+ * [Types Mime](#types-mime)
82
+ * [Former des URLs](#former-des-urls)
83
+ * [Redirection du navigateur](#redirection-du-navigateur)
84
+ * [Contrôle du cache](#contrôle-du-cache)
85
+ * [Envoyer des fichiers](#envoyer-des-fichiers)
86
+ * [Accéder à l'objet requête](#accéder-à-lobjet-requête)
87
+ * [Fichiers joints](#fichiers-joints)
88
+ * [Gérer Date et Time](#gérer-date-et-time)
89
+ * [Chercher les fichiers de templates](#chercher-les-fichiers-de-templates)
90
+ * [Configuration](#configuration)
91
+ * [Se protéger des attaques](#se-protéger-des-attaques)
92
+ * [Paramètres disponibles](#paramètres-disponibles)
93
+ * [Environements](#environements)
94
+ * [Gérer les erreurs](#gérer-les-erreurs)
95
+ * [NotFound](#notfound)
96
+ * [Error](#error)
97
+ * [Les Middlewares Rack](#les-middlewares-rack)
98
+ * [Tester](#tester)
99
+ * [Sinatra::Base - Les Middlewares, Bibliothèques, et Applications Modulaires](#sinatrabase---les-middlewares-bibliothèques-et-applications-modulaires)
100
+ * [Style modulaire vs. style classique](#style-modulaire-vs-style-classique)
101
+ * [Servir une application modulaire](#servir-une-application-modulaire)
102
+ * [Utiliser une application de style classique avec un fichier config.ru](#utiliser-une-application-de-style-classique-avec-un-fichier-configru)
103
+ * [Quand utiliser un fichier config.ru ?](#quand-utiliser-un-fichier-configru-)
104
+ * [Utiliser Sinatra comme Middleware](#utiliser-sinatra-comme-middleware)
105
+ * [Création dynamique d'applications](#création-dynamique-dapplications)
106
+ * [Contextes et Binding](#contextes-et-binding)
107
+ * [Contexte de l'application/classe](#contexte-de-lapplicationclasse)
108
+ * [Contexte de la requête/instance](#contexte-de-la-requêteinstance)
109
+ * [Le contexte de délégation](#le-contexte-de-délégation)
110
+ * [Ligne de commande](#ligne-de-commande)
111
+ * [Configuration nécessaire](#configuration-nécessaire)
112
+ * [Essuyer les plâtres](#essuyer-les-plâtres)
113
+ * [Installer avec Bundler](#installer-avec-bundler)
114
+ * [Faire un clone local](#faire-un-clone-local)
115
+ * [Installer globalement](#installer-globalement)
116
+ * [Versions](#versions)
117
+ * [Mais encore](#mais-encore)
118
+
119
+ ## Routes
120
+
121
+ Dans Sinatra, une route est une méthode HTTP couplée à un masque (pattern)
122
+ URL. Chaque route est associée à un bloc :
123
+
124
+ ``` ruby
125
+ get '/' do
126
+ .. montrer quelque chose ..
127
+ end
128
+
129
+ post '/' do
130
+ .. créer quelque chose ..
131
+ end
132
+
133
+ put '/' do
134
+ .. remplacer quelque chose ..
135
+ end
136
+
137
+ patch '/' do
138
+ .. changer quelque chose ..
139
+ end
140
+
141
+ delete '/' do
142
+ .. effacer quelque chose ..
143
+ end
144
+
145
+ options '/' do
146
+ .. paramétrer quelque chose ..
147
+ end
148
+
149
+ link '/' do
150
+ .. relier quelque chose ..
151
+ end
152
+
153
+ unlink '/' do
154
+ .. séparer quelque chose ..
155
+ end
156
+ ```
157
+
158
+ Les routes sont évaluées dans l'ordre où elles ont été définies. La première
159
+ route qui correspond à la requête est appelée.
160
+
161
+ Les masques peuvent inclure des paramètres nommés, accessibles par
162
+ l'intermédiaire du hash `params` :
163
+
164
+ ``` ruby
165
+ get '/bonjour/:nom' do
166
+ # répond aux requêtes "GET /bonjour/foo" et "GET /bonjour/bar"
167
+ # params[:nom] est 'foo' ou 'bar'
168
+ "Bonjour #{params[:nom]} !"
169
+ end
170
+ ```
171
+
172
+ Vous pouvez aussi accéder aux paramètres nommés directement grâce aux
173
+ paramètres du bloc comme ceci :
174
+
175
+ ``` ruby
176
+ get '/bonjour/:nom' do |n|
177
+ # répond aux requêtes "GET /bonjour/foo" et "GET /bonjour/bar"
178
+ # params[:nom] est 'foo' ou 'bar'
179
+ # n contient params[:nom]
180
+ "Bonjour #{n} !"
181
+ end
182
+ ```
183
+
184
+ Une route peut contenir un splat (caractère joker), accessible par
185
+ l'intermédiaire du tableau `params[:splat]` :
186
+
187
+ ``` ruby
188
+ get '/dire/*/a/*' do
189
+ # répond à /dire/bonjour/a/monde
190
+ params[:splat] # => ["bonjour", "monde"]
191
+ end
192
+
193
+ get '/telecharger/*.*' do
194
+ # répond à /telecharger/chemin/vers/fichier.xml
195
+ params[:splat] # => ["chemin/vers/fichier", "xml"]
196
+ end
197
+ ```
198
+
199
+ Ou par l'intermédiaire des paramètres du bloc :
200
+
201
+ ``` ruby
202
+ get '/telecharger/*.*' do |chemin, ext|
203
+ [chemin, ext] # => ["path/to/file", "xml"]
204
+ end
205
+ ```
206
+
207
+ Une route peut aussi être définie par une expression régulière :
208
+
209
+ ``` ruby
210
+ get %r{/bonjour/([\w]+)} do
211
+ "Bonjour, #{params[:captures].first} !"
212
+ end
213
+ ```
214
+
215
+ Là encore on peut utiliser les paramètres de bloc :
216
+
217
+ ``` ruby
218
+ get %r{/bonjour/([\w]+)} do |c|
219
+ "Bonjour, #{c} !"
220
+ end
221
+ ```
222
+
223
+ Les routes peuvent aussi comporter des paramètres optionnels :
224
+
225
+ ``` ruby
226
+ get '/posts.?:format?' do
227
+ # répond à "GET /posts" et aussi à "GET /posts.json", "GET /posts.xml" etc...
228
+ end
229
+ ```
230
+
231
+ A ce propos, à moins d'avoir désactivé la protection contre les attaques par
232
+ "path transversal" (voir plus loin), l'URL demandée peut avoir été modifiée
233
+ avant d'être comparée à vos routes.
234
+
235
+ ## Conditions
236
+
237
+ Les routes peuvent définir toutes sortes de conditions, comme par exemple le
238
+ "user agent" :
239
+
240
+ ``` ruby
241
+ get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
242
+ "Vous utilisez Songbird version #{params[:agent][0]}"
243
+ end
244
+
245
+ get '/foo' do
246
+ # Correspond à tous les autres navigateurs
247
+ end
248
+ ```
249
+
250
+ Les autres conditions disponibles sont `host_name` et `provides` :
251
+
252
+ ``` ruby
253
+ get '/', :host_name => /^admin\./ do
254
+ "Zone Administrateur, Accès refusé !"
255
+ end
256
+
257
+ get '/', :provides => 'html' do
258
+ haml :index
259
+ end
260
+
261
+ get '/', :provides => ['rss', 'atom', 'xml'] do
262
+ builder :feed
263
+ end
264
+ ```
265
+
266
+ Vous pouvez facilement définir vos propres conditions :
267
+
268
+ ``` ruby
269
+ set(:probability) { |value| condition { rand <= value } }
270
+
271
+ get '/gagner_une_voiture', :probability => 0.1 do
272
+ "Vous avez gagné !"
273
+ end
274
+
275
+ get '/gagner_une_voiture' do
276
+ "Désolé, vous avez perdu."
277
+ end
278
+ ```
279
+
280
+ Utilisez un splat (caractère joker) dans le cas d'une condition qui prend
281
+ plusieurs valeurs :
282
+
283
+ ``` ruby
284
+ set(:auth) do |*roles| # <- ici on utilise un splat
285
+ condition do
286
+ unless logged_in? && roles.any? {|role| current_user.in_role? role }
287
+ redirect "/login/", 303
288
+ end
289
+ end
290
+ end
291
+
292
+ get "/mon/compte/", :auth => [:user, :admin] do
293
+ "Informations sur votre compte"
294
+ end
295
+
296
+ get "/reserve/aux/admins/", :auth => :admin do
297
+ "Seuls les administrateurs sont acceptés ici !"
298
+ end
299
+ ```
300
+
301
+ ## Valeurs de retour
302
+
303
+ La valeur renvoyée par le bloc correspondant à une route constitue le corps de
304
+ la réponse qui sera transmise au client HTTP ou du moins au prochain middleware
305
+ dans la pile Rack. Le plus souvent, il s'agit d'une chaîne de caractères,
306
+ comme dans les exemples précédents. Cependant, d'autres valeurs sont
307
+ acceptées.
308
+
309
+ Vous pouvez renvoyer n'importe quel objet qu'il s'agisse d'une réponse Rack
310
+ valide, d'un corps de réponse Rack ou d'un code statut HTTP :
311
+
312
+ * Un tableau de 3 éléments : `[code statut (Fixnum), entêtes (Hash), corps
313
+ de la réponse (répondant à #each)]`
314
+ * Un tableau de 2 élements : `[code statut (Fixnum), corps de la réponse
315
+ (répondant à #each)]`
316
+ * Un objet qui répond à `#each` et qui ne transmet que des chaînes de
317
+ caractères au bloc fourni
318
+ * Un Fixnum représentant le code statut
319
+
320
+ Avec cela, on peut facilement implémenter un streaming par exemple :
321
+
322
+ ``` ruby
323
+ class Stream
324
+ def each
325
+ 100.times { |i| yield "#{i}\n" }
326
+ end
327
+ end
328
+
329
+ get('/') { Stream.new }
330
+ ```
331
+
332
+ Vous pouvez aussi utiliser le helper `stream` (présenté un peu plus loin) pour
333
+ éviter la surcharge et intégrer le traitement relatif au streaming dans le bloc
334
+ de code de la route.
335
+
336
+ ## Masques de route spécifiques
337
+
338
+ Comme cela a été vu auparavant, Sinatra offre la possibilité d'utiliser des
339
+ masques sous forme de chaines de caractères ou des expressions régulières
340
+ pour définir les routes. Mais il est possible de faire bien plus. Vous pouvez
341
+ facilement définir vos propres masques :
342
+
343
+ ``` ruby
344
+ class MasqueToutSauf
345
+ Masque = Struct.new(:captures)
346
+
347
+ def initialize(except)
348
+ @except = except
349
+ @captures = Masque.new([])
350
+ end
351
+
352
+ def match(str)
353
+ @caputres unless @except === str
354
+ end
355
+ end
356
+
357
+ def tout_sauf(masque)
358
+ MasqueToutSauf.new(masque)
359
+ end
360
+
361
+ get tout_sauf("/index") do
362
+ # ...
363
+ end
364
+ ```
365
+
366
+ Notez que l'exemple ci-dessus est bien trop compliqué et que le même résultat
367
+ peut être obtenu avec :
368
+
369
+ ``` ruby
370
+ get // do
371
+ pass if request.path_info == "/index"
372
+ # ...
373
+ end
374
+ ```
375
+
376
+ Ou bien en utilisant la forme négative :
377
+
378
+ ``` ruby
379
+ get %r{^(?!/index$)} do
380
+ # ...
381
+ end
382
+ ```
383
+
384
+ ## Fichiers statiques
385
+
386
+ Les fichiers du dossier `./public` sont servis de façon statique. Vous
387
+ avez la possibilité d'utiliser un autre répertoire en définissant le paramètre
388
+ `:public_folder` :
389
+
390
+ ``` ruby
391
+ set :public_folder, File.dirname(__FILE__) + '/statique'
392
+ ```
393
+
394
+ Notez que le nom du dossier public n'apparait pas dans l'URL. Le fichier
395
+ `./public/css/style.css` sera appelé via l'URL :
396
+ `http://exemple.com/css/style.css`.
397
+
398
+ Utilisez le paramètre `:static_cache_control` pour ajouter l'information
399
+ d'en-tête <tt>Cache-Control</tt> (voir plus loin).
400
+
401
+ ## Vues / Templates
402
+
403
+ Chaqie langage de template est disponible via sa propre méthode de rendu,
404
+ lesquelles renvoient tout simplement une chaîne de caractères.
405
+
406
+ ``` ruby
407
+ get '/' do
408
+ erb :index
409
+ end
410
+ ```
411
+
412
+ Ceci effectue le rendu de la vue `views/index.erb`.
413
+
414
+ Plutôt que d'utiliser le nom d'un template, vous pouvez directement passer
415
+ le contenu du template :
416
+
417
+ ``` ruby
418
+ get '/' do
419
+ code = "<%= Time.now %>"
420
+ erb code
421
+ end
422
+ ```
423
+
424
+ Les méthodes de templates acceptent un second paramètre, un hash d'options :
425
+
426
+ ``` ruby
427
+ get '/' do
428
+ erb :index, :layout => :post
429
+ end
430
+ ```
431
+
432
+ Ceci effectuera le rendu de la vue `views/index.erb` en l'intégrant
433
+ au *layout* `views/post.erb` (les vues Erb sont intégrées par défaut
434
+ au *layout* `views/layout.erb` quand ce fichier existe).
435
+
436
+ Toute option que Sinatra ne comprend pas sera passée au moteur de rendu :
437
+
438
+ ``` ruby
439
+ get '/' do
440
+ haml :index, :format => :html5
441
+ end
442
+ ```
443
+
444
+ Vous pouvez également définir des options par langage de template de façon
445
+ générale :
446
+
447
+ ``` ruby
448
+ set :haml, :format => html5
449
+
450
+ get '/' do
451
+ haml :index
452
+ end
453
+ ```
454
+
455
+ Les options passées à la méthode de rendu prennent le pas sur les options
456
+ définies au moyen de `set`.
457
+
458
+ Options disponibles :
459
+
460
+ <dl>
461
+ <dt>locals</dt>
462
+ <dd>
463
+ Liste de variables locales passées au document. Pratique pour les vues
464
+ partielles.
465
+ Exemple : <tt>erb "<%= foo %>", :locals => {:foo => "bar"}</tt>.
466
+ </dd>
467
+
468
+ <dt>default_encoding</dt>
469
+ <dd>
470
+ Encodage de caractères à utiliser en cas d'incertitude. Par défaut, c'est
471
+ <tt>settings.default_encoding</tt>.
472
+ </dd>
473
+
474
+ <dt>views</dt>
475
+ <dd>
476
+ Dossier de vues dans lequel chercher les templates. Par défaut
477
+ <tt>settings.views</tt>.
478
+ </dd>
479
+
480
+ <dt>layout</dt>
481
+ <dd>
482
+ S'il faut ou non utiliser un layout (<tt>true</tt> ou <tt>false</tt>).
483
+ Indique le template à utiliser lorsque c'est un symbole. Exemple :
484
+ <tt>erb :index, :layout => !request.xhr?</tt>.
485
+ </dd>
486
+
487
+ <dt>content_type</dt>
488
+ <dd>
489
+ Content-Type que le template produit, dépend par défaut du langage de
490
+ template.
491
+ </dd>
492
+
493
+ <dt>scope</dt>
494
+ <dd>
495
+ Contexte sous lequel effectuer le rendu du template. Par défaut il s'agit
496
+ de l'instance de l'application. Si vous changez cela, les variables
497
+ d'instance et les méthodes utilitaires ne seront pas disponibles.
498
+ </dd>
499
+
500
+ <dt>layout_engine</dt>
501
+ <dd>
502
+ Moteur de rendu à utiliser pour le layout. Utile pour les langages ne
503
+ supportant pas les layouts. Il s'agit par défaut du moteur utilisé pour
504
+ le rendu du template. Exemple : <tt>set :rdoc, :layout_engine => :erb</tt>
505
+ </dd>
506
+
507
+ <dt>layout_options</dt>
508
+ <dd>
509
+ Options spécifiques destinées au moteur de rendu. Exemple : <tt>set :rdoc,
510
+ :layout_options => { :views => 'views/layouts' }</tt>
511
+ </dd>
512
+ </dl>
513
+
514
+ Les templates sont supposés se trouver directement dans le dossier
515
+ `./views`. Pour utiliser un dossier de vues différent :
516
+
517
+ ``` ruby
518
+ set :views, settings.root + '/templates'
519
+ ```
520
+
521
+ Il est important de se souvenir que les templates sont toujours référencés
522
+ sous forme de symboles, même lorsqu'ils sont dans un sous-répertoire (dans
523
+ ce cas, utilisez `:'sous_repertoire/template'`). Il faut utiliser
524
+ un symbole car les méthodes de rendu évaluent le contenu des chaînes de
525
+ caractères au lieu de les considérer comme un chemin vers un fichier.
526
+
527
+ ### Templates littéraux
528
+
529
+ ``` ruby
530
+ get '/' do
531
+ haml '%div.title Bonjour le monde'
532
+ end
533
+ ```
534
+
535
+ Générera le code du template spécifié dans la chaîne de caractères.
536
+
537
+ ### Langages de template disponibles
538
+
539
+ Certains langages ont plusieurs implémentations. Pour préciser l'implémentation
540
+ à utiliser (et garantir l'aspect thread-safe), vous devez simplement l'avoir
541
+ chargée au préalable :
542
+
543
+ ``` ruby
544
+ require 'rdiscount' # ou require 'bluecloth'
545
+ get('/') { markdown :index }
546
+ ```
547
+
548
+ #### Templates Haml
549
+
550
+ <table>
551
+ <tr>
552
+ <td>Dépendances</td>
553
+ <td><a href="http://haml.info/" title="haml">haml</a></td>
554
+ </tr>
555
+ <tr>
556
+ <td>Extensions de fichier</td>
557
+ <td><tt>.haml</tt></td>
558
+ </tr>
559
+ <tr>
560
+ <td>Exemple</td>
561
+ <td><tt>haml :index, :format => :html5</tt></td>
562
+ </tr>
563
+ </table>
564
+
565
+ #### Templates Erb
566
+
567
+ <table>
568
+ <tr>
569
+ <td>Dépendances</td>
570
+ <td>
571
+ <a href="http://www.kuwata-lab.com/erubis/" title="erubis">erubis</a>
572
+ ou erb (inclus avec Ruby)
573
+ </td>
574
+ </tr>
575
+ <tr>
576
+ <td>Extensions de fichier</td>
577
+ <td><tt>.erb</tt>, <tt>.rhtml</tt> ou <tt>.erubis</tt> (Erubis seulement)</td>
578
+ </tr>
579
+ <tr>
580
+ <td>Exemple</td>
581
+ <td><tt>erb :index</tt></td>
582
+ </tr>
583
+ </table>
584
+
585
+ #### Templates Builder
586
+
587
+ <table>
588
+ <tr>
589
+ <td>Dépendances</td>
590
+ <td>
591
+ <a href="http://builder.rubyforge.org/" title="builder">builder</a>
592
+ </td>
593
+ </tr>
594
+ <tr>
595
+ <td>Extensions de fichier</td>
596
+ <td><tt>.builder</tt></td>
597
+ </tr>
598
+ <tr>
599
+ <td>Exemple</td>
600
+ <td><tt>builder { |xml| xml.em "salut" }</tt></td>
601
+ </tr>
602
+ </table>
603
+
604
+ Ce moteur accepte également un bloc pour des templates en ligne (voir
605
+ exemple).
606
+
607
+ #### Templates Nokogiri
608
+
609
+ <table>
610
+ <tr>
611
+ <td>Dépendances</td>
612
+ <td><a href="http://nokogiri.org/" title="nokogiri">nokogiri</a></td>
613
+ </tr>
614
+ <tr>
615
+ <td>Extensions de fichier</td>
616
+ <td><tt>.nokogiri</tt></td>
617
+ </tr>
618
+ <tr>
619
+ <td>Exemple</td>
620
+ <td><tt>nokogiri { |xml| xml.em "salut" }</tt>
621
+ </td>
622
+ </tr>
623
+ </table>
624
+
625
+ Ce moteur accepte également un bloc pour des templates en ligne (voir
626
+ exemple).
627
+
628
+ #### Templates Sass
629
+
630
+ <table>
631
+ <tr>
632
+ <td>Dépendances</td>
633
+ <td><a href="http://sass-lang.com/" title="sass">sass</a></td>
634
+ </tr>
635
+ <tr>
636
+ <td>Extensions de fichier</td>
637
+ <td><tt>.sass</tt></td>
638
+ </tr>
639
+ <tr>
640
+ <td>Exemple</td>
641
+ <td><tt>sass :stylesheet, :style => :expanded</tt></td>
642
+ </tr>
643
+ </table>
644
+
645
+ #### Templates SCSS
646
+
647
+ <table>
648
+ <tr>
649
+ <td>Dépendances</td>
650
+ <td><a href="http://sass-lang.com/" title="sass">sass</a></td>
651
+ </tr>
652
+ <tr>
653
+ <td>Extensions de fichier</td>
654
+ <td><tt>.scss</tt></td>
655
+ </tr>
656
+ <tr>
657
+ <td>Exemple</td>
658
+ <td><tt>scss :stylesheet, :style => :expanded</tt></p>
659
+ </td>
660
+ </tr>
661
+ </table>
662
+
663
+ #### Templates Less
664
+
665
+ <table>
666
+ <tr>
667
+ <td>Dépendances</td>
668
+ <td><a href="http://www.lesscss.org/" title="less">less</a></td>
669
+ </tr>
670
+ <tr>
671
+ <td>Extensions de fichier</td>
672
+ <td><tt>.less</tt></td>
673
+ </tr>
674
+ <tr>
675
+ <td>Exemple</td>
676
+ <td><tt>less :stylesheet</tt>
677
+ </td>
678
+ </tr>
679
+ </table>
680
+
681
+ #### Templates Liquid
682
+
683
+ <table>
684
+ <tr>
685
+ <td>Dépendances</td>
686
+ <td><a href="http://www.liquidmarkup.org/" title="liquid">liquid</a></td>
687
+ </tr>
688
+ <tr>
689
+ <td>Extensions de fichier</td>
690
+ <td><tt>.liquid</tt></td>
691
+ </tr>
692
+ <tr>
693
+ <td>Exemple</td>
694
+ <td><tt>liquid :index, :locals => { :key => 'value' }</tt></td>
695
+ </tr>
696
+ </table>
697
+
698
+ Comme vous ne pouvez appeler de méthodes Ruby (autres que `yield`)
699
+ dans un template Liquid, vous aurez sûrement à lui passer des variables
700
+ locales.
701
+
702
+ #### Templates Markdown
703
+
704
+ <table>
705
+ <tr>
706
+ <td><p>Dépendances</p></td>
707
+ <td>
708
+ Au choix :
709
+ <a href="https://github.com/rtomayko/rdiscount" title="RDiscount">RDiscount</a>,
710
+ <a href="https://github.com/vmg/redcarpet" title="RedCarpet">RedCarpet</a>,
711
+ <a href="http://deveiate.org/projects/BlueCloth" title="BlueCloth">BlueCloth</a>,
712
+ <a href="http://kramdown.rubyforge.org/" title="kramdown">kramdown</a>,
713
+ <a href="http://maruku.rubyforge.org/" title="maruku">maruku</a>
714
+ </td>
715
+ </tr>
716
+
717
+ <tr>
718
+ <td>Extensions de fichier</td>
719
+ <td><tt>.markdown</tt>, <tt>.mkd</tt> et <tt>.md</tt></td>
720
+ </tr>
721
+ <tr>
722
+ <td>Exemple</td>
723
+ <td><tt>markdown :index, :layout_engine => :erb</tt></td>
724
+ </tr>
725
+ </table>
726
+
727
+ Il n’est pas possible d’appeler des méthodes depuis markdown, ni de
728
+ lui passer des variables locales. Par conséquent, il sera souvent utilisé
729
+ en combinaison avec un autre moteur de rendu :
730
+
731
+ ``` ruby
732
+ erb :overview, :locals => { :text => markdown(:introduction) }
733
+ ```
734
+
735
+ Notez que vous pouvez également appeler la méthode `markdown` au
736
+ sein d’autres templates :
737
+
738
+ ``` ruby
739
+ %h1 Hello From Haml !
740
+ %p= markdown(:greetings)
741
+ ```
742
+
743
+ Comme vous ne pouvez pas appeler de Ruby au sein de Markdown, vous ne
744
+ pouvez pas utiliser de layouts écrits en Markdown. Toutefois, il
745
+ est possible d’utiliser un moteur de rendu différent pour le template et
746
+ pour le layout en utilisant l’option `:layout_engine`.
747
+
748
+ #### Templates Textile
749
+
750
+ <table>
751
+ <tr>
752
+ <td>Dépendances</td>
753
+ <td><a href="http://redcloth.org/" title="RedCloth">RedCloth</a></td>
754
+ </tr>
755
+ <tr>
756
+ <td>Extensions de fichier</td>
757
+ <td><tt>.textile</tt></td>
758
+ </tr>
759
+ <tr>
760
+ <td>Exemple</td>
761
+ <td><tt>textile :index, :layout_engine => :erb</tt></td>
762
+ </tr>
763
+ </table>
764
+
765
+ Il n’est pas possible d’appeler des méthodes depuis textile, ni de lui
766
+ passer des variables locales. Par conséquent, il sera souvent utilisé en
767
+ combinaison avec un autre moteur de rendu :
768
+
769
+ ``` ruby
770
+ erb :overview, :locals => { :text => textile(:introduction) }
771
+ ```
772
+
773
+ Notez que vous pouvez également appeler la méthode `textile` au
774
+ sein d’autres templates :
775
+
776
+ ``` ruby
777
+ %h1 Hello From Haml !
778
+ %p= textile(:greetings)
779
+ ```
780
+
781
+ Comme vous ne pouvez pas appeler de Ruby au sein de Textile, vous ne pouvez
782
+ pas utiliser de layouts écrits en Textile. Toutefois, il est
783
+ possible d’utiliser un moteur de rendu différent pour le template et
784
+ pour le layout en utilisant l’option `:layout_engine`.
785
+
786
+ #### Templates RDoc
787
+
788
+ <table>
789
+ <tr>
790
+ <td>Dépendances</td>
791
+ <td><a href="http://rdoc.rubyforge.org/" title="RDoc">RDoc</a></td>
792
+ </tr>
793
+ <tr>
794
+ <td>Extensions de fichier</td>
795
+ <td><tt>.rdoc</tt></td>
796
+ </tr>
797
+ <tr>
798
+ <td>Exemple</td>
799
+ <td><tt>rdoc :README, :layout_engine => :erb</tt></td>
800
+ </tr>
801
+ </table>
802
+
803
+ Il n’est pas possible d’appeler des méthodes depuis rdoc, ni de lui
804
+ passer des variables locales. Par conséquent, il sera souvent utilisé en
805
+ combinaison avec un autre moteur de rendu :
806
+
807
+ ``` ruby
808
+ erb :overview, :locals => { :text => rdoc(:introduction) }
809
+ ```
810
+
811
+ Notez que vous pouvez également appeler la méthode `rdoc` au sein
812
+ d’autres templates :
813
+
814
+ ``` ruby
815
+ %h1 Hello From Haml !
816
+ %p= rdoc(:greetings)
817
+ ```
818
+
819
+ Comme vous ne pouvez pas appeler de Ruby au sein de RDoc, vous ne pouvez
820
+ pas utiliser de layouts écrits en RDoc. Toutefois, il est
821
+ possible d’utiliser un moteur de rendu différent pour le template et
822
+ pour le layout en utilisant l’option `:layout_engine`.
823
+
824
+ #### Templates Radius
825
+ <table>
826
+ <tr>
827
+ <td>Dépendances</td>
828
+ <td><a href="http://radius.rubyforge.org/" title="Radius">Radius</a></td>
829
+ </tr>
830
+ <tr>
831
+ <td>Extensions de fichier</td>
832
+ <td><tt>.radius</tt></td>
833
+ </tr>
834
+ <tr>
835
+ <td>Exemple</td>
836
+ <td><tt>radius :index, :locals => { :key => 'value' }</tt></td>
837
+ </tr>
838
+ </table>
839
+
840
+ Comme vous ne pouvez pas appeler de méthodes Ruby depuis un template
841
+ Radius, vous aurez sûrement à lui passer des variables locales.
842
+
843
+ #### Templates Markaby
844
+
845
+ <table>
846
+ <tr>
847
+ <td>Dépendances</td>
848
+ <td><a href="http://markaby.github.com/" title="Markaby">Markaby</a></td>
849
+ </tr>
850
+ <tr>
851
+ <td>Extensions de fichier</td>
852
+ <td><tt>.mab</tt></td>
853
+ </tr>
854
+ <tr>
855
+ <td>Exemple</td>
856
+ <td><tt>markaby { h1 "Bienvenue !" }</tt></td>
857
+ </tr>
858
+ </table>
859
+
860
+ Ce moteur accepte également un bloc pour des templates en ligne (voir
861
+ exemple).
862
+
863
+ #### Templates RABL
864
+
865
+ <table>
866
+ <tr>
867
+ <td>Dépendances</td>
868
+ <td><a href="https://github.com/nesquena/rabl" title="Rabl">Rabl</a></td>
869
+ </tr>
870
+ <tr>
871
+ <td>Extensions de fichier</td>
872
+ <td><tt>.rabl</tt></td>
873
+ </tr>
874
+ <tr>
875
+ <td>Exemple</td>
876
+ <td><tt>rabl :index</tt></td>
877
+ </tr>
878
+ </table>
879
+
880
+ #### Templates Slim
881
+
882
+ <table>
883
+ <tr>
884
+ <td>Dépendances</td>
885
+ <td><a href="http://slim-lang.com/" title="Slim Lang">Slim Lang</a></td>
886
+ </tr>
887
+ <tr>
888
+ <td>Extensions de fichier</td>
889
+ <td><tt>.slim</tt></td>
890
+ </tr>
891
+ <tr>
892
+ <td>Exemple</td>
893
+ <td><tt>slim :index</tt></td>
894
+ </tr>
895
+ </table>
896
+
897
+ #### Templates Creole
898
+
899
+ <table>
900
+ <tr>
901
+ <td>Dépendances</td>
902
+ <td><a href="https://github.com/minad/creole" title="Creole">Creole</a></td>
903
+ </tr>
904
+ <tr>
905
+ <td>Extensions de fichier</td>
906
+ <td><tt>.creole</tt></td>
907
+ </tr>
908
+ <tr>
909
+ <td>Exemple</td>
910
+ <td><tt>creole :wiki, :layout_engine => :erb</tt></td>
911
+ </tr>
912
+ </table>
913
+
914
+ Il n'est pas possible d'appeler des méthodes depuis creole, ni de lui
915
+ passer des variables locales. Par conséquent, il sera souvent utilisé en
916
+ combinaison avec un autre moteur de rendu :
917
+
918
+ ``` ruby
919
+ erb :overview, :locals => { :text => markdown(:introduction) }
920
+ ```
921
+
922
+ Notez que vous pouvez également appeler la méthode `creole` au sein d'autres
923
+ templates :
924
+
925
+ ``` ruby
926
+ %h1 Hello From Haml !
927
+ %p= creole(:greetings)
928
+ ```
929
+
930
+ Comme vous ne pouvez pas appeler de Ruby au sein de Creole, vous ne pouvez
931
+ pas utiliser de layouts écrits en Creole. Toutefois, il est possible
932
+ d'utiliser un moteur de rendu différent pour le template et pour le layout
933
+ en utilisant l'option `:layout_engine`.
934
+
935
+ #### Templates CoffeeScript
936
+
937
+ <table>
938
+ <tr>
939
+ <td>Dépendances</td>
940
+ <td>
941
+ <a href="https://github.com/josh/ruby-coffee-script" title="Ruby CoffeeScript">
942
+ CoffeeScript
943
+ </a>
944
+ et un
945
+ <a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
946
+ moyen d'exécuter javascript
947
+ </a>
948
+ </td>
949
+ </tr>
950
+ <tr>
951
+ <td>Extensions de fichier</td>
952
+ <td><tt>.coffee</tt></td>
953
+ </tr>
954
+ <tr>
955
+ <td>Exemple</td>
956
+ <td><tt>coffee :index</tt></td>
957
+ </tr>
958
+ </table>
959
+
960
+ #### Templates Stylus
961
+
962
+ <table>
963
+ <tr>
964
+ <td>Dépendances</td>
965
+ <td>
966
+ <a href="https://github.com/lucasmazza/ruby-stylus" title="Ruby Stylus">
967
+ Stylus
968
+ </a>
969
+ et un
970
+ <a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
971
+ moyen d'exécuter javascript
972
+ </a>
973
+ </td>
974
+ </tr>
975
+ <tr>
976
+ <td>Extensions de fichier</td>
977
+ <td><tt>.styl</tt></td>
978
+ </tr>
979
+ <tr>
980
+ <td>Exemple</td>
981
+ <td><tt>stylus :index</tt></td>
982
+ </tr>
983
+ </table>
984
+
985
+ Avant de pouvoir utiliser des templates Stylus, vous devez auparavant charger
986
+ `stylus` et `stylus/tilt` :
987
+
988
+ ``` ruby
989
+ require 'sinatra'
990
+ require 'stylus'
991
+ require 'stylus/tilt'
992
+
993
+ get '/' do
994
+ stylus :exemple
995
+ end
996
+ ```
997
+
998
+ #### Templates Yajl
999
+
1000
+ <table>
1001
+ <tr>
1002
+ <td>Dépendances</td>
1003
+ <td>
1004
+ <a href="https://github.com/brianmario/yajl-ruby" title="yajl-ruby">yajl-ruby</a>
1005
+ </td>
1006
+ </tr>
1007
+ <tr>
1008
+ <td>Extensions de fichier</td>
1009
+ <td><tt>.yajl</tt></td>
1010
+ </tr>
1011
+ <tr>
1012
+ <td>Exemple</td>
1013
+ <td><tt>yajl :index, :locals => { :key => 'qux' }, :callback => 'present', :variable => 'resource'</tt></p>
1014
+ </td>
1015
+ </tr>
1016
+ </table>
1017
+
1018
+ Le source du template est évalué en tant que chaine Ruby, puis la
1019
+ variable json obtenue est convertie avec #to_json.
1020
+
1021
+ ``` ruby
1022
+ json = { :foo => 'bar' }
1023
+ json[:baz] = key
1024
+ ```
1025
+
1026
+ Les options `:callback` et `:variable` peuvent être utilisées pour décorer
1027
+ l’objet retourné.
1028
+
1029
+ ``` ruby
1030
+ var resource = {"foo":"bar","baz":"qux"}; present(resource);</pre>
1031
+ ```
1032
+
1033
+ #### Templates WLang
1034
+
1035
+ <table>
1036
+ <tr>
1037
+ <td>Dépendances</td>
1038
+ <td><a href="https://github.com/blambeau/wlang/" title="wlang">wlang</a></td>
1039
+ </tr>
1040
+ <tr>
1041
+ <td>Extensions de fichier</td>
1042
+ <td><tt>.wlang</tt></td>
1043
+ </tr>
1044
+ <tr>
1045
+ <td>Exemple</td>
1046
+ <td><tt>wlang :index, :locals => { :key => 'value' }</tt></td>
1047
+ </tr>
1048
+ </table>
1049
+
1050
+ L’appel de code ruby au sein des templates n’est pas idiomatique en wlang.
1051
+ L’écriture de templates sans logique est encouragé, via le passage de variables
1052
+ locales. Il est néanmoins possible d’écrire un layout en wlang et d’y utiliser
1053
+ `yield`.
1054
+
1055
+ ### Accéder aux variables dans un Template
1056
+
1057
+ Un template est évalué dans le même contexte que l'endroit d'où il a été
1058
+ appelé (gestionnaire de route). Les variables d'instance déclarées dans le
1059
+ gestionnaire de route sont directement accessibles dans le template :
1060
+
1061
+ ``` ruby
1062
+ get '/:id' do
1063
+ @foo = Foo.find(params[:id])
1064
+ haml '%h1= @foo.nom'
1065
+ end
1066
+ ```
1067
+
1068
+ Alternativement, on peut passer un hash contenant des variables locales :
1069
+
1070
+ ``` ruby
1071
+ get '/:id' do
1072
+ foo = Foo.find(params[:id])
1073
+ haml '%h1= foo.nom', :locals => { :foo => foo }
1074
+ end
1075
+ ```
1076
+
1077
+ Ceci est généralement utilisé lorsque l'on veut utiliser un template comme
1078
+ partiel (depuis un autre template) et qu'il est donc nécessaire d'adapter les
1079
+ noms de variables.
1080
+
1081
+
1082
+ ### Templates avec `yield` et layouts imbriqués
1083
+
1084
+ En général, un layout est un simple template qui appelle `yield`. Ce genre de
1085
+ template peut s'utiliser via l'option `:template` comme décrit précédemment ou
1086
+ peut être rendu depuis un bloc :
1087
+
1088
+ ``` ruby
1089
+ erb :post, :layout => false do
1090
+ erb :index
1091
+ end
1092
+ ```
1093
+
1094
+ Ce code est à globalement équivalent à `erb :index, :layout => :post`.
1095
+
1096
+ Le fait de passer des blocs aux méthodes de rendu est particulièrement utile
1097
+ pour gérer des templates imbriqués :
1098
+
1099
+ ``` ruby
1100
+ erb :main_layout, :layout => false do
1101
+ erb :admin_layout do
1102
+ erb :user
1103
+ end
1104
+ end
1105
+ ```
1106
+
1107
+ Ce qui peut aussi être fait avec un peu moins de code :
1108
+
1109
+ ``` ruby
1110
+ erb :admin_layout, :layout => :main_layout do
1111
+ erb :user
1112
+ end
1113
+ ```
1114
+
1115
+ Actuellement, les méthodes de rendu qui acceptent un bloc sont : `erb`, `haml`,
1116
+ `liquid`, `slim ` et `wlang`. La méthode générale `render` accepte elle aussi
1117
+ un bloc.
1118
+
1119
+
1120
+ ### Templates dans le fichier source
1121
+
1122
+ Des templates peuvent être définis dans le fichier source comme ceci :
1123
+
1124
+ ``` ruby
1125
+ require 'sinatra'
1126
+
1127
+ get '/' do
1128
+ haml :index
1129
+ end
1130
+
1131
+ __END__
1132
+
1133
+ @@ layout
1134
+ %html
1135
+ = yield
1136
+
1137
+ @@ index
1138
+ %div.title Bonjour le monde !
1139
+ ```
1140
+
1141
+ NOTE : Les templates du fichier source qui contient `require 'sinatra'`
1142
+ sont automatiquement chargés. Si vous avez des templates dans d'autres
1143
+ fichiers source, il faut explicitement les déclarer avec
1144
+ `enable :inline_templates`.
1145
+
1146
+
1147
+ ### Templates nommés
1148
+
1149
+ Les templates peuvent aussi être définis grâce à la méthode de haut niveau `template` :
1150
+
1151
+ ``` ruby
1152
+ template :layout do
1153
+ "%html\n =yield\n"
1154
+ end
1155
+
1156
+ template :index do
1157
+ '%div.title Bonjour le monde !'
1158
+ end
1159
+
1160
+ get '/' do
1161
+ haml :index
1162
+ end
1163
+ ```
1164
+
1165
+ Si un template nommé "layout" existe, il sera utilisé à chaque fois qu'un
1166
+ template sera affiché. Vous pouvez désactivez les layouts au cas par cas en
1167
+ passant `:layout => false` ou bien les désactiver par défaut au moyen
1168
+ de `set :haml, :layout => false` :
1169
+
1170
+ ``` ruby
1171
+ get '/' do
1172
+ haml :index, :layout => !request.xhr?
1173
+ end
1174
+ ```
1175
+
1176
+ ### Associer des extensions de fichier
1177
+
1178
+ Pour associer une extension de fichier avec un moteur de rendu, utilisez
1179
+ `Tilt.register`. Par exemple, si vous désirez utiliser l'extension
1180
+ de fichier `tt` pour les templates Textile, vous pouvez faire comme suit :
1181
+
1182
+ ``` ruby
1183
+ Tilt.register :tt, Tilt[:textile]
1184
+ ```
1185
+
1186
+ ### Ajouter son propre moteur de rendu
1187
+
1188
+ En premier lieu, déclarez votre moteur de rendu avec Tilt, ensuite créez
1189
+ votre méthode de rendu :
1190
+
1191
+ ``` ruby
1192
+ Tilt.register :monmoteur, MonMerveilleurMoteurDeRendu
1193
+
1194
+ helpers do
1195
+ def monmoteur(*args) render(:monmoteur, *args) end
1196
+ end
1197
+
1198
+ get '/' do
1199
+ monmoteur :index
1200
+ end
1201
+ ```
1202
+
1203
+ Utilisera `./views/index.monmoteur`. Voir [le dépôt Github](https://github.com/rtomayko/tilt) pour en savoir plus sur Tilt.
1204
+
1205
+ ## Filtres
1206
+
1207
+ Les filtres before sont exécutés avant chaque requête, dans le même contexte
1208
+ que les routes, et permettent de modifier la requête et sa réponse. Les
1209
+ variables d'instance déclarées dans les filtres sont accessibles au niveau
1210
+ des routes et des templates :
1211
+
1212
+ ``` ruby
1213
+ before do
1214
+ @note = 'Coucou !'
1215
+ request.path_info = '/foo/bar/baz'
1216
+ end
1217
+
1218
+ get '/foo/*' do
1219
+ @note #=> 'Coucou !'
1220
+ params[:splat] #=> 'bar/baz'
1221
+ end
1222
+ ```
1223
+
1224
+ Les filtres after sont exécutés après chaque requête à l'intérieur du même
1225
+ contexte et permettent de modifier la requête et sa réponse. Les variables
1226
+ d'instance déclarées dans les filtres before ou les routes sont accessibles
1227
+ au niveau des filtres after :
1228
+
1229
+ ``` ruby
1230
+ after do
1231
+ puts response.status
1232
+ end
1233
+ ```
1234
+
1235
+ Note : Le corps de la réponse n'est pas disponible au niveau du filtre after
1236
+ car il ne sera généré que plus tard (sauf dans le cas où vous utilisez la
1237
+ méthode `body` au lieu de simplement renvoyer une chaine depuis vos routes).
1238
+
1239
+ Les filtres peuvent être associés à un masque, ce qui permet de limiter leur
1240
+ exécution aux cas où la requête correspond à ce masque :
1241
+
1242
+ ``` ruby
1243
+ before '/secret/*' do
1244
+ authentification!
1245
+ end
1246
+
1247
+ after '/faire/:travail' do |travail|
1248
+ session[:dernier_travail] = travail
1249
+ end
1250
+ ```
1251
+
1252
+ Tout comme les routes, les filtres acceptent également des conditions :
1253
+
1254
+ ``` ruby
1255
+ before :agent => /Songbird/ do
1256
+ # ...
1257
+ end
1258
+
1259
+ after '/blog/*', :host_name => 'example.com' do
1260
+ # ...
1261
+ end
1262
+ ```
1263
+
1264
+ ## Helpers
1265
+
1266
+ Utilisez la méthode de haut niveau `helpers` pour définir des routines
1267
+ qui seront accessibles dans vos gestionnaires de route et dans vos templates :
1268
+
1269
+ ``` ruby
1270
+ helpers do
1271
+ def bar(nom)
1272
+ "#{nom}bar"
1273
+ end
1274
+ end
1275
+
1276
+ get '/:nom' do
1277
+ bar(params[:nom])
1278
+ end
1279
+ ```
1280
+
1281
+ Vous pouvez aussi définir les méthodes helper dans un module séparé :
1282
+
1283
+ ``` ruby
1284
+ module FooUtils
1285
+ def foo(nom) "#{nom}foo" end
1286
+ end
1287
+
1288
+ module BarUtils
1289
+ def bar(nom) "#{nom}bar" end
1290
+ end
1291
+
1292
+ helpers FooUtils, BarUtils
1293
+ ```
1294
+
1295
+ Cela a le même résultat que d'inclure les modules dans la classe de
1296
+ l'application.
1297
+
1298
+ ### Utiliser les sessions
1299
+
1300
+ Une session est utilisée pour conserver un état entre les requêtes. Une fois
1301
+ activées, vous avez un hash de session par session utilisateur :
1302
+
1303
+ ``` ruby
1304
+ enable :sessions
1305
+
1306
+ get '/' do
1307
+ "valeur = " << session[:valeur].inspect
1308
+ end
1309
+
1310
+ get '/:value' do
1311
+ session[:valeur] = params[:valeur]
1312
+ end
1313
+ ```
1314
+
1315
+ Notez que `enable :sessions` enregistre en fait toutes les données dans
1316
+ un cookie. Ce n'est pas toujours ce que vous voulez (enregistrer beaucoup de
1317
+ données va augmenter le traffic par exemple). Vous pouvez utiliser n'importe
1318
+ quel middleware Rack de session afin d'éviter cela. N'utilisez **pas**
1319
+ `enable :sessions` dans ce cas mais chargez le middleware de votre
1320
+ choix comme vous le feriez pour n'importe quel autre middleware :
1321
+
1322
+ ``` ruby
1323
+ use Rack::Session::Pool, :expire_after => 2592000
1324
+
1325
+ get '/' do
1326
+ "valeur = " << session[:valeur].inspect
1327
+ end
1328
+
1329
+ get '/:value' do
1330
+ session[:valeur] = params[:valeur]
1331
+ end
1332
+ ```
1333
+
1334
+ Pour renforcer la sécurité, les données de session dans le cookie sont signées
1335
+ avec une clé secrète de session. Une clé secrète est générée pour vous au
1336
+ hasard par Sinatra. Toutefois, comme cette clé change à chaque démarrage de
1337
+ votre application, vous pouvez définir cette clé vous-même afin que toutes
1338
+ les instances de votre application la partage :
1339
+
1340
+ ``` ruby
1341
+ set :session_secret, 'super secret'
1342
+ ```
1343
+
1344
+ Si vous souhaitez avoir plus de contrôle, vous pouvez également enregistrer un
1345
+ hash avec des options lors de la configuration de `sessions` :
1346
+
1347
+ ``` ruby
1348
+ set :sessions, :domain => 'foo.com'
1349
+ ```
1350
+
1351
+ Pour que les différents sous-domaines de foo.com puisse partager une session,
1352
+ vous devez préfixer le domaine par *.* :
1353
+
1354
+ ``` ruby
1355
+ set :sessions, :domain => '.foo.com'
1356
+ ```
1357
+
1358
+
1359
+ ### Halt
1360
+
1361
+ Pour arrêter immédiatement la requête dans un filtre ou un gestionnaire de
1362
+ route :
1363
+
1364
+ ``` ruby
1365
+ halt
1366
+ ```
1367
+
1368
+ Vous pouvez aussi passer le code retour ...
1369
+
1370
+ ``` ruby
1371
+ halt 410
1372
+ ```
1373
+
1374
+ Ou le texte ...
1375
+
1376
+ ``` ruby
1377
+ halt 'Ceci est le texte'
1378
+ ```
1379
+
1380
+ Ou les deux ...
1381
+
1382
+ ``` ruby
1383
+ halt 401, 'Partez !'
1384
+ ```
1385
+
1386
+ Ainsi que les entêtes ...
1387
+
1388
+ ``` ruby
1389
+ halt 402, {'Content-Type' => 'text/plain'}, 'revanche'
1390
+ ```
1391
+
1392
+ Bien sûr il est possible de combiner un template avec `halt` :
1393
+
1394
+ ``` ruby
1395
+ halt erb(:erreur)
1396
+ ```
1397
+
1398
+ ### Passer
1399
+
1400
+ Une route peut passer le relais aux autres routes qui correspondent également
1401
+ avec `pass` :
1402
+
1403
+ ``` ruby
1404
+ get '/devine/:qui' do
1405
+ pass unless params[:qui] == 'Frank'
1406
+ "Tu m'as eu !"
1407
+ end
1408
+
1409
+ get '/devine/*' do
1410
+ 'Manqué !'
1411
+ end
1412
+ ```
1413
+
1414
+ On sort donc immédiatement de ce gestionnaire et on continue à chercher,
1415
+ dans les masques suivants, le prochain qui correspond à la requête.
1416
+ Si aucun des masques suivants ne correspond, un code 404 est retourné.
1417
+
1418
+ ### Déclencher une autre route
1419
+
1420
+ Parfois, `pass` n'est pas ce que vous recherchez, au lieu de cela vous
1421
+ souhaitez obtenir le résultat d'une autre route. Pour cela, utilisez
1422
+ simplement `call` :
1423
+
1424
+ ``` ruby
1425
+ get '/foo' do
1426
+ status, headers, body = call env.merge("PATH_INFO" => '/bar')
1427
+ [status, headers, body.map(&:upcase)]
1428
+ end
1429
+
1430
+ get '/bar' do
1431
+ "bar"
1432
+ end
1433
+ ```
1434
+
1435
+ Notez que dans l'exemple ci-dessus, vous faciliterez les tests et améliorerez
1436
+ la performance en déplaçant simplement `"bar"` dans un helper
1437
+ utilisé à la fois par `/foo` et `/bar`.
1438
+
1439
+ Si vous souhiatez que la requête soit envoyée à la même instance de
1440
+ l'application plutôt qu'à une copie, utilisez `call!` au lieu de
1441
+ `call`.
1442
+
1443
+ Lisez la spécification Rack si vous souhaitez en savoir plus sur
1444
+ `call`.
1445
+
1446
+ ### Définir le corps, le code retour et les entêtes
1447
+
1448
+ Il est possible et recommandé de définir le code retour et le corps de la
1449
+ réponse au moyen de la valeur de retour d'un bloc définissant une route.
1450
+ Quoiqu'il en soit, dans certains cas vous pourriez avoir besoin de définir
1451
+ le coprs de la réponse à un moment arbitraire de l'exécution. Vous pouvez le
1452
+ faire au moyen de la méthode `body`. Si vous faites ainsi, vous pouvez alors
1453
+ utiliser cette même méthode pour accéder au corps de la réponse :
1454
+
1455
+ ``` ruby
1456
+ get '/foo' do
1457
+ body "bar"
1458
+ end
1459
+
1460
+ after do
1461
+ puts body
1462
+ end
1463
+ ```
1464
+
1465
+ Il est également possible de passer un bloc à `body`, qui sera exécuté par le
1466
+ gestionnaire Rack (ceci peut être utilisé pour implémenter un streaming,
1467
+ voir "Valeurs de retour").
1468
+
1469
+ Pareillement au corps de la réponse, vous pouvez également définir le code
1470
+ retour et les entêtes :
1471
+
1472
+ ``` ruby
1473
+ get '/foo' do
1474
+ status 418
1475
+ headers \
1476
+ "Allow" => "BREW, POST, GET, PROPFIND, WHEN",
1477
+ "Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
1478
+ body "Je suis une théière !"
1479
+ end
1480
+ ```
1481
+
1482
+ Comme `body` `headers` et `status` peuvent être utilisés sans arguments
1483
+ pour accéder à leurs valeurs.
1484
+
1485
+ ### Faire du streaming
1486
+
1487
+ Il y a des cas où vous voulez commencer à renvoyer des données pendant que
1488
+ vous êtes en train de générer le reste de la réponse. Dans les cas les plus
1489
+ extrèmes, vous souhaitez continuer à envoyer des données tant que le client
1490
+ n'abandonne pas la connection. Vous pouvez alors utiliser le helper `stream`
1491
+ pour éviter de créer votre propre système :
1492
+
1493
+ ``` ruby
1494
+ get '/' do
1495
+ stream do |out|
1496
+ out << "Ca va être hallu -\n"
1497
+ sleep 0.5
1498
+ out << " (attends la suite) \n"
1499
+ sleep 1
1500
+ out << "- cinant !\n"
1501
+ end
1502
+ end
1503
+ ```
1504
+
1505
+ Cela permet d'implémenter des API de streaming ou de
1506
+ [Server Sent Events](http://dev.w3.org/html5/eventsource/) et peut servir de
1507
+ base pour des [WebSockets](http://en.wikipedia.org/wiki/WebSocket). Vous
1508
+ pouvez aussi l'employer pour augmenter le débit quand une partie du contenu
1509
+ provient d'une resource lente.
1510
+
1511
+ Le fonctionnement du streaming, notamment le nombre de requêtes simultanées,
1512
+ dépend énormément du serveur web utilisé. Certains ne prennent pas du tout en
1513
+ charge le streaming (WEBRick par exemple). Lorsque le serveur ne gère pas le
1514
+ streaming, la partie body de la réponse sera envoyée au client en une seule
1515
+ fois, après que l'exécution du bloc passé au helper `stream` sera terminée. Le
1516
+ streaming ne fonctionne pas du tout avec Shotgun.
1517
+
1518
+ En utilisant le helper stream avec le paramètre `keep_open`, il n'appelera
1519
+ pas la méthode `close` du flux, vous laissant la possibilité de le fermer à
1520
+ tout moment au cours de l'exécution. Ceci ne fonctionne qu'avec les serveurs
1521
+ evented (ie non threadés) tels que Thin et Rainbows. Les autres serveurs
1522
+ fermeront malgré tout le flux :
1523
+
1524
+ ``` ruby
1525
+ # interrogation prolongée
1526
+
1527
+ set :server, :thin
1528
+ connexions = []
1529
+
1530
+ get '/souscrire' do
1531
+ # abonne un client aux évènements du serveur
1532
+ stream(:keep_open) { |out| connexions << out }
1533
+
1534
+ # purge les connexions abandonnées
1535
+ connexions.reject!(&:closed?)
1536
+
1537
+ # compte-rendu
1538
+ "abonné"
1539
+ end
1540
+
1541
+ post '/message' do
1542
+ connexions.each do |out|
1543
+ # prévient le client qu'un nouveau message est arrivé
1544
+ out << params[:message] << "\n"
1545
+
1546
+ # indique au client de se connecter à nouveau
1547
+ out.close
1548
+ end
1549
+
1550
+ # compte-rendu
1551
+ "message reçu"
1552
+ end
1553
+ ```
1554
+
1555
+ ### Journalisation (Logging)
1556
+
1557
+ Dans le contexte de la requête, la méthode utilitaire `logger` expose une
1558
+ instance de `Logger` :
1559
+
1560
+ ``` ruby
1561
+ get '/' do
1562
+ logger.info "chargement des données"
1563
+ # ...
1564
+ end
1565
+ ```
1566
+
1567
+ Ce logger va automatiquement prendre en compte les paramètres de
1568
+ configuration pour la journalisation de votre gestionnaire Rack. Si la
1569
+ journalisation est désactivée, cette méthode renverra un objet factice et
1570
+ vous n'avez pas à vous en inquiéter dans vos routes en le filtrant.
1571
+
1572
+ Notez que la journalisation est seulement activée par défaut pour
1573
+ `Sinatra::Application`, donc si vous héritez de `>Sinatra::Base`,
1574
+ vous aurez à l'activer vous-même :
1575
+
1576
+ ``` ruby
1577
+ class MonApp < Sinatra::Base
1578
+ configure :production, :development do
1579
+ enable :logging
1580
+ end
1581
+ end
1582
+ ```
1583
+
1584
+ Si vous souhaitez utiliser votre propre logger, vous devez définir le paramètre
1585
+ `logging` à `nil` pour être certain qu'aucun middleware de logging ne sera
1586
+ installé (notez toutefois que `logger` renverra alors `nil`). Dans ce cas,
1587
+ Sinatra utilisera ce qui sera présent dans `env['rack.logger']`.
1588
+
1589
+ ### Types Mime
1590
+
1591
+ Quand vous utilisez `send_file` ou des fichiers statiques, vous
1592
+ pouvez rencontrer des types mime que Sinatra ne connaît pas. Utilisez
1593
+ `mime_type` pour les déclarer par extension de fichier :
1594
+
1595
+ ``` ruby
1596
+ configure do
1597
+ mime_type :foo, 'text/foo'
1598
+ end
1599
+ ```
1600
+
1601
+ Vous pouvez également les utiliser avec la méthode `content_type` :
1602
+
1603
+ ``` ruby
1604
+ get '/' do
1605
+ content_type :foo
1606
+ "foo foo foo"
1607
+ end
1608
+ ```
1609
+
1610
+ ### Former des URLs
1611
+
1612
+ Pour former des URLs, vous devriez utiliser la méthode `url`, par exemple en
1613
+ Haml :
1614
+
1615
+ ``` ruby
1616
+ %a{:href => url('/foo')} foo
1617
+ ```
1618
+
1619
+ Cela prend en compte les proxy inverse et les routeurs Rack, s'ils existent.
1620
+
1621
+ Cette méthode est également disponible sous l'alias `to` (voir ci-dessous
1622
+ pour un exemple).
1623
+
1624
+ ### Redirection du navigateur
1625
+
1626
+ Vous pouvez déclencher une redirection du navigateur avec la méthode
1627
+ `redirect` :
1628
+
1629
+ ``` ruby
1630
+ get '/foo' do
1631
+ redirect to('/bar')
1632
+ end
1633
+ ```
1634
+
1635
+ Tout paramètre additionnel est géré comme des arguments pour la méthode
1636
+ `halt` :
1637
+
1638
+ ``` ruby
1639
+ redirect to('/bar'), 303
1640
+ redirect 'http://google.com', 'mauvais endroit mon pote'
1641
+ ```
1642
+
1643
+ Vous pouvez aussi rediriger vers la page dont l'utilisateur venait au moyen de
1644
+ `redirect back` :
1645
+
1646
+ ``` ruby
1647
+ get '/foo' do
1648
+ "<a href='/bar'>faire quelque chose</a>"
1649
+ end
1650
+
1651
+ get '/bar' do
1652
+ faire_quelque_chose
1653
+ redirect back
1654
+ end
1655
+ ```
1656
+
1657
+ Pour passer des arguments à une redirection, ajoutez-les soit à la requête :
1658
+
1659
+ ``` ruby
1660
+ redirect to('/bar?sum=42')
1661
+ ```
1662
+
1663
+ Ou bien utilisez une session :
1664
+
1665
+ ``` ruby
1666
+ enable :sessions
1667
+
1668
+ get '/foo' do
1669
+ session[:secret] = 'foo'
1670
+ redirect to('/bar')
1671
+ end
1672
+
1673
+ get '/bar' do
1674
+ session[:secret]
1675
+ end
1676
+ ```
1677
+
1678
+ ### Contrôle du cache
1679
+
1680
+ Définir correctement vos entêtes à la base pour un bon cache HTTP.
1681
+
1682
+ Vous pouvez facilement définir l'entête Cache-Control de la manière suivante :
1683
+
1684
+ ``` ruby
1685
+ get '/' do
1686
+ cache_control :public
1687
+ "met le en cache !"
1688
+ end
1689
+ ```
1690
+
1691
+ Conseil de pro : définir le cache dans un filtre before :
1692
+
1693
+ ``` ruby
1694
+ before do
1695
+ cache_control :public, :must_revalidate, :max_age => 60
1696
+ end
1697
+ ```
1698
+
1699
+ Si vous utilisez la méthode `expires` pour définir l'entête correspondant,
1700
+ `Cache-Control` sera alors défini automatiquement :
1701
+
1702
+ ``` ruby
1703
+ before do
1704
+ expires 500, :public, :must_revalidate
1705
+ end
1706
+ ```
1707
+
1708
+ Pour utiliser correctement les caches, vous devriez utiliser `etag` ou
1709
+ `last_modified`. Il est recommandé d'utiliser ces méthodes *avant* de faire
1710
+ d'importantes modifications, car elles vont immédiatement déclencher la réponse
1711
+ si le client a déjà la version courante dans son cache :
1712
+
1713
+ ``` ruby
1714
+ get '/article/:id' do
1715
+ @article = Article.find params[:id]
1716
+ last_modified @article.updated_at
1717
+ etag @article.sha1
1718
+ erb :article
1719
+ end
1720
+ ```
1721
+
1722
+ Il est également possible d'utiliser un
1723
+ [weak ETag](http://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation) :
1724
+
1725
+ ``` ruby
1726
+ etag @article.sha1, :weak
1727
+ ```
1728
+
1729
+ Ces méthodes ne sont pas chargées de mettre des données en cache, mais elles
1730
+ fournissent les informations nécessaires pour votre cache. Si vous êtes à la
1731
+ recherche de solutions rapides pour un reverse-proxy de cache, essayez
1732
+ [rack-cache](https://github.com/rtomayko/rack-cache) :
1733
+
1734
+ ``` ruby
1735
+ require "rack/cache"
1736
+ require "sinatra"
1737
+
1738
+ use Rack::Cache
1739
+
1740
+ get '/' do
1741
+ cache_control :public, :max_age => 36000
1742
+ sleep 5
1743
+ "hello"
1744
+ end
1745
+ ```
1746
+
1747
+ Utilisez le paramètre `:static_cache_control` pour ajouter l'information
1748
+ d'en-tête `Cache-Control` (voir plus loin).
1749
+
1750
+ D'après la RFC 2616, votre application devrait se comporter différement lorsque
1751
+ l'en-tête If-Match ou If-None-Match est défini à `*` en tenant compte du
1752
+ fait que la resource demandée existe déjà ou pas. Sinatra considère que les
1753
+ requêtes portant sur des resources sûres (tel que get) ou idempotentes (tel que
1754
+ put) existent déjà et pour les autres resources (par exemple dans le cas
1755
+ de requêtes post) qu'il s'agit de nouvelles resources. Vous pouvez modifier ce
1756
+ comportement en passant une option `:new_resource` :
1757
+
1758
+ ``` ruby
1759
+ get '/create' do
1760
+ etag '', :new_resource => true
1761
+ Article.create
1762
+ erb :new_article
1763
+ end
1764
+ ```
1765
+
1766
+ Si vous souhaitez utilisez un ETag faible, utilisez l'option <tt>:kind</tt> :
1767
+
1768
+ ``` ruby
1769
+ etag '', :new_resource => true, :kind => :weak
1770
+ ```
1771
+
1772
+ ### Envoyer des fichiers
1773
+
1774
+ Pour envoyer des fichiers, vous pouvez utiliser la méthode `send_file` :
1775
+
1776
+ ``` ruby
1777
+ get '/' do
1778
+ send_file 'foo.png'
1779
+ end
1780
+ ```
1781
+
1782
+ Quelques options sont également acceptées :
1783
+
1784
+ ``` ruby
1785
+ send_file 'foo.png', :type => :jpg
1786
+ ```
1787
+
1788
+ Les options sont :
1789
+
1790
+ <dl>
1791
+ <dt>filename</dt>
1792
+ <dd>
1793
+ le nom du fichier dans la réponse, par défaut le nom du fichier envoyé.
1794
+ </dd>
1795
+
1796
+ <dt>last_modified</dt>
1797
+ <dd>
1798
+ valeur pour l’entête Last-Modified, par défaut la date de modification du
1799
+ fichier
1800
+ </dd>
1801
+
1802
+ <dt>type</dt>
1803
+ <dd>
1804
+ type de contenu à utiliser, deviné à partir de l’extension de fichier si
1805
+ absent
1806
+ </dd>
1807
+
1808
+ <dt>disposition</dt>
1809
+ <dd>
1810
+ utilisé pour Content-Disposition, les valuers possibles étant : <tt>nil</tt>
1811
+ (par défaut), <tt>:attachment</tt> et <tt>:inline</tt>
1812
+ </dd>
1813
+
1814
+ <dt>length</dt>
1815
+ <dd>entête Content-Length, par défaut la taille du fichier</dd>
1816
+
1817
+ <dt>status</dt>
1818
+ <dd>
1819
+ code état à renvoyer. Utile quand un fichier statique sert de page d’erreur.
1820
+ </dd>
1821
+ </dl>
1822
+
1823
+ Si le gestionnaire Rack le supporte, d'autres moyens que le streaming via le
1824
+ processus Ruby seront utilisés. Si vous utilisez cette méthode, Sinatra gérera
1825
+ automatiquement les requêtes de type range.
1826
+
1827
+ ### Accéder à l'objet requête
1828
+
1829
+ L'objet correspondant à la requête envoyée peut être récupéré dans le contexte
1830
+ de la requête (filtres, routes, gestionnaires d'erreur) au moyen de la méthode
1831
+ `request` :
1832
+
1833
+ ``` ruby
1834
+ # application tournant à l'adresse http://exemple.com/exemple
1835
+ get '/foo' do
1836
+ t = %w[text/css text/html application/javascript]
1837
+ request.accept # ['text/html', '*/*']
1838
+ request.accept? 'text/xml' # true
1839
+ request.preferred_type(t) # 'text/html'
1840
+ request.body # corps de la requête envoyée par le client
1841
+ # (voir ci-dessous)
1842
+ request.scheme # "http"
1843
+ request.script_name # "/exemple"
1844
+ request.path_info # "/foo"
1845
+ request.port # 80
1846
+ request.request_method # "GET"
1847
+ request.query_string # ""
1848
+ request.content_length # taille de request.body
1849
+ request.media_type # type de média pour request.body
1850
+ request.host # "exemple.com"
1851
+ request.get? # true (méthodes similaires pour les autres
1852
+ # verbes HTTP)
1853
+ request.form_data? # false
1854
+ request["UN_ENTETE"] # valeur de l'entête UN_ENTETE
1855
+ request.referrer # référant du client ou '/'
1856
+ request.user_agent # user agent (utilisé par la condition :agent)
1857
+ request.cookies # tableau contenant les cookies du navigateur
1858
+ request.xhr? # requête AJAX ?
1859
+ request.url # "http://exemple.com/exemple/foo"
1860
+ request.path # "/exemple/foo"
1861
+ request.ip # adresse IP du client
1862
+ request.secure? # false
1863
+ request.forwarded? # vrai (si on est derrière un proxy inverse)
1864
+ request.env # tableau brut de l'environnement fourni par Rack
1865
+ end
1866
+ ```
1867
+
1868
+ Certaines options, telles que `script_name` ou `path_info`
1869
+ peuvent également être modifiées :
1870
+
1871
+ ``` ruby
1872
+ before { request.path_info = "/" }
1873
+
1874
+ get "/" do
1875
+ "toutes les requêtes arrivent ici"
1876
+ end
1877
+ ```
1878
+
1879
+ `request.body` est un objet IO ou StringIO :
1880
+
1881
+ ``` ruby
1882
+ post "/api" do
1883
+ request.body.rewind # au cas où il a déjà été lu
1884
+ donnees = JSON.parse request.body.read
1885
+ "Bonjour #{donnees['nom']} !"
1886
+ end
1887
+ ```
1888
+
1889
+ ### Fichiers joints
1890
+
1891
+ Vous pouvez utiliser la méthode `attachment` pour indiquer au navigateur que
1892
+ la réponse devrait être stockée sur le disque plutôt qu'affichée :
1893
+
1894
+
1895
+ ``` ruby
1896
+ get '/' do
1897
+ attachment
1898
+ "enregistre-le !"
1899
+ end
1900
+ ```
1901
+
1902
+ Vous pouvez également lui passer un nom de fichier :
1903
+
1904
+ ``` ruby
1905
+ get '/' do
1906
+ attachment "info.txt"
1907
+ "enregistre-le !"
1908
+ end
1909
+ ```
1910
+
1911
+ ### Gérer Date et Time
1912
+
1913
+ Sinatra fourni un helper `time_for` pour convertir une valeur donnée en
1914
+ objet `Time`. Il peut aussi faire la conversion à partir d'objets `DateTime`,
1915
+ `Date` ou de classes similaires :
1916
+
1917
+ ``` ruby
1918
+ get '/' do
1919
+ pass if Time.now > time_for('Dec 23, 2012')
1920
+ "encore temps"
1921
+ end
1922
+ ```
1923
+
1924
+ Cette méthode est utilisée en interne par `expires`, `last_modified` et
1925
+ consorts. Par conséquent, vous pouvez très facilement étendre le
1926
+ fonctionnement de ces méthodes en surchargeant le helper `time_for` dans
1927
+ votre application :
1928
+
1929
+ ``` ruby
1930
+ helpers do
1931
+ def time_for(value)
1932
+ case value
1933
+ when :yesterday then Time.now - 24*60*60
1934
+ when :tomorrow then Time.now + 24*60*60
1935
+ else super
1936
+ end
1937
+ end
1938
+ end
1939
+
1940
+ get '/' do
1941
+ last_modified :yesterday
1942
+ expires :tomorrow
1943
+ "salut"
1944
+ end
1945
+ ```
1946
+
1947
+ ### Chercher les fichiers de templates
1948
+
1949
+ La méthode `find_template` est utilisée pour trouver les fichiers de
1950
+ templates à générer :
1951
+
1952
+ ``` ruby
1953
+ find_template settings.views, 'foo', Tilt[:haml] do |file|
1954
+ puts "pourrait être #{file}"
1955
+ end
1956
+ ```
1957
+
1958
+ Ce n'est pas très utilise. En revanche, il est utile de pouvoir surcharger
1959
+ cette méthode afin de définir son propre mécanisme de recherche. Par exemple,
1960
+ vous pouvez utiliser plus d'un répertoire de vues :
1961
+
1962
+ ``` ruby
1963
+ set :views, ['views', 'templates']
1964
+
1965
+ helpers do
1966
+ def find_template(views, name, engine, &block)
1967
+ Array(views).each { |v| super(v, name, engine, &block) }
1968
+ end
1969
+ end
1970
+ ```
1971
+
1972
+ Un autre exemple est d'utiliser des répertoires différents pour des moteurs
1973
+ de rendu différents :
1974
+
1975
+ ``` ruby
1976
+ set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
1977
+
1978
+ helpers do
1979
+ def find_template(views, name, engine, &block)
1980
+ _, folder = views.detect { |k,v| engine == Tilt[k] }
1981
+ folder ||= views[:default]
1982
+ super(folder, name, engine, &block)
1983
+ end
1984
+ end
1985
+ ```
1986
+
1987
+ Vous pouvez également écrire cela dans une extension et la partager avec
1988
+ d'autres !
1989
+
1990
+ Notez que `find_template` ne vérifie pas que le fichier existe mais
1991
+ va plutôt exécuter le bloc pour tous les chemins possibles. Cela n'induit pas
1992
+ un problème de performance dans le sens où `render` va utiliser `break` dès
1993
+ qu'un fichier est trouvé. De plus, l'emplacement des templates (et leur
1994
+ contenu) est mis en cache si vous n'êtes pas en mode développement. Vous
1995
+ devriez garder cela en tête si vous écrivez une méthode vraiment dingue.
1996
+
1997
+ ## Configuration
1998
+
1999
+ Lancé une seule fois au démarrage de tous les environnements :
2000
+
2001
+ ``` ruby
2002
+ configure do
2003
+ # définir un paramètre
2004
+ set :option, 'value'
2005
+
2006
+ # définir plusieurs paramètre
2007
+ set :a => 1, :b => 2
2008
+
2009
+ # identique à "set :option, true"
2010
+ enable :option
2011
+
2012
+ # identique à "set :option, false""
2013
+ disable :option
2014
+
2015
+ # vous pouvez également avoir des paramètres dynamiques avec des blocs
2016
+ set(:css_dir) { File.join(views, 'css') }
2017
+ end
2018
+ ```
2019
+
2020
+ Lancé si l'environnement (variable d'environnement RACK_ENV) est défini comme
2021
+ `:production` :
2022
+
2023
+ ``` ruby
2024
+ configure :production do
2025
+ ...
2026
+ end
2027
+ ```
2028
+
2029
+ Lancé si l'environnement est `:production` ou `:test` :
2030
+
2031
+ ``` ruby
2032
+ configure :production, :test do
2033
+ ...
2034
+ end
2035
+ ```
2036
+
2037
+ Vous pouvez accéder à ces paramètres via `settings` :
2038
+
2039
+ ``` ruby
2040
+ configure do
2041
+ set :foo, 'bar'
2042
+ end
2043
+
2044
+ get '/' do
2045
+ settings.foo? # => true
2046
+ settings.foo # => 'bar'
2047
+ ...
2048
+ end
2049
+ ```
2050
+
2051
+ ### Se protéger des attaques
2052
+
2053
+ Sinatra utilise [Rack::Protection](https://github.com/rkh/rack-protection#readme)
2054
+ pour protéger votre application contre les principales attaques opportunistes.
2055
+ Vous pouvez très simplement désactiver cette fonctionnalité (ce qui exposera
2056
+ votre application à beaucoup de vulnerabilités courantes) :
2057
+
2058
+ ``` ruby
2059
+ disable :protection
2060
+ ```
2061
+
2062
+ Pour désactiver seulement un type de protection, vous pouvez définir `protection`
2063
+ avec un hash d'options :
2064
+
2065
+ ``` ruby
2066
+ set :protection, :except => :path_traversal
2067
+ ```
2068
+
2069
+ Vous pouvez également lui passer un tableau pour désactiver plusieurs types de
2070
+ protection :
2071
+
2072
+ ``` ruby
2073
+ set :protection, :except => [:path_traversal, :session_hijacking]
2074
+ ```
2075
+
2076
+ Par défaut, il faut que `:sessions` soit activé pour que Sinatra mette en place
2077
+ un système de protection au niveau de la session. Dans le cas où vous gérez
2078
+ vous même les sessions, vous devez utiliser l'option `:session` pour que cela
2079
+ soit le cas :
2080
+
2081
+ ``` ruby
2082
+ use Rack::Session::Pool
2083
+ set :protection, :session => true
2084
+ ```
2085
+
2086
+ ### Paramètres disponibles
2087
+
2088
+ <dl>
2089
+ <dt>absolute_redirects</dt>
2090
+ <dd>Si désactivé, Sinatra permettra les redirections relatives. Toutefois,
2091
+ Sinatra ne sera plus conforme à la RFC 2616 (HTTP 1.1), qui n’autorise
2092
+ que les redirections absolues.</p>
2093
+
2094
+ Activez si votre application tourne derrière un proxy inverse qui n’a
2095
+ pas été correctement configuré. Notez que la méthode <tt>url</tt>
2096
+ continuera de produire des URLs absolues, sauf si vous lui passez
2097
+ <tt>false</tt> comme second argument.</p>
2098
+
2099
+ <p>Désactivé par défaut.</p></dd>
2100
+
2101
+ <dt>add_charsets</dt>
2102
+ <dd><p>types mime pour lesquels la méthode <tt>content_type</tt> va
2103
+ automatiquement ajouter l’information du <tt>charset</tt>.</p>
2104
+
2105
+ <p>Vous devriez lui ajouter des valeurs plutôt que de l’écraser :</p>
2106
+
2107
+ <pre>settings.add_charsets >> "application/foobar"</pre></dd>
2108
+
2109
+ <dt>app_file</dt>
2110
+ <dd><p>chemin pour le fichier de l’application principale, utilisé pour
2111
+ détecter la racine du projet, les dossiers public et vues, et les
2112
+ templates en ligne.</p></dd>
2113
+
2114
+ <dt>bind</dt>
2115
+ <dd>adresse IP sur laquelle se brancher (par défaut : 0.0.0.0). Utiliser
2116
+ seulement pour le serveur intégré.</dd>
2117
+
2118
+ <dt>default_encoding</dt>
2119
+ <dd>encodage à utiliser si inconnu (par défaut <tt>"utf-8"</tt>)</dd>
2120
+
2121
+ <dt>dump_errors</dt>
2122
+ <dd>afficher les erreurs dans le <tt>log</tt>.
2123
+ </dd>
2124
+
2125
+ <dt>environment</dt>
2126
+ <dd>environnement courant, par défaut <tt>ENV['RACK_ENV']</tt>, ou
2127
+ <tt>"development"</tt> si absent.</dd>
2128
+
2129
+ <dt>logging</dt>
2130
+ <dd>utiliser le <tt>logger</tt>.</dd>
2131
+
2132
+ <dt>lock</dt>
2133
+ <dd><p>Place un <tt>lock</tt> autour de chaque requête, n’exécutant donc
2134
+ qu’une seule requête par processus Ruby.</p>
2135
+
2136
+ <p>Activé si votre application n’est pas <tt>thread-safe</tt>. Désactivé
2137
+ par défaut.</p></dd>
2138
+
2139
+ <dt>method_override</dt>
2140
+ <dd>utilise la magie de <tt>_method</tt> afin de permettre des formulaires
2141
+ put/delete dans des navigateurs qui ne le permettent pas.
2142
+
2143
+ </dd>
2144
+ <dt>port</dt>
2145
+ <dd>port à écouter. Utiliser seulement pour le serveur intégré.</dd>
2146
+
2147
+ <dt>prefixed_redirects</dt>
2148
+ <dd>si oui ou non <tt>request.script_name</tt> doit être inséré dans les
2149
+ redirections si un chemin non absolu est utilisé. Ainsi, <tt>redirect
2150
+ '/foo'</tt> se comportera comme <tt>redirect to('/foo')</tt>. Désactivé
2151
+ par défaut.</dd>
2152
+
2153
+ <dt>protection</dt>
2154
+ <dd>défini s’il faut activer ou non la protection contre les attaques web.
2155
+ Voir la section protection précédente.</dd>
2156
+
2157
+ <dt>public_dir</dt>
2158
+ <dd>alias pour <tt>public_folder</tt>. Voir ci-dessous.</dd>
2159
+
2160
+ <dt>public_folder</dt>
2161
+ <dd>chemin pour le dossier à partir duquel les fichiers publics sont servis.
2162
+ Utilisé seulement si les fichiers statiques doivent être servis (voir le
2163
+ paramètre <tt>static</tt>). Si non défini, il découle du paramètre
2164
+ <tt>app_file</tt>.</dd>
2165
+
2166
+ <dt>reload_templates</dt>
2167
+ <dd>si oui ou non les templates doivent être rechargés entre les requêtes.
2168
+ Activé en mode développement.</dd>
2169
+
2170
+ <dt>root</dt>
2171
+ <dd>chemin pour le dossier racine du projet. Si non défini, il découle du
2172
+ paramètre <tt>app_file</tt>.</dd>
2173
+
2174
+ <dt>raise_errors</dt>
2175
+ <dd>soulever les erreurs (ce qui arrêtera l’application). Désactivé par
2176
+ défaut sauf lorsque <tt>environment</tt> est défini à
2177
+ <tt>"test"</tt>.</dd>
2178
+
2179
+ <dt>run</dt>
2180
+ <dd>si activé, Sinatra s’occupera de démarrer le serveur, ne pas activer si
2181
+ vous utiliser rackup ou autres.</dd>
2182
+
2183
+ <dt>running</dt>
2184
+ <dd>est-ce que le serveur intégré est en marche ? ne changez pas ce
2185
+ paramètre !</dd>
2186
+
2187
+ <dt>server</dt>
2188
+ <dd>serveur ou liste de serveurs à utiliser pour le serveur intégré. Par
2189
+ défaut [‘thin’, ‘mongrel’, ‘webrick’], l’ordre indiquant la
2190
+ priorité.</dd>
2191
+
2192
+ <dt>sessions</dt>
2193
+ <dd>active le support des sessions basées sur les cookies, en utilisant
2194
+ <tt>Rack::Session::Cookie</tt>. Reportez-vous à la section ‘Utiliser les
2195
+ sessions’ pour plus d’informations.</dd>
2196
+
2197
+ <dt>show_exceptions</dt>
2198
+ <dd>affiche la trace de l’erreur dans le navigateur lorsqu’une exception se
2199
+ produit. Désactivé par défaut sauf lorsque <tt>environment</tt> est
2200
+ défini à <tt>"development"</tt>.</dd>
2201
+
2202
+ <dt>static</dt>
2203
+ <dd>Si oui ou non Sinatra doit s’occuper de servir les fichiers statiques.
2204
+ Désactivez si vous utilisez un serveur capable de le gérer lui même. Le
2205
+ désactiver augmentera la performance. Activé par défaut pour le style
2206
+ classique, désactivé pour le style modulaire.</dd>
2207
+
2208
+ <dt>static_cache_control</dt>
2209
+ <dd>A définir quand Sinatra rend des fichiers statiques pour ajouter les
2210
+ en-têtes <tt>Cache-Control</tt>. Utilise le helper <tt>cache_control</tt>.
2211
+ Désactivé par défaut. Utiliser un array explicite pour définir des
2212
+ plusieurs valeurs : <tt>set :static_cache_control, [:public, :max_age =>
2213
+ 300]</tt></dd>
2214
+
2215
+ <dt>threaded</dt>
2216
+ <dd>à définir à <tt>true</tt> pour indiquer à Thin d’utiliser
2217
+ <tt>EventMachine.defer</tt> pour traiter la requête.</dd>
2218
+
2219
+ <dt>views</dt>
2220
+ <dd>chemin pour le dossier des vues. Si non défini, il découle du paramètre
2221
+ <tt>app_file</tt>.</dd>
2222
+
2223
+ <dt>x_cascade</dt>
2224
+ <dd>
2225
+ Indique s'il faut ou non définir le header X-Cascade lorsqu'aucune route
2226
+ ne correspond. Défini à <tt>true</tt> par défaut.
2227
+ </dd>
2228
+ </dl>
2229
+
2230
+ ## Environements
2231
+
2232
+ Il existe trois environnements prédéfinis : `"development"`,
2233
+ `"production"` et `"test"`. Les environements peuvent être
2234
+ sélectionné via la variable d'environnement `RACK_ENV`. Sa valeur par défaut
2235
+ est `"development"`. Dans ce mode, tous les templates sont rechargés à
2236
+ chaque requête. Des handlers spécifiques pour `not_found` et
2237
+ `error` sont installés pour vous permettre d'avoir une pile de trace
2238
+ dans votre navigateur. En mode `"production"` et `"test"` les
2239
+ templates sont mis en cache par défaut.
2240
+
2241
+ Pour exécuter votre application dans un environnement différent, définissez la
2242
+ variable d'environnement `RACK_ENV` :
2243
+
2244
+ ``` shell
2245
+ RACK_ENV=production ruby my_app.rb
2246
+ ```
2247
+
2248
+ Vous pouvez utiliser une des méthodes `development?`, `test?` et `production?`
2249
+ pour déterminer quel est l'environnement en cours :
2250
+
2251
+ ``` ruby
2252
+ get '/' do
2253
+ if settings.development?
2254
+ "développement !"
2255
+ else
2256
+ "pas en développement !"
2257
+ end
2258
+ end
2259
+ ```
2260
+
2261
+ ## Gérer les erreurs
2262
+
2263
+ Les gestionnaires d'erreur s'exécutent dans le même contexte que les routes ou
2264
+ les filtres, ce qui veut dire que vous avez accès (entre autres) aux bons
2265
+ vieux `haml`, `erb`, `halt`, etc.
2266
+
2267
+ ### NotFound
2268
+
2269
+ Quand une exception <tt>Sinatra::NotFound</tt> est soulevée, ou que le code
2270
+ retour est 404, le gestionnaire <tt>not_found</tt> est invoqué :
2271
+
2272
+ ``` ruby
2273
+ not_found do
2274
+ 'Pas moyen de trouver ce que vous cherchez'
2275
+ end
2276
+ ```
2277
+
2278
+ ### Error
2279
+
2280
+ Le gestionnaire `error` est invoqué à chaque fois qu'une exception est
2281
+ soulevée dans une route ou un filtre. L'objet exception est accessible via la
2282
+ variable Rack `sinatra.error` :
2283
+
2284
+ ``` ruby
2285
+ error do
2286
+ 'Désolé mais une méchante erreur est survenue - ' + env['sinatra.error'].name
2287
+ end
2288
+ ```
2289
+
2290
+ Erreur sur mesure :
2291
+
2292
+ ``` ruby
2293
+ error MonErreurSurMesure do
2294
+ 'Donc il est arrivé ceci...' + env['sinatra.error'].message
2295
+ end
2296
+ ```
2297
+
2298
+ Donc si ceci arrive :
2299
+
2300
+ ``` ruby
2301
+ get '/' do
2302
+ raise MonErreurSurMesure, 'quelque chose de mal'
2303
+ end
2304
+ ```
2305
+
2306
+ Vous obtenez ça :
2307
+
2308
+ Donc il est arrivé ceci... quelque chose de mal
2309
+
2310
+ Alternativement, vous pouvez avoir un gestionnaire d'erreur associé à un code
2311
+ particulier :
2312
+
2313
+ ``` ruby
2314
+ error 403 do
2315
+ 'Accès interdit'
2316
+ end
2317
+
2318
+ get '/secret' do
2319
+ 403
2320
+ end
2321
+ ```
2322
+
2323
+ Ou un intervalle :
2324
+
2325
+ ``` ruby
2326
+ error 400..510 do
2327
+ 'Boom'
2328
+ end
2329
+ ```
2330
+
2331
+ Sinatra installe pour vous quelques gestionnaires `not_found` et
2332
+ `error` génériques lorsque vous êtes en environnement
2333
+ `development`.
2334
+
2335
+ ## Les Middlewares Rack
2336
+
2337
+ Sinatra tourne avec [Rack](http://rack.rubyforge.org/), une interface standard
2338
+ et minimale pour les web frameworks Ruby. Un des points forts de Rack est le
2339
+ support de ce que l'on appelle des "middlewares" -- composant qui vient se
2340
+ situer entre le serveur et votre application, et dont le but est de
2341
+ visualiser/manipuler la requête/réponse HTTP, et d'offrir diverses
2342
+ fonctionnalités classiques.
2343
+
2344
+ Sinatra permet de construire facilement des middlewares Rack via la méthode de
2345
+ haut niveau `use` :
2346
+
2347
+ ``` ruby
2348
+ require 'sinatra'
2349
+ require 'mon_middleware_perso'
2350
+
2351
+ use Rack::Lint
2352
+ use MonMiddlewarePerso
2353
+
2354
+ get '/bonjour' do
2355
+ 'Bonjour le monde'
2356
+ end
2357
+ ```
2358
+
2359
+ La sémantique de `use` est identique à celle définie dans le DSL de
2360
+ [Rack::Builder](http://rack.rubyforge.org/doc/classes/Rack/Builder.html)
2361
+ (le plus souvent utilisé dans un fichier rackup). Par exemple, la méthode
2362
+ `use` accepte divers arguments ainsi que des blocs :
2363
+
2364
+ ``` ruby
2365
+ use Rack::Auth::Basic do |login, password|
2366
+ login == 'admin' && password == 'secret'
2367
+ end
2368
+ ```
2369
+
2370
+ Rack est distribué avec de nombreux middlewares standards pour loguer, débuguer,
2371
+ faire du routage URL, de l'authentification ou gérer des sessions. Sinatra gère
2372
+ plusieurs de ces composants automatiquement via son système de configuration, ce
2373
+ qui vous dispense de faire un `use` en ce qui les concerne.
2374
+
2375
+ Vous trouverez d'autres middlewares intéressants sur
2376
+ [rack](https://github.com/rack/rack/tree/master/lib/rack),
2377
+ [rack-contrib](https://github.com/rack/rack-contrib#readm),
2378
+ ou en consultant le [wiki de Rack](https://github.com/rack/rack/wiki/List-of-Middleware).
2379
+
2380
+ ## Tester
2381
+
2382
+ Les tests pour Sinatra peuvent être écrit avec n'importe quelle bibliothèque
2383
+ basée sur Rack. [Rack::Test](http://gitrdoc.com/brynary/rack-test) est
2384
+ recommandé :
2385
+
2386
+ ``` ruby
2387
+ require 'mon_application_sinatra'
2388
+ require 'test/unit'
2389
+ require 'rack/test'
2390
+
2391
+ class MonTest < Test::Unit::TestCase
2392
+ include Rack::Test::Methods
2393
+
2394
+ def app
2395
+ Sinatra::Application
2396
+ end
2397
+
2398
+ def test_ma_racine
2399
+ get '/'
2400
+ assert_equal 'Bonjour le monde !', last_response.body
2401
+ end
2402
+
2403
+ def test_avec_des_parametres
2404
+ get '/rencontrer', :name => 'Frank'
2405
+ assert_equal 'Salut Frank !', last_response.body
2406
+ end
2407
+
2408
+ def test_avec_rack_env
2409
+ get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
2410
+ assert_equal "Vous utilisez Songbird !", last_response.body
2411
+ end
2412
+ end
2413
+ ```
2414
+
2415
+ ## Sinatra::Base - Les Middlewares, Bibliothèques, et Applications Modulaires
2416
+
2417
+ Définir votre application au niveau supérieur fonctionne bien dans le cas des
2418
+ micro-applications mais présente pas mal d'inconvénients pour créer des
2419
+ composants réutilisables sous forme de middlewares Rack, de Rails metal, de
2420
+ simples librairies avec un composant serveur ou même d'extensions Sinatra. Le
2421
+ niveau supérieur suppose une configuration dans le style des micro-applications
2422
+ (une application d'un seul fichier, des répertoires `./public` et
2423
+ `./views`, des logs, une page d'erreur, etc...). C'est là que
2424
+ `Sinatra::Base` prend tout son intérêt :
2425
+
2426
+ ``` ruby
2427
+ require 'sinatra/base'
2428
+
2429
+ class MonApplication < Sinatra::Base
2430
+ set :sessions, true
2431
+ set :foo, 'bar'
2432
+
2433
+ get '/' do
2434
+ 'Bonjour le monde !'
2435
+ end
2436
+ end
2437
+ ```
2438
+
2439
+ Les méthodes de la classe `Sinatra::Base` sont parfaitement identiques à
2440
+ celles disponibles via le DSL de haut niveau. Il suffit de deux modifications
2441
+ pour transformer la plupart des applications de haut niveau en un composant
2442
+ `Sinatra::Base` :
2443
+
2444
+ * Votre fichier doit charger `sinatra/base` au lieu de `sinatra`, sinon toutes
2445
+ les méthodes du DSL Sinatra seront importées dans l'espace de nom principal.
2446
+ * Les gestionnaires de routes, la gestion d'erreur, les filtres et les options
2447
+ doivent être placés dans une classe héritant de `Sinatra::Base`.
2448
+
2449
+ `Sinatra::Base` est une page blanche. La plupart des options sont
2450
+ désactivées par défaut, y compris le serveur intégré. Reportez-vous à
2451
+ [Options et Configuration](http://sinatra.github.com/configuration.html)
2452
+ pour plus d'informations sur les options et leur fonctionnement.
2453
+
2454
+ ### Style modulaire vs. style classique
2455
+
2456
+ Contrairement aux idées reçues, il n'y a rien de mal à utiliser le style
2457
+ classique. Si c'est ce qui convient pour votre application, vous n'avez pas
2458
+ aucune raison de passer à une application modulaire.
2459
+
2460
+ Le principal inconvénient du style classique sur le style modulaire est que vous
2461
+ ne pouvez avoir qu'une application Ruby par processus Ruby. Si vous pensez en
2462
+ utiliser plus, passez au style modulaire. Et rien ne vous empêche de mixer style
2463
+ classique et style modulaire.
2464
+
2465
+ Si vous passez d'un style à l'autre, souvenez-vous des quelques différences
2466
+ mineures en ce qui concerne les paramètres par défaut :
2467
+
2468
+ Paramètre Classique Modulaire
2469
+
2470
+ app_file fichier chargeant sinatra fichier héritant de Sinatra::Base
2471
+ run $0 == app_file false
2472
+ logging true false
2473
+ method_override true false
2474
+ inline_templates true false
2475
+ static true false
2476
+
2477
+ ### Servir une application modulaire
2478
+
2479
+ Il y a deux façons de faire pour démarrer une application modulaire, démarrez
2480
+ avec `run!` :
2481
+
2482
+ ``` ruby
2483
+ # my_app.rb
2484
+ require 'sinatra/base'
2485
+
2486
+ class MyApp < Sinatra::Base
2487
+ # ... code de l'application ici ...
2488
+
2489
+ # démarre le serveur si ce fichier est directement exécuté
2490
+ run! if app_file == $0
2491
+ end
2492
+ ```
2493
+
2494
+ Démarrez ensuite avec :
2495
+
2496
+ ``` shell
2497
+ ruby my_app.rb
2498
+ ```
2499
+
2500
+ Ou alors avec un fichier `config.ru`, qui permet d'utiliser n'importe
2501
+ quel gestionnaire Rack :
2502
+
2503
+ ``` ruby
2504
+ # config.ru
2505
+ require './my_app'
2506
+ run MyApp
2507
+ ```
2508
+
2509
+ Exécutez :
2510
+
2511
+ ``` shell
2512
+ rackup -p 4567
2513
+ ```
2514
+
2515
+ ### Utiliser une application de style classique avec un fichier config.ru
2516
+
2517
+ Ecrivez votre application :
2518
+
2519
+ ``` ruby
2520
+ # app.rb
2521
+ require 'sinatra'
2522
+
2523
+ get '/' do
2524
+ 'Bonjour le monde !'
2525
+ end
2526
+ ```
2527
+
2528
+ Et un fichier `config.ru` correspondant :
2529
+
2530
+ ``` ruby
2531
+ require './app'
2532
+ run Sinatra::Application
2533
+ ```
2534
+
2535
+ ### Quand utiliser un fichier config.ru ?
2536
+
2537
+ Quelques cas où vous devriez utiliser un fichier `config.ru` :
2538
+
2539
+ * Vous souhaitez déployer avec un autre gestionnaire Rack (Passenger, Unicorn,
2540
+ Heroku, ...).
2541
+ * Vous souhaitez utiliser plus d'une sous-classe de `Sinatra::Base`.
2542
+ * Vous voulez utiliser Sinatra comme un middleware, non en tant que
2543
+ endpoint.
2544
+
2545
+ **Il n'est pas nécessaire de passer par un fichier `config.ru` pour la
2546
+ seule raison que vous êtes passé au style modulaire, et vous n'avez pas besoin
2547
+ de passer au style modulaire pour utiliser un fichier `config.ru`.**
2548
+
2549
+ ### Utiliser Sinatra comme Middleware
2550
+
2551
+ Non seulement Sinatra peut utiliser d'autres middlewares Rack, il peut
2552
+ également être à son tour utilisé au-dessus de n'importe quel endpoint Rack
2553
+ en tant que middleware. Ce endpoint peut très bien être une autre
2554
+ application Sinatra, ou n'importe quelle application basée sur Rack
2555
+ (Rails/Ramaze/Camping/...) :
2556
+
2557
+ ``` ruby
2558
+ require 'sinatra/base'
2559
+
2560
+ class EcranDeConnexion < Sinatra::Base
2561
+ enable :sessions
2562
+
2563
+ get('/connexion') { haml :connexion }
2564
+
2565
+ post('/connexion') do
2566
+ if params[:nom] = 'admin' && params[:motdepasse] = 'admin'
2567
+ session['nom_utilisateur'] = params[:nom]
2568
+ else
2569
+ redirect '/connexion'
2570
+ end
2571
+ end
2572
+ end
2573
+
2574
+ class MonApp < Sinatra::Base
2575
+ # le middleware sera appelé avant les filtres
2576
+ use EcranDeConnexion
2577
+
2578
+ before do
2579
+ unless session['nom_utilisateur']
2580
+ halt "Accès refusé, merci de vous <a href='/connexion'>connecter</a>."
2581
+ end
2582
+ end
2583
+
2584
+ get('/') { "Bonjour #{session['nom_utilisateur']}." }
2585
+ end
2586
+ ```
2587
+
2588
+ ### Création dynamique d'applications
2589
+
2590
+ Il se peut que vous ayez besoin de créer une nouvelle application à l'exécution
2591
+ sans avoir à les assigner à une constante, vous pouvez le faire grâce à
2592
+ `Sinatra.new` :
2593
+
2594
+ ``` ruby
2595
+ require 'sinatra/base'
2596
+ mon_app = Sinatra.new { get('/') { "salut" } }
2597
+ mon_app.run!
2598
+ ```
2599
+
2600
+ L'application dont elle hérite peut être passé en argument optionnel :
2601
+
2602
+ ``` ruby
2603
+ # config.ru
2604
+ require 'sinatra/base'
2605
+
2606
+ controleur = Sinatra.new do
2607
+ enable :logging
2608
+ helpers MyHelpers
2609
+ end
2610
+
2611
+ map('/a') do
2612
+ run Sinatra.new(controleur) { get('/') { 'a' } }
2613
+ end
2614
+
2615
+ map('/b') do
2616
+ run Sinatra.new(controleur) { get('/') { 'b' } }
2617
+ end
2618
+ ```
2619
+
2620
+ C'est notamment utile pour tester des extensions à Sinatra ou bien pour
2621
+ utiliser Sinatra dans votre propre bibliothèque.
2622
+
2623
+ Cela permet également d'utiliser très facilement Sinatra comme middleware :
2624
+
2625
+ ``` ruby
2626
+ require 'sinatra/base'
2627
+
2628
+ use Sinatra do
2629
+ get('/') { ... }
2630
+ end
2631
+
2632
+ run RailsProject::Application
2633
+ ```
2634
+
2635
+ ## Contextes et Binding
2636
+
2637
+ Le contexte dans lequel vous êtes détermine les méthodes et variables
2638
+ disponibles.
2639
+
2640
+ ### Contexte de l'application/classe
2641
+
2642
+ Une application Sinatra correspond à une sous-classe de `Sinatra::Base`. Il
2643
+ s'agit de `Sinatra::Application` si vous utilisez le DSL de haut niveau
2644
+ (`require 'sinatra'`). Sinon c'est la sous-classe que vous avez définie. Dans
2645
+ le contexte de cette classe, vous avez accès aux méthodes telles que `get` ou
2646
+ `before`, mais pas aux objets `request` ou `session` étant donné que toutes
2647
+ les requêtes sont traitées par une seule classe d'application.
2648
+
2649
+ Les options définies au moyen de `set` deviennent des méthodes de classe :
2650
+
2651
+ ``` ruby
2652
+ class MonApp < Sinatra::Base
2653
+ # Eh, je suis dans le contexte de l'application !
2654
+ set :foo, 42
2655
+ foo # => 42
2656
+
2657
+ get '/foo' do
2658
+ # Eh, je ne suis plus dans le contexte de l'application !
2659
+ end
2660
+ end
2661
+ ```
2662
+
2663
+ Vous avez le binding du contexte de l'application dans :
2664
+
2665
+ * Le corps de la classe d'application
2666
+ * Les méthodes définies par les extensions
2667
+ * Le bloc passé à `helpers`
2668
+ * Les procs/blocs utilisés comme argument pour `set`
2669
+ * Le bloc passé à `Sinatra.new`
2670
+
2671
+ Vous pouvez atteindre ce contexte (donc la classe) de la façon suivante :
2672
+
2673
+ * Via l'objet passé dans les blocs `configure` (`configure { |c| ... }`)
2674
+ * En utilisant `settings` dans le contexte de la requête
2675
+
2676
+ ### Contexte de la requête/instance
2677
+
2678
+ Pour chaque requête traitée, une nouvelle instance de votre classe
2679
+ d'application est créée et tous vos gestionnaires sont exécutés dans ce
2680
+ contexte. Depuis celui-ci, vous pouvez accéder aux objets `request` et
2681
+ `session` ou faire appel aux fonctions de rendu telles que `erb` ou `haml`.
2682
+ Vous pouvez accéder au contexte de l'application depuis le contexte de la
2683
+ requête au moyen de `settings` :
2684
+
2685
+ ``` ruby
2686
+ class MonApp < Sinatra::Base
2687
+ # Eh, je suis dans le contexte de l'application !
2688
+ get '/ajouter_route/:nom' do
2689
+ # Contexte de la requête pour '/ajouter_route/:nom'
2690
+ @value = 42
2691
+
2692
+ settings.get("/#{params[:nom]}") do
2693
+ # Contexte de la requête pour "/#{params[:nom]}"
2694
+ @value # => nil (on est pas au sein de la même requête)
2695
+ end
2696
+
2697
+ "Route ajoutée !"
2698
+ end
2699
+ end
2700
+ ```
2701
+
2702
+ Vous avez le binding du contexte de la requête dans :
2703
+
2704
+ * les blocs get, head, post, put, delete, options, patch, link et unlink
2705
+ * les filtres before et after
2706
+ * les méthodes utilitaires (définies au moyen de `helpers`)
2707
+ * les vues et templates
2708
+
2709
+ ### Le contexte de délégation
2710
+
2711
+ Le contexte de délégation se contente de transmettre les appels de méthodes au
2712
+ contexte de classe. Toutefois, il ne se comporte pas à 100% comme le contexte
2713
+ de classe car vous n'avez pas le binding de la classe : seules les méthodes
2714
+ spécifiquement déclarées pour délégation sont disponibles et il n'est pas
2715
+ possible de partager des variables/états avec le contexte de classe
2716
+ (comprenez : `self` n'est pas le même). Vous pouvez ajouter des délégation de
2717
+ méthodes en appelant `Sinatra::Delegator.delegate :method_name`.
2718
+
2719
+ Vous avez le binding du contexte de délégation dans :
2720
+
2721
+ * Le binding de haut niveau, si vous avez utilisé `require "sinatra"`
2722
+ * Un objet qui inclut le module `Sinatra::Delegator`
2723
+
2724
+ Pour vous faire une idée, vous pouvez jeter un coup d'oeil au
2725
+ [mixin Sinatra::Delegator](https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/base.rb#L1609-1633)
2726
+ qui [étend l'objet principal](https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/main.rb#L28-30).
2727
+
2728
+ ## Ligne de commande
2729
+
2730
+ Les applications Sinatra peuvent être lancées directement :
2731
+
2732
+ ``` shell
2733
+ ruby mon_application.rb [-h] [-x] [-e ENVIRONNEMENT] [-p PORT] [-o HOTE] [-s SERVEUR]
2734
+ ```
2735
+
2736
+ Avec les options :
2737
+
2738
+ ```
2739
+ -h # aide
2740
+ -p # déclare le port (4567 par défaut)
2741
+ -o # déclare l'hôte (0.0.0.0 par défaut)
2742
+ -e # déclare l'environnement (development par défaut)
2743
+ -s # déclare le serveur/gestionnaire à utiliser (thin par défaut)
2744
+ -x # active le mutex lock (off par défaut)
2745
+ ```
2746
+
2747
+ ## Configuration nécessaire
2748
+
2749
+ Les versions suivantes de Ruby sont officiellement supportées :
2750
+
2751
+ <dl>
2752
+ <dt>Ruby 1.8.7</dt>
2753
+ <dd>
2754
+ 1.8.7 est complètement supporté, toutefois si rien ne vous en empêche,
2755
+ nous vous recommandons de faire une mise à jour ou bien de passer à JRuby
2756
+ ou Rubinius. Le support de Ruby 1.8.7 ne sera pas supprimé avant la sortie
2757
+ de Sinatra 2.0. Ruby 1.8.6 n’est plus supporté.
2758
+ </dd>
2759
+
2760
+ <dt>Ruby 1.9.2</dt>
2761
+ <dd>
2762
+ 1.9.2 est totalement supporté. N’utilisez pas 1.9.2p0 car il provoque des
2763
+ erreurs de segmentation à l’exécution de Sinatra. Son support continuera
2764
+ au minimum jusqu’à la sortie de Sinatra 1.5.
2765
+ </dd>
2766
+
2767
+ <dt>Ruby 1.9.3</dt>
2768
+ <dd>
2769
+ 1.9.3 est totalement supporté et recommandé. Nous vous rappelons que passer
2770
+ à 1.9.3 depuis une version précédente annulera toutes les sessions. 1.9.3
2771
+ sera supporté jusqu'à la sortie de Sinatra 2.0.
2772
+ </dd>
2773
+
2774
+ <dt>Ruby 2.0.0</dt>
2775
+ <dd>
2776
+ 2.0.0 est totalement supporté et recommandé. L'abandon de son support
2777
+ officiel n'est pas à l'ordre du jour.
2778
+ </dd>
2779
+
2780
+ <dt>Rubinius</dt>
2781
+ <dd>
2782
+ Rubinius est officiellement supporté (Rubinius >= 2.x). Un <tt>gem install
2783
+ puma</tt> est recommandé.
2784
+ </dd>
2785
+
2786
+ <dt>JRuby</dt>
2787
+ <dd>
2788
+ La dernière version stable de JRuby est officiellement supportée. Il est
2789
+ déconseillé d'utiliser des extensions C avec JRuby. Un <tt>gem install
2790
+ trinidad</tt> est recommandé.
2791
+ </dd>
2792
+ </dl>
2793
+
2794
+ Nous gardons également un oeil sur les versions Ruby à venir.
2795
+
2796
+ Les implémentations Ruby suivantes ne sont pas officiellement supportées mais
2797
+ sont malgré tout connues pour permettre de faire fonctionner Sinatra :
2798
+
2799
+ * Versions plus anciennes de JRuby et Rubinius
2800
+ * Ruby Enterprise Edition
2801
+ * MacRuby, Maglev, IronRuby
2802
+ * Ruby 1.9.0 et 1.9.1 (mais nous déconseillons leur utilisation)
2803
+
2804
+ Le fait de ne pas être officiellement supporté signifie que si quelque chose
2805
+ ne fonctionne pas sur cette plateforme uniquement alors c'est un problème de la
2806
+ plateforme et pas un bug de Sinatra.
2807
+
2808
+ Nous lançons également notre intégration continue (CI) avec ruby-head (la
2809
+ future 2.1.0), mais nous ne pouvont rien garantir étant donné les évolutions
2810
+ continuelles. La version 2.1.0 devrait être totalement supportée.
2811
+
2812
+ Sinatra devrait fonctionner sur n'importe quel système d'exploitation
2813
+ supporté par l'implémentation Ruby choisie.
2814
+
2815
+ Si vous utilisez MacRuby, vous devriez `gem install control_tower`.
2816
+
2817
+ Il n'est pas possible d'utiliser Sinatra sur Cardinal, SmallRuby, BlueRuby ou
2818
+ toute version de Ruby antérieure à 1.8.7 à l'heure actuelle.
2819
+
2820
+ ## Essuyer les plâtres
2821
+
2822
+ Si vous souhaitez tester la toute dernière version de Sinatra, n'hésitez pas
2823
+ à faire tourner votre application sur la branche master, celle-ci devrait être
2824
+ stable.
2825
+
2826
+ Pour cela, la méthode la plus simple est d'installer une gem de prerelease que
2827
+ nous publions de temps en temps :
2828
+
2829
+ ``` shell
2830
+ gem install sinatra --pre
2831
+ ```
2832
+ Ce qui permet de bénéficier des toutes dernières fonctionnalités.
2833
+
2834
+ ### Installer avec Bundler
2835
+
2836
+ Il est cependant conseillé de passer par [Bundler](http://gembundler.com/) pour
2837
+ faire tourner votre application avec la dernière version de Sinatra.
2838
+
2839
+ Pour commencer, installez bundler si nécessaire :
2840
+
2841
+ ``` shell
2842
+ gem install bundler
2843
+ ```
2844
+
2845
+ Ensuite, créez un fichier `Gemfile` dans le dossier de votre projet :
2846
+
2847
+ ``` ruby
2848
+ source 'https://rubygems.org'
2849
+ gem 'sinatra', :github => "sinatra/sinatra"
2850
+
2851
+ # autres dépendances
2852
+ gem 'haml' # si par exemple vous utilisez haml
2853
+ gem 'activerecord', '~> 3.0' # au cas où vous auriez besoin de ActiveRecord 3.x
2854
+ ```
2855
+
2856
+ Notez que vous devez lister toutes les dépendances de votre application dans
2857
+ ce fichier `Gemfile`. Les dépendances directes de Sinatra (Rack et Tilt) seront
2858
+ automatiquement téléchargées et ajoutées par Bundler.
2859
+
2860
+ Vous pouvez alors lancer votre application de la façon suivante :
2861
+
2862
+ ``` shell
2863
+ bundle exec ruby myapp.rb
2864
+ ```
2865
+
2866
+ ### Faire un clone local
2867
+
2868
+ Si vous ne souhaitez pas employer Bundler, vous pouvez cloner Sinatra en local
2869
+ dans votre projet et démarrez votre application avec le dossier `sinatra/lib`
2870
+ dans le `$LOAD_PATH` :
2871
+
2872
+ ``` shell
2873
+ cd myapp
2874
+ git clone git://github.com/sinatra/sinatra.git
2875
+ ruby -I sinatra/lib myapp.rb
2876
+ ```
2877
+
2878
+ Et de temps en temps, vous devrez récupérer la dernière version du code source
2879
+ de Sinatra :
2880
+
2881
+ ``` shell
2882
+ cd myapp/sinatra
2883
+ git pull
2884
+ ```
2885
+
2886
+ ### Installer globalement
2887
+
2888
+ Une dernière méthode consiste à construire la gem vous-même :
2889
+
2890
+ ``` shell
2891
+ git clone git://github.com/sinatra/sinatra.git
2892
+ cd sinatra
2893
+ rake sinatra.gemspec
2894
+ rake install
2895
+ ```
2896
+
2897
+ Si vous installez les gems en tant que root, vous devez encore faire un :
2898
+
2899
+ ``` shell
2900
+ sudo rake install
2901
+ ```
2902
+
2903
+ ## Versions
2904
+
2905
+ Sinatra se conforme aux [versions sémantiques](http://semver.org/), aussi bien
2906
+ SemVer que SemVerTag.
2907
+
2908
+ ## Mais encore
2909
+
2910
+ * [Site internet](http://www.sinatrarb.com/) - Plus de documentation,
2911
+ de news, et des liens vers d'autres ressources.
2912
+ * [Contribuer](http://www.sinatrarb.com/contributing) - Vous avez trouvé un
2913
+ bug ? Besoin d'aide ? Vous avez un patch ?
2914
+ * [Suivi des problèmes](http://github.com/sinatra/sinatra/issues)
2915
+ * [Twitter](http://twitter.com/sinatra)
2916
+ * [Mailing List](http://groups.google.com/group/sinatrarb/topics)
2917
+ * IRC : [#sinatra](irc://chat.freenode.net/#sinatra) sur http://freenode.net
2918
+ * [Sinatra Book](http://sinatra-book.gittr.com) Tutoriels et recettes
2919
+ * [Sinatra Recipes](http://recipes.sinatrarb.com/) trucs et astuces rédigés par
2920
+ la communauté
2921
+ * Documentation API de la [dernière version](http://rubydoc.info/gems/sinatra)
2922
+ ou du [HEAD courant](http://rubydoc.info/github/sinatra/sinatra) sur
2923
+ http://rubydoc.info
2924
+ * [CI server](http://travis-ci.org/sinatra/sinatra)