devcenter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +8 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +39 -0
  5. data/Rakefile +2 -0
  6. data/bin/devcenter +7 -0
  7. data/devcenter.gemspec +30 -0
  8. data/lib/devcenter.rb +6 -0
  9. data/lib/devcenter/cli.rb +45 -0
  10. data/lib/devcenter/coderay_extensions.rb +70 -0
  11. data/lib/devcenter/commands.rb +4 -0
  12. data/lib/devcenter/commands/base.rb +47 -0
  13. data/lib/devcenter/commands/open.rb +34 -0
  14. data/lib/devcenter/commands/preview.rb +28 -0
  15. data/lib/devcenter/commands/pull.rb +37 -0
  16. data/lib/devcenter/helpers.rb +41 -0
  17. data/lib/devcenter/layout.html +299 -0
  18. data/lib/devcenter/md_parser.rb +87 -0
  19. data/lib/devcenter/previewer.rb +36 -0
  20. data/lib/devcenter/previewer/assets/images/public/article-icon-large.png +0 -0
  21. data/lib/devcenter/previewer/assets/images/public/article-icon.png +0 -0
  22. data/lib/devcenter/previewer/assets/images/public/aside_accordion_indicator_default.png +0 -0
  23. data/lib/devcenter/previewer/assets/images/public/aside_accordion_indicator_open.png +0 -0
  24. data/lib/devcenter/previewer/assets/images/public/body_bg.png +0 -0
  25. data/lib/devcenter/previewer/assets/images/public/callout_bg.png +0 -0
  26. data/lib/devcenter/previewer/assets/images/public/feed-icon-sprite.png +0 -0
  27. data/lib/devcenter/previewer/assets/images/public/heroku-header-logo-mobile.png +0 -0
  28. data/lib/devcenter/previewer/assets/images/public/heroku-header-logo.png +0 -0
  29. data/lib/devcenter/previewer/assets/images/public/heroku-logo.png +0 -0
  30. data/lib/devcenter/previewer/assets/images/public/icon_sprite_16.png +0 -0
  31. data/lib/devcenter/previewer/assets/images/public/index_li_bullet.png +0 -0
  32. data/lib/devcenter/previewer/assets/images/public/intro_bg.png +0 -0
  33. data/lib/devcenter/previewer/assets/images/public/jive_discussion_arrow.png +0 -0
  34. data/lib/devcenter/previewer/assets/images/public/jive_discussion_glyph.png +0 -0
  35. data/lib/devcenter/previewer/assets/images/public/line.png +0 -0
  36. data/lib/devcenter/previewer/assets/images/public/pre_code_background.png +0 -0
  37. data/lib/devcenter/previewer/assets/images/public/search-icon.png +0 -0
  38. data/lib/devcenter/previewer/assets/images/public/search_glyph.png +0 -0
  39. data/lib/devcenter/previewer/assets/images/public/search_return.png +0 -0
  40. data/lib/devcenter/previewer/assets/images/public/tag-icon-large.png +0 -0
  41. data/lib/devcenter/previewer/assets/images/public/toc-icon.png +0 -0
  42. data/lib/devcenter/previewer/assets/public.css +2125 -0
  43. data/lib/devcenter/previewer/assets/public/article-icon-large.png +0 -0
  44. data/lib/devcenter/previewer/assets/public/article-icon.png +0 -0
  45. data/lib/devcenter/previewer/assets/public/aside_accordion_indicator_default.png +0 -0
  46. data/lib/devcenter/previewer/assets/public/aside_accordion_indicator_open.png +0 -0
  47. data/lib/devcenter/previewer/assets/public/body_bg.png +0 -0
  48. data/lib/devcenter/previewer/assets/public/callout_bg.png +0 -0
  49. data/lib/devcenter/previewer/assets/public/feed-icon-sprite.png +0 -0
  50. data/lib/devcenter/previewer/assets/public/heroku-header-logo-mobile.png +0 -0
  51. data/lib/devcenter/previewer/assets/public/heroku-header-logo.png +0 -0
  52. data/lib/devcenter/previewer/assets/public/heroku-logo.png +0 -0
  53. data/lib/devcenter/previewer/assets/public/icon_sprite_16.png +0 -0
  54. data/lib/devcenter/previewer/assets/public/index_li_bullet.png +0 -0
  55. data/lib/devcenter/previewer/assets/public/intro_bg.png +0 -0
  56. data/lib/devcenter/previewer/assets/public/jive_discussion_arrow.png +0 -0
  57. data/lib/devcenter/previewer/assets/public/jive_discussion_glyph.png +0 -0
  58. data/lib/devcenter/previewer/assets/public/line.png +0 -0
  59. data/lib/devcenter/previewer/assets/public/pre_code_background.png +0 -0
  60. data/lib/devcenter/previewer/assets/public/public.css +2125 -0
  61. data/lib/devcenter/previewer/assets/public/search-icon.png +0 -0
  62. data/lib/devcenter/previewer/assets/public/search_glyph.png +0 -0
  63. data/lib/devcenter/previewer/assets/public/search_return.png +0 -0
  64. data/lib/devcenter/previewer/assets/public/tag-icon-large.png +0 -0
  65. data/lib/devcenter/previewer/assets/public/toc-icon.png +0 -0
  66. data/lib/devcenter/previewer/file_listener.rb +23 -0
  67. data/lib/devcenter/previewer/views/article.erb +345 -0
  68. data/lib/devcenter/previewer/web_app.rb +53 -0
  69. data/lib/devcenter/previewer/web_server.rb +29 -0
  70. data/lib/devcenter/version.rb +3 -0
  71. data/vendor/sinatra/.gitignore +6 -0
  72. data/vendor/sinatra/.travis.yml +16 -0
  73. data/vendor/sinatra/.yardopts +4 -0
  74. data/vendor/sinatra/AUTHORS +61 -0
  75. data/vendor/sinatra/Gemfile +91 -0
  76. data/vendor/sinatra/LICENSE +22 -0
  77. data/vendor/sinatra/README.de.rdoc +2116 -0
  78. data/vendor/sinatra/README.es.rdoc +2106 -0
  79. data/vendor/sinatra/README.fr.rdoc +2133 -0
  80. data/vendor/sinatra/README.hu.rdoc +608 -0
  81. data/vendor/sinatra/README.jp.rdoc +1056 -0
  82. data/vendor/sinatra/README.ko.rdoc +1932 -0
  83. data/vendor/sinatra/README.pt-br.rdoc +778 -0
  84. data/vendor/sinatra/README.pt-pt.rdoc +647 -0
  85. data/vendor/sinatra/README.rdoc +2049 -0
  86. data/vendor/sinatra/README.ru.rdoc +2033 -0
  87. data/vendor/sinatra/README.zh.rdoc +1816 -0
  88. data/vendor/sinatra/Rakefile +182 -0
  89. data/vendor/sinatra/examples/chat.rb +61 -0
  90. data/vendor/sinatra/examples/simple.rb +3 -0
  91. data/vendor/sinatra/examples/stream.ru +26 -0
  92. data/vendor/sinatra/lib/sinatra.rb +5 -0
  93. data/vendor/sinatra/lib/sinatra/base.rb +1820 -0
  94. data/vendor/sinatra/lib/sinatra/images/404.png +0 -0
  95. data/vendor/sinatra/lib/sinatra/images/500.png +0 -0
  96. data/vendor/sinatra/lib/sinatra/main.rb +30 -0
  97. data/vendor/sinatra/lib/sinatra/showexceptions.rb +345 -0
  98. data/vendor/sinatra/lib/sinatra/version.rb +3 -0
  99. data/vendor/sinatra/sinatra.gemspec +18 -0
  100. data/vendor/sinatra/test/base_test.rb +172 -0
  101. data/vendor/sinatra/test/builder_test.rb +91 -0
  102. data/vendor/sinatra/test/coffee_test.rb +90 -0
  103. data/vendor/sinatra/test/compile_test.rb +139 -0
  104. data/vendor/sinatra/test/contest.rb +98 -0
  105. data/vendor/sinatra/test/creole_test.rb +65 -0
  106. data/vendor/sinatra/test/delegator_test.rb +160 -0
  107. data/vendor/sinatra/test/encoding_test.rb +20 -0
  108. data/vendor/sinatra/test/erb_test.rb +98 -0
  109. data/vendor/sinatra/test/extensions_test.rb +98 -0
  110. data/vendor/sinatra/test/filter_test.rb +437 -0
  111. data/vendor/sinatra/test/haml_test.rb +91 -0
  112. data/vendor/sinatra/test/helper.rb +123 -0
  113. data/vendor/sinatra/test/helpers_test.rb +1768 -0
  114. data/vendor/sinatra/test/integration/app.rb +62 -0
  115. data/vendor/sinatra/test/integration_helper.rb +222 -0
  116. data/vendor/sinatra/test/integration_test.rb +87 -0
  117. data/vendor/sinatra/test/less_test.rb +69 -0
  118. data/vendor/sinatra/test/liquid_test.rb +59 -0
  119. data/vendor/sinatra/test/mapped_error_test.rb +305 -0
  120. data/vendor/sinatra/test/markaby_test.rb +80 -0
  121. data/vendor/sinatra/test/markdown_test.rb +82 -0
  122. data/vendor/sinatra/test/middleware_test.rb +68 -0
  123. data/vendor/sinatra/test/nokogiri_test.rb +67 -0
  124. data/vendor/sinatra/test/public/favicon.ico +0 -0
  125. data/vendor/sinatra/test/rabl_test.rb +89 -0
  126. data/vendor/sinatra/test/rack_test.rb +45 -0
  127. data/vendor/sinatra/test/radius_test.rb +59 -0
  128. data/vendor/sinatra/test/rdoc_test.rb +66 -0
  129. data/vendor/sinatra/test/readme_test.rb +120 -0
  130. data/vendor/sinatra/test/request_test.rb +45 -0
  131. data/vendor/sinatra/test/response_test.rb +64 -0
  132. data/vendor/sinatra/test/result_test.rb +76 -0
  133. data/vendor/sinatra/test/route_added_hook_test.rb +59 -0
  134. data/vendor/sinatra/test/routing_test.rb +1175 -0
  135. data/vendor/sinatra/test/sass_test.rb +116 -0
  136. data/vendor/sinatra/test/scss_test.rb +89 -0
  137. data/vendor/sinatra/test/server_test.rb +48 -0
  138. data/vendor/sinatra/test/settings_test.rb +561 -0
  139. data/vendor/sinatra/test/sinatra_test.rb +12 -0
  140. data/vendor/sinatra/test/slim_test.rb +84 -0
  141. data/vendor/sinatra/test/static_test.rb +219 -0
  142. data/vendor/sinatra/test/streaming_test.rb +149 -0
  143. data/vendor/sinatra/test/templates_test.rb +333 -0
  144. data/vendor/sinatra/test/textile_test.rb +65 -0
  145. data/vendor/sinatra/test/views/a/in_a.str +1 -0
  146. data/vendor/sinatra/test/views/ascii.erb +2 -0
  147. data/vendor/sinatra/test/views/b/in_b.str +1 -0
  148. data/vendor/sinatra/test/views/calc.html.erb +1 -0
  149. data/vendor/sinatra/test/views/error.builder +3 -0
  150. data/vendor/sinatra/test/views/error.erb +3 -0
  151. data/vendor/sinatra/test/views/error.haml +3 -0
  152. data/vendor/sinatra/test/views/error.sass +2 -0
  153. data/vendor/sinatra/test/views/explicitly_nested.str +1 -0
  154. data/vendor/sinatra/test/views/foo/hello.test +1 -0
  155. data/vendor/sinatra/test/views/hello.builder +1 -0
  156. data/vendor/sinatra/test/views/hello.coffee +1 -0
  157. data/vendor/sinatra/test/views/hello.creole +1 -0
  158. data/vendor/sinatra/test/views/hello.erb +1 -0
  159. data/vendor/sinatra/test/views/hello.haml +1 -0
  160. data/vendor/sinatra/test/views/hello.less +5 -0
  161. data/vendor/sinatra/test/views/hello.liquid +1 -0
  162. data/vendor/sinatra/test/views/hello.mab +1 -0
  163. data/vendor/sinatra/test/views/hello.md +1 -0
  164. data/vendor/sinatra/test/views/hello.nokogiri +1 -0
  165. data/vendor/sinatra/test/views/hello.rabl +2 -0
  166. data/vendor/sinatra/test/views/hello.radius +1 -0
  167. data/vendor/sinatra/test/views/hello.rdoc +1 -0
  168. data/vendor/sinatra/test/views/hello.sass +2 -0
  169. data/vendor/sinatra/test/views/hello.scss +3 -0
  170. data/vendor/sinatra/test/views/hello.slim +1 -0
  171. data/vendor/sinatra/test/views/hello.str +1 -0
  172. data/vendor/sinatra/test/views/hello.test +1 -0
  173. data/vendor/sinatra/test/views/hello.textile +1 -0
  174. data/vendor/sinatra/test/views/hello.wlang +1 -0
  175. data/vendor/sinatra/test/views/hello.yajl +1 -0
  176. data/vendor/sinatra/test/views/layout2.builder +3 -0
  177. data/vendor/sinatra/test/views/layout2.erb +2 -0
  178. data/vendor/sinatra/test/views/layout2.haml +2 -0
  179. data/vendor/sinatra/test/views/layout2.liquid +2 -0
  180. data/vendor/sinatra/test/views/layout2.mab +2 -0
  181. data/vendor/sinatra/test/views/layout2.nokogiri +3 -0
  182. data/vendor/sinatra/test/views/layout2.rabl +3 -0
  183. data/vendor/sinatra/test/views/layout2.radius +2 -0
  184. data/vendor/sinatra/test/views/layout2.slim +3 -0
  185. data/vendor/sinatra/test/views/layout2.str +2 -0
  186. data/vendor/sinatra/test/views/layout2.test +1 -0
  187. data/vendor/sinatra/test/views/layout2.wlang +2 -0
  188. data/vendor/sinatra/test/views/nested.str +1 -0
  189. data/vendor/sinatra/test/views/utf8.erb +2 -0
  190. data/vendor/sinatra/test/wlang_test.rb +70 -0
  191. data/vendor/sinatra/test/yajl_test.rb +86 -0
  192. metadata +414 -0
@@ -0,0 +1,2133 @@
1
+ = Sinatra
2
+ <i>Attention : Ce document correspond à la traduction de la version anglaise et
3
+ il n'est peut être plus à jour.</i>
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
+ # mon_application.rb
9
+ require 'sinatra'
10
+
11
+ get '/' do
12
+ 'Bonjour le monde !'
13
+ end
14
+
15
+ Installez la gem et lancez avec :
16
+
17
+ gem install sinatra
18
+ ruby -rubygems mon_application.rb
19
+
20
+ Le résultat est visible sur : http://localhost:4567
21
+
22
+ Il est recommandé d'exécuter également <tt>gem install thin</tt>, pour que
23
+ Sinatra utilise le server Thin quand il est disponible.
24
+
25
+ == Routes
26
+
27
+ Dans Sinatra, une route est une méthode HTTP couplée à un masque (pattern)
28
+ URL. Chaque route est associée à un bloc :
29
+
30
+ get '/' do
31
+ .. montrer quelque chose ..
32
+ end
33
+
34
+ post '/' do
35
+ .. créer quelque chose ..
36
+ end
37
+
38
+ put '/' do
39
+ .. remplacer quelque chose ..
40
+ end
41
+
42
+ patch '/' do
43
+ .. changer quelque chose ..
44
+ end
45
+
46
+ delete '/' do
47
+ .. effacer quelque chose ..
48
+ end
49
+
50
+ options '/' do
51
+ .. apaiser quelquechose ..
52
+ end
53
+
54
+ Les routes sont évaluées dans l'ordre où elles ont été définies. La première
55
+ route qui correspond à la requête est appelée.
56
+
57
+ Les masques peuvent inclure des paramètres nommés, accessibles par
58
+ l'intermédiaire du hash <tt>params</tt> :
59
+
60
+ get '/bonjour/:nom' do
61
+ # répond aux requêtes "GET /bonjour/foo" et "GET /bonjour/bar"
62
+ # params[:nom] est 'foo' ou 'bar'
63
+ "Bonjour #{params[:nom]} !"
64
+ end
65
+
66
+ Vous pouvez aussi accéder aux paramètres nommés directement grâce aux
67
+ paramètres du bloc comme ceci :
68
+
69
+ get '/bonjour/:nom' do |n|
70
+ "Bonjour #{n} !"
71
+ end
72
+
73
+ Une route peut contenir un splat (caractère joker), accessible par
74
+ l'intermédiaire du tableau <tt>params[:splat]</tt> :
75
+
76
+ get '/dire/*/a/*' do
77
+ # répond à /dire/bonjour/a/monde
78
+ params[:splat] # => ["bonjour", "monde"]
79
+ end
80
+
81
+ get '/telecharger/*.*' do
82
+ # répond à /telecharger/chemin/vers/fichier.xml
83
+ params[:splat] # => ["chemin/vers/fichier", "xml"]
84
+ end
85
+
86
+ Ou par l'intermédiaire des paramètres du bloc :
87
+
88
+ get '/telecharger/*.*' do |chemin, ext|
89
+ [chemin, ext] # => ["path/to/file", "xml"]
90
+ end
91
+
92
+ Une route peut aussi être définie par une Expression Régulière :
93
+
94
+ get %r{/bonjour/([\w]+)} do
95
+ "Bonjour, #{params[:captures].first} !"
96
+ end
97
+
98
+ Là encore on peut utiliser les paramètres de bloc :
99
+
100
+ get %r{/bonjour/([\w]+)} do |c|
101
+ "Bonjour, #{c} !"
102
+ end
103
+
104
+ Les routes peuvent aussi comporter des paramètres optionnels :
105
+
106
+ get '/posts.?:format?' do
107
+ # répond à "GET /posts" et aussi à "GET /posts.json", "GET /posts.xml" etc...
108
+ end
109
+
110
+ A ce propos, à moins d'avoir désactivé la protection contre les attaques par
111
+ "path transversal" (voir plus loin), l'URL demandée peut avoir été modifiée
112
+ avant d'être comparée à vos routes.
113
+
114
+ === Conditions
115
+
116
+ Les routes peuvent définir toutes sortes de conditions, comme par exemple le
117
+ "user agent" :
118
+
119
+ get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
120
+ "Vous utilisez Songbird version #{params[:agent][0]}"
121
+ end
122
+
123
+ get '/foo' do
124
+ # Correspond à tous les autres navigateurs
125
+ end
126
+
127
+ Les autres conditions disponibles sont +host_name+ et +provides+ :
128
+
129
+ get '/', :host_name => /^admin\./ do
130
+ "Zone Administrateur, Accès refusé !"
131
+ end
132
+
133
+ get '/', :provides => 'html' do
134
+ haml :index
135
+ end
136
+
137
+ get '/', :provides => ['rss', 'atom', 'xml'] do
138
+ builder :feed
139
+ end
140
+
141
+ Vous pouvez facilement définir vos propres conditions :
142
+
143
+ set(:probability) { |value| condition { rand <= value } }
144
+
145
+ get '/gagner_une_voiture', :probability => 0.1 do
146
+ "Vous avez gagné !"
147
+ end
148
+
149
+ get '/gagner_une_voiture' do
150
+ "Désolé, vous avez perdu."
151
+ end
152
+
153
+ Utilisez un splat (caractère joker) dans le cas d'une condition qui prend
154
+ plusieurs valeurs :
155
+
156
+ set(:auth) do |*roles| # <- ici on utilise un splat
157
+ condition do
158
+ unless logged_in? && roles.any? {|role| current_user.in_role? role }
159
+ redirect "/login/", 303
160
+ end
161
+ end
162
+ end
163
+
164
+ get "/mon/compte/", :auth => [:user, :admin] do
165
+ "Informations sur votre compte"
166
+ end
167
+
168
+ get "/reserve/aux/admins/", :auth => :admin do
169
+ "Seuls les administrateurs sont acceptés ici !"
170
+ end
171
+
172
+ === Valeurs de retour
173
+
174
+ La valeur renvoyée par le bloc correspondant à une route constitue le corps de
175
+ la réponse qui sera transmise au client HTTP ou du moins au prochain middleware
176
+ dans la pile Rack. Le plus souvent, il s'agit d'une chaîne de caractères,
177
+ comme dans les exemples précédents. Cependant, d'autres valeurs sont
178
+ acceptées.
179
+
180
+ Vous pouvez renvoyer n'importe quel objet qu'il s'agisse d'une réponse Rack
181
+ valide, d'un corps de réponse Rack ou d'un code statut HTTP :
182
+
183
+ * Un tableau de 3 éléments : <tt>[code statut (Fixnum), entêtes (Hash), corps
184
+ de la réponse (répondant à #each)]</tt>
185
+ * Un tableau de 2 élements : <tt>[code statut (Fixnum), corps de la réponse
186
+ (répondant à #each)]</tt>
187
+ * Un objet qui répond à <tt>#each</tt> et qui ne transmet que des chaînes de
188
+ caractères au bloc fourni
189
+ * Un Fixnum représentant le code statut
190
+
191
+ Avec cela, on peut facilement implémenter un streaming par exemple :
192
+
193
+ class Stream
194
+ def each
195
+ 100.times { |i| yield "#{i}\n" }
196
+ end
197
+ end
198
+
199
+ get('/') { Stream.new }
200
+
201
+ Vous pouvez aussi utiliser le helper +stream+ (présenté un peu plus loin) pour
202
+ éviter la surcharge et intégrer le traitement relatif au streaming dans le bloc
203
+ de code de la route.
204
+
205
+ === Masques de route spécifiques
206
+
207
+ Comme cela a été vu auparavant, Sinatra offre la possibilité d'utiliser des
208
+ masques sous forme de chaines de caractères ou des expressions régulières
209
+ pour définir les routes. Mais il est possible de faire bien plus. Vous pouvez
210
+ facilement définir vos propres masques :
211
+
212
+ class MasqueToutSauf
213
+ Masque = Struct.new(:captures)
214
+
215
+ def initialize(except)
216
+ @except = except
217
+ @captures = Masque.new([])
218
+ end
219
+
220
+ def match(str)
221
+ @caputres unless @except === str
222
+ end
223
+ end
224
+
225
+ def tout_sauf(masque)
226
+ MasqueToutSauf.new(masque)
227
+ end
228
+
229
+ get tout_sauf("/index") do
230
+ # ...
231
+ end
232
+
233
+ Notez que l'exemple ci-dessus est bien trop compliqué et que le même résultat
234
+ peut être obtenu avec :
235
+
236
+ get // do
237
+ pass if request.path_info == "/index"
238
+ # ...
239
+ end
240
+
241
+ Ou bien en utilisant la forme négative :
242
+
243
+ get %r{^(?!/index$)} do
244
+ # ...
245
+ end
246
+
247
+ == Fichiers statiques
248
+
249
+ Les fichiers du dossier <tt>./public</tt> sont servis de façon statique. Vous
250
+ avez la possibilité d'utiliser un autre répertoire en définissant le paramètre
251
+ <tt>:public_folder</tt> :
252
+
253
+ set :public_folder, File.dirname(__FILE__) + '/statique'
254
+
255
+ Notez que le nom du dossier public n'apparait pas dans l'URL. Le fichier
256
+ <tt>./public/css/style.css</tt> sera appelé via l'URL :
257
+ <tt>http://exemple.com/css/style.css</tt>.
258
+
259
+ Utilisez le paramètre <tt>:static_cache_control</tt> pour ajouter l'information
260
+ d'en-tête <tt>Cache-Control</tt> (voir plus loin).
261
+
262
+ == Vues / Templates
263
+
264
+ Chaqie langage de template est disponible via sa propre méthode de rendu,
265
+ lesquelles renvoient tout simplement une chaîne de caractères.
266
+
267
+ get '/' do
268
+ erb :index
269
+ end
270
+
271
+ Ceci effectue le rendu de la vue <tt>views/index.erb</tt>.
272
+
273
+ Plutôt que d'utiliser le nom d'un template, vous pouvez directement passer
274
+ le contenu du template :
275
+
276
+ get '/' do
277
+ code = "<%= Time.now %>"
278
+ erb code
279
+ end
280
+
281
+ Les méthodes de templates acceptent un second paramètre, un hash d'options :
282
+
283
+ get '/' do
284
+ erb :index, :layout => :post
285
+ end
286
+
287
+ Ceci effectuera le rendu de la vue <tt>views/index.erb</tt> en l'intégrant
288
+ au +layout+ <tt>views/post.erb</tt> (les vues Erb sont intégrées par défaut
289
+ au +layout+ <tt>views/layout.erb</tt> quand ce fichier existe).
290
+
291
+ Toute option que Sinatra ne comprend pas sera passée au moteur de rendu :
292
+
293
+ get '/' do
294
+ haml :index, :format => :html5
295
+ end
296
+
297
+ Vous pouvez également définir des options par langage de template de façon
298
+ générale :
299
+
300
+ set :haml, :format => html5
301
+
302
+ get '/' do
303
+ haml :index
304
+ end
305
+
306
+ Les options passées à la méthode de rendu prennent le pas sur les options
307
+ définies au moyen de +set+.
308
+
309
+ Options disponibles :
310
+
311
+ [locals]
312
+ Liste de variables locales passées au document. Pratique pour les vues
313
+ partielles.
314
+ Exemple : <tt>erb "<%= foo %>", :locals => {:foo => "bar"}</tt>.
315
+
316
+ [default_encoding]
317
+ Encodage de caractères à utiliser en cas d'incertitude. Par défaut, c'est
318
+ <tt>settings.default_encoding</tt>.
319
+
320
+ [views]
321
+ Dossier de vues dans lequel chercher les templates. Par défaut
322
+ <tt>settings.views</tt>.
323
+
324
+ [layout]
325
+ S'il faut ou non utiliser un +layout+ (+true+ or +false+). Indique le
326
+ template à utiliser lorsque c'est un symbole. Exemple : <tt>erb :index,
327
+ :layout => !request.xhr?</tt>.
328
+
329
+ [content_type]
330
+ Content-Type que le template produit, dépend par défaut du langage de
331
+ template.
332
+
333
+ [scope]
334
+ Contexte sous lequel effectuer le rendu du template. Par défaut il s'agit
335
+ de l'instance de l'application. Si vous changez cela, les variables
336
+ d'instance et les méthodes utilitaires ne seront pas disponibles.
337
+
338
+ [layout_engine]
339
+ Moteur de rendu à utiliser pour le +layout+. Utile pour les langages ne
340
+ supportant pas les +layouts+. Il s'agit par défaut du moteur utilisé pour
341
+ le rendu du template. Exemple : <tt>set :rdoc, :layout_engine => :erb</tt>
342
+
343
+ Les templates sont supposés se trouver directement dans le dossier
344
+ <tt>./views</tt>. Pour utiliser un dossier de vues différent :
345
+
346
+ set :views, settings.root + '/templates'
347
+
348
+ Il est important de se souvenir que les templates sont toujours référencés
349
+ sous forme de symboles, même lorsqu'ils sont dans un sous-répertoire (dans
350
+ ce cas, utilisez <tt>:'sous_repertoire/template'</tt>). Il faut utiliser
351
+ un symbole car les méthodes de rendu évaluent le contenu des chaînes de
352
+ caractères au lieu de les considérer comme un chemin vers un fichier.
353
+
354
+ === Langages de template disponibles
355
+
356
+ Certains langages ont plusieurs implémentations. Pour préciser l'implémentation
357
+ à utiliser (et garantir l'aspect thread-safe), vous devez simplement l'avoir
358
+ chargée au préalable :
359
+
360
+ require 'rdiscount' # ou require 'bluecloth'
361
+ get('/') { markdown :index }
362
+
363
+ === Templates Haml
364
+
365
+ Dépendances:: {haml}[http://haml.info/]
366
+ Extensions de fichier:: <tt>.haml</tt>
367
+ Exemple:: <tt>haml :index, :format => :html5</tt>
368
+
369
+ === Templates Erb
370
+
371
+ Dépendances:: {erubis}[http://www.kuwata-lab.com/erubis/] ou
372
+ erb (inclus avec Ruby)
373
+ Extensions de fichier:: <tt>.erb</tt>, <tt>.rhtml</tt> ou <tt>.erubis</tt>
374
+ (Erubis seulement)
375
+ Exemple:: <tt>erb :index</tt>
376
+
377
+ === Templates Builder
378
+
379
+ Dépendances:: {builder}[http://builder.rubyforge.org/]
380
+ Extensions de fichier:: <tt>.builder</tt>
381
+ Exemple:: <tt>builder { |xml| xml.em "salut" }</tt>
382
+
383
+ Ce moteur accepte également un bloc pour des templates en ligne (voir exemple).
384
+
385
+ === Templates Nokogiri
386
+
387
+ Dépendances:: {nokogiri}[http://nokogiri.org/]
388
+ Extensions de fichier:: <tt>.nokogiri</tt>
389
+ Exemple:: <tt>nokogiri { |xml| xml.em "salut" }</tt>
390
+
391
+ Ce moteur accepte également un bloc pour des templates en ligne (voir exemple).
392
+
393
+ === Templates Sass
394
+
395
+ Dépendances:: {sass}[http://sass-lang.com/]
396
+ Extensions de fichier:: <tt>.sass</tt>
397
+ Exemple:: <tt>sass :stylesheet, :style => :expanded</tt>
398
+
399
+ === Templates SCSS
400
+
401
+ Dépendances:: {sass}[http://sass-lang.com/]
402
+ Extensions de fichier:: <tt>.scss</tt>
403
+ Exemple:: <tt>scss :stylesheet, :style => :expanded</tt>
404
+
405
+ === Templates Less
406
+
407
+ Dépendances:: {less}[http://www.lesscss.org/]
408
+ Extensions de fichier:: <tt>.less</tt>
409
+ Exemple:: <tt>less :stylesheet</tt>
410
+
411
+ === Templates Liquid
412
+
413
+ Dépendances:: {liquid}[http://www.liquidmarkup.org/]
414
+ Extensions de fichier:: <tt>.liquid</tt>
415
+ Exemple:: <tt>liquid :index, :locals => { :key => 'value' }</tt>
416
+
417
+ Comme vous ne pouvez appeler de méthodes Ruby (autres que +yield+) dans un
418
+ template Liquid, vous aurez sûrement à lui passer des variables locales.
419
+
420
+ === Templates Markdown
421
+
422
+ Dépendances:: {rdiscount}[https://github.com/rtomayko/rdiscount],
423
+ {redcarpet}[https://github.com/vmg/redcarpet],
424
+ {bluecloth}[http://deveiate.org/projects/BlueCloth],
425
+ {kramdown}[http://kramdown.rubyforge.org/] *ou*
426
+ {maruku}[http://maruku.rubyforge.org/]
427
+ Extensions de fichier:: <tt>.markdown</tt>, <tt>.mkd</tt> et <tt>.md</tt>
428
+ Exemple:: <tt>markdown :index, :layout_engine => :erb</tt>
429
+
430
+ Il n'est pas possible d'appeler des méthodes depuis markdown, ni de lui
431
+ passer des variables locales. Par conséquent, il sera souvent utilisé en
432
+ combinaison avec un autre moteur de rendu :
433
+
434
+ erb :overview, :locals => { :text => markdown(:introduction) }
435
+
436
+ Notez que vous pouvez également appeler la méthode +markdown+ au sein d'autres
437
+ templates :
438
+
439
+ %h1 Hello From Haml !
440
+ %p= markdown(:greetings)
441
+
442
+ Comme vous ne pouvez pas appeler de Ruby au sein de Markdown, vous ne pouvez
443
+ pas utiliser de +layouts+ écrits en Markdown. Toutefois, il est possible
444
+ d'utiliser un moteur de rendu différent pour le template et pour le +layout+
445
+ en utilisant l'option <tt>:layout_engine</tt>.
446
+
447
+ === Templates Textile
448
+
449
+ Dépendances:: {RedCloth}[http://redcloth.org/]
450
+ Extensions de fichier:: <tt>.textile</tt>
451
+ Exemple:: <tt>textile :index, :layout_engine => :erb</tt>
452
+
453
+ Il n'est pas possible d'appeler des méthodes depuis textile, ni de lui
454
+ passer des variables locales. Par conséquent, il sera souvent utilisé en
455
+ combinaison avec un autre moteur de rendu :
456
+
457
+ erb :overview, :locals => { :text => textile(:introduction) }
458
+
459
+ Notez que vous pouvez également appeler la méthode +textile+ au sein d'autres
460
+ templates :
461
+
462
+ %h1 Hello From Haml !
463
+ %p= textile(:greetings)
464
+
465
+ Comme vous ne pouvez pas appeler de Ruby au sein de Textile, vous ne pouvez
466
+ pas utiliser de +layouts+ écrits en Textile. Toutefois, il est possible
467
+ d'utiliser un moteur de rendu différent pour le template et pour le +layout+
468
+ en utilisant l'option <tt>:layout_engine</tt>.
469
+
470
+ === Templates RDoc
471
+
472
+ Dépendances:: {rdoc}[http://rdoc.rubyforge.org/]
473
+ Extensions de fichier:: <tt>.rdoc</tt>
474
+ Exemple:: <tt>rdoc :README, :layout_engine => :erb</tt>
475
+
476
+ Il n'est pas possible d'appeler des méthodes depuis rdoc, ni de lui
477
+ passer des variables locales. Par conséquent, il sera souvent utilisé en
478
+ combinaison avec un autre moteur de rendu :
479
+
480
+ erb :overview, :locals => { :text => rdoc(:introduction) }
481
+
482
+ Notez que vous pouvez également appeler la méthode +rdoc+ au sein d'autres
483
+ templates :
484
+
485
+ %h1 Hello From Haml !
486
+ %p= rdoc(:greetings)
487
+
488
+ Comme vous ne pouvez pas appeler de Ruby au sein de RDoc, vous ne pouvez
489
+ pas utiliser de +layouts+ écrits en RDoc. Toutefois, il est possible
490
+ d'utiliser un moteur de rendu différent pour le template et pour le +layout+
491
+ en utilisant l'option <tt>:layout_engine</tt>.
492
+
493
+ === Templates Radius
494
+
495
+ Dépendances:: {radius}[http://radius.rubyforge.org/]
496
+ Extensions de fichier:: <tt>.radius</tt>
497
+ Exemple:: <tt>radius :index, :locals => { :key => 'value' }</tt>
498
+
499
+ Comme vous ne pouvez pas appeler de méthodes Ruby depuis un template Radius,
500
+ vous aurez sûrement à lui passer des variables locales.
501
+
502
+ === Templates Markaby
503
+
504
+ Dépendances:: {markaby}[http://markaby.github.com/]
505
+ Extensions de fichier:: <tt>.mab</tt>
506
+ Exemple:: <tt>markaby { h1 "Bienvenue !" }</tt>
507
+
508
+ Ce moteur accepte également un bloc pour des templates en ligne (voir exemple).
509
+
510
+ === Templates RABL
511
+
512
+ Dépendances:: {rabl}[https://github.com/nesquena/rabl]
513
+ Extensions de fichier:: <tt>.rabl</tt>
514
+ Exemple:: <tt>rabl :index</tt>
515
+
516
+ === Templates Slim
517
+
518
+ Dépendances:: {slim}[http://slim-lang.com/]
519
+ Extensions de fichier:: <tt>.slim</tt>
520
+ Exemple:: <tt>slim :index</tt>
521
+
522
+ === Templates Creole
523
+
524
+ Dépendances:: {creole}[https://github.com/minad/creole]
525
+ Extensions de fichier:: <tt>.creole</tt>
526
+ Exemple:: <tt>creole :wiki, :layout_engine => :erb</tt>
527
+
528
+ Il n'est pas possible d'appeler des méthodes depuis creole, ni de lui
529
+ passer des variables locales. Par conséquent, il sera souvent utilisé en
530
+ combinaison avec un autre moteur de rendu :
531
+
532
+ erb :overview, :locals => { :text => creole(:introduction) }
533
+
534
+ Notez que vous pouvez également appeler la méthode +creole+ au sein d'autres
535
+ templates :
536
+
537
+ %h1 Hello From Haml !
538
+ %p= creole(:greetings)
539
+
540
+ Comme vous ne pouvez pas appeler de Ruby au sein de Creole, vous ne pouvez
541
+ pas utiliser de +layouts+ écrits en Creole. Toutefois, il est possible
542
+ d'utiliser un moteur de rendu différent pour le template et pour le +layout+
543
+ en utilisant l'option <tt>:layout_engine</tt>.
544
+
545
+ === Templates CoffeeScript
546
+
547
+ Dépendances:: {coffee-script}[https://github.com/josh/ruby-coffee-script]
548
+ et un {moyen d'exécuter javascript}[https://github.com/sstephenson/execjs/blob/master/README.md#readme]
549
+ Extensions de fichier:: <tt>.coffee</tt>
550
+ Exemple:: <tt>coffee :index</tt>
551
+
552
+ === Templates Yajl
553
+
554
+ Dépendances:: {yajl-ruby}[https://github.com/brianmario/yajl-ruby]
555
+ Extensions de fichier:: <tt>.yajl</tt>
556
+ Exemple:: <tt>yajl :index, :locals => { :key => 'qux' }, :callback => 'present', :variable => 'resource'</tt>
557
+
558
+ Le source du template est évalué en tant que chaine Ruby, puis la variable json
559
+ obtenue est convertie avec #to_json.
560
+
561
+ json = { :foo => 'bar' }
562
+ json[:baz] = key
563
+
564
+ Les options <tt>:callback</tt> et <tt>:variable</tt> peuvent être utilisées
565
+ pour décorer l'objet retourné.
566
+
567
+ var resource = {"foo":"bar","baz":"qux"}; present(resource);
568
+
569
+ === Templates WLang
570
+
571
+ Dependency:: {wlang}[https://github.com/blambeau/wlang/]
572
+ File Extensions:: <tt>.wlang</tt>
573
+ Example:: <tt>wlang :index, :locals => { :key => 'value' }</tt>
574
+
575
+ L'appel de code ruby au sein des templates n'est pas idiomatique en wlang. L'écriture de
576
+ templates sans logique est encouragé, via le passage de variables locales. Il est néanmoins
577
+ possible d'écrire un +layout+ en wlang et d'y utiliser +yield+.
578
+
579
+ === Templates embarqués
580
+
581
+ get '/' do
582
+ haml '%div.title Bonjour le monde'
583
+ end
584
+
585
+ Générera le code du template spécifié dans la chaîne de caractères.
586
+
587
+ === Accéder aux variables dans un Template
588
+
589
+ Un template est évalué dans le même contexte que l'endroit d'où il a été
590
+ appelé (gestionnaire de route). Les variables d'instance déclarées dans le
591
+ gestionnaire de route sont directement accessibles dans le template :
592
+
593
+ get '/:id' do
594
+ @foo = Foo.find(params[:id])
595
+ haml '%h1= @foo.nom'
596
+ end
597
+
598
+ Alternativement, on peut passer un hash contenant des variables locales :
599
+
600
+ get '/:id' do
601
+ foo = Foo.find(params[:id])
602
+ haml '%h1= foo.nom', :locals => { :foo => foo }
603
+ end
604
+
605
+ Ceci est généralement utilisé lorsque l'on veut utiliser un template comme
606
+ partiel (depuis un autre template) et qu'il est donc nécessaire d'adapter les
607
+ noms de variables.
608
+
609
+ === Templates dans le fichier source
610
+
611
+ Des templates peuvent être définis dans le fichier source comme ceci :
612
+
613
+ require 'sinatra'
614
+
615
+ get '/' do
616
+ haml :index
617
+ end
618
+
619
+ __END__
620
+
621
+ @@ layout
622
+ %html
623
+ = yield
624
+
625
+ @@ index
626
+ %div.title Bonjour le monde !
627
+
628
+ NOTE : Les templates du fichier source qui contient <tt>require 'sinatra'</tt>
629
+ sont automatiquement chargés. Si vous avez des templates dans d'autres
630
+ fichiers source, il faut explicitement les déclarer avec
631
+ <tt>enable :inline_templates</tt>.
632
+
633
+ === Templates nommés
634
+
635
+ Les templates peuvent aussi être définis grâce à la méthode de haut niveau
636
+ <tt>template</tt> :
637
+
638
+ template :layout do
639
+ "%html\n =yield\n"
640
+ end
641
+
642
+ template :index do
643
+ '%div.title Bonjour le monde !'
644
+ end
645
+
646
+ get '/' do
647
+ haml :index
648
+ end
649
+
650
+ Si un template nommé "layout" existe, il sera utilisé à chaque fois qu'un
651
+ template sera affiché. Vous pouvez désactivez les layouts au cas par cas en
652
+ passant <tt>:layout => false</tt> ou bien les désactiver par défaut au moyen
653
+ de <tt>set :haml, :layout => false</tt> :
654
+
655
+ get '/' do
656
+ haml :index, :layout => !request.xhr?
657
+ end
658
+
659
+ === Associer des extensions de fichier
660
+
661
+ Pour associer une extension de fichier avec un moteur de rendu, utilisez
662
+ <tt>Tilt.register</tt>. Par exemple, si vous désirez utiliser l'extension
663
+ de fichier +tt+ pour les templates Textile, vous pouvez faire comme suit :
664
+
665
+ Tilt.register :tt, Tilt[:textile]
666
+
667
+ === Ajouter son propre moteur de rendu
668
+
669
+ En premier lieu, déclarez votre moteur de rendu avec Tilt, ensuite créez
670
+ votre méthode de rendu :
671
+
672
+ Tilt.register :monmoteur, MonMerveilleurMoteurDeRendu
673
+
674
+ helpers do
675
+ def monmoteur(*args) render(:monmoteur, *args) end
676
+ end
677
+
678
+ get '/' do
679
+ monmoteur :index
680
+ end
681
+
682
+ Utilisera <tt>./views/index.monmoteur</tt>. Voir
683
+ https://github.com/rtomayko/tilt pour en savoir plus sur Tilt.
684
+
685
+ == Filtres
686
+
687
+ Les filtres before sont exécutés avant chaque requête, dans le même contexte
688
+ que les routes, et permettent de modifier la requête et sa réponse. Les
689
+ variables d'instance déclarées dans les filtres sont accessibles au niveau
690
+ des routes et des templates :
691
+
692
+ before do
693
+ @note = 'Coucou !'
694
+ request.path_info = '/foo/bar/baz'
695
+ end
696
+
697
+ get '/foo/*' do
698
+ @note #=> 'Coucou !'
699
+ params[:splat] #=> 'bar/baz'
700
+ end
701
+
702
+ Les filtres after sont exécutés après chaque requête à l'intérieur du même
703
+ contexte et permettent de modifier la requête et sa réponse. Les variables
704
+ d'instance déclarées dans les filtres before ou les routes sont accessibles
705
+ au niveau des filtres after :
706
+
707
+ after do
708
+ puts response.status
709
+ end
710
+
711
+ Note : Le corps de la réponse n'est pas disponible au niveau du filtre after
712
+ car il ne sera généré que plus tard (sauf dans le cas où vous utilisez la
713
+ méthode +body+ au lieu de simplement renvoyer une chaine depuis vos routes).
714
+
715
+ Les filtres peuvent être associés à un masque, ce qui permet de limiter leur
716
+ exécution aux cas où la requête correspond à ce masque :
717
+
718
+ before '/secret/*' do
719
+ authentification!
720
+ end
721
+
722
+ after '/faire/:travail' do |travail|
723
+ session[:dernier_travail] = travail
724
+ end
725
+
726
+ Tout comme les routes, les filtres acceptent également des conditions :
727
+
728
+ before :agent => /Songbird/ do
729
+ # ...
730
+ end
731
+
732
+ after '/blog/*', :host_name => 'example.com' do
733
+ # ...
734
+ end
735
+
736
+ == Helpers
737
+
738
+ Utilisez la méthode de haut niveau <tt>helpers</tt> pour définir des routines
739
+ qui seront accessibles dans vos gestionnaires de route et dans vos templates :
740
+
741
+ helpers do
742
+ def bar(nom)
743
+ "#{nom}bar"
744
+ end
745
+ end
746
+
747
+ get '/:nom' do
748
+ bar(params[:nom])
749
+ end
750
+
751
+ Vous pouvez aussi définir les méthodes helper dans un module séparé :
752
+
753
+ module FooUtils
754
+ def foo(nom) "#{nom}foo" end
755
+ end
756
+
757
+ module BarUtils
758
+ def bar(nom) "#{nom}bar" end
759
+ end
760
+
761
+ helpers FooUtils, BarUtils
762
+
763
+ Cela a le même résultat que d'inclure les modules dans la classe de
764
+ l'application.
765
+
766
+ === Utiliser les sessions
767
+
768
+ Une session est utilisée pour conserver un état entre les requêtes. Une fois
769
+ activées, vous avez un +hash+ de session par session utilisateur :
770
+
771
+ enable :sessions
772
+
773
+ get '/' do
774
+ "valeur = " << session[:valeur].inspect
775
+ end
776
+
777
+ get '/:value' do
778
+ session[:valeur] = params[:valeur]
779
+ end
780
+
781
+ Notez que <tt>enable :sessions</tt> enregistre en fait toutes les données dans
782
+ un +cookie+. Ce n'est pas toujours ce que vous voulez (enregistrer beaucoup de
783
+ données va augmenter le traffic par exemple). Vous pouvez utiliser n'importe
784
+ quel +middleware+ Rack de session afin d'éviter cela. N'utiliser *pas*
785
+ <tt>enable :sessions</tt> dans ce cas mais charger le +middleware+ de votre
786
+ choix comme vous le feriez pour n'importe quel autre +middleware+ :
787
+
788
+ use Rack::Session::Pool, :expire_after => 2592000
789
+
790
+ get '/' do
791
+ "valeur = " << session[:valeur].inspect
792
+ end
793
+
794
+ get '/:value' do
795
+ session[:valeur] = params[:valeur]
796
+ end
797
+
798
+ Pour renforcer la sécurité, les données de session dans le cookie sont signées
799
+ avec une clé secrète de session. Une clé secrète est générée pour vous au
800
+ hasard par Sinatra. Toutefois, comme cette clé change à chaque démarrage de
801
+ votre application, vous pouvez définir cette clé vous-même afin que toutes
802
+ les instances de votre application la partage :
803
+
804
+ set :session_secret, 'super secret'
805
+
806
+ Si vous souhaitez avoir plus de contrôle, vous pouvez également enregistrer un
807
+ +hash+ avec des options lors de la configuration de +sessions+ :
808
+
809
+ set :sessions, :domain => 'foo.com'
810
+
811
+ === Halt
812
+
813
+ Pour arrêter immédiatement la requête dans un filtre ou un gestionnaire de
814
+ route :
815
+
816
+ halt
817
+
818
+ Vous pouvez aussi passer le code retour ...
819
+
820
+ halt 410
821
+
822
+ Ou le texte ...
823
+
824
+ halt 'Ceci est le texte'
825
+
826
+ Ou les deux ...
827
+
828
+ halt 401, 'Partez !'
829
+
830
+ Ainsi que les entêtes ...
831
+
832
+ halt 402, {'Content-Type' => 'text/plain'}, 'revanche'
833
+
834
+ Bien sûr il est possible de combiner un template avec +halt+ :
835
+
836
+ halt erb(:erreur)
837
+
838
+ === Passer
839
+
840
+ Une route peut passer le relais aux autres routes qui correspondent également
841
+ avec <tt>pass</tt> :
842
+
843
+ get '/devine/:qui' do
844
+ pass unless params[:qui] == 'Frank'
845
+ "Tu m'as eu !"
846
+ end
847
+
848
+ get '/devine/*' do
849
+ 'Manqué !'
850
+ end
851
+
852
+ On sort donc immédiatement de ce gestionnaire et on continue à chercher,
853
+ dans les masques suivants, le prochain qui correspond à la requête.
854
+ Si aucun des masques suivants ne correspond, un code 404 est retourné.
855
+
856
+ === Déclencher une autre route
857
+
858
+ Parfois, +pass+ n'est pas ce que vous recherchez, au lieu de cela vous
859
+ souhaitez obtenir le résultat d'une autre route. Pour cela, utilisez
860
+ simplement +call+ :
861
+
862
+ get '/foo' do
863
+ status, headers, body = call env.merge("PATH_INFO" => '/bar')
864
+ [status, headers, body.map(&:upcase)]
865
+ end
866
+
867
+ get '/bar' do
868
+ "bar"
869
+ end
870
+
871
+ Notez que dans l'exemple ci-dessus, vous faciliterez les tests et améliorerez
872
+ la performance en déplaçant simplement <tt>"bar"</tt> dans un +helper+
873
+ utilisé à la fois par <tt>/foo</tt> et <tt>/bar</tt>.
874
+
875
+ Si vous souhiatez que la requête soit envoyée à la même instance de
876
+ l'application plutôt qu'à une copie, utilisez <tt>call!</tt> au lieu de
877
+ <tt>call</tt>.
878
+
879
+ Lisez la spécification Rack si vous souhaitez en savoir plus sur
880
+ <tt>call</tt>.
881
+
882
+ === Définir le corps, le code retour et les entêtes
883
+
884
+ Il est possible et recommandé de définir le code retour et le corps de la
885
+ réponse au moyen de la valeur de retour d'un bloc définissant une route.
886
+ Quoiqu'il en soit, dans certains cas vous pourriez avoir besoin de définir
887
+ le coprs de la réponse à un moment arbitraire de l'exécution. Vous pouvez le
888
+ faire au moyen de la méthode +body+. Si vous faites ainsi, vous pouvez alors
889
+ utiliser cette même méthode pour accéder au corps de la réponse :
890
+
891
+ get '/foo' do
892
+ body "bar"
893
+ end
894
+
895
+ after do
896
+ puts body
897
+ end
898
+
899
+ Il est également possible de passer un bloc à +body+, qui sera exécuté par le
900
+ gestionnaire Rack (ceci peut être utilisé pour implémenter un +streaming+,
901
+ voir "Valeurs de retour").
902
+
903
+ Pareillement au corps de la réponse, vous pouvez également définir le code
904
+ retour et les entêtes :
905
+
906
+ get '/foo' do
907
+ status 418
908
+ headers \
909
+ "Allow" => "BREW, POST, GET, PROPFIND, WHEN",
910
+ "Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
911
+ body "Je suis une théière !"
912
+ end
913
+
914
+ Comme +body+, +headers+ et +status+ peuvent être utilisés sans arguments
915
+ pour accéder à leurs valeurs.
916
+
917
+ === Faire du streaming
918
+
919
+ Il y a des cas où vous voulez commencer à renvoyer des données pendant que
920
+ vous êtes en train de générer le reste de la réponse. Dans les cas les plus
921
+ extrèmes, vous souhaitez continuer à envoyer des données tant que le client
922
+ n'abandonne pas la connection. Vous pouvez alors utiliser le helper +stream+
923
+ pour éviter de créer votre propre système :
924
+
925
+ get '/' do
926
+ stream do |out|
927
+ out << "Ca va être hallu -\n"
928
+ sleep 0.5
929
+ out << " (attends la suite) \n"
930
+ sleep 1
931
+ out << "- cinant !\n"
932
+ end
933
+ end
934
+
935
+ Cela permet d'implémenter des API de streaming ou de
936
+ {Server Sent Events}[http://dev.w3.org/html5/eventsource/] et peut servir de
937
+ base pour des {WebSockets}[http://en.wikipedia.org/wiki/WebSocket]. Vous
938
+ pouvez aussi l'employer pour augmenter le débit quand une partie du contenu
939
+ provient d'une resource lente.
940
+
941
+ Le fonctionnement du streaming, notamment le nombre de requêtes simultanées,
942
+ dépend énormément du serveur web utilisé. Certains ne prennent pas du tout en
943
+ charge le streaming (WEBRick par exemple). Lorsque le serveur ne gère pas le
944
+ streaming, la partie body de la réponse sera envoyée au client en une seule
945
+ fois, après que l'exécution du bloc passé au helper +stream+ sera terminée. Le
946
+ streaming ne fonctionne pas du tout avec Shotgun.
947
+
948
+ En utilisant le helper +stream+ avec le paramètre +keep_open+, il n'appelera
949
+ pas la méthode +close+ du flux, vous laissant la possibilité de le fermer à
950
+ tout moment au cours de l'exécution. Ceci ne fonctionne qu'avec les serveurs
951
+ evented (ie non threadés) tels que Thin et Rainbows. Les autres serveurs
952
+ fermeront malgré tout le flux :
953
+
954
+ set :server, :thin
955
+ connections = []
956
+
957
+ get '/' do
958
+ # conserve le flux ouvert
959
+ stream(:keep_open) { |out| connections << out }
960
+ end
961
+
962
+ post '/' do
963
+ # écrit dans tous les flux ouverts
964
+ connections.each { |out| out << params[:message] << "\n" }
965
+ "message sent"
966
+ end
967
+
968
+ === Journalisation (Logging)
969
+
970
+ Dans le contexte de la requête, la méthode utilitaire +logger+ expose une
971
+ instance de +logger+ :
972
+
973
+ get '/' do
974
+ logger.info "chargement des données"
975
+ # ...
976
+ end
977
+
978
+ Ce +logger+ va automatiquement prendre en compte les paramètres de
979
+ configuration pour la journalisation de votre gestionnaire Rack. Si la
980
+ journalisation est désactivée, cette méthode renverra un objet factice et
981
+ vous n'avez pas à vous en inquiéter dans vos routes en le filtrant.
982
+
983
+ Notez que la journalisation est seulement activée par défaut pour
984
+ <tt>Sinatra::Application</tt>, donc si vous héritez de <tt>Sinatra::Base</tt>,
985
+ vous aurez à l'activer vous-même :
986
+
987
+ class MonApp < Sinatra::Base
988
+ configure :production, :development do
989
+ enable :logging
990
+ end
991
+ end
992
+
993
+ Si vous souhaitez utiliser votre propre logger, vous devez définir le paramètre
994
+ +logging+ à +nil+ pour être certain qu'aucun middleware de logging ne sera
995
+ installé (notez toutefois que +logger+ renverra alors +nil+). Dans ce cas,
996
+ Sinatra utilisera ce qui sera présent dans <tt>env['rack.logger']</tt>.
997
+
998
+ === Types Mime
999
+
1000
+ Quand vous utilisez <tt>send_file</tt> ou des fichiers statiques, vous
1001
+ pouvez rencontrer des types mime que Sinatra ne connaît pas. Utilisez
1002
+ +mime_type+ pour les déclarer par extension de fichier :
1003
+
1004
+ configure do
1005
+ mime_type :foo, 'text/foo'
1006
+ end
1007
+
1008
+ Vous pouvez également les utiliser avec la méthode +content_type+ :
1009
+
1010
+ get '/' do
1011
+ content_type :foo
1012
+ "foo foo foo"
1013
+ end
1014
+
1015
+ === Former des URLs
1016
+
1017
+ Pour former des URLs, vous devriez utiliser la méthode +url+, par exemple en
1018
+ Haml :
1019
+
1020
+ %a{:href => url('/foo')} foo
1021
+
1022
+ Cela prend en compte les proxy inverse et les routeurs Rack, s'ils existent.
1023
+
1024
+ Cette méthode est également disponible sous l'alias +to+ (voir ci-dessous
1025
+ pour un exemple).
1026
+
1027
+ === Redirection du navigateur
1028
+
1029
+ Vous pouvez déclencher une redirection du navigateur avec la méthode
1030
+ +redirect+ :
1031
+
1032
+ get '/foo' do
1033
+ redirect to('/bar')
1034
+ end
1035
+
1036
+ Tout paramètre additionnel est géré comme des arguments pour la méthode
1037
+ +halt+ :
1038
+
1039
+ redirect to('/bar'), 303
1040
+ redirect 'http://google.com', 'mauvais endroit mon pote'
1041
+
1042
+ Vous pouvez aussi rediriger vers la page dont l'utilisateur venait au moyen de
1043
+ <tt>redirect back</tt> :
1044
+
1045
+ get '/foo' do
1046
+ "<a href='/bar'>faire quelque chose</a>"
1047
+ end
1048
+
1049
+ get '/bar' do
1050
+ faire_quelque_chose
1051
+ redirect back
1052
+ end
1053
+
1054
+ Pour passer des arguments à une redirection, ajoutez-les soit à la requête :
1055
+
1056
+ redirect to('/bar?sum=42')
1057
+
1058
+ Ou bien utilisez une session :
1059
+
1060
+ enable :sessions
1061
+
1062
+ get '/foo' do
1063
+ session[:secret] = 'foo'
1064
+ redirect to('/bar')
1065
+ end
1066
+
1067
+ get '/bar' do
1068
+ session[:secret]
1069
+ end
1070
+
1071
+ === Contrôle du cache
1072
+
1073
+ Définir correctement vos entêtes à la base pour un bon cache HTTP.
1074
+
1075
+ Vous pouvez facilement définir l'entête Cache-Control de la manière suivante :
1076
+
1077
+ get '/' do
1078
+ cache_control :public
1079
+ "met le en cache !"
1080
+ end
1081
+
1082
+ Conseil de pro : définir le cache dans un filtre +before+ :
1083
+
1084
+ before do
1085
+ cache_control :public, :must_revalidate, :max_age => 60
1086
+ end
1087
+
1088
+ Si vous utilisez la méthode +expires+ pour définir l'entête correspondant,
1089
+ <tt>Cache-Control</tt> sera alors défini automatiquement :
1090
+
1091
+ before do
1092
+ expires 500, :public, :must_revalidate
1093
+ end
1094
+
1095
+ Pour utiliser correctement les caches, vous devriez utiliser +etag+ ou
1096
+ +last_modified+. Il est recommandé d'utiliser ces méthodes *avant* de faire
1097
+ d'importantes modifications, car elles vont immédiatement déclencher la réponse
1098
+ si le client a déjà la version courante dans son cache :
1099
+
1100
+ get '/article/:id' do
1101
+ @article = Article.find params[:id]
1102
+ last_modified @article.updated_at
1103
+ etag @article.sha1
1104
+ erb :article
1105
+ end
1106
+
1107
+ Il est également possible d'utiliser un
1108
+ {weak ETag}[http://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation] :
1109
+
1110
+ etag @article.sha1, :weak
1111
+
1112
+ Ces méthodes ne sont pas chargées de mettre des données en cache, mais elles
1113
+ fournissent les informations nécessaires pour votre cache. Si vous êtes à la
1114
+ recherche de solutions rapides pour un reverse-proxy de cache, essayez
1115
+ {rack-cache}[https://github.com/rtomayko/rack-cache] :
1116
+
1117
+ require "rack/cache"
1118
+ require "sinatra"
1119
+
1120
+ use Rack::Cache
1121
+
1122
+ get '/' do
1123
+ cache_control :public, :max_age => 36000
1124
+ sleep 5
1125
+ "hello"
1126
+ end
1127
+
1128
+ Utilisez le paramètre <tt>:static_cache_control</tt> pour ajouter l'information
1129
+ d'en-tête <tt>Cache-Control</tt> (voir plus loin).
1130
+
1131
+ D'après la RFC 2616, votre application devrait se comporter différement lorsque
1132
+ l'en-tête If-Match ou If-None-Match est défini à <tt>*</tt> en tenant compte du
1133
+ fait que la resource demandée existe déjà ou pas. Sinatra considère que les
1134
+ requêtes portant sur des resources sûres (tel que get) ou idempotentes (tel que
1135
+ put) existent déjà et pour les autres resources (par exemple dans le cas
1136
+ de requêtes post) qu'il s'agit de nouvelles resources. Vous pouvez modifier ce
1137
+ comportement en passant une option <tt>:new_resource</tt> :
1138
+
1139
+ get '/create' do
1140
+ etag '', :new_resource => true
1141
+ Article.create
1142
+ erb :new_article
1143
+ end
1144
+
1145
+ Si vous souhaitez utilisez un ETag faible, utilisez l'option <tt>:kind</tt> :
1146
+
1147
+ etag '', :new_resource => true, :kind => :weak
1148
+
1149
+ === Envoyer des fichiers
1150
+
1151
+ Pour envoyer des fichiers, vous pouvez utiliser la méthode
1152
+ <tt>send_file</tt> :
1153
+
1154
+ get '/' do
1155
+ send_file 'foo.png'
1156
+ end
1157
+
1158
+ Quelques options sont également acceptées :
1159
+
1160
+ send_file 'foo.png', :type => :jpg
1161
+
1162
+ Les options sont :
1163
+
1164
+ [filename]
1165
+ le nom du fichier dans la réponse, par défaut le nom du fichier envoyé.
1166
+
1167
+ [last_modified]
1168
+ valeur pour l'entête Last-Modified, par défaut la date de modification du
1169
+ fichier
1170
+
1171
+ [type]
1172
+ type de contenu à utiliser, deviné à partir de l'extension de fichier si
1173
+ absent
1174
+
1175
+ [disposition]
1176
+ utilisé pour Content-Disposition, les valuers possibles étant : +nil+ (par
1177
+ défaut), <tt>:attachment</tt> et <tt>:inline</tt>
1178
+
1179
+ [length]
1180
+ entête Content-Length, par défaut la taille du fichier
1181
+
1182
+ [status]
1183
+ code état à renvoyer. Utile quand un fichier statique sert de page d'erreur.
1184
+
1185
+ Si le gestionnaire Rack le supporte, d'autres moyens que le +streaming+ via le
1186
+ processus Ruby seront utilisés. Si vous utilisez cette méthode, Sinatra gérera
1187
+ automatiquement les requêtes de type +range+.
1188
+
1189
+ === Accéder à l'objet requête
1190
+
1191
+ L'objet correspondant à la requête envoyée peut être récupéré dans le contexte
1192
+ de la requête (filtres, routes, gestionnaires d'erreur) au moyen de la méthode
1193
+ +request+ :
1194
+
1195
+ # application tournant à l'adresse http://exemple.com/exemple
1196
+ get '/foo' do
1197
+ t = %w[text/css text/html application/javascript]
1198
+ request.accept # ['text/html', '*/*']
1199
+ request.accept? 'text/xml' # true
1200
+ request.preferred_type(t) # 'text/html'
1201
+ request.body # corps de la requête envoyée par le client
1202
+ # (voir ci-dessous)
1203
+ request.scheme # "http"
1204
+ request.script_name # "/exemple"
1205
+ request.path_info # "/foo"
1206
+ request.port # 80
1207
+ request.request_method # "GET"
1208
+ request.query_string # ""
1209
+ request.content_length # taille de request.body
1210
+ request.media_type # type de média pour request.body
1211
+ request.host # "exemple.com"
1212
+ request.get? # true (méthodes similaires pour les autres
1213
+ # verbes HTTP)
1214
+ request.form_data? # false
1215
+ request["UN_ENTETE"] # valeur de l'entête UN_ENTETE
1216
+ request.referer # référant du client ou '/'
1217
+ request.user_agent # user agent (utilisé par la condition :agent)
1218
+ request.cookies # tableau contenant les cookies du navigateur
1219
+ request.xhr? # requête AJAX ?
1220
+ request.url # "http://exemple.com/exemple/foo"
1221
+ request.path # "/exemple/foo"
1222
+ request.ip # adresse IP du client
1223
+ request.secure? # false
1224
+ request.forwarded? # vrai (si on est derrière un proxy inverse)
1225
+ request.env # tableau brut de l'environnement fourni par
1226
+ # Rack
1227
+ end
1228
+
1229
+ Certaines options, telles que <tt>script_name</tt> ou <tt>path_info</tt>
1230
+ peuvent également être modifiées :
1231
+
1232
+ before { request.path_info = "/" }
1233
+
1234
+ get "/" do
1235
+ "toutes les requêtes arrivent ici"
1236
+ end
1237
+
1238
+ <tt>request.body</tt> est un objet IO ou StringIO :
1239
+
1240
+ post "/api" do
1241
+ request.body.rewind # au cas où il a déjà été lu
1242
+ donnees = JSON.parse request.body.read
1243
+ "Bonjour #{donnees['nom']} !"
1244
+ end
1245
+
1246
+ === Fichiers joints
1247
+
1248
+ Vous pouvez utiliser la méthode +attachment+ pour indiquer au navigateur que
1249
+ la réponse devrait être stockée sur le disque plutôt qu'affichée :
1250
+
1251
+ get '/' do
1252
+ attachment
1253
+ "enregistre-le !"
1254
+ end
1255
+
1256
+ Vous pouvez également lui passer un nom de fichier :
1257
+
1258
+ get '/' do
1259
+ attachment "info.txt"
1260
+ "enregistre-le !"
1261
+ end
1262
+
1263
+ === Gérer Date et Time
1264
+
1265
+ Sinatra fourni un helper +time_for+ pour convertir une valeur donnée en
1266
+ objet +Time+. Il peut aussi faire la conversion à partir d'objets +DateTime+,
1267
+ +Date+ ou de classes similaires :
1268
+
1269
+ get '/' do
1270
+ pass if Time.now > time_for('Dec 23, 2012')
1271
+ "encore temps"
1272
+ end
1273
+
1274
+ Cette méthode est utilisée en interne par +expires+, +last_modified+ et
1275
+ consorts. Par conséquent, vous pouvez très facilement étendre le
1276
+ fonctionnement de ces méthodes en surchargeant le helper +time_for+ dans
1277
+ votre application :
1278
+
1279
+ helpers do
1280
+ def time_for(value)
1281
+ case value
1282
+ when :yesterday then Time.now - 24*60*60
1283
+ when :tomorrow then Time.now + 24*60*60
1284
+ else super
1285
+ end
1286
+ end
1287
+ end
1288
+
1289
+ get '/' do
1290
+ last_modified :yesterday
1291
+ expires :tomorrow
1292
+ "salut"
1293
+ end
1294
+
1295
+ === Chercher les fichiers de templates
1296
+
1297
+ La méthode <tt>find_template</tt> est utilisée pour trouver les fichiers de
1298
+ templates à générer :
1299
+
1300
+ find_template settings.views, 'foo', Tilt[:haml] do |file|
1301
+ puts "pourrait être #{file}"
1302
+ end
1303
+
1304
+ Ce n'est pas très utilise. En revanche, il est utile de pouvoir surcharger
1305
+ cette méthode afin de définir son propre mécanisme de recherche. Par exemple,
1306
+ vous pouvez utiliser plus d'un répertoire de vues :
1307
+
1308
+ set :views, ['views', 'templates']
1309
+
1310
+ helpers do
1311
+ def find_template(views, name, engine, &block)
1312
+ Array(views).each { |v| super(v, name, engine, &block) }
1313
+ end
1314
+ end
1315
+
1316
+ Un autre exemple est d'utiliser des répertoires différents pour des moteurs
1317
+ de rendu différents :
1318
+
1319
+ set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
1320
+
1321
+ helpers do
1322
+ def find_template(views, name, engine, &block)
1323
+ _, folder = views.detect { |k,v| engine == Tilt[k] }
1324
+ folder ||= views[:default]
1325
+ super(folder, name, engine, &block)
1326
+ end
1327
+ end
1328
+
1329
+ Vous pouvez également écrire cela dans une extension et la partager avec
1330
+ d'autres !
1331
+
1332
+ Notez que <tt>find_template</tt> ne vérifie pas que le fichier existe mais
1333
+ va plutôt exécuter le bloc pour tous les chemins possibles. Cela n'induit pas
1334
+ un problème de performance dans le sens où +render+ va utiliser +break+ dès
1335
+ qu'un fichier est trouvé. De plus, l'emplacement des templates (et leur
1336
+ contenu) est mis en cache si vous n'êtes pas en mode développement. Vous
1337
+ devriez garder cela en tête si vous écrivez une méthode vraiment dingue.
1338
+
1339
+ == Configuration
1340
+
1341
+ Lancé une seule fois au démarrage de tous les environnements :
1342
+
1343
+ configure do
1344
+ # définir un paramètre
1345
+ set :option, 'value'
1346
+
1347
+ # définir plusieurs paramètre
1348
+ set :a => 1, :b => 2
1349
+
1350
+ # identique à "set :option, true"
1351
+ enable :option
1352
+
1353
+ # identique à "set :option, false""
1354
+ disable :option
1355
+
1356
+ # vous pouvez également avoir des paramètres dynamiques avec des blocs
1357
+ set(:css_dir) { File.join(views, 'css') }
1358
+ end
1359
+
1360
+ Lancé si l'environnement (variable d'environnement RACK_ENV) est défini comme
1361
+ <tt>:production</tt> :
1362
+
1363
+ configure :production do
1364
+ ...
1365
+ end
1366
+
1367
+ Lancé si l'environnement est <tt>:production</tt> ou
1368
+ <tt>:test</tt> :
1369
+
1370
+ configure :production, :test do
1371
+ ...
1372
+ end
1373
+
1374
+ Vous pouvez accéder à ces paramètres via <tt>settings</tt> :
1375
+
1376
+ configure do
1377
+ set :foo, 'bar'
1378
+ end
1379
+
1380
+ get '/' do
1381
+ settings.foo? # => true
1382
+ settings.foo # => 'bar'
1383
+ ...
1384
+ end
1385
+
1386
+ === Se protéger des attaques
1387
+
1388
+ Sinatra utilise {Rack::Protection}[https://github.com/rkh/rack-protection#readme]
1389
+ pour protéger votre application contre les principales attaques opportunistes.
1390
+ Vous pouvez très simplement désactiver cette fonctionnalité (ce qui exposera
1391
+ votre application à beaucoup de vulnerabilités courantes) :
1392
+
1393
+ disable :protection
1394
+
1395
+ Pour désactiver seulement un type de protection, vous pouvez définir +protection+
1396
+ avec un hash d'options :
1397
+
1398
+ set :protection, :except => :path_traversal
1399
+
1400
+ Vous pouvez également lui passer un tableau pour désactiver plusieurs types de
1401
+ protection :
1402
+
1403
+ set :protection, :except => [:path_traversal, :session_hijacking]
1404
+
1405
+ === Paramètres disponibles
1406
+
1407
+ [absolute_redirects] Si désactivé, Sinatra permettra les redirections
1408
+ relatives. Toutefois, Sinatra ne sera plus conforme à la
1409
+ RFC 2616 (HTTP 1.1), qui n'autorise que les redirections
1410
+ absolues.
1411
+
1412
+ Activez si votre application tourne derrière un proxy
1413
+ inverse qui n'a pas été correctement configuré. Notez
1414
+ que la méthode +url+ continuera de produire des URLs
1415
+ absolues, sauf si vous lui passez +false+ comme second
1416
+ argument.
1417
+
1418
+ Désactivé par défaut.
1419
+
1420
+ [add_charsets] types mime pour lesquels la méthode
1421
+ <tt>content_type</tt> va automatiquement ajouter
1422
+ l'information du +charset+.
1423
+
1424
+ Vous devriez lui ajouter des valeurs plutôt que de
1425
+ l'écraser :
1426
+
1427
+ settings.add_charsets << "application/foobar"
1428
+
1429
+ [app_file] chemin pour le fichier de l'application principale,
1430
+ utilisé pour détecter la racine du projet, les dossiers
1431
+ public et vues, et les templates en ligne.
1432
+
1433
+ [bind] adresse IP sur laquelle se brancher
1434
+ (par défaut : 0.0.0.0).
1435
+ Utiliser seulement pour le serveur intégré.
1436
+
1437
+ [default_encoding] encodage à utiliser si inconnu (par défaut
1438
+ <tt>"utf-8"</tt>).
1439
+
1440
+ [dump_errors] afficher les erreurs dans le +log+.
1441
+
1442
+ [environment] environnement courant, par défaut
1443
+ <tt>ENV['RACK_ENV']</tt>, ou
1444
+ <tt>"development"</tt> si absent.
1445
+
1446
+ [logging] utiliser le +logger+.
1447
+
1448
+ [lock] Place un +lock+ autour de chaque requête, n'exécutant
1449
+ donc qu'une seule requête par processus Ruby.
1450
+
1451
+ Activé si votre application n'est pas +thread-safe+.
1452
+ Désactivé par défaut.
1453
+
1454
+ [method_override] utilise la magie de <tt>_method</tt> afin de permettre
1455
+ des formulaires put/delete dans des navigateurs qui ne
1456
+ le permettent pas.
1457
+
1458
+ [port] port à écouter. Utiliser seulement pour le serveur
1459
+ intégré.
1460
+
1461
+ [prefixed_redirects] si oui ou non <tt>request.script_name</tt> doit être
1462
+ inséré dans les redirections si un chemin non absolu
1463
+ est utilisé. Ainsi, <tt>redirect '/foo'</tt> se
1464
+ comportera comme <tt>redirect to('/foo')</tt>.
1465
+ Désactivé par défaut.
1466
+
1467
+ [protection] défini s'il faut activer ou non la protection contre
1468
+ les attaques web. Voir la section protection précédente.
1469
+
1470
+ [public_dir] alias pour <tt>public_folder</tt>. Voir ci-dessous.
1471
+
1472
+ [public_folder] chemin pour le dossier à partir duquel les fichiers
1473
+ publics sont servis. Utilisé seulement si les fichiers
1474
+ statiques doivent être servis (voir le paramètre
1475
+ <tt>static</tt>). Si non défini, il découle du paramètre
1476
+ <tt>app_file</tt>.
1477
+
1478
+ [reload_templates] si oui ou non les templates doivent être rechargés
1479
+ entre les requêtes. Activé en mode développement.
1480
+
1481
+ [root] chemin pour le dossier racine du projet. Si non défini,
1482
+ il découle du paramètre <tt>app_file</tt>.
1483
+
1484
+ [raise_errors] soulever les erreurs (ce qui arrêtera l'application).
1485
+ Désactivé par défaut sauf lorsque <tt>environment</tt>
1486
+ est défini à <tt>"test"</tt>.
1487
+
1488
+ [run] si activé, Sinatra s'occupera de démarrer le serveur,
1489
+ ne pas activer si vous utiliser rackup ou autres.
1490
+
1491
+ [running] est-ce que le serveur intégré est en marche ?
1492
+ ne changez pas ce paramètre !
1493
+
1494
+ [server] serveur ou liste de serveurs à utiliser pour le serveur
1495
+ intégré.
1496
+ Par défaut ['thin', 'mongrel', 'webrick'], l'ordre
1497
+ indiquant la priorité.
1498
+
1499
+ [sessions] active le support des sessions basées sur les cookies, en
1500
+ utilisant <tt>Rack::Session::Cookie</tt>. Reportez-vous
1501
+ à la section 'Utiliser les sessions' pour plus
1502
+ d'informations.
1503
+
1504
+ [show_exceptions] affiche la trace de l'erreur dans le navigateur lorsqu'une
1505
+ exception se produit. Désactivé par défaut sauf lorsque
1506
+ <tt>environment</tt> est défini à <tt>"development"</tt>.
1507
+
1508
+ [static] Si oui ou non Sinatra doit s'occuper de servir les
1509
+ fichiers statiques.
1510
+ Désactivez si vous utilisez un serveur capable de le
1511
+ gérer lui même. Le désactiver augmentera la performance.
1512
+ Activé par défaut pour le style classique, désactivé pour
1513
+ le style modulaire.
1514
+
1515
+ [static_cache_control] A définir quand Sinatra rend des fichiers statiques pour
1516
+ ajouter les en-têtes <tt>Cache-Control</tt>. Utilise le
1517
+ helper +cache_control+. Désactivé par défaut.
1518
+ Utiliser un array explicite pour définir des plusieurs
1519
+ valeurs :
1520
+ <tt>set :static_cache_control, [:public, :max_age => 300]</tt>
1521
+
1522
+ [threaded] à définir à +true+ pour indiquer à Thin d'utiliser
1523
+ <tt>EventMachine.defer</tt> pour traiter la requête.
1524
+
1525
+ [views] chemin pour le dossier des vues. Si non défini, il
1526
+ découle du paramètre <tt>app_file</tt>.
1527
+
1528
+ == Environements
1529
+
1530
+ Il existe trois environnements prédéfinis : <tt>"development"</tt>,
1531
+ <tt>"production"</tt> et <tt>"test"</tt>. Les environements peuvent être
1532
+ sélectionné via la variable d'environnement +RACK_ENV+. Sa valeur par défaut
1533
+ est <tt>"development"</tt>. Dans ce mode, tous les templates sont rechargés à
1534
+ chaque requête. Des handlers spécifiques pour <tt>not_found</tt> et
1535
+ <tt>error</tt> sont installés pour vous permettre d'avoir une pile de trace
1536
+ dans votre navigateur. En mode <tt>"production"</tt> et <tt>"test"</tt> les
1537
+ templates sont mis en cache par défaut.
1538
+
1539
+ Pour exécuter votre application dans un environnement différent, utilisez
1540
+ l'option <tt>-e</tt> de Ruby :
1541
+
1542
+ ruby mon_application.rb -e [ENVIRONMENT]
1543
+
1544
+ Vous pouvez utiliser une des méthodes +development?+, +test?+ et +production?+
1545
+ pour déterminer quel est l'environnement en cours.
1546
+
1547
+ == Gérer les erreurs
1548
+
1549
+ Les gestionnaires d'erreur s'exécutent dans le même contexte que les routes ou
1550
+ les filtres, ce qui veut dire que vous avez accès (entre autres) aux bons
1551
+ vieux <tt>haml</tt>, <tt>erb</tt>, <tt>halt</tt>, etc.
1552
+
1553
+ === NotFound
1554
+
1555
+ Quand une exception <tt>Sinatra::NotFound</tt> est soulevée, ou que le code
1556
+ retour est 404, le gestionnaire <tt>not_found</tt> est invoqué :
1557
+
1558
+ not_found do
1559
+ 'Pas moyen de trouver ce que vous cherchez'
1560
+ end
1561
+
1562
+ === Error
1563
+
1564
+ Le gestionnaire +error+ est invoqué à chaque fois qu'une exception est
1565
+ soulevée dans une route ou un filtre. L'objet exception est accessible via la
1566
+ variable Rack <tt>sinatra.error</tt> :
1567
+
1568
+ error do
1569
+ 'Désolé mais une méchante erreur est survenue - ' + env['sinatra.error'].name
1570
+ end
1571
+
1572
+ Erreur sur mesure :
1573
+
1574
+ error MonErreurSurMesure do
1575
+ 'Donc il est arrivé ceci...' + env['sinatra.error'].message
1576
+ end
1577
+
1578
+ Donc si ceci arrive :
1579
+
1580
+ get '/' do
1581
+ raise MonErreurSurMesure, 'quelque chose de mal'
1582
+ end
1583
+
1584
+ Vous obtenez ça :
1585
+
1586
+ Donc il est arrivé ceci... quelque chose de mal
1587
+
1588
+ Alternativement, vous pouvez avoir un gestionnaire d'erreur associé à un code
1589
+ particulier :
1590
+
1591
+ error 403 do
1592
+ 'Accès interdit'
1593
+ end
1594
+
1595
+ get '/secret' do
1596
+ 403
1597
+ end
1598
+
1599
+ Ou un intervalle :
1600
+
1601
+ error 400..510 do
1602
+ 'Boom'
1603
+ end
1604
+
1605
+ Sinatra installe pour vous quelques gestionnaires <tt>not_found</tt> et
1606
+ <tt>error</tt> génériques lorsque vous êtes en environnement
1607
+ <tt>development</tt>.
1608
+
1609
+ == Les Middlewares Rack
1610
+
1611
+ Sinatra tourne avec Rack[http://rack.rubyforge.org/], une interface standard
1612
+ et minimale pour les web frameworks Ruby. Un des points forts de Rack est le
1613
+ support de ce que l'on appelle des "middlewares" -- composant qui vient se
1614
+ situer entre le serveur et votre application, et dont le but est de
1615
+ visualiser/manipuler la requête/réponse HTTP, et d'offrir diverses
1616
+ fonctionnalités classiques.
1617
+
1618
+ Sinatra permet de construire facilement des middlewares Rack via la méthode de
1619
+ haut niveau +use+ :
1620
+
1621
+ require 'sinatra'
1622
+ require 'mon_middleware_perso'
1623
+
1624
+ use Rack::Lint
1625
+ use MonMiddlewarePerso
1626
+
1627
+ get '/bonjour' do
1628
+ 'Bonjour le monde'
1629
+ end
1630
+
1631
+ La sémantique de +use+ est identique à celle définie dans le DSL de
1632
+ Rack::Builder[http://rack.rubyforge.org/doc/classes/Rack/Builder.html]
1633
+ (le plus souvent utilisé dans un fichier rackup). Par exemple, la méthode
1634
+ +use+ accepte divers arguments ainsi que des blocs :
1635
+
1636
+ use Rack::Auth::Basic do |login, password|
1637
+ login == 'admin' && password == 'secret'
1638
+ end
1639
+
1640
+ Rack est distribué avec une bonne variété de middlewares standards pour les
1641
+ logs, débuguer, faire du routage URL, de l'authentification, gérer des
1642
+ sessions. Sinatra utilise beaucoup de ces composants automatiquement via la
1643
+ configuration, donc pour ceux-ci vous n'aurez pas à utiliser la méthode +use+.
1644
+
1645
+ == Tester
1646
+
1647
+ Les tests pour Sinatra peuvent être écrit avec n'importe quelle bibliothèque
1648
+ basée sur Rack. {Rack::Test}[http://gitrdoc.com/brynary/rack-test] est
1649
+ recommandé :
1650
+
1651
+ require 'mon_application_sinatra'
1652
+ require 'test/unit'
1653
+ require 'rack/test'
1654
+
1655
+ class MonTest < Test::Unit::TestCase
1656
+ include Rack::Test::Methods
1657
+
1658
+ def app
1659
+ Sinatra::Application
1660
+ end
1661
+
1662
+ def test_ma_racine
1663
+ get '/'
1664
+ assert_equal 'Bonjour le monde !', last_response.body
1665
+ end
1666
+
1667
+ def test_avec_des_parametres
1668
+ get '/rencontrer', :name => 'Frank'
1669
+ assert_equal 'Salut Frank !', last_response.body
1670
+ end
1671
+
1672
+ def test_avec_rack_env
1673
+ get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
1674
+ assert_equal "Vous utilisez Songbird !", last_response.body
1675
+ end
1676
+ end
1677
+
1678
+ == Sinatra::Base - Les Middlewares, Bibliothèques, et Applications Modulaires
1679
+
1680
+ Définir votre application au niveau supérieur fonctionne bien dans le cas des
1681
+ micro-applications mais présente pas mal d'inconvénients pour créer des
1682
+ composants réutilisables sous forme de middlewares Rack, de Rails metal, de
1683
+ simples librairies avec un composant serveur ou même d'extensions Sinatra. Le
1684
+ niveau supérieur suppose une configuration dans le style des micro-applications
1685
+ (une application d'un seul fichier, des répertoires <tt>./public</tt> et
1686
+ <tt>./views</tt>, des logs, une page d'erreur, etc...). C'est là que
1687
+ <tt>Sinatra::Base</tt> prend tout son intérêt :
1688
+
1689
+ require 'sinatra/base'
1690
+
1691
+ class MonApplication < Sinatra::Base
1692
+ set :sessions, true
1693
+ set :foo, 'bar'
1694
+
1695
+ get '/' do
1696
+ 'Bonjour le monde !'
1697
+ end
1698
+ end
1699
+
1700
+ Les méthodes de la classe <tt>Sinatra::Base</tt> sont parfaitement identiques à
1701
+ celles disponibles via le DSL de haut niveau. Il suffit de deux modifications
1702
+ pour transformer la plupart des applications de haut niveau en un composant
1703
+ <tt>Sinatra::Base</tt> :
1704
+
1705
+ * Votre fichier doit charger +sinatra/base+ au lieu de +sinatra+, sinon toutes
1706
+ les méthodes du DSL Sinatra seront importées dans l'espace de nom principal.
1707
+ * Les gestionnaires de routes, la gestion d'erreur, les filtres et les options
1708
+ doivent être placés dans une classe héritant de <tt>Sinatra::Base</tt>.
1709
+
1710
+ <tt>Sinatra::Base</tt> est une page blanche. La plupart des options sont
1711
+ désactivées par défaut, y compris le serveur intégré. Reportez-vous à
1712
+ {Options et Configuration}[http://sinatra.github.com/configuration.html]
1713
+ pour plus d'informations sur les options et leur fonctionnement.
1714
+
1715
+ === Style modulaire vs. style classique
1716
+
1717
+ Contrairement aux idées reçues, il n'y a rien de mal à utiliser le style
1718
+ classique. Si c'est ce qui convient pour votre application, vous n'avez pas
1719
+ aucune raison de passer à une application modulaire.
1720
+
1721
+ Le principal inconvénient du style classique sur le style modulaire est que vous
1722
+ ne pouvez avoir qu'une application Ruby par processus Ruby. Si vous pensez en
1723
+ utiliser plus, passez au style modulaire. Et rien ne vous empêche de mixer style
1724
+ classique et style modulaire.
1725
+
1726
+ Si vous passez d'un style à l'autre, souvenez-vous des quelques différences
1727
+ mineures en ce qui concerne les paramètres par défaut :
1728
+
1729
+ Paramètre Classique Modulaire
1730
+
1731
+ app_file fichier chargeant sinatra fichier héritant de Sinatra::Base
1732
+ run $0 == app_file false
1733
+ logging true false
1734
+ method_override true false
1735
+ inline_templates true false
1736
+ static true false
1737
+
1738
+ === Servir une application modulaire
1739
+
1740
+ Il y a deux façons de faire pour démarrer une application modulaire, démarrez
1741
+ avec <tt>run!</tt> :
1742
+
1743
+ # my_app.rb
1744
+ require 'sinatra/base'
1745
+
1746
+ class MyApp < Sinatra::Base
1747
+ # ... code de l'application ici ...
1748
+
1749
+ # démarre le serveur si ce fichier est directement exécuté
1750
+ run! if app_file == $0
1751
+ end
1752
+
1753
+ Démarrez ensuite avec :
1754
+
1755
+ ruby my_app.rb
1756
+
1757
+ Ou alors avec un fichier <tt>config.ru</tt>, qui permet d'utiliser n'importe
1758
+ quel gestionnaire Rack :
1759
+
1760
+ # config.ru
1761
+ require './my_app'
1762
+ run MyApp
1763
+
1764
+ Exécutez :
1765
+
1766
+ rackup -p 4567
1767
+
1768
+ === Utiliser une application de style classique avec un fichier config.ru
1769
+
1770
+ Ecrivez votre application :
1771
+
1772
+ # app.rb
1773
+ require 'sinatra'
1774
+
1775
+ get '/' do
1776
+ 'Bonjour le monde !'
1777
+ end
1778
+
1779
+ Et un fichier <tt>config.ru</tt> correspondant :
1780
+
1781
+ require './app'
1782
+ run Sinatra::Application
1783
+
1784
+ === Quand utiliser un fichier config.ru ?
1785
+
1786
+ Quelques cas où vous devriez utiliser un fichier <tt>config.ru</tt> :
1787
+
1788
+ * Vous souhaitez déployer avec un autre gestionnaire Rack (Passenger, Unicorn,
1789
+ Heroku, ...).
1790
+ * Vous souhaitez utiliser plus d'une sous-classe de <tt>Sinatra::Base</tt>.
1791
+ * Vous voulez utiliser Sinatra comme un +middleware+, non en tant que
1792
+ +endpoint+.
1793
+
1794
+ <b>Il n'est pas nécessaire de passer par un fichier <tt>config.ru</tt> pour la
1795
+ seule raison que vous êtes passé au style modulaire, et vous n'avez pas besoin
1796
+ de passer au style modulaire pour utiliser un fichier <tt>config.ru</tt>.</b>
1797
+
1798
+ === Utiliser Sinatra comme Middleware
1799
+
1800
+ Non seulement Sinatra peut utiliser d'autres middlewares Rack, il peut
1801
+ également être à son tour utilisé au-dessus de n'importe quel +endpoint+ Rack
1802
+ en tant que middleware. Ce +endpoint+ peut très bien être une autre
1803
+ application Sinatra, ou n'importe quelle application basée sur Rack
1804
+ (Rails/Ramaze/Camping/...) :
1805
+
1806
+ require 'sinatra/base'
1807
+
1808
+ class EcranDeConnexion < Sinatra::Base
1809
+ enable :sessions
1810
+
1811
+ get('/connexion') { haml :connexion }
1812
+
1813
+ post('/connexion') do
1814
+ if params[:nom] = 'admin' && params[:motdepasse] = 'admin'
1815
+ session['nom_utilisateur'] = params[:nom]
1816
+ else
1817
+ redirect '/connexion'
1818
+ end
1819
+ end
1820
+ end
1821
+
1822
+ class MonApp < Sinatra::Base
1823
+ # le middleware sera appelé avant les filtres
1824
+ use EcranDeConnexion
1825
+
1826
+ before do
1827
+ unless session['nom_utilisateur']
1828
+ halt "Accès refusé, merci de vous <a href='/connexion'>connecter</a>."
1829
+ end
1830
+ end
1831
+
1832
+ get('/') { "Bonjour #{session['nom_utilisateur']}." }
1833
+ end
1834
+
1835
+ === Création dynamique d'applications
1836
+
1837
+ Il se peut que vous ayez besoin de créer une nouvelle application à l'exécution
1838
+ sans avoir à les assigner à une constante, vous pouvez le faire grâce à
1839
+ <tt>Sinatra.new</tt> :
1840
+
1841
+ require 'sinatra/base'
1842
+ mon_app = Sinatra.new { get('/') { "salut" } }
1843
+ mon_app.run!
1844
+
1845
+ L'application dont elle hérite peut être passé en argument optionnel :
1846
+
1847
+ # config.ru
1848
+ require 'sinatra/base'
1849
+
1850
+ controleur = Sinatra.new do
1851
+ enable :logging
1852
+ helpers MyHelpers
1853
+ end
1854
+
1855
+ map('/a') do
1856
+ run Sinatra.new(controleur) { get('/') { 'a' } }
1857
+ end
1858
+
1859
+ map('/b') do
1860
+ run Sinatra.new(controleur) { get('/') { 'b' } }
1861
+ end
1862
+
1863
+ C'est notamment utile pour tester des extensions à Sinatra ou bien pour
1864
+ utiliser Sinatra dans votre propre bibliothèque.
1865
+
1866
+ Cela permet également d'utiliser très facilement Sinatra comme middleware :
1867
+
1868
+ require 'sinatra/base'
1869
+
1870
+ use Sinatra do
1871
+ get('/') { ... }
1872
+ end
1873
+
1874
+ run RailsProject::Application
1875
+
1876
+ == Contextes et Binding
1877
+
1878
+ Le contexte dans lequel vous êtes détermine les méthodes et variables
1879
+ disponibles.
1880
+
1881
+ === Contexte de l'application/classe
1882
+
1883
+ Toute application Sinatra correspond à une sous-classe de <tt>Sinatra::Base</tt>.
1884
+ Si vous utilisez le DSL haut niveau (<tt>require 'sinatra'</tt>), alors cette
1885
+ classe est <tt>Sinatra::Application</tt>, sinon il s'agit de la sous-classe que
1886
+ vous avez définie. Dans le contexte de la classe, vous avez accès aux méthodes
1887
+ telles que +get+ ou +before+, mais vous n'avez pas accès aux objets +request+
1888
+ ou +session+ car c'est la même classe d'application qui traitera toutes les
1889
+ requêtes.
1890
+
1891
+ Les options définies au moyen de +set+ deviennent des méthodes de classe :
1892
+
1893
+ class MonApp < Sinatra::Base
1894
+ # Eh, je suis dans le contexte de l'application !
1895
+ set :foo, 42
1896
+ foo # => 42
1897
+
1898
+ get '/foo' do
1899
+ # Eh, je ne suis plus dans le contexte de l'application !
1900
+ end
1901
+ end
1902
+
1903
+ Vous avez le binding du contexte de l'application dans :
1904
+
1905
+ * Le corps de la classe d'application
1906
+ * Les méthodes définies par les extensions
1907
+ * Le bloc passé à +helpers+
1908
+ * Les procs/blocs utilisés comme argument pour +set+
1909
+ * Le bloc passé à <tt>Sinatra.new</tt>
1910
+
1911
+ Vous pouvez atteindre ce contexte (donc la classe) de la façon suivante :
1912
+
1913
+ * Via l'objet passé dans les blocs +configure+ (<tt>configure { |c| ... }</tt>)
1914
+ * En utilisant +settings+ dans le contexte de la requête
1915
+
1916
+ === Contexte de la requête/instance
1917
+
1918
+ Pour tout traitement d'une requête, une nouvelle instance de votre classe
1919
+ d'application est créée et tous vos gestionnaires sont exécutés dans ce
1920
+ contexte. Dans ce dernier, vous pouvez accéder aux objets +request+ et
1921
+ +session+ et faire appel aux fonctions de rendu telles que +erb+ ou +haml+.
1922
+ Vous pouvez accéder au contexte de l'application depuis le contexte de la
1923
+ requête au moyen de +settings+ :
1924
+
1925
+ class MonApp < Sinatra::Base
1926
+ # Eh, je suis dans le contexte de l'application !
1927
+ get '/ajouter_route/:nom' do
1928
+ # Contexte de la requête pour '/ajouter_route/:nom'
1929
+ @value = 42
1930
+
1931
+ settings.get("/#{params[:nom]}") do
1932
+ # Contexte de la requête pour "/#{params[:nom]}"
1933
+ @value # => nil (on est pas au sein de la même requête)
1934
+ end
1935
+
1936
+ "Route ajoutée !"
1937
+ end
1938
+ end
1939
+
1940
+ Vous avez le binding du contexte de la requête dans :
1941
+
1942
+ * les blocs get/head/post/put/delete/options
1943
+ * les filtres before/after
1944
+ * les méthodes utilitaires (définies au moyen de +helpers+)
1945
+ * les vues/templates
1946
+
1947
+ === Le contexte de délégation
1948
+
1949
+ Le contexte de délégation se contente de transmettre les appels de méthodes au
1950
+ contexte de classe. Toutefois, il ne se comporte pas à 100% comme le contexte
1951
+ de classe car vous n'avez pas le binding de la classe : seules les méthodes
1952
+ spécifiquement déclarées pour délégation sont disponibles et il n'est pas
1953
+ possible de partager des variables/états avec le contexte de classe
1954
+ (comprenez : +self+ n'est pas le même). Vous pouvez ajouter des délégation de
1955
+ méthodes en appelant <tt>Sinatra::Delegator.delegate :method_name</tt>.
1956
+
1957
+ Vous avez le binding du contexte de délégation dans :
1958
+
1959
+ * Le binding de haut niveau, si vous avez utilisé <tt>require "sinatra"</tt>
1960
+ * Un objet qui inclut le module +Sinatra::Delegator+
1961
+
1962
+ Jetez un oeil pour vous faire une idée : voici le
1963
+ {mixin Sinatra::Delegator}[https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/base.rb#L1609-1633]
1964
+ qui {étend l'objet principal}[https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/main.rb#L28-30].
1965
+
1966
+ == Ligne de commande
1967
+
1968
+ Les applications en Sinatra peuvent être lancées directement :
1969
+
1970
+ ruby mon_application.rb [-h] [-x] [-e ENVIRONNEMENT] [-p PORT] [-o HOTE] [-s SERVEUR]
1971
+
1972
+ Les options sont :
1973
+
1974
+ -h # aide
1975
+ -p # déclare le port (4567 par défaut)
1976
+ -o # déclare l'hôte (0.0.0.0 par défaut)
1977
+ -e # déclare l'environnement (+development+ par défaut)
1978
+ -s # déclare le serveur/gestionnaire à utiliser (thin par défaut)
1979
+ -x # active le mutex lock (off par défaut)
1980
+
1981
+ == Configuration nécessaire
1982
+
1983
+ Les versions suivantes de Ruby sont officiellement supportées :
1984
+
1985
+ [ Ruby 1.8.7 ]
1986
+ 1.8.7 est complètement supporté, toutefois si rien ne vous en empêche, nous
1987
+ vous recommandons de passer à 1.9.2 ou bien de passer à JRuby ou Rubinius. Le
1988
+ support de Ruby 1.8.7 ne sera pas supprimé avant la sortie de Sinatra 2.0 et
1989
+ de Ruby 2.0, à moins qu'un improbable Ruby 1.8.8 apparaisse. Et même dans ce
1990
+ cas, nous pourrions continuer à le supporter. <b>Ruby 1.8.6 n'est plus
1991
+ supporté.</b> Si vous souhaitez utiliser la version 1.8.6, vous devez revenir
1992
+ à Sinatra 1.2 qui continuera à recevoir des corrections de bugs tant que
1993
+ Sinatra 1.4.0 ne sera pas livré.
1994
+
1995
+ [ Ruby 1.9.2 ]
1996
+ 1.9.2 est totalement supporté et recommandé. N'utilisez pas 1.9.2p0 car il
1997
+ provoque des erreurs de segmentation à l'exécution de Sinatra. Son support
1998
+ continuera au minimum jusqu'à la sortie de Ruby 1.9.4/2.0 et le support de la
1999
+ dernière version 1.9 se poursuivra aussi longtemps que la core team de Ruby la
2000
+ supportera.
2001
+
2002
+ [ Ruby 1.9.3 ]
2003
+ 1.9.3 est totalement supporté et recommandé. Nous vous rappelons que passer à
2004
+ 1.9.3 depuis une version précédente annulera toutes les sessions.
2005
+
2006
+ [ Rubinius ]
2007
+ Rubinius est officiellement supporté (Rubinius >= 1.2.4), tout fonctionne,
2008
+ y compris tous les langages de template. La version 2.0 à venir est
2009
+ également supportée.
2010
+
2011
+ [ JRuby ]
2012
+ JRuby est officiellement supporté (JRuby >= 1.6.5). Aucune anomalie avec
2013
+ des bibliothèques de templates tierces ne sont connues. Toutefois, si vous
2014
+ choisissez JRuby, alors tournez vous vers des gestionnaires Rack JRuby car
2015
+ le serveur Thin n'est pas complètement supporté par JRuby. Le support des
2016
+ extensions C dans JRuby est encore expérimental, ce qui n'affecte que
2017
+ RDiscount, Redcarpet and RedCloth pour l'instant.
2018
+
2019
+ Nous gardons également un oeil sur les versions Ruby à venir.
2020
+
2021
+ Les implémentations Ruby suivantes ne sont pas officiellement supportées mais
2022
+ sont malgré tout connues pour permettre de faire fonctionner Sinatra :
2023
+
2024
+ * Versions plus anciennes de JRuby et Rubinius
2025
+ * Ruby Enterprise Edition
2026
+ * MacRuby, Maglev, IronRuby
2027
+ * Ruby 1.9.0 et 1.9.1 (mais nous déconseillons leur utilisation)
2028
+
2029
+ Le fait de ne pas être officiellement supporté signifie que si quelque chose
2030
+ ne fonctionne pas uniquement sur cette plateforme alors c'est un problème de la
2031
+ plateforme et pas un bug de Sinatra.
2032
+
2033
+ Nous lançons également notre intégration continue (CI) avec ruby-head (la
2034
+ future 2.0.0) et la branche 1.9.4, mais étant donné les évolutions continuelles,
2035
+ nous ne pouvont rien garantir, si ce n'est que les versions 1.9.4p0 et 2.0.0p0
2036
+ seront supportées.
2037
+
2038
+ Sinatra devrait fonctionner sur n'importe quel système d'exploitation
2039
+ supportant l'implémentation Ruby choisie.
2040
+
2041
+ Il n'est pas possible d'utiliser Sinatra sur Cardinal, SmallRuby, Blueuby ou
2042
+ toute version de Ruby antérieure à 1.8.7 à l'heure actuelle.
2043
+
2044
+ == Essuyer les plâtres
2045
+
2046
+ Si vous voulez utiliser la toute dernière version de Sinatra, n'ayez pas peur
2047
+ de faire tourner votre application sur la branche master, cela devrait être
2048
+ stable.
2049
+
2050
+ Nous publions également une gem de +prerelease+ de temps en temps que vous
2051
+ pouvez installer comme suit :
2052
+
2053
+ gem install sinatra --pre
2054
+
2055
+ afin d'avoir les toutes dernières fonctionnalités.
2056
+
2057
+ === Avec Bundler
2058
+
2059
+ Si vous voulez faire tourner votre application avec le tout dernier
2060
+ Sinatra, {Bundler}[http://gembundler.com/] est recommandé.
2061
+
2062
+ Tout d'abord, installer bundler si vous ne l'avez pas :
2063
+
2064
+ gem install bundler
2065
+
2066
+ Ensuite, dans le dossier de votre projet, créez un fichier +Gemfile+ :
2067
+
2068
+ source :rubygems
2069
+ gem 'sinatra', :git => "git://github.com/sinatra/sinatra.git"
2070
+
2071
+ # autres dépendances
2072
+ gem 'haml' # par exemple, si vous utilisez haml
2073
+ gem 'activerecord', '~> 3.0' # peut-être que vous avez également besoin
2074
+ # de ActiveRecord 3.x
2075
+
2076
+ Notez que vous aurez à lister toutes les dépendances de votre application dans
2077
+ ce fichier. Les dépendances directes de Sinatra (Rack et Tilt) seront
2078
+ automatiquement téléchargées et ajoutées par Bundler.
2079
+
2080
+ Maintenant, vous pouvez faire tourner votre application de la façon suivante :
2081
+
2082
+ bundle exec ruby myapp.rb
2083
+
2084
+ === Faites le vous-même
2085
+
2086
+ Créez un clone local et démarrez votre application avec le dossier
2087
+ <tt>sinatra/lib</tt> dans le <tt>$LOAD_PATH</tt> :
2088
+
2089
+ cd myapp
2090
+ git clone git://github.com/sinatra/sinatra.git
2091
+ ruby -Isinatra/lib myapp.rb
2092
+
2093
+ A l'avenir, pour mettre à jour le code source de Sinatra :
2094
+
2095
+ cd myapp/sinatra
2096
+ git pull
2097
+
2098
+ === Installez globalement
2099
+
2100
+ Vous pouvez construire la gem vous-même :
2101
+
2102
+ git clone git://github.com/sinatra/sinatra.git
2103
+ cd sinatra
2104
+ rake sinatra.gemspec
2105
+ rake install
2106
+
2107
+ Si vous installez les gems en tant que +root+, la dernière étape sera :
2108
+
2109
+ sudo rake install
2110
+
2111
+ == Versions
2112
+
2113
+ Sinatra se conforme aux {versions sémantiques}[http://semver.org/], aussi bien
2114
+ SemVer que SemVerTag.
2115
+
2116
+ == Mais encore
2117
+
2118
+ * {Site internet}[http://www.sinatrarb.com/] - Plus de documentation,
2119
+ de news, et des liens vers d'autres ressources.
2120
+ * {Contribuer}[http://www.sinatrarb.com/contributing] - Vous avez trouvé un
2121
+ bug ? Besoin d'aide ? Vous avez un patch ?
2122
+ * {Suivi des problèmes}[http://github.com/sinatra/sinatra/issues]
2123
+ * {Twitter}[http://twitter.com/sinatra]
2124
+ * {Mailing List}[http://groups.google.com/group/sinatrarb/topics]
2125
+ * {IRC : #sinatra}[irc://chat.freenode.net/#sinatra] sur http://freenode.net
2126
+ * {IRC : #sinatra}[irc://chat.freenode.net/#sinatra] on http://freenode.net
2127
+ * {Sinatra Book}[http://sinatra-book.gittr.com] Tutoriels et recettes
2128
+ * {Sinatra Recipes}[http://recipes.sinatrarb.com/] Recettes contribuées
2129
+ par la communauté
2130
+ * Documentation API de la {dernière version}[http://rubydoc.info/gems/sinatra]
2131
+ ou du {HEAD courant}[http://rubydoc.info/github/sinatra/sinatra] sur
2132
+ http://rubydoc.info
2133
+ * {CI server}[http://travis-ci.org/sinatra/sinatra]