sinatra 1.0 → 1.1.a

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sinatra might be problematic. Click here for more details.

Files changed (57) hide show
  1. data/CHANGES +108 -1
  2. data/LICENSE +1 -1
  3. data/README.de.rdoc +1024 -0
  4. data/README.es.rdoc +1047 -0
  5. data/README.fr.rdoc +1038 -0
  6. data/README.hu.rdoc +607 -0
  7. data/README.jp.rdoc +473 -15
  8. data/README.rdoc +429 -41
  9. data/Rakefile +17 -6
  10. data/lib/sinatra/base.rb +357 -158
  11. data/lib/sinatra/showexceptions.rb +9 -1
  12. data/sinatra.gemspec +52 -9
  13. data/test/builder_test.rb +25 -1
  14. data/test/coffee_test.rb +88 -0
  15. data/test/encoding_test.rb +18 -0
  16. data/test/filter_test.rb +61 -2
  17. data/test/hello.mab +1 -0
  18. data/test/helper.rb +1 -0
  19. data/test/helpers_test.rb +141 -37
  20. data/test/less_test.rb +26 -2
  21. data/test/liquid_test.rb +58 -0
  22. data/test/markaby_test.rb +58 -0
  23. data/test/markdown_test.rb +35 -0
  24. data/test/nokogiri_test.rb +69 -0
  25. data/test/radius_test.rb +59 -0
  26. data/test/rdoc_test.rb +34 -0
  27. data/test/request_test.rb +12 -0
  28. data/test/routing_test.rb +35 -1
  29. data/test/sass_test.rb +46 -16
  30. data/test/scss_test.rb +88 -0
  31. data/test/settings_test.rb +32 -0
  32. data/test/sinatra_test.rb +4 -0
  33. data/test/static_test.rb +64 -0
  34. data/test/templates_test.rb +55 -1
  35. data/test/textile_test.rb +34 -0
  36. data/test/views/ascii.haml +2 -0
  37. data/test/views/explicitly_nested.str +1 -0
  38. data/test/views/hello.coffee +1 -0
  39. data/test/views/hello.liquid +1 -0
  40. data/test/views/hello.mab +1 -0
  41. data/test/views/hello.md +1 -0
  42. data/test/views/hello.nokogiri +1 -0
  43. data/test/views/hello.radius +1 -0
  44. data/test/views/hello.rdoc +1 -0
  45. data/test/views/hello.sass +1 -1
  46. data/test/views/hello.scss +3 -0
  47. data/test/views/hello.str +1 -0
  48. data/test/views/hello.textile +1 -0
  49. data/test/views/layout2.liquid +2 -0
  50. data/test/views/layout2.mab +2 -0
  51. data/test/views/layout2.nokogiri +3 -0
  52. data/test/views/layout2.radius +2 -0
  53. data/test/views/layout2.str +2 -0
  54. data/test/views/nested.str +1 -0
  55. data/test/views/utf8.haml +2 -0
  56. metadata +240 -33
  57. data/lib/sinatra/tilt.rb +0 -746
@@ -0,0 +1,1038 @@
1
+ = Sinatra
2
+ <i>Attention: Ce document correspond à la traduction de la version anglaise et il n'est peut être plus à jour.</i>
3
+
4
+ Sinatra est un DSL pour créer rapidement des applications web en Ruby et sans
5
+ effort:
6
+
7
+ # mon_application.rb
8
+ require 'sinatra'
9
+ get '/' do
10
+ 'Bonjour Monde!'
11
+ end
12
+
13
+ Installez le gem et lancez avec:
14
+
15
+ gem install sinatra
16
+ ruby -rubygems mon_application.rb
17
+
18
+ Le résultat est visible sur: http://localhost:4567
19
+
20
+ == Routes
21
+
22
+ Dans Sinatra, une route est une méthode HTTP couplée à un masque (pattern) URL.
23
+ Chaque route est associée à un bloc:
24
+
25
+ get '/' do
26
+ .. montrer quelque chose ..
27
+ end
28
+
29
+ post '/' do
30
+ .. créer quelque chose ..
31
+ end
32
+
33
+ put '/' do
34
+ .. changer quelque chose ..
35
+ end
36
+
37
+ delete '/' do
38
+ .. effacer quelque chose ..
39
+ end
40
+
41
+ Les routes sont comparées dans l'ordre où elles ont été définies. La première route qui
42
+ correspond à la requête est invoquée.
43
+
44
+ Les masques peuvent inclure des paramètres, accessibles par l'intermédiaire du
45
+ hash <tt>params</tt>:
46
+
47
+ get '/bonjour/:nom' do
48
+ # répond aux requêtes "GET /bonjour/foo" et "GET /bonjour/bar"
49
+ # params[:nom] est 'foo' ou 'bar'
50
+ "Bonjour #{params[:nom]}!"
51
+ end
52
+
53
+ Vous pouvez aussi les nommer directement dans les paramètres du bloc comme ceci:
54
+
55
+ get '/bonjour/:nom' do |n|
56
+ "Bonjour #{n}!"
57
+ end
58
+
59
+ Une route peut contenir un splat (caractère joker), accessible par l'intermédiaire de
60
+ la liste <tt>params[:splat]</tt>.
61
+
62
+ get '/dire/*/a/*' do
63
+ # répondrait à /dire/bonjour/a/monde
64
+ params[:splat] # => ["bonjour", "monde"]
65
+ end
66
+
67
+ get '/telecharger/*.*' do
68
+ # répondrait à /telecharger/chemin/vers/fichier.xml
69
+ params[:splat] # => ["chemin/vers/fichier", "xml"]
70
+ end
71
+
72
+ Une route peut s'exprimer avec une Expression Régulière:
73
+
74
+ get %r{/bonjour/([\w]+)} do
75
+ "Bonjour, #{params[:captures].first}!"
76
+ end
77
+
78
+ Là aussi on peut utiliser les paramètres de bloc:
79
+
80
+ get %r{/bonjour/([\w]+)} do |c|
81
+ "Bonjour, #{c}!"
82
+ end
83
+
84
+ === Conditions
85
+
86
+ Les routes peuvent définir toutes sortes de conditions, comme par exemple le "user agent":
87
+
88
+ get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
89
+ "Vous utilisez Songbird version #{params[:agent][0]}"
90
+ end
91
+
92
+ get '/foo' do
93
+ # Correspond à tous les autres navigateurs
94
+ end
95
+
96
+ Les autres conditions disponibles sont +host_name+ et +provides+:
97
+
98
+ get '/', :host_name => /^admin\./ do
99
+ "Zone Administrateur, Accès refusé!"
100
+ end
101
+
102
+ get '/', :provides => 'html' do
103
+ haml :index
104
+ end
105
+
106
+ get '/', :provides => ['rss', 'atom', 'xml'] do
107
+ builder :feed
108
+ end
109
+
110
+ Vous pouvez facilement définir vos propres conditions:
111
+
112
+ set(:probability) { |value| condition { rand <= value } }
113
+
114
+ get '/gagner_une_voiture', :probability => 0.1 do
115
+ "Vous avez gagné!"
116
+ end
117
+
118
+ get '/gagner_une_voiture' do
119
+ "Désolé, vous avez perdu."
120
+ end
121
+
122
+ === Valeurs de retour
123
+
124
+ La valeur de retour d'un bloc définissant une route détermine le corps de la réponse
125
+ qui sera transmise au client HTTP ou du moins au prochain middleware dans la pile Rack.
126
+ Le plus généralement, il s'agit d'une chaîne de caractères, comme dans les exemples
127
+ précédents. Cependant, d'autres valeurs sont acceptées.
128
+
129
+ Vous pouvez renvoyer n'importe quel objet qui soit une réponse Rack valide, un corps de
130
+ réponse Rack ou un code retour HTTP:
131
+
132
+ * Un tableau de 3 éléments: <tt>[code retour (Fixnum), entêtes (Hash), corps de réponse (répondant à #each)]</tt>
133
+ * Un tableau de 2 élements: <tt>[code retour (Fixnum), corps de réponse (répondant à #each)]</tt>
134
+ * Un objet qui répond à <tt>#each</tt> et qui ne transmet que des chaînes de caractères au bloc fourni
135
+ * Un Fixnum représentant le code retour
136
+
137
+ Ainsi, on peut facilement implémenter un streaming par exemple:
138
+
139
+ class Stream
140
+ def each
141
+ 100.times { |i| yield "#{i}\n" }
142
+ end
143
+ end
144
+
145
+ get('/') { Stream.new }
146
+
147
+ == Fichiers statiques
148
+
149
+ Par défaut, le dossier <tt>./public</tt> est utilisé pour servir les fichiers statiques.
150
+ Vous pouvez changer ce dossier pour un autre nom grâce à l'option <tt>:public</tt>:
151
+
152
+ set :public, File.dirname(__FILE__) + '/statique'
153
+
154
+ Notez que le nom du dossier public n'est pas inclus dans l'URL. Un fichier sous
155
+ <tt>./public/css/style.css</tt> est appelé avec l'URL: <tt>http://exemple.com/css/style.css</tt>.
156
+
157
+ == Vues / Templates
158
+
159
+ Par défaut, les templates sont cherchés dans le dossier <tt>./views</tt>.
160
+ Pour utiliser un autre dossier, il faut le déclarer:
161
+
162
+ set :views, File.dirname(__FILE__) + '/templates'
163
+
164
+ Il est important de noter que les templates sont toujours référencés
165
+ sous forme de symboles, même s'il s'agit d'un sous-répertoire (dans ce
166
+ cas, utilisez <tt>:'sous_repertoire/template'</tt>). Vous devez utiliser un symbole
167
+ car les méthodes de rendu évalueront le contenu des chaînes de caractères
168
+ au lieu de les considérer comme un chemin vers un fichier.
169
+
170
+ === Templates Haml
171
+
172
+ Le gem haml est nécessaire pour utiliser la fonction de rendu Haml:
173
+
174
+ ## Chargez la bibliothèque haml dans votre application
175
+ require 'haml'
176
+
177
+ get '/' do
178
+ haml :index
179
+ end
180
+
181
+ Utilisera le template: <tt>./views/index.haml</tt>.
182
+
183
+ {Les options de Haml}[http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#options]
184
+ peuvent se manipuler directement avec la configuration de Sinatra,
185
+ voir {Options et Configuration}[http://www.sinatrarb.com/configuration.html],
186
+ et supportent aussi la réécriture (surcharge) comme dans cet exemple.
187
+
188
+ set :haml, :format => :html5 # le format par défaut dans Haml est :xhtml
189
+
190
+ get '/' do
191
+ haml :index, :format => :html4 # surcharge
192
+ end
193
+
194
+
195
+ === Templates Erb
196
+
197
+ ## Chargez la bibliothèque erb dans votre application
198
+ require 'erb'
199
+
200
+ get '/' do
201
+ erb :index
202
+ end
203
+
204
+ Utilisera le template: <tt>./views/index.erb</tt>
205
+
206
+ === Erubis
207
+
208
+ Le gem erubis est nécessaire pour utiliser la fonction de rendu erubis:
209
+
210
+ ## Chargez la bibliothèque erubis dans votre application
211
+ require 'erubis'
212
+
213
+ get '/' do
214
+ erubis :index
215
+ end
216
+
217
+ Utilisera le template: <tt>./views/index.erubis</tt>
218
+
219
+ === Templates Builder
220
+
221
+ Le gem builder est nécessaire pour utiliser la fonction de rendu builder:
222
+
223
+ ## Chargez la bibliothèque builder dans votre application
224
+ require 'builder'
225
+
226
+ get '/' do
227
+ builder :index
228
+ end
229
+
230
+ Utilisera le template: <tt>./views/index.builder</tt>.
231
+
232
+ === Templates Nokogiri
233
+
234
+ Le gem nokogiri est nécessaire pour utiliser la fonction de rendu nokogiri:
235
+
236
+ ## Chargez la bibliothèque nokogiri dans votre application
237
+ require 'nokogiri'
238
+
239
+ get '/' do
240
+ nokogiri :index
241
+ end
242
+
243
+ Utilisera le template: <tt>./views/index.nokogiri</tt>.
244
+
245
+ === Templates Sass
246
+
247
+ Le gem sass est nécessaire pour utiliser la fonction de rendu Sass:
248
+
249
+ ## Chargez la bibliothèque haml ou sass dans votre application
250
+ require 'sass'
251
+
252
+ get '/stylesheet.css' do
253
+ sass :stylesheet
254
+ end
255
+
256
+ Utilisera le template: <tt>./views/stylesheet.sass</tt>.
257
+
258
+ {Les options de Sass}[http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options]
259
+ peuvent se manipuler directement avec la configuration de Sinatra,
260
+ voir {Options et Configuration}[http://www.sinatrarb.com/configuration.html],
261
+ et supportent aussi la réécriture (surcharge) comme dans cet exemple.
262
+
263
+ set :sass, :style => :compact # le style par défaut dans Sass est :nested
264
+
265
+ get '/stylesheet.css' do
266
+ sass :stylesheet, :style => :expanded # surcharge
267
+ end
268
+
269
+ === Scss Templates
270
+
271
+ Le gem sass est nécessaire pour utiliser la fonction de rendu Scss:
272
+
273
+ ## Chargez la bibliothèque haml ou sass dans votre application
274
+ require 'sass'
275
+
276
+ get '/stylesheet.css' do
277
+ scss :stylesheet
278
+ end
279
+
280
+ Utilisera le template <tt>./views/stylesheet.scss</tt>.
281
+
282
+ {Les options de Scss}[http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options]
283
+ peuvent se manipuler directement avec la configuration de Sinatra,
284
+ voir {Options et Configuration}[http://www.sinatrarb.com/configuration.html],
285
+ et supportent aussi la réécriture (surcharge) comme dans cet exemple.
286
+
287
+ set :scss, :style => :compact # le style par défaut de Scss est :nested
288
+
289
+ get '/stylesheet.css' do
290
+ scss :stylesheet, :style => :expanded # surcharge
291
+ end
292
+
293
+ === Templates Less
294
+
295
+ Le gem less est nécessaire pour utiliser la fonction de rendu Less:
296
+
297
+ ## Chargez la bibliothèque less dans votre application
298
+ require 'less'
299
+
300
+ get '/stylesheet.css' do
301
+ less :stylesheet
302
+ end
303
+
304
+ Utilisera le template: <tt>./views/stylesheet.less</tt>.
305
+
306
+ === Templates Liquid
307
+
308
+ Le gem liquid est nécessaire pour utiliser la fonction de rendu Liquid:
309
+
310
+ ## Chargez la bibliothèque liquid dans votre application
311
+ require 'liquid'
312
+
313
+ get '/' do
314
+ liquid :index
315
+ end
316
+
317
+ Utilisera <tt>./views/index.liquid</tt>.
318
+
319
+ Comme vous ne pouvez pas appeler des méthodes Ruby (excepté +yield+) dans un
320
+ template Liquid, il sera toujours nécessaire de lui passer des variables locales:
321
+
322
+ liquid :index, :locals => { :key => 'value' }
323
+
324
+ === Templates Markdown
325
+
326
+ Le gem rdiscount est nécessaire pour utiliser la fonction de rendu Markdown:
327
+
328
+ ## Chargez la bibliothèque rdiscount dans votre application
329
+ require "rdiscount"
330
+
331
+ get '/' do
332
+ markdown :index
333
+ end
334
+
335
+ Utilisera <tt>./views/index.markdown</tt> (les extensions de fichier +md+ et +mkd+
336
+ sont également acceptées).
337
+
338
+ Il n'est pas possible d'appeler des méthodes depuis markdown, ni même de lui passer des variables
339
+ locales. Par conséquent, il sera le plus souvent utilisé en combinaison avec un autre moteur
340
+ de rendu:
341
+
342
+ erb :vuedensemble, :locals => { :texte => markdown(:introduction) }
343
+
344
+ Notez que vous pouvez également appeler la méthode markdown au sein d'autres templates:
345
+
346
+ %h1 Bonjour Depuis Haml!
347
+ %p= markdown(:salutations)
348
+
349
+ === Templates Textile
350
+
351
+ Le gem RedCloth est nécessaire pour utiliser la fonction de rendu Textile:
352
+
353
+ ## Chargez la bibliothèqye redcloth dans votre application
354
+ require "redcloth"
355
+
356
+ get '/' do
357
+ textile :index
358
+ end
359
+
360
+ Utilisera <tt>./views/index.textile</tt>.
361
+
362
+ Il n'est pas possible d'appeler des méthodes depuis textile, ni même de lui passer des variables
363
+ locales. Par conséquent, il sera le plus souvent utilisé en combinaison avec un autre moteur
364
+ de rendu:
365
+
366
+ erb :vuedensemble, :locals => { :texte => textile(:introduction) }
367
+
368
+ Notez que vous pouvez également appeler la méthode textile au sein d'autres templates:
369
+
370
+ %h1 Bonjour Depuis Haml!
371
+ %p= textile(:salutations)
372
+
373
+ === Templates RDoc
374
+
375
+ Le gem RDoc est nécessaire pour utiliser la fonction de rendu RDoc:
376
+
377
+ ## Chargez la bibliothèque rdoc dans votre application
378
+ require "rdoc"
379
+
380
+ get '/' do
381
+ rdoc :index
382
+ end
383
+
384
+ Utilisera <tt>./views/index.rdoc</tt>.
385
+
386
+ Il n'est pas possible d'appeler des méthodes depuis rdoc, ni même de lui passer des variables
387
+ locales. Par conséquent, il sera le plus souvent utilisé en combinaison avec un autre moteur
388
+ de rendu:
389
+
390
+ erb :vuedensemble, :locals => { :texte => rdoc(:introduction) }
391
+
392
+ Notez que vous pouvez également appeler la méthode rdoc au sein d'autres templates:
393
+
394
+ %h1 Bonjour Depuis Haml!
395
+ %p= rdoc(:salutations)
396
+
397
+ === Templates Radius
398
+
399
+ Le gem radius est nécessaire pour utiliser la fonction de rendu Radius:
400
+
401
+ ## Chargez la bibliotèque radius dans votre application
402
+ require 'radius'
403
+
404
+ get '/' do
405
+ radius :index
406
+ end
407
+
408
+ Utilisera <tt>./views/index.radius</tt>.
409
+
410
+ Comme vous ne pouvez pas appeler des méthodes Ruby (excepté +yield+) dans un
411
+ template Radius, il sera toujours nécessaire de lui passer des variables locales:
412
+
413
+ radius :index, :locals => { :key => 'value' }
414
+
415
+ === Templates Markaby
416
+
417
+ Le gem markaby est nécessaire pour utiliser la fonction de rendu Markaby:
418
+
419
+ ## Chargez la bibliothèque markaby dans votre application
420
+ require 'markaby'
421
+
422
+ get '/' do
423
+ markaby :index
424
+ end
425
+
426
+ Utilisera <tt>./views/index.mab</tt>.
427
+
428
+ === Templates CoffeeScript
429
+
430
+ Le gem coffee-script et l'exécutable `coffee` sont nécessaires pour utiliser la
431
+ fonction de rendu CoffeeScript:
432
+
433
+ ## Chargez la bibliothèque coffee-script dans votre application
434
+ require 'coffee-script'
435
+
436
+ get '/application.js' do
437
+ coffee :application
438
+ end
439
+
440
+ Utilisera <tt>./views/application.coffee</tt>.
441
+
442
+ === Templates en ligne
443
+
444
+ get '/' do
445
+ haml '%div.title Bonjour Monde'
446
+ end
447
+
448
+ Utilisera le texte passé en argument pour générer la page, au lieu d'aller
449
+ chercher le texte dans un fichier.
450
+
451
+ === Accéder aux variables dans un Template
452
+
453
+ Un template est évalué dans le même contexte que l'endroit d'où il a été
454
+ appelé (gestionnaire de route). Les variables d'instance déclarées dans le
455
+ gestionnaire de route sont directement accessibles dans le template:
456
+
457
+ get '/:id' do
458
+ @foo = Foo.find(params[:id])
459
+ haml '%h1= @foo.nom'
460
+ end
461
+
462
+ Alternativement, on peut passer un hash contenant des variables locales:
463
+
464
+ get '/:id' do
465
+ foo = Foo.find(params[:id])
466
+ haml '%h1= foo.nom', :locals => { :foo => foo }
467
+ end
468
+
469
+ Ceci est généralement utilisé lorsque l'on veut utiliser un template comme partiel
470
+ (depuis un autre template) et qu'il est donc nécessaire d'adapter les noms de variables.
471
+
472
+ === Templates dans le fichier source
473
+
474
+ Des templates peuvent être définis dans le fichier source comme ceci:
475
+
476
+ require 'rubygems'
477
+ require 'sinatra'
478
+
479
+ get '/' do
480
+ haml :index
481
+ end
482
+
483
+ __END__
484
+
485
+ @@ layout
486
+ %html
487
+ = yield
488
+
489
+ @@ index
490
+ %div.title Bonjour Monde!!!!!
491
+
492
+ NOTE: Les templates du fichier source qui contient <tt>require 'sinatra'</tt>
493
+ sont automatiquement chargés. Si vous avez des templates dans d'autres fichiers source,
494
+ il faut explicitement les déclarer via: <tt>enable :inline_templates</tt>.
495
+
496
+ === Templates nommés
497
+
498
+ Les templates peuvent aussi être définis grâce à la méthode de haut niveau <tt>template</tt>:
499
+
500
+ template :layout do
501
+ "%html\n =yield\n"
502
+ end
503
+
504
+ template :index do
505
+ '%div.title Bonjour Monde!'
506
+ end
507
+
508
+ get '/' do
509
+ haml :index
510
+ end
511
+
512
+ Si un template nommé "layout" existe, il sera utilisé à chaque fois qu'un template
513
+ sera affiché. Vous pouvez désactivez le layout à tout moment en passant
514
+ <tt>:layout => false</tt>.
515
+
516
+ get '/' do
517
+ haml :index, :layout => !request.xhr?
518
+ end
519
+
520
+ == Helpers
521
+
522
+ Utilisez la méthode de haut niveau <tt>helpers</tt> pour définir des routines qui
523
+ seront accessibles dans vos gestionnaires de route et dans vos templates:
524
+
525
+ helpers do
526
+ def bar(nom)
527
+ "#{nom}bar"
528
+ end
529
+ end
530
+
531
+ get '/:nom' do
532
+ bar(params[:nom])
533
+ end
534
+
535
+ == Filtres
536
+
537
+ Un filtre <tt>before</tt> est évalué avant n'importe quelle requête, dans le
538
+ contexte de celle-ci, et peut modifier la requête ou la réponse. Les variables
539
+ d'instance déclarées dans le filtre sont accessibles au gestionnaire de route
540
+ et au template:
541
+
542
+ before do
543
+ @note = 'Coucou!'
544
+ request.path_info = '/foo/bar/baz'
545
+ end
546
+
547
+ get '/foo/*' do
548
+ @note #=> 'Coucou!'
549
+ params[:splat] #=> 'bar/baz'
550
+ end
551
+
552
+ Un filtre <tt>after</tt> est évalué après chaque requête, dans le contexte
553
+ de celle-ci et peut également modifier la requête et/ou la réponse. Toutes les
554
+ variables d'instance déclarées dans un filtre <tt>before</tt> et dans le gestionnaire
555
+ de route sont accessibles dans le filtre <tt>after</tt>:
556
+
557
+ after do
558
+ puts response.status
559
+ end
560
+
561
+ En option, on peut passer un masque au filtre, ce qui le rend actif uniquement
562
+ si la requête correspond au masque en question:
563
+
564
+ before '/secret/*' do
565
+ authentification!
566
+ end
567
+
568
+ after '/faire/:travail' do |travail|
569
+ session[:dernier_travail] = travail
570
+ end
571
+
572
+ == Halt
573
+
574
+ Pour arrêter immédiatement la requête dans un filtre ou un gestionnaire de route:
575
+
576
+ halt
577
+
578
+ Vous pouvez aussi passer le code retour ...
579
+
580
+ halt 410
581
+
582
+ Ou le texte ...
583
+
584
+ halt 'Ceci est le texte'
585
+
586
+ Ou les deux ...
587
+
588
+ halt 401, 'Partez!'
589
+
590
+ Ainsi que les entêtes ...
591
+
592
+ halt 402, {'Content-Type' => 'text/plain'}, 'revanche'
593
+
594
+ == Passer
595
+
596
+ Une route peut passer le relais aux autres routes qui correspondent également
597
+ avec <tt>pass</tt>:
598
+
599
+ get '/devine/:qui' do
600
+ pass unless params[:qui] == 'Frank'
601
+ "Tu m'as eu!"
602
+ end
603
+
604
+ get '/devine/*' do
605
+ 'Manqué!'
606
+ end
607
+
608
+ On sort donc immédiatement de ce gestionnaire et on continue à chercher,
609
+ dans les masques suivants, le prochain qui correspond à la requête.
610
+ Si aucun des masques suivants ne correspond, un code 404 est retourné.
611
+
612
+ == Accéder à l'objet requête
613
+
614
+ L'objet correspondant à la requête envoyée peut être récupéré dans le contexte de la requête (filtres, routes, gestionnaires d'erreur) au moyen de la méthode `request`:
615
+
616
+ # application tournant à l'adresse http://exemple.com/exemple
617
+ get '/foo' do
618
+ request.body # corps de la requête envoyée par le client (voir ci-dessous)
619
+ request.scheme # "http"
620
+ request.script_name # "/exemple"
621
+ request.path_info # "/foo"
622
+ request.port # 80
623
+ request.request_method # "GET"
624
+ request.query_string # ""
625
+ request.content_length # taille de request.body
626
+ request.media_type # type de média pour request.body
627
+ request.host # "exemple.com"
628
+ request.get? # true (méthodes similaires pour les autres verbes HTTP)
629
+ request.form_data? # false
630
+ request["UN_ENTETE"] # valeur de l'entête UN_ENTETE
631
+ request.referer # référant du client ou '/'
632
+ request.user_agent # user agent (utilisé par la condition :agent)
633
+ request.cookies # tableau contenant les cookies du navigateur
634
+ request.xhr? # requête AJAX ?
635
+ request.url # "http://exemple.com/exemple/foo"
636
+ request.path # "/exemple/foo"
637
+ request.ip # adresse IP du client
638
+ request.secure? # false
639
+ request.env # tableau brut de l'environnement fourni par Rack
640
+ end
641
+
642
+ Certaines options, telles que <tt>script_name</tt> ou <tt>path_info</tt> peuvent
643
+ également être modifiées:
644
+
645
+ before { request.path_info = "/" }
646
+
647
+ get "/" do
648
+ "toutes les requêtes arrivent ici"
649
+ end
650
+
651
+ <tt>request.body</tt> est un objet IO ou StringIO:
652
+
653
+ post "/api" do
654
+ request.body.rewind # au cas où il a déjà été lu
655
+ donnees = JSON.parse request.body.read
656
+ "Bonjour #{donnees['nom']}!"
657
+ end
658
+
659
+ == Configuration
660
+
661
+ Lancé une seule fois au démarrage de tous les environnements:
662
+
663
+ configure do
664
+ ...
665
+ end
666
+
667
+ Lancé si l'environnement (variable d'environnement RACK_ENV) est défini comme
668
+ <tt>:production</tt>:
669
+
670
+ configure :production do
671
+ ...
672
+ end
673
+
674
+ Lancé si l'environnement est <tt>:production</tt> ou
675
+ <tt>:test</tt>:
676
+
677
+ configure :production, :test do
678
+ ...
679
+ end
680
+
681
+ == Gérer les erreurs
682
+
683
+ Les gestionnaires d'erreur s'exécutent dans le même contexte que les routes ou les
684
+ filtres, ce qui veut dire que vous avez accès (entre autres) aux bons vieux
685
+ <tt>haml</tt>, <tt>erb</tt>, <tt>halt</tt>, etc.
686
+
687
+ === Pas Trouvé
688
+
689
+ Quand une exception <tt>Sinatra::NotFound</tt> est soulevée, ou que le code retour
690
+ est 404, le gestionnaire <tt>not_found</tt> est invoqué:
691
+
692
+ not_found do
693
+ 'Pas moyen de trouver ce que vous cherchez'
694
+ end
695
+
696
+ === Erreur
697
+
698
+ Le gestionnaire +error+ est invoqué à chaque fois qu'une exception est soulevée dans une route
699
+ ou un filtre. L'objet exception est accessible via la variable Rack <tt>sinatra.error</tt>:
700
+
701
+ error do
702
+ 'Désolé mais une méchante erreur est survenue - ' + env['sinatra.error'].name
703
+ end
704
+
705
+ Erreur sur mesure:
706
+
707
+ error MonErreurSurMesure do
708
+ 'Donc il est arrivé ceci...' + request.env['sinatra.error'].message
709
+ end
710
+
711
+ Donc si ceci arrive:
712
+
713
+ get '/' do
714
+ raise MonErreurSurMesure, 'quelque chose de mal'
715
+ end
716
+
717
+ Vous obtenez ça:
718
+
719
+ Donc il est arrivé ceci... quelque chose de mal
720
+
721
+ Alternativement, vous pouvez avoir un gestionnaire d'erreur associé à un code particulier:
722
+
723
+ error 403 do
724
+ 'Accès interdit'
725
+ end
726
+
727
+ get '/secret' do
728
+ 403
729
+ end
730
+
731
+ Ou un intervalle:
732
+
733
+ error 400..510 do
734
+ 'Boom'
735
+ end
736
+
737
+ Sinatra installe pour vous quelques gestionnaires <tt>not_found</tt> et <tt>error</tt>
738
+ génériques lorsque vous êtes en environnement <tt>development</tt>.
739
+
740
+ == Types Mime
741
+
742
+ Quand vous utilisez <tt>send_file</tt> et que le fichier possède une extension que Sinatra
743
+ ne reconnaît pas, utilisez +mime_type+ pour la déclarer:
744
+
745
+ mime_type :foo, 'text/foo'
746
+
747
+ Vous pouvez aussi l'utiliser avec +content_type+:
748
+
749
+ content_type :foo
750
+
751
+ == Les Middlewares Rack
752
+
753
+ Sinatra tourne avec Rack[http://rack.rubyforge.org/], une interface standard
754
+ et minimale pour les web frameworks Ruby. Un des points forts de Rack est le
755
+ support de ce que l'on appelle des "middlewares" -- composant qui vient se situer
756
+ entre le serveur et votre application, et dont le but est de visualiser/manipuler la
757
+ requête/réponse HTTP, et d'offrir diverses fonctionnalités classiques.
758
+
759
+ Sinatra permet de construire facilement des middlewares Rack via la méthode de
760
+ haut niveau +use+:
761
+
762
+ require 'sinatra'
763
+ require 'mon_middleware_perso'
764
+
765
+ use Rack::Lint
766
+ use MonMiddlewarePerso
767
+
768
+ get '/bonjour' do
769
+ 'Bonjour Monde'
770
+ end
771
+
772
+ La sémantique de +use+ est identique à celle définie dans le DSL de
773
+ Rack::Builder[http://rack.rubyforge.org/doc/classes/Rack/Builder.html]
774
+ (le plus souvent utilisé dans un fichier rackup). Par exemple, la méthode +use+
775
+ accepte divers arguments ainsi que des blocs:
776
+
777
+ use Rack::Auth::Basic do |login, password|
778
+ login == 'admin' && password == 'secret'
779
+ end
780
+
781
+ Rack est distribué avec une bonne variété de middlewares standards pour les logs,
782
+ débuguer, faire du routage URL, de l'authentification, gérer des sessions.
783
+ Sinatra utilise beaucoup de ces composants automatiquement via la configuration,
784
+ donc pour ceux-ci vous n'aurez pas à utiliser la méthode +use+.
785
+
786
+ == Tester
787
+
788
+ Les tests pour Sinatra peuvent être écrit avec n'importe quelle bibliothèque
789
+ basée sur Rack. {Rack::Test}[http://gitrdoc.com/brynary/rack-test] est
790
+ recommandé:
791
+
792
+ require 'mon_application_sinatra'
793
+ require 'rack/test'
794
+
795
+ class MonTest < Test::Unit::TestCase
796
+ include Rack::Test::Methods
797
+
798
+ def app
799
+ Sinatra::Application
800
+ end
801
+
802
+ def test_ma_racine
803
+ get '/'
804
+ assert_equal 'Bonjour Monde!', last_response.body
805
+ end
806
+
807
+ def test_avec_des_parametres
808
+ get '/rencontrer', :name => 'Frank'
809
+ assert_equal 'Salut Frank!', last_response.body
810
+ end
811
+
812
+ def test_avec_rack_env
813
+ get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
814
+ assert_equal "Vous utilisez Songbird!", last_response.body
815
+ end
816
+ end
817
+
818
+ NOTE: Le module intégré Sinatra::Test et la classe Sinatra::TestHarness
819
+ sont désapprouvés depuis la version 0.9.2 .
820
+
821
+ == Sinatra::Base - Les Middlewares, les Bibliothèques, et les Applications Modulaires
822
+
823
+ Définir votre application au niveau supérieur fonctionne bien pour les
824
+ micro-applications, mais peut s'avérer moins pratique lorsqu'il s'agit
825
+ de créer des composants réutilisables comme des middlewares Rack, faire
826
+ du Rails metal, ou de simples bibliothèques avec un composant serveur, ou
827
+ même une extension pour Sinatra. Le DSL de haut niveau pollue l'espace de noms
828
+ et est une configuration adaptée à une micro-application (un fichier unique
829
+ pour l'application, les dossiers ./public et ./views, les logs, pages d'erreur, etc.).
830
+ C'est là que Sinatra::Base entre en jeu:
831
+
832
+ require 'sinatra/base'
833
+
834
+ class MonApplication < Sinatra::Base
835
+ set :sessions, true
836
+ set :foo, 'bar'
837
+
838
+ get '/' do
839
+ 'Bonjour Monde!'
840
+ end
841
+ end
842
+
843
+ La classe MonApplication est un composant Rack indépendant qui peut agir
844
+ comme un middleware Rack, une application Rack, ou Rails metal. vous pouvez
845
+ donc le lancer avec +run+ ou l'utiliser avec +use+ dans un fichier rackup;
846
+ ou contrôler un composant de serveur sous forme de bibliothèque:
847
+
848
+ MonApplication.run! :host => 'localhost', :port => 9090
849
+
850
+ Les méthodes disponibles dans Sinatra::Base sont exactement identiques à
851
+ celles disponibles dans le DSL de haut niveau. La plupart des applications
852
+ de haut niveau peuvent être converties en composant Sinatra::Base avec
853
+ deux modifications:
854
+
855
+ * Votre fichier doit charger +sinatra/base+ au lieu de +sinatra+;
856
+ autrement, toutes les méthodes de la DSL seront chargées dans l'espace
857
+ de noms.
858
+ * Mettre vos gestionnaires de route, vos gestionnaires d'erreur, vos filtres
859
+ et options dans une sous-classe de Sinatra::Base.
860
+
861
+ <tt>Sinatra::Base</tt> est plutôt épuré. La plupart des options sont désactivées par défaut,
862
+ ceci inclus le serveur. Voir {Options et Configuration}[http://sinatra.github.com/configuration.html]
863
+ pour plus de détails sur les options et leur comportement.
864
+
865
+ === Utiliser Sinatra comme Middleware
866
+
867
+ Non seulement Sinatra peut utiliser d'autres middlewares Rack, il peut également être
868
+ à son tour utilisé au-dessus de n'importe quel +endpoint+ Rack en tant que middleware.
869
+ Ce +endpoint+ peut très bien être une autre application Sinatra, ou n'importe quelle
870
+ application basée sur Rack (Rails/Ramaze/Camping/...).
871
+
872
+ require 'sinatra/base'
873
+
874
+ class EcranDeConnexion < Sinatra::Base
875
+ enable :session
876
+
877
+ get('/connexion') { haml :connexion }
878
+
879
+ post('/connexion') do
880
+ if params[:nom] = 'admin' and params[:motdepasse] = 'admin'
881
+ session['nom_utilisateur'] = params[:nom]
882
+ else
883
+ redirect '/connexion'
884
+ end
885
+ end
886
+ end
887
+
888
+ class MonApp < Sinatra::Base
889
+ # le middleware sera appelé avant les filtres
890
+ use EcranDeConnexion
891
+
892
+ before do
893
+ unless session['nom_utilisateur']
894
+ halt "Accès refusé, merci de vous <a href='/connexion'>connecter</a>."
895
+ end
896
+ end
897
+
898
+ get('/') { "Bonjour #{session['nom_utilisateur']}." }
899
+ end
900
+
901
+ == Contextes et Binding
902
+
903
+ Le contexte dans lequel vous êtes détermine les méthodes et variables
904
+ disponibles.
905
+
906
+ === Contexte de l'application/classe
907
+
908
+ Toute application Sinatra correspond à une sous-classe de Sinatra::Base. Si
909
+ vous utilisez le DSL haut niveau (<tt>require 'sinatra'</tt>), alors cette classe
910
+ est Sinatra::Application, sinon il s'agit de la sous-classe que vous avez définie.
911
+ Dans le contexte de la classe, vous avez accès aux méthodes telles que `get` ou
912
+ `before`, mais vous n'avez pas accès aux objets `request` ou `session` car c'est la
913
+ même classe d'application qui traitera toutes les requêtes.
914
+
915
+ Les options définies au moyen de `set` deviennent des méthodes de classe:
916
+
917
+ class MonApp << Sinatra::Base
918
+ # Eh, je suis dans le contexte de l'application!
919
+ set :foo, 42
920
+ foo # => 42
921
+
922
+ get '/foo' do
923
+ # Eh, je ne suis plus dans le contexte de l'application!
924
+ end
925
+ end
926
+
927
+ Vous avez le binding du contexte de l'application dans:
928
+
929
+ * Le corps de la classe d'application
930
+ * Les méthodes définies par les extensions
931
+ * Le bloc passé à `helpers`
932
+ * Les procs/blocs utilisés comme argument pour `set`
933
+
934
+ Vous pouvez atteindre ce contexte (donc la classe) de la façon suivante:
935
+
936
+ * Via l'objet passé dans les blocs `configure` (<tt>configure { |c| ... }</tt>)
937
+ * En utilisant `settings` dans le contexte de la requête
938
+
939
+ === Contexte de la requête/instance
940
+
941
+ Pour tout traitement d'une requête, une nouvelle instance de votre classe d'application
942
+ est créée et tous vos gestionnaires sont exécutés dans ce contexte. Dans ce dernier,
943
+ vous pouvez accéder aux objets `request` et `session` et faire appel aux fonctions
944
+ de rendu telles que `erb` ou `haml`. Vous pouvez accéder au contexte de l'application
945
+ depuis le contexte de la requête au moyen de `settings`:
946
+
947
+ class MonApp << Sinatra::Base
948
+ # Eh, je suis dans le contexte de l'application!
949
+ get '/ajouter_route/:nom' do
950
+ # Contexte de la requête pour '/ajouter_route/:nom'
951
+ @value = 42
952
+
953
+ settings.get("/#{params[:nom]}") do
954
+ # Contexte de la requête pour "/#{params[:nom]}"
955
+ @value # => nil (on est pas au sein de la même requête)
956
+ end
957
+
958
+ "Route ajoutée!"
959
+ end
960
+ end
961
+
962
+ Vous avez le binding du contexte de la requête dans:
963
+
964
+ * les blocs get/head/post/put/delete
965
+ * les filtres before/after
966
+ * les méthodes utilitaires (définies au moyen de `helpers`)
967
+ * les vues/templates
968
+
969
+ === Le contexte de délégation
970
+
971
+ Le contexte de délégation se contente de transmettre les appels de méthodes au
972
+ contexte de classe. Toutefois, il ne se comporte pas à 100% comme le contexte de
973
+ classe car vous n'avez pas le binding de la classe: seules les méthodes
974
+ spécifiquement déclarées pour délégation sont disponibles et il n'est pas possible
975
+ de partager des variables/états avec le contexte de classe (comprenez: `self` n'est
976
+ pas le même). Vous pouvez ajouter des délégation de méthodes en appelant
977
+ <tt>Sinatra::Delegator.delegate :method_name</tt>.
978
+
979
+ Vous avez le binding du contexte de délégation dans:
980
+
981
+ * Le binding de haut niveau, si vous avez utilisé <tt>require "sinatra"</tt>
982
+ * Un objet qui inclut le module `Sinatra::Delegator`
983
+
984
+ Jetez un oeil
985
+ pour vous faire une idée: voici le mixin {Sinatra::Delegator}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/base.rb#L1128]
986
+ qui est {inclus dans l'espace de noms principal}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/main.rb#L28]
987
+
988
+ == Ligne de commande
989
+
990
+ Les applications en Sinatra peuvent être lancées directement:
991
+
992
+ ruby mon_application.rb [-h] [-x] [-e ENVIRONNEMENT] [-p PORT] [-o HOTE] [-s SERVEUR]
993
+
994
+ Les options sont:
995
+
996
+ -h # aide
997
+ -p # déclare le port (4567 par défaut)
998
+ -o # déclare l'hôte (0.0.0.0 par défaut)
999
+ -e # déclare l'environnement (+development+ par défaut)
1000
+ -s # déclare le serveur/gestionnaire à utiliser (thin par défaut)
1001
+ -x # active le mutex lock (off par défaut)
1002
+
1003
+ == Essuyer les plâtres
1004
+
1005
+ Si vous voulez utiliser la toute dernière version de Sinatra, créez un
1006
+ clone local et lancez votre application avec le dossier <tt>sinatra/lib</tt>
1007
+ dans votre <tt>LOAD_PATH</tt>:
1008
+
1009
+ cd mon_application
1010
+ git clone git://github.com/sinatra/sinatra.git
1011
+ ruby -Isinatra/lib mon_application.rb
1012
+
1013
+ Alternativement, vous pouvez ajoutez le dossier <tt>sinatra/lib</tt> à votre
1014
+ <tt>LOAD_PATH</tt> à l'intérieur de votre application:
1015
+
1016
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
1017
+ require 'rubygems'
1018
+ require 'sinatra'
1019
+
1020
+ get '/a_propos' do
1021
+ "J'utilise la version " + Sinatra::VERSION
1022
+ end
1023
+
1024
+ Pour mettre à jour les sources de Sinatra par la suite:
1025
+
1026
+ cd mon_projet/sinatra
1027
+ git pull
1028
+
1029
+ == Mais encore
1030
+
1031
+ * {Site internet}[http://www.sinatrarb.com/] - Plus de documentation,
1032
+ de news, et des liens vers d'autres ressources.
1033
+ * {Contribuer}[http://www.sinatrarb.com/contributing] - Vous avez trouvé un bug? Besoin
1034
+ d'aide? Vous avez un patch?
1035
+ * {Suivi des problèmes}[http://github.com/sinatra/sinatra/issues]
1036
+ * {Twitter}[http://twitter.com/sinatra]
1037
+ * {Mailing List}[http://groups.google.com/group/sinatrarb/topics]
1038
+ * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] sur http://freenode.net