sinatra-acd 1.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +5 -0
  3. data/AUTHORS +61 -0
  4. data/CHANGES +1293 -0
  5. data/Gemfile +76 -0
  6. data/LICENSE +23 -0
  7. data/README.de.md +2864 -0
  8. data/README.es.md +2786 -0
  9. data/README.fr.md +2924 -0
  10. data/README.hu.md +694 -0
  11. data/README.ja.md +2726 -0
  12. data/README.ko.md +2832 -0
  13. data/README.md +2980 -0
  14. data/README.pt-br.md +965 -0
  15. data/README.pt-pt.md +791 -0
  16. data/README.ru.md +2799 -0
  17. data/README.zh.md +2158 -0
  18. data/Rakefile +199 -0
  19. data/examples/chat.rb +61 -0
  20. data/examples/simple.rb +3 -0
  21. data/examples/stream.ru +26 -0
  22. data/lib/sinatra.rb +4 -0
  23. data/lib/sinatra/base.rb +2044 -0
  24. data/lib/sinatra/images/404.png +0 -0
  25. data/lib/sinatra/images/500.png +0 -0
  26. data/lib/sinatra/main.rb +34 -0
  27. data/lib/sinatra/show_exceptions.rb +345 -0
  28. data/lib/sinatra/version.rb +3 -0
  29. data/sinatra.gemspec +19 -0
  30. data/test/asciidoctor_test.rb +72 -0
  31. data/test/base_test.rb +171 -0
  32. data/test/builder_test.rb +91 -0
  33. data/test/coffee_test.rb +90 -0
  34. data/test/compile_test.rb +183 -0
  35. data/test/contest.rb +100 -0
  36. data/test/creole_test.rb +65 -0
  37. data/test/delegator_test.rb +160 -0
  38. data/test/encoding_test.rb +20 -0
  39. data/test/erb_test.rb +116 -0
  40. data/test/extensions_test.rb +98 -0
  41. data/test/filter_test.rb +487 -0
  42. data/test/haml_test.rb +109 -0
  43. data/test/helper.rb +131 -0
  44. data/test/helpers_test.rb +1917 -0
  45. data/test/integration/app.rb +79 -0
  46. data/test/integration_helper.rb +236 -0
  47. data/test/integration_test.rb +104 -0
  48. data/test/less_test.rb +69 -0
  49. data/test/liquid_test.rb +77 -0
  50. data/test/mapped_error_test.rb +285 -0
  51. data/test/markaby_test.rb +80 -0
  52. data/test/markdown_test.rb +82 -0
  53. data/test/mediawiki_test.rb +68 -0
  54. data/test/middleware_test.rb +68 -0
  55. data/test/nokogiri_test.rb +67 -0
  56. data/test/public/favicon.ico +0 -0
  57. data/test/rabl_test.rb +89 -0
  58. data/test/rack_test.rb +45 -0
  59. data/test/radius_test.rb +59 -0
  60. data/test/rdoc_test.rb +66 -0
  61. data/test/readme_test.rb +130 -0
  62. data/test/request_test.rb +97 -0
  63. data/test/response_test.rb +63 -0
  64. data/test/result_test.rb +76 -0
  65. data/test/route_added_hook_test.rb +59 -0
  66. data/test/routing_test.rb +1412 -0
  67. data/test/sass_test.rb +115 -0
  68. data/test/scss_test.rb +88 -0
  69. data/test/server_test.rb +48 -0
  70. data/test/settings_test.rb +582 -0
  71. data/test/sinatra_test.rb +12 -0
  72. data/test/slim_test.rb +102 -0
  73. data/test/static_test.rb +236 -0
  74. data/test/streaming_test.rb +149 -0
  75. data/test/stylus_test.rb +90 -0
  76. data/test/templates_test.rb +382 -0
  77. data/test/textile_test.rb +65 -0
  78. data/test/views/a/in_a.str +1 -0
  79. data/test/views/ascii.erb +2 -0
  80. data/test/views/b/in_b.str +1 -0
  81. data/test/views/calc.html.erb +1 -0
  82. data/test/views/error.builder +3 -0
  83. data/test/views/error.erb +3 -0
  84. data/test/views/error.haml +3 -0
  85. data/test/views/error.sass +2 -0
  86. data/test/views/explicitly_nested.str +1 -0
  87. data/test/views/foo/hello.test +1 -0
  88. data/test/views/hello.asciidoc +1 -0
  89. data/test/views/hello.builder +1 -0
  90. data/test/views/hello.coffee +1 -0
  91. data/test/views/hello.creole +1 -0
  92. data/test/views/hello.erb +1 -0
  93. data/test/views/hello.haml +1 -0
  94. data/test/views/hello.less +5 -0
  95. data/test/views/hello.liquid +1 -0
  96. data/test/views/hello.mab +1 -0
  97. data/test/views/hello.md +1 -0
  98. data/test/views/hello.mediawiki +1 -0
  99. data/test/views/hello.nokogiri +1 -0
  100. data/test/views/hello.rabl +2 -0
  101. data/test/views/hello.radius +1 -0
  102. data/test/views/hello.rdoc +1 -0
  103. data/test/views/hello.sass +2 -0
  104. data/test/views/hello.scss +3 -0
  105. data/test/views/hello.slim +1 -0
  106. data/test/views/hello.str +1 -0
  107. data/test/views/hello.styl +2 -0
  108. data/test/views/hello.test +1 -0
  109. data/test/views/hello.textile +1 -0
  110. data/test/views/hello.wlang +1 -0
  111. data/test/views/hello.yajl +1 -0
  112. data/test/views/layout2.builder +3 -0
  113. data/test/views/layout2.erb +2 -0
  114. data/test/views/layout2.haml +2 -0
  115. data/test/views/layout2.liquid +2 -0
  116. data/test/views/layout2.mab +2 -0
  117. data/test/views/layout2.nokogiri +3 -0
  118. data/test/views/layout2.rabl +3 -0
  119. data/test/views/layout2.radius +2 -0
  120. data/test/views/layout2.slim +3 -0
  121. data/test/views/layout2.str +2 -0
  122. data/test/views/layout2.test +1 -0
  123. data/test/views/layout2.wlang +2 -0
  124. data/test/views/nested.str +1 -0
  125. data/test/views/utf8.erb +2 -0
  126. data/test/wlang_test.rb +87 -0
  127. data/test/yajl_test.rb +86 -0
  128. metadata +280 -0
@@ -0,0 +1,2786 @@
1
+ # Sinatra
2
+
3
+ *Atención: Este documento es una traducción de la versión en inglés y puede estar desactualizado.*
4
+
5
+ Sinatra es un
6
+ [DSL](http://es.wikipedia.org/wiki/Lenguaje_específico_del_dominio) para
7
+ crear aplicaciones web rápidamente en Ruby con un mínimo esfuerzo:
8
+
9
+ ``` ruby
10
+ # miapp.rb
11
+ require 'sinatra'
12
+
13
+ get '/' do
14
+ 'Hola mundo!'
15
+ end
16
+ ```
17
+
18
+ Instalar la gema y correr la aplicación con:
19
+
20
+ ``` shell
21
+ gem install sinatra
22
+ ruby miapp.rb
23
+ ```
24
+
25
+ Ver en <http://localhost:4567>.
26
+
27
+ Se recomienda ejecutar `gem install thin`, porque Sinatra lo utilizará si está disponible.
28
+
29
+ ## Rutas
30
+
31
+ En Sinatra, una ruta es un método HTTP junto a un patrón de un URL.
32
+ Cada ruta está asociada a un bloque:
33
+
34
+ ``` ruby
35
+ get '/' do
36
+ .. mostrar algo ..
37
+ end
38
+
39
+ post '/' do
40
+ .. crear algo ..
41
+ end
42
+
43
+ put '/' do
44
+ .. reemplazar algo ..
45
+ end
46
+
47
+ patch '/' do
48
+ .. modificar algo ..
49
+ end
50
+
51
+ delete '/' do
52
+ .. aniquilar algo ..
53
+ end
54
+
55
+ options '/' do
56
+ .. informar algo ..
57
+ end
58
+
59
+ link '/' do
60
+ .. afiliar a algo ..
61
+ end
62
+
63
+ unlink '/' do
64
+ .. separar algo ..
65
+ end
66
+
67
+ ```
68
+
69
+ Las rutas son comparadas en el orden en el que son definidas. La primera ruta
70
+ que coincide con la petición es escogida.
71
+
72
+ Los patrones de las rutas pueden incluir parámetros nombrados, accesibles a
73
+ través del hash `params`:
74
+
75
+ ``` ruby
76
+ get '/hola/:nombre' do
77
+ # coincide con "GET /hola/foo" y "GET /hola/bar"
78
+ # params[:nombre] es 'foo' o 'bar'
79
+ "Hola #{params[:nombre]}!"
80
+ end
81
+ ```
82
+
83
+ También puede acceder a los parámetros nombrados usando parámetros de bloque:
84
+
85
+ ``` ruby
86
+ get '/hola/:nombre' do |n|
87
+ # coincide con "GET /hola/foo" y "GET /hola/bar"
88
+ # params[:nombre] es 'foo' o 'bar'
89
+ # n almacena params[:nombre]
90
+ "Hola #{n}!"
91
+ end
92
+ ```
93
+
94
+ Los patrones de ruta también pueden incluir parámetros splat (o wildcard),
95
+ accesibles a través del arreglo `params[:splat]`:
96
+
97
+ ``` ruby
98
+ get '/decir/*/al/*' do
99
+ # coincide con /decir/hola/al/mundo
100
+ params[:splat] # => ["hola", "mundo"]
101
+ end
102
+
103
+ get '/descargar/*.*' do
104
+ # coincide con /descargar/path/al/archivo.xml
105
+ params[:splat] # => ["path/al/archivo", "xml"]
106
+ end
107
+ ```
108
+
109
+ O, con parámetros de bloque:
110
+
111
+ ``` ruby
112
+ get '/descargar/*.*' do |path, ext|
113
+ [path, ext] # => ["path/al/archivo", "xml"]
114
+ end
115
+ ```
116
+
117
+ Rutas con Expresiones Regulares:
118
+
119
+ ``` ruby
120
+ get %r{/hola/([\w]+)} do
121
+ "Hola, #{params[:captures].first}!"
122
+ end
123
+ ```
124
+
125
+ O con un parámetro de bloque:
126
+
127
+ ``` ruby
128
+ get %r{/hola/([\w]+)} do |c|
129
+ "Hola, #{c}!"
130
+ end
131
+ ```
132
+
133
+ Los patrones de ruta pueden contener parámetros opcionales:
134
+
135
+ ``` ruby
136
+ get '/posts.?:formato?' do
137
+ # coincide con "GET /posts" y además admite cualquier extensión, por
138
+ # ejemplo, "GET /posts.json", "GET /posts.xml", etc.
139
+ end
140
+ ```
141
+
142
+ A propósito, a menos que desactives la protección para el ataque *path
143
+ traversal* (ver más abajo), el path de la petición puede ser modificado
144
+ antes de que se compare con los de tus rutas.
145
+
146
+ ## Condiciones
147
+
148
+ Las rutas pueden incluir una variedad de condiciones de selección, como por
149
+ ejemplo el user agent:
150
+
151
+ ``` ruby
152
+ get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
153
+ "Estás usando la versión de Songbird #{params[:agent][0]}"
154
+ end
155
+
156
+ get '/foo' do
157
+ # Coincide con navegadores que no sean songbird
158
+ end
159
+ ```
160
+
161
+ Otras condiciones disponibles son `host_name` y `provides`:
162
+
163
+ ``` ruby
164
+ get '/', :host_name => /^admin\./ do
165
+ "Área de Administración, Acceso denegado!"
166
+ end
167
+
168
+ get '/', :provides => 'html' do
169
+ haml :index
170
+ end
171
+
172
+ get '/', :provides => ['rss', 'atom', 'xml'] do
173
+ builder :feed
174
+ end
175
+ ```
176
+
177
+ Puede definir sus propias condiciones fácilmente:
178
+
179
+ ``` ruby
180
+ set(:probabilidad) { |valor| condition { rand <= valor } }
181
+
182
+ get '/gana_un_auto', :probabilidad => 0.1 do
183
+ "Ganaste!"
184
+ end
185
+
186
+ get '/gana_un_auto' do
187
+ "Lo siento, perdiste."
188
+ end
189
+ ```
190
+
191
+ Si su condición acepta más de un argumento, puede pasarle un arreglo. Al
192
+ definir la condición, se puede utilizar el operador splat en
193
+ la lista de parámetros:
194
+
195
+ ``` ruby
196
+ set(:autorizar) do |*roles| # <- mirá el splat
197
+ condition do
198
+ unless sesion_iniciada? && roles.any? {|rol| usuario_actual.tiene_rol? rol }
199
+ redirect "/iniciar_sesion/", 303
200
+ end
201
+ end
202
+ end
203
+
204
+ get "/mi/cuenta/", :autorizar => [:usuario, :administrador] do
205
+ "Detalles de mi cuenta"
206
+ end
207
+
208
+ get "/solo/administradores/", :autorizar => :administrador do
209
+ "Únicamente para administradores!"
210
+ end
211
+ ```
212
+
213
+ ### Valores de Retorno
214
+
215
+ El valor de retorno de un bloque de ruta que determina al menos el cuerpo de la
216
+ respuesta que se le pasa al cliente HTTP o al siguiente middleware en la pila
217
+ de Rack. Lo más común es que sea un string, como en los ejemplos anteriores.
218
+ Sin embargo, otros valores también son aceptados.
219
+
220
+ Puede devolver cualquier objeto que sea una respuesta Rack válida, un objeto
221
+ que represente el cuerpo de una respuesta Rack o un código de estado HTTP:
222
+
223
+ * Un arreglo con tres elementos: `[estado (Fixnum), cabeceras (Hash), cuerpo de
224
+ la respuesta (responde a #each)]`
225
+ * Un arreglo con dos elementos: `[estado (Fixnum), cuerpo de la respuesta
226
+ (responde a #each)]`
227
+ * Un objeto que responde a `#each` y que le pasa únicamente strings al bloque
228
+ dado
229
+ * Un Fixnum representando el código de estado
230
+
231
+ De esa manera, podemos fácilmente implementar un ejemplo de streaming:
232
+
233
+ ``` ruby
234
+ class Stream
235
+ def each
236
+ 100.times { |i| yield "#{i}\n" }
237
+ end
238
+ end
239
+
240
+ get('/') { Stream.new }
241
+ ```
242
+
243
+ ### Comparadores de Rutas Personalizados
244
+
245
+ Como se mostró anteriormente, Sinatra permite utilizar strings y expresiones
246
+ regulares para definir las rutas. Sin embargo, la cosa no termina ahí. Podés
247
+ definir tus propios comparadores muy fácilmente:
248
+
249
+ ``` ruby
250
+ class PatronCualquieraMenos
251
+ Match = Struct.new(:captures)
252
+
253
+ def initialize(excepto)
254
+ @excepto = excepto
255
+ @capturas = Match.new([])
256
+ end
257
+
258
+ def match(str)
259
+ @capturas unless @excepto === str
260
+ end
261
+ end
262
+
263
+ def cualquiera_menos(patron)
264
+ PatronCualquieraMenos.new(patron)
265
+ end
266
+
267
+ get cualquiera_menos("/index") do
268
+ # ...
269
+ end
270
+ ```
271
+
272
+ Tenga en cuenta que el ejemplo anterior es un poco rebuscado. Un resultado
273
+ similar puede conseguirse más sencillamente:
274
+
275
+ ``` ruby
276
+ get // do
277
+ pass if request.path_info == "/index"
278
+ # ...
279
+ end
280
+ ```
281
+
282
+ O, usando un lookahead negativo:
283
+
284
+ ``` ruby
285
+ get %r{^(?!/index$)} do
286
+ # ...
287
+ end
288
+ ```
289
+
290
+ ### Archivos Estáticos
291
+
292
+ Los archivos estáticos son servidos desde el directorio público
293
+ `./public`. Puede especificar una ubicación diferente ajustando la
294
+ opción `:public_folder`:
295
+
296
+ ``` ruby
297
+ set :public_folder, File.dirname(__FILE__) + '/estaticos'
298
+ ```
299
+
300
+ Note que el nombre del directorio público no está incluido en la URL. Por
301
+ ejemplo, el archivo `./public/css/style.css` se accede a través de
302
+ `http://ejemplo.com/css/style.css`.
303
+
304
+ Use la configuración `:static_cache_control` para agregar el encabezado
305
+ `Cache-Control` (ver la sección de configuración para más detalles).
306
+
307
+ ### Vistas / Plantillas
308
+
309
+ Cada lenguaje de plantilla se expone a través de un método de renderizado que
310
+ lleva su nombre. Estos métodos simplemente devuelven un string:
311
+
312
+ ``` ruby
313
+ get '/' do
314
+ erb :index
315
+ end
316
+ ```
317
+
318
+ Renderiza `views/index.erb`.
319
+
320
+ En lugar del nombre de la plantilla podés proporcionar directamente el
321
+ contenido de la misma:
322
+
323
+ ``` ruby
324
+ get '/' do
325
+ codigo = "<%= Time.now %>"
326
+ erb codigo
327
+ end
328
+ ```
329
+
330
+ Los métodos de renderizado, aceptan además un segundo argumento, el hash de
331
+ opciones:
332
+
333
+ ``` ruby
334
+ get '/' do
335
+ erb :index, :layout => :post
336
+ end
337
+ ```
338
+
339
+ Renderiza `views/index.erb` incrustado en `views/post.erb` (por
340
+ defecto, la plantilla `:index` es incrustada en `views/layout.erb` siempre y
341
+ cuando este último archivo exista).
342
+
343
+ Cualquier opción que Sinatra no entienda le será pasada al motor de renderizado
344
+ de la plantilla:
345
+
346
+ ``` ruby
347
+ get '/' do
348
+ haml :index, :format => :html5
349
+ end
350
+ ```
351
+
352
+ Además, puede definir las opciones para un lenguaje de plantillas de forma
353
+ general:
354
+
355
+ ``` ruby
356
+ set :haml, :format => :html5
357
+
358
+ get '/' do
359
+ haml :index
360
+ end
361
+ ```
362
+
363
+ Las opciones pasadas al método de renderizado tienen precedencia sobre las
364
+ definidas mediante `set`.
365
+
366
+ Opciones disponibles:
367
+
368
+ <dl>
369
+
370
+ <dt>locals</dt>
371
+ <dd>
372
+ Lista de variables locales pasadas al documento. Resultan muy útiles cuando
373
+ se combinan con parciales.
374
+ Ejemplo: <tt>erb "<%= foo %>", :locals => {:foo => "bar"}</tt>
375
+ </dd>
376
+
377
+ <dt>default_encoding</dt>
378
+ <dd>
379
+ Encoding utilizado cuando el de un string es dudoso. Por defecto toma el
380
+ valor de <tt>settings.default_encoding</tt>.
381
+ </dd>
382
+
383
+ <dt>views</dt>
384
+ <dd>
385
+ Directorio desde donde se cargan las vistas. Por defecto toma el valor de
386
+ <tt>settings.views</tt>.
387
+ </dd>
388
+
389
+ <dt>layout</dt>
390
+ <dd>
391
+ Si es <tt>true</tt> o <tt>false</tt> indica que se debe usar, o no, un layout,
392
+ respectivamente. También puede ser un símbolo que especifique qué plantilla
393
+ usar. Ejemplo: <tt>erb :index, :layout => !request.xhr?</tt>
394
+ </dd>
395
+
396
+ <dt>content_type</dt>
397
+ <dd>
398
+ Content-Type que produce la plantilla. El valor por defecto depende de cada
399
+ lenguaje de plantillas.
400
+ </dd>
401
+
402
+ <dt>scope</dt>
403
+ <dd>
404
+ Ámbito en el que se renderiza la plantilla. Por defecto utiliza la instancia
405
+ de la aplicación. Tené en cuenta que si cambiás esta opción las variables de
406
+ instancia y los helpers van a dejar de estar disponibles.
407
+ </dd>
408
+
409
+ <dt>layout_engine</dt>
410
+ <dd>
411
+ Motor de renderizado de plantillas que usa para el layout. Resulta
412
+ conveniente para lenguajes que no soportan layouts. Por defecto toma el valor
413
+ del motor usado para renderizar la plantilla.
414
+ Ejemplo: <tt>set :rdoc, :layout_engine => :erb</tt>
415
+ </dd>
416
+
417
+ <dd>
418
+ Se asume que las plantillas están ubicadas directamente bajo el directorio
419
+ <tt>./views</tt>. Para usar un directorio de vistas diferente:
420
+ <tt>set :views, settings.root + '/plantillas'</tt>
421
+ </dd>
422
+
423
+ <dd>
424
+ Es importante acordarse que siempre tenés que referenciar a las plantillas con
425
+ símbolos, incluso cuando se encuentran en un subdirectorio (en este caso
426
+ tenés que usar: `:'subdir/plantilla'` o `'subdir/plantilla'.to_sym`). Tenés que
427
+ usar un símbolo porque los métodos de renderización van a renderizar
428
+ directamente cualquier string que se les pase como argumento.
429
+ </dd>
430
+ </dl>
431
+
432
+ ### Lenguajes de Plantillas Disponibles
433
+
434
+ Algunos lenguajes tienen varias implementaciones. Para especificar que
435
+ implementación usar (y para ser thread-safe), deberías requerirla antes de
436
+ usarla:
437
+
438
+ ``` ruby
439
+ require 'rdiscount' # o require 'bluecloth'
440
+ get('/') { markdown :index }
441
+ ```
442
+
443
+ ### Plantillas Haml
444
+
445
+ <table>
446
+ <tr>
447
+ <td>Dependencias</td>
448
+ <td><a href="http://haml.info/" title="haml">haml</a></td>
449
+ </tr>
450
+ <tr>
451
+ <td>Expresiones de Archivo</td>
452
+ <td><tt>.haml</tt></td>
453
+ </tr>
454
+ <tr>
455
+ <td>Ejemplo</td>
456
+ <td><tt>haml :index, :format => :html5</tt></td>
457
+ </tr>
458
+ </table>
459
+
460
+ ### Plantillas Erb
461
+
462
+ <table>
463
+ <tr>
464
+ <td>Dependencias</td>
465
+ <td>
466
+ <a href="http://www.kuwata-lab.com/erubis/" title="erubis">erubis</a>
467
+ o erb (incluida en Ruby)
468
+ </td>
469
+ </tr>
470
+ <tr>
471
+ <td>Extensiones de Archivo</td>
472
+ <td><tt>.erb</tt>, <tt>.rhtml</tt> o <tt>.erubis</tt> (solamente con Erubis)</td>
473
+ </tr>
474
+ <tr>
475
+ <td>Ejemplo</td>
476
+ <td><tt>erb :index</tt></td>
477
+ </tr>
478
+ </table>
479
+
480
+ ### Plantillas Builder
481
+
482
+ <table>
483
+ <tr>
484
+ <td>Dependencias</td>
485
+ <td>
486
+ <a href="http://builder.rubyforge.org/" title="builder">builder</a>
487
+ </td>
488
+ </tr>
489
+ <tr>
490
+ <td>Extensiones de Archivo</td>
491
+ <td><tt>.builder</tt></td>
492
+ </tr>
493
+ <tr>
494
+ <td>Ejemplo</td>
495
+ <td><tt>builder { |xml| xml.em "hola" }</tt></td>
496
+ </tr>
497
+ </table>
498
+
499
+ Además, acepta un bloque con la definición de la plantilla (ver ejemplo).
500
+
501
+ ### Plantillas Nokogiri
502
+
503
+ <table>
504
+ <tr>
505
+ <td>Dependencias</td>
506
+ <td><a href="http://nokogiri.org/" title="nokogiri">nokogiri</a></td>
507
+ </tr>
508
+ <tr>
509
+ <td>Extensiones de Archivo</td>
510
+ <td><tt>.nokogiri</tt></td>
511
+ </tr>
512
+ <tr>
513
+ <td>Ejemplo</td>
514
+ <td><tt>nokogiri { |xml| xml.em "hola" }</tt></td>
515
+ </tr>
516
+ </table>
517
+
518
+ Además, acepta un bloque con la definición de la plantilla (ver ejemplo).
519
+
520
+ ### Plantillas Sass
521
+
522
+ <table>
523
+ <tr>
524
+ <td>Dependencias</td>
525
+ <td><a href="http://sass-lang.com/" title="sass">sass</a></td>
526
+ </tr>
527
+ <tr>
528
+ <td>Extensiones de Archivo</td>
529
+ <td><tt>.sass</tt></td>
530
+ </tr>
531
+ <tr>
532
+ <td>Ejemplo</td>
533
+ <td><tt>sass :stylesheet, :style => :expanded</tt></td>
534
+ </tr>
535
+ </table>
536
+
537
+ ### Plantillas SCSS
538
+
539
+ <table>
540
+ <tr>
541
+ <td>Dependencias</td>
542
+ <td><a href="http://sass-lang.com/" title="sass">sass</a></td>
543
+ </tr>
544
+ <tr>
545
+ <td>Extensiones de Archivo</td>
546
+ <td><tt>.scss</tt></td>
547
+ </tr>
548
+ <tr>
549
+ <td>Ejemplo</td>
550
+ <td><tt>scss :stylesheet, :style => :expanded</tt></td>
551
+ </tr>
552
+ </table>
553
+
554
+ ### Plantillas Less
555
+
556
+ <table>
557
+ <tr>
558
+ <td>Dependencias</td>
559
+ <td><a href="http://www.lesscss.org/" title="less">less</a></td>
560
+ </tr>
561
+ <tr>
562
+ <td>Extensiones de Archivo</td>
563
+ <td><tt>.less</tt></td>
564
+ </tr>
565
+ <tr>
566
+ <td>Ejemplo</td>
567
+ <td><tt>less :stylesheet</tt></td>
568
+ </tr>
569
+ </table>
570
+
571
+ ### Plantillas Liquid
572
+
573
+ <table>
574
+ <tr>
575
+ <td>Dependencias</td>
576
+ <td><a href="http://www.liquidmarkup.org/" title="liquid">liquid</a></td>
577
+ </tr>
578
+ <tr>
579
+ <td>Extensiones de Archivo</td>
580
+ <td><tt>.liquid</tt></td>
581
+ </tr>
582
+ <tr>
583
+ <td>Ejemplo</td>
584
+ <td><tt>liquid :index, :locals => { :clave => 'valor' }</tt></td>
585
+ </tr>
586
+ </table>
587
+
588
+ Como no va a poder llamar a métodos de Ruby (excepto por `yield`) desde una
589
+ plantilla Liquid, casi siempre va a querer pasarle locales.
590
+
591
+ ### Plantillas Markdown
592
+
593
+ <table>
594
+ <tr>
595
+ <td>Dependencias</td>
596
+ <td>
597
+ <a href="https://github.com/rtomayko/rdiscount" title="RDiscount">RDiscount</a>,
598
+ <a href="https://github.com/vmg/redcarpet" title="RedCarpet">RedCarpet</a>,
599
+ <a href="http://deveiate.org/projects/BlueCloth" title="BlueCloth">BlueCloth</a>,
600
+ <a href="http://kramdown.rubyforge.org/" title="kramdown">kramdown</a> o
601
+ <a href="http://maruku.rubyforge.org/" title="maruku">maruku</a>
602
+ </td>
603
+ </tr>
604
+ <tr>
605
+ <td>Extensiones de Archivo</td>
606
+ <td><tt>.markdown</tt>, <tt>.mkd</tt> y <tt>.md</tt></td>
607
+ </tr>
608
+ <tr>
609
+ <td>Ejemplo</td>
610
+ <td><tt>markdown :index, :layout_engine => :erb</tt></td>
611
+ </tr>
612
+ </table>
613
+
614
+ No es posible llamar métodos desde markdown, ni pasarle locales. Por lo tanto,
615
+ generalmente va a usarlo en combinación con otro motor de renderizado:
616
+
617
+ ``` ruby
618
+ erb :resumen, :locals => { :texto => markdown(:introduccion) }
619
+ ```
620
+
621
+ Tenga en cuenta que también podés llamar al método `markdown` desde otras
622
+ plantillas:
623
+
624
+ ``` ruby
625
+ %h1 Hola Desde Haml!
626
+ %p= markdown(:saludos)
627
+ ```
628
+
629
+ Como no puede utilizar Ruby desde Markdown, no puede usar layouts escritos en
630
+ Markdown. De todos modos, es posible usar un motor de renderizado para el
631
+ layout distinto al de la plantilla pasando la opción `:layout_engine`.
632
+
633
+ ### Plantillas Textile
634
+
635
+ <table>
636
+ <tr>
637
+ <td>Dependencias</td>
638
+ <td><a href="http://redcloth.org/" title="RedCloth">RedCloth</a></td>
639
+ </tr>
640
+ <tr>
641
+ <td>Extensiones de Archivo</td>
642
+ <td><tt>.textile</tt></td>
643
+ </tr>
644
+ <tr>
645
+ <td>Ejemplo</td>
646
+ <td><tt>textile :index, :layout_engine => :erb</tt></td>
647
+ </tr>
648
+ </table>
649
+
650
+ No es posible llamar métodos desde textile, ni pasarle locales. Por lo tanto,
651
+ generalmente vas a usarlo en combinación con otro motor de renderizado:
652
+
653
+ ``` ruby
654
+ erb :resumen, :locals => { :texto => textile(:introduccion) }
655
+ ```
656
+
657
+ Tené en cuenta que también podés llamar al método `textile` desde otras
658
+ plantillas:
659
+
660
+ ``` ruby
661
+ %h1 Hola Desde Haml!
662
+ %p= textile(:saludos)
663
+ ```
664
+
665
+ Como no podés utilizar Ruby desde Textile, no podés usar layouts escritos en
666
+ Textile. De todos modos, es posible usar un motor de renderizado para el
667
+ layout distinto al de la plantilla pasando la opción `:layout_engine`.
668
+
669
+ ### Plantillas RDoc
670
+
671
+ <table>
672
+ <tr>
673
+ <td>Dependencias</td>
674
+ <td><a href="http://rdoc.rubyforge.org/" title="RDoc">RDoc</a></td>
675
+ </tr>
676
+ <tr>
677
+ <td>Extensiones de Archivo</td>
678
+ <td><tt>.rdoc</tt></td>
679
+ </tr>
680
+ <tr>
681
+ <td>Ejemplo</td>
682
+ <td><tt>rdoc :README, :layout_engine => :erb</tt></td>
683
+ </tr>
684
+ </table>
685
+
686
+ No es posible llamar métodos desde rdoc, ni pasarle locales. Por lo tanto,
687
+ generalmente vas a usarlo en combinación con otro motor de renderizado:
688
+
689
+ ``` ruby
690
+ erb :resumen, :locals => { :texto => rdoc(:introduccion) }
691
+ ```
692
+
693
+ Tené en cuenta que también podés llamar al método `rdoc` desde otras
694
+ plantillas:
695
+
696
+ ``` ruby
697
+ %h1 Hola Desde Haml!
698
+ %p= rdoc(:saludos)
699
+ ```
700
+
701
+ Como no podés utilizar Ruby desde RDoc, no podés usar layouts escritos en RDoc.
702
+ De todos modos, es posible usar un motor de renderizado para el layout distinto
703
+ al de la plantilla pasando la opción `:layout_engine`.
704
+
705
+ ### Plantillas Radius
706
+
707
+ <table>
708
+ <tr>
709
+ <td>Dependencias</td>
710
+ <td><a href="http://radius.rubyforge.org/" title="Radius">Radius</a></td>
711
+ </tr>
712
+ <tr>
713
+ <td>Extensiones de Archivo</td>
714
+ <td><tt>.radius</tt></td>
715
+ </tr>
716
+ <tr>
717
+ <td>Ejemplo</td>
718
+ <td><tt>radius :index, :locals => { :clave => 'valor' }</tt></td>
719
+ </tr>
720
+ </table>
721
+
722
+ Desde que no se puede utilizar métodos de Ruby (excepto por `yield`) de una
723
+ plantilla Radius, casi siempre se necesita pasar locales.
724
+
725
+ ### Plantillas Markaby
726
+
727
+ <table>
728
+ <tr>
729
+ <td>Dependencias</td>
730
+ <td><a href="http://markaby.github.com/" title="Markaby">Markaby</a></td>
731
+ </tr>
732
+ <tr>
733
+ <td>Extensiones de Archivo</td>
734
+ <td><tt>.mab</tt></td>
735
+ </tr>
736
+ <tr>
737
+ <td>Ejemplo</td>
738
+ <td><tt>markaby { h1 "Bienvenido!" }</tt></td>
739
+ </tr>
740
+ </table>
741
+
742
+ Además, acepta un bloque con la definición de la plantilla (ver ejemplo).
743
+
744
+ ### Plantillas RABL
745
+
746
+ <table>
747
+ <tr>
748
+ <td>Dependencias</td>
749
+ <td><a href="https://github.com/nesquena/rabl" title="Rabl">Rabl</a></td>
750
+ </tr>
751
+ <tr>
752
+ <td>Extensiones de Archivo</td>
753
+ <td><tt>.rabl</tt></td>
754
+ </tr>
755
+ <tr>
756
+ <td>Ejemplo</td>
757
+ <td><tt>rabl :index</tt></td>
758
+ </tr>
759
+ </table>
760
+
761
+ ### Plantillas Slim
762
+
763
+ <table>
764
+ <tr>
765
+ <td>Dependencias</td>
766
+ <td><a href="http://slim-lang.com/" title="Slim Lang">Slim Lang</a></td>
767
+ </tr>
768
+ <tr>
769
+ <td>Extensiones de Archivo</td>
770
+ <td><tt>.slim</tt></td>
771
+ </tr>
772
+ <tr>
773
+ <td>Ejemplo</td>
774
+ <td><tt>slim :index</tt></td>
775
+ </tr>
776
+ </table>
777
+
778
+ ### Plantillas Creole
779
+
780
+ <table>
781
+ <tr>
782
+ <td>Dependencias</td>
783
+ <td><a href="https://github.com/minad/creole" title="Creole">Creole</a></td>
784
+ </tr>
785
+ <tr>
786
+ <td>Extensiones de Archivo</td>
787
+ <td><tt>.creole</tt></td>
788
+ </tr>
789
+ <tr>
790
+ <td>Ejemplo</td>
791
+ <td><tt>creole :wiki, :layout_engine => :erb</tt></td>
792
+ </tr>
793
+ </table>
794
+
795
+ No es posible llamar métodos desde creole, ni pasarle locales. Por lo tanto,
796
+ generalmente va a usarlo en combinación con otro motor de renderizado:
797
+
798
+ ``` ruby
799
+ erb :resumen, :locals => { :texto => cerole(:introduccion) }
800
+ ```
801
+
802
+ Debe tomar en cuenta que también puede llamar al método `creole` desde otras
803
+ plantillas:
804
+
805
+ ``` ruby
806
+ %h1 Hola Desde Haml!
807
+ %p= creole(:saludos)
808
+ ```
809
+
810
+ Como no podés utilizar Ruby desde Creole, no podés usar layouts escritos en
811
+ Creole. De todos modos, es posible usar un motor de renderizado para el layout
812
+ distinto al de la plantilla pasando la opción `:layout_engine`.
813
+
814
+ ### Plantillas CoffeeScript
815
+
816
+ <table>
817
+ <tr>
818
+ <td>Dependencias</td>
819
+ <td>
820
+ <a href="https://github.com/josh/ruby-coffee-script" title="Ruby CoffeeScript">
821
+ CoffeeScript
822
+ </a> y un
823
+ <a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
824
+ mecanismo para ejecutar javascript
825
+ </a>
826
+ </td>
827
+ </tr>
828
+ <tr>
829
+ <td>Extensiones de Archivo</td>
830
+ <td><tt>.coffee</tt></td>
831
+ </tr>
832
+ <tr>
833
+ <td>Ejemplo</td>
834
+ <td><tt>coffee :index</tt></td>
835
+ </tr>
836
+ </table>
837
+
838
+ ### Plantillas Stylus
839
+
840
+ <table>
841
+ <tr>
842
+ <td>Dependencias</td>
843
+ <td>
844
+ <a href="https://github.com/lucasmazza/ruby-stylus" title="Ruby Stylus">
845
+ Stylus
846
+ </a> y un
847
+ <a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
848
+ mecanismo para ejecutar javascript
849
+ </a>
850
+ </td>
851
+ </tr>
852
+ <tr>
853
+ <td>Extensiones de Archivo</td>
854
+ <td><tt>.styl</tt></td>
855
+ </tr>
856
+ <tr>
857
+ <td>Ejemplo</td>
858
+ <td><tt>stylus :index</tt></td>
859
+ </tr>
860
+ </table>
861
+
862
+ ### Plantillas Yajl
863
+
864
+ <table>
865
+ <tr>
866
+ <td>Dependencias</td>
867
+ <td><a href="https://github.com/brianmario/yajl-ruby" title="yajl-ruby">yajl-ruby</a></td>
868
+ </tr>
869
+ <tr>
870
+ <td>Extensiones de Archivo</td>
871
+ <td><tt>.yajl</tt></td>
872
+ </tr>
873
+ <tr>
874
+ <td>Ejemplo</td>
875
+ <td>
876
+ <tt>
877
+ yajl :index,
878
+ :locals => { :key => 'qux' },
879
+ :callback => 'present',
880
+ :variable => 'resource'
881
+ </tt>
882
+ </td>
883
+ </tr>
884
+ </table>
885
+
886
+ El contenido de La plantilla se evalúa como código Ruby, y la variable `json` es convertida a JSON mediante `#to_json`.
887
+
888
+ ``` ruby
889
+ json = { :foo => 'bar' }
890
+ json[:baz] = key
891
+ ```
892
+
893
+ Las opciones `:callback` y `:variable` se pueden utilizar para decorar el objeto renderizado:
894
+
895
+ ``` ruby
896
+ var resource = {"foo":"bar","baz":"qux"}; present(resource);
897
+ ```
898
+
899
+ ### Plantillas WLang
900
+
901
+ <table>
902
+ <tr>
903
+ <td>Dependencias</td>
904
+ <td><a href="https://github.com/blambeau/wlang/" title="wlang">wlang</a></td>
905
+ </tr>
906
+ <tr>
907
+ <td>Extensiones de Archivo</td>
908
+ <td><tt>.wlang</tt></td>
909
+ </tr>
910
+ <tr>
911
+ <td>Ejemplo</td>
912
+ <td><tt>wlang :index, :locals => { :clave => 'valor' }</tt></td>
913
+ </tr>
914
+ </table>
915
+
916
+ Como no vas a poder llamar a métodos de Ruby (excepto por `yield`) desde una
917
+ plantilla WLang, casi siempre vas a querer pasarle locales.
918
+
919
+ ### Plantillas Embebidas
920
+
921
+ ``` ruby
922
+ get '/' do
923
+ haml '%div.titulo Hola Mundo'
924
+ end
925
+ ```
926
+
927
+ Renderiza el template embebido en el string.
928
+
929
+ ### Accediendo a Variables en Plantillas
930
+
931
+ Las plantillas son evaluadas dentro del mismo contexto que los manejadores de
932
+ ruta. Las variables de instancia asignadas en los manejadores de ruta son
933
+ accesibles directamente por las plantillas:
934
+
935
+ ``` ruby
936
+ get '/:id' do
937
+ @foo = Foo.find(params[:id])
938
+ haml '%h1= @foo.nombre'
939
+ end
940
+ ```
941
+
942
+ O es posible especificar un Hash de variables locales explícitamente:
943
+
944
+ ``` ruby
945
+ get '/:id' do
946
+ foo = Foo.find(params[:id])
947
+ haml '%h1= bar.nombre', :locals => { :bar => foo }
948
+ end
949
+ ```
950
+
951
+ Esto es usado típicamente cuando se renderizan plantillas como parciales desde
952
+ adentro de otras plantillas.
953
+
954
+ ### Plantillas Inline
955
+
956
+ Las plantillas pueden ser definidas al final del archivo fuente:
957
+
958
+ ``` ruby
959
+ require 'rubygems'
960
+ require 'sinatra'
961
+
962
+ get '/' do
963
+ haml :index
964
+ end
965
+
966
+ __END__
967
+
968
+ @@ layout
969
+ %html
970
+ = yield
971
+
972
+ @@ index
973
+ %div.titulo Hola mundo!!!!!
974
+ ```
975
+
976
+ NOTA: únicamente las plantillas inline definidas en el archivo fuente que
977
+ requiere Sinatra son cargadas automáticamente. Llamá `enable
978
+ :inline_templates` explícitamente si tenés plantillas inline en otros
979
+ archivos fuente.
980
+
981
+ ### Plantillas Nombradas
982
+
983
+ Las plantillas también pueden ser definidas usando el método top-level
984
+ `template`:
985
+
986
+ ``` ruby
987
+ template :layout do
988
+ "%html\n =yield\n"
989
+ end
990
+
991
+ template :index do
992
+ '%div.titulo Hola Mundo!'
993
+ end
994
+
995
+ get '/' do
996
+ haml :index
997
+ end
998
+ ```
999
+
1000
+ Si existe una plantilla con el nombre "layout", va a ser usada cada vez que
1001
+ una plantilla es renderizada. Podés desactivar los layouts individualmente
1002
+ pasando `:layout => false` o globalmente con
1003
+ `set :haml, :layout => false`:
1004
+
1005
+ ``` ruby
1006
+ get '/' do
1007
+ haml :index, :layout => !request.xhr?
1008
+ end
1009
+ ```
1010
+
1011
+ ### Asociando Extensiones de Archivo
1012
+
1013
+ Para asociar una extensión de archivo con un motor de renderizado, usá
1014
+ `Tilt.register`. Por ejemplo, si querés usar la extensión `tt` para
1015
+ las plantillas Textile, podés hacer lo siguiente:
1016
+
1017
+ ``` ruby
1018
+ Tilt.register :tt, Tilt[:textile]
1019
+ ```
1020
+
1021
+ ### Agregando Tu Propio Motor de Renderizado
1022
+
1023
+ Primero, registrá tu motor con Tilt, y después, creá tu método de renderizado:
1024
+
1025
+ ``` ruby
1026
+ Tilt.register :mipg, MiMotorParaPlantillaGenial
1027
+
1028
+ helpers do
1029
+ def mypg(*args) render(:mypg, *args) end
1030
+ end
1031
+
1032
+ get '/' do
1033
+ mypg :index
1034
+ end
1035
+ ```
1036
+
1037
+ Renderiza `./views/index.mypg`. Mirá https://github.com/rtomayko/tilt
1038
+ para aprender más de Tilt.
1039
+
1040
+ ## Filtros
1041
+
1042
+ Los filtros `before` son evaluados antes de cada petición dentro del mismo
1043
+ contexto que las rutas. Pueden modificar la petición y la respuesta. Las
1044
+ variables de instancia asignadas en los filtros son accesibles por las rutas y
1045
+ las plantillas:
1046
+
1047
+ ``` ruby
1048
+ before do
1049
+ @nota = 'Hey!'
1050
+ request.path_info = '/foo/bar/baz'
1051
+ end
1052
+
1053
+ get '/foo/*' do
1054
+ @nota #=> 'Hey!'
1055
+ params[:splat] #=> 'bar/baz'
1056
+ end
1057
+ ```
1058
+
1059
+ Los filtros `after` son evaluados después de cada petición dentro del mismo
1060
+ contexto y también pueden modificar la petición y la respuesta. Las variables
1061
+ de instancia asignadas en los filtros `before` y en las rutas son accesibles por
1062
+ los filtros `after`:
1063
+
1064
+ ``` ruby
1065
+ after do
1066
+ puts response.status
1067
+ end
1068
+ ```
1069
+
1070
+ Nota: A menos que uses el método `body` en lugar de simplemente devolver un
1071
+ string desde una ruta, el cuerpo de la respuesta no va a estar disponible en
1072
+ un filtro after, debido a que todavía no se ha generado.
1073
+
1074
+ Los filtros aceptan un patrón opcional, que cuando está presente causa que los
1075
+ mismos sean evaluados únicamente si el path de la petición coincide con ese
1076
+ patrón:
1077
+
1078
+ ``` ruby
1079
+ before '/protegido/*' do
1080
+ autenticar!
1081
+ end
1082
+
1083
+ after '/crear/:slug' do |slug|
1084
+ session[:ultimo_slug] = slug
1085
+ end
1086
+ ```
1087
+
1088
+ Al igual que las rutas, los filtros también pueden aceptar condiciones:
1089
+
1090
+ ``` ruby
1091
+ before :agent => /Songbird/ do
1092
+ # ...
1093
+ end
1094
+
1095
+ after '/blog/*', :host_name => 'ejemplo.com' do
1096
+ # ...
1097
+ end
1098
+ ```
1099
+
1100
+ ## Ayudantes
1101
+
1102
+ Usá el método top-level *helpers* para definir métodos ayudantes que
1103
+ pueden ser utilizados dentro de los manejadores de rutas y las plantillas:
1104
+
1105
+ ``` ruby
1106
+ helpers do
1107
+ def bar(nombre)
1108
+ "#{nombre}bar"
1109
+ end
1110
+ end
1111
+
1112
+ get '/:nombre' do
1113
+ bar(params[:nombre])
1114
+ end
1115
+ ```
1116
+
1117
+ Por cuestiones organizativas, puede resultar conveniente organizar los métodos
1118
+ ayudantes en distintos módulos:
1119
+
1120
+ ``` ruby
1121
+ module FooUtils
1122
+ def foo(nombre) "#{nombre}foo" end
1123
+ end
1124
+
1125
+ module BarUtils
1126
+ def bar(nombre) "#{nombre}bar" end
1127
+ end
1128
+
1129
+ helpers FooUtils, BarUtils
1130
+ ```
1131
+
1132
+ El efecto de utilizar *helpers* de esta manera es el mismo que resulta de
1133
+ incluir los módulos en la clase de la aplicación.
1134
+
1135
+ ### Usando Sesiones
1136
+
1137
+ Una sesión es usada para mantener el estado a través de distintas peticiones.
1138
+ Cuando están activadas, proporciona un hash de sesión para cada sesión de usuario:
1139
+
1140
+ ``` ruby
1141
+ enable :sessions
1142
+
1143
+ get '/' do
1144
+ "valor = " << session[:valor].inspect
1145
+ end
1146
+
1147
+ get '/:valor' do
1148
+ session[:valor] = params[:valor]
1149
+ end
1150
+ ```
1151
+
1152
+ Tené en cuenta que `enable :sessions` guarda todos los datos en una
1153
+ cookie, lo cual no es siempre deseable (guardar muchos datos va a incrementar
1154
+ el tráfico, por citar un ejemplo). Podés usar cualquier middleware Rack para
1155
+ manejar sesiones, de la misma manera que usarías cualquier otro middleware,
1156
+ pero con la salvedad de que *no* tenés que llamar a `enable :sessions`:
1157
+
1158
+ ``` ruby
1159
+ use Rack::Session::Pool, :expire_after => 2592000
1160
+
1161
+ get '/' do
1162
+ "valor = " << session[:valor].inspect
1163
+ end
1164
+
1165
+ get '/:valor' do
1166
+ session[:valor] = params[:valor]
1167
+ end
1168
+ ```
1169
+
1170
+ Para incrementar la seguridad, los datos de la sesión almacenados en
1171
+ la cookie son firmados con un secreto de sesión. Este secreto, es
1172
+ generado aleatoriamente por Sinatra. De cualquier manera, hay que
1173
+ tener en cuenta que cada vez que inicies la aplicación se va a generar
1174
+ uno nuevo. Así, si querés que todas las instancias de tu aplicación
1175
+ compartan un único secreto, tenés que definirlo vos:
1176
+
1177
+ ``` ruby
1178
+ set :session_secret, 'super secreto'
1179
+ ```
1180
+
1181
+ Si necesitás una configuración más específica, `sessions` acepta un
1182
+ Hash con opciones:
1183
+
1184
+ ``` ruby
1185
+ set :sessions, :domain => 'foo.com'
1186
+ ```
1187
+
1188
+ ### Interrupción
1189
+
1190
+ Para detener inmediatamente una petición dentro de un filtro o una ruta usá:
1191
+
1192
+ ``` ruby
1193
+ halt
1194
+ ```
1195
+
1196
+ También podés especificar el estado:
1197
+
1198
+ ``` ruby
1199
+ halt 410
1200
+ ```
1201
+
1202
+ O el cuerpo:
1203
+
1204
+ ``` ruby
1205
+ halt 'esto va a ser el cuerpo'
1206
+ ```
1207
+
1208
+ O los dos:
1209
+
1210
+ ``` ruby
1211
+ halt 401, 'salí de acá!'
1212
+ ```
1213
+
1214
+ Con cabeceras:
1215
+
1216
+ ``` ruby
1217
+ halt 402, { 'Content-Type' => 'text/plain' }, 'venganza'
1218
+ ```
1219
+
1220
+ Obviamente, es posible utilizar `halt` con una plantilla:
1221
+
1222
+ ``` ruby
1223
+ halt erb(:error)
1224
+ ```
1225
+
1226
+ ### Paso
1227
+
1228
+ Una ruta puede pasarle el procesamiento a la siguiente ruta que coincida con
1229
+ la petición usando `pass`:
1230
+
1231
+ ``` ruby
1232
+ get '/adivina/:quien' do
1233
+ pass unless params[:quien] == 'Franco'
1234
+ 'Adivinaste!'
1235
+ end
1236
+
1237
+ get '/adivina/*' do
1238
+ 'Erraste!'
1239
+ end
1240
+ ```
1241
+
1242
+ Se sale inmediatamente del bloque de la ruta y se le pasa el control a la
1243
+ siguiente ruta que coincida. Si no coincide ninguna ruta, se devuelve 404.
1244
+
1245
+ ### Ejecutando Otra Ruta
1246
+
1247
+ Cuando querés obtener el resultado de la llamada a una ruta, `pass` no te va a
1248
+ servir. Para lograr esto, podés usar `call`:
1249
+
1250
+ ``` ruby
1251
+ get '/foo' do
1252
+ status, headers, body = call env.merge("PATH_INFO" => '/bar')
1253
+ [status, headers, body.map(&:upcase)]
1254
+ end
1255
+
1256
+ get '/bar' do
1257
+ "bar"
1258
+ end
1259
+ ```
1260
+
1261
+ Notá que en el ejemplo anterior, es conveniente mover `"bar"` a un
1262
+ helper, y llamarlo desde `/foo` y `/bar`. Así, vas a simplificar
1263
+ las pruebas y a mejorar el rendimiento.
1264
+
1265
+ Si querés que la petición se envíe a la misma instancia de la aplicación en
1266
+ lugar de otra, usá `call!` en lugar de `call`.
1267
+
1268
+ En la especificación de Rack podés encontrar más información sobre
1269
+ `call`.
1270
+
1271
+ ### Asignando el Código de Estado, los Encabezados y el Cuerpo de una Respuesta
1272
+
1273
+ Es posible, y se recomienda, asignar el código de estado y el cuerpo de una
1274
+ respuesta con el valor de retorno de una ruta. De cualquier manera, en varios
1275
+ escenarios, puede que sea conveniente asignar el cuerpo en un punto arbitrario
1276
+ del flujo de ejecución con el método `body`. A partir de ahí, podés usar ese
1277
+ mismo método para acceder al cuerpo de la respuesta:
1278
+
1279
+ ``` ruby
1280
+ get '/foo' do
1281
+ body "bar"
1282
+ end
1283
+
1284
+ after do
1285
+ puts body
1286
+ end
1287
+ ```
1288
+
1289
+ También es posible pasarle un bloque a `body`, que será ejecutado por el Rack
1290
+ handler (podés usar esto para implementar streaming, mirá "Valores de retorno").
1291
+
1292
+ De manera similar, también podés asignar el código de estado y encabezados:
1293
+
1294
+ ``` ruby
1295
+ get '/foo' do
1296
+ status 418
1297
+ headers \
1298
+ "Allow" => "BREW, POST, GET, PROPFIND, WHEN",
1299
+ "Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
1300
+ body "I'm a tea pot!"
1301
+ end
1302
+ ```
1303
+
1304
+ También, al igual que `body`, tanto `status` como `headers` pueden utilizarse
1305
+ para obtener sus valores cuando no se les pasa argumentos.
1306
+
1307
+ ### Streaming De Respuestas
1308
+
1309
+ A veces vas a querer empezar a enviar la respuesta a pesar de que todavía no
1310
+ terminaste de generar su cuerpo. También es posible que, en algunos casos,
1311
+ quieras seguir enviando información hasta que el cliente cierre la conexión.
1312
+ Cuando esto ocurra, el helper `stream` te va a ser de gran ayuda:
1313
+
1314
+ ``` ruby
1315
+ get '/' do
1316
+ stream do |out|
1317
+ out << "Esto va a ser legen -\n"
1318
+ sleep 0.5
1319
+ out << " (esperalo) \n"
1320
+ sleep 1
1321
+ out << "- dario!\n"
1322
+ end
1323
+ end
1324
+ ```
1325
+
1326
+ Podés implementar APIs de streaming,
1327
+ [Server-Sent Events](http://dev.w3.org/html5/eventsource/) y puede ser usado
1328
+ como base para [WebSockets](http://es.wikipedia.org/wiki/WebSockets). También
1329
+ puede ser usado para incrementar el throughput si solo una parte del contenido
1330
+ depende de un recurso lento.
1331
+
1332
+ Hay que tener en cuenta que el comportamiento del streaming, especialmente el
1333
+ número de peticiones concurrentes, depende del servidor web utilizado para
1334
+ alojar la aplicación. Puede que algunos servidores, como es el caso de
1335
+ WEBRick, no soporten streaming directamente, así el cuerpo de la respuesta será
1336
+ enviado completamente de una vez cuando el bloque pasado a `stream` finalice su
1337
+ ejecución. Si estás usando Shotgun, el streaming no va a funcionar.
1338
+
1339
+ Cuando se pasa `keep_open` como parámetro, no se va a enviar el mensaje
1340
+ `close` al objeto de stream. Queda en vos cerrarlo en el punto de ejecución
1341
+ que quieras. Nuevamente, hay que tener en cuenta que este comportamiento es
1342
+ posible solo en servidores que soporten eventos, como Thin o Rainbows. El
1343
+ resto de los servidores van a cerrar el stream de todos modos:
1344
+
1345
+ ``` ruby
1346
+ set :server, :thin
1347
+ conexiones = []
1348
+
1349
+ get '/' do
1350
+ # mantenemos abierto el stream
1351
+ stream(:keep_open) { |salida| conexiones << salida }
1352
+ end
1353
+
1354
+ post '/' do
1355
+ # escribimos a todos los streams abiertos
1356
+ conexiones.each { |salida| salida << params[:mensaje] << "\n" }
1357
+ "mensaje enviado"
1358
+ end
1359
+ ```
1360
+
1361
+ ### Log (Registro)
1362
+
1363
+ En el ámbito de la petición, el helper `logger` (registrador) expone
1364
+ una instancia de `Logger`:
1365
+
1366
+ ``` ruby
1367
+ get '/' do
1368
+ logger.info "cargando datos"
1369
+ # ...
1370
+ end
1371
+ ```
1372
+
1373
+ Este logger tiene en cuenta la configuración de logueo de tu Rack
1374
+ handler. Si el logueo está desactivado, este método va a devolver un
1375
+ objeto que se comporta como un logger pero que en realidad no hace
1376
+ nada. Así, no vas a tener que preocuparte por esta situación.
1377
+
1378
+ Tené en cuenta que el logueo está habilitado por defecto únicamente
1379
+ para `Sinatra::Application`. Si heredaste de
1380
+ `Sinatra::Base`, probablemente quieras habilitarlo manualmente:
1381
+
1382
+ ``` ruby
1383
+ class MiApp < Sinatra::Base
1384
+ configure :production, :development do
1385
+ enable :logging
1386
+ end
1387
+ end
1388
+ ```
1389
+
1390
+ Para evitar que se inicialice cualquier middleware de logging, configurá
1391
+ `logging` a `nil`. Tené en cuenta que, cuando hagas esto, `logger` va a
1392
+ devolver `nil`. Un caso común es cuando querés usar tu propio logger. Sinatra
1393
+ va a usar lo que encuentre en `env['rack.logger']`.
1394
+
1395
+ ### Tipos Mime
1396
+
1397
+ Cuando usás `send_file` o archivos estáticos tal vez tengas tipos mime
1398
+ que Sinatra no entiende. Usá `mime_type` para registrarlos a través de la
1399
+ extensión de archivo:
1400
+
1401
+ ``` ruby
1402
+ configure do
1403
+ mime_type :foo, 'text/foo'
1404
+ end
1405
+ ```
1406
+
1407
+ También lo podés usar con el ayudante `content_type`:
1408
+
1409
+ ``` ruby
1410
+ get '/' do
1411
+ content_type :foo
1412
+ "foo foo foo"
1413
+ end
1414
+ ```
1415
+
1416
+ ### Generando URLs
1417
+
1418
+ Para generar URLs deberías usar el método `url`. Por ejemplo, en Haml:
1419
+
1420
+ ``` ruby
1421
+ %a{:href => url('/foo')} foo
1422
+ ```
1423
+
1424
+ Tiene en cuenta proxies inversos y encaminadores de Rack, si están presentes.
1425
+
1426
+ Este método también puede invocarse mediante su alias `to` (mirá un ejemplo
1427
+ a continuación).
1428
+
1429
+ ### Redirección del Navegador
1430
+
1431
+ Podés redireccionar al navegador con el método `redirect`:
1432
+
1433
+ ``` ruby
1434
+ get '/foo' do
1435
+ redirect to('/bar')
1436
+ end
1437
+ ```
1438
+
1439
+ Cualquier parámetro adicional se utiliza de la misma manera que los argumentos
1440
+ pasados a `halt`:
1441
+
1442
+ ``` ruby
1443
+ redirect to('/bar'), 303
1444
+ redirect 'http://google.com', 'te confundiste de lugar, compañero'
1445
+ ```
1446
+
1447
+ También podés redireccionar fácilmente de vuelta hacia la página desde donde
1448
+ vino el usuario con `redirect back`:
1449
+
1450
+ ``` ruby
1451
+ get '/foo' do
1452
+ "<a href='/bar'>hacer algo</a>"
1453
+ end
1454
+
1455
+ get '/bar' do
1456
+ hacer_algo
1457
+ redirect back
1458
+ end
1459
+ ```
1460
+
1461
+ Para pasar argumentos con una redirección, podés agregarlos a la cadena de
1462
+ búsqueda:
1463
+
1464
+ ``` ruby
1465
+ redirect to('/bar?suma=42')
1466
+ ```
1467
+
1468
+ O usar una sesión:
1469
+
1470
+ ``` ruby
1471
+ enable :sessions
1472
+
1473
+ get '/foo' do
1474
+ session[:secreto] = 'foo'
1475
+ redirect to('/bar')
1476
+ end
1477
+
1478
+ get '/bar' do
1479
+ session[:secreto]
1480
+ end
1481
+ ```
1482
+
1483
+ ### Cache Control
1484
+
1485
+ Asignar tus encabezados correctamente es el cimiento para realizar un cacheo
1486
+ HTTP correcto.
1487
+
1488
+ Podés asignar el encabezado Cache-Control fácilmente:
1489
+
1490
+ ``` ruby
1491
+ get '/' do
1492
+ cache_control :public
1493
+ "cachealo!"
1494
+ end
1495
+ ```
1496
+
1497
+ Pro tip: configurar el cacheo en un filtro `before`:
1498
+
1499
+ ``` ruby
1500
+ before do
1501
+ cache_control :public, :must_revalidate, :max_age => 60
1502
+ end
1503
+ ```
1504
+
1505
+ Si estás usando el helper `expires` para definir el encabezado correspondiente,
1506
+ `Cache-Control` se va a definir automáticamente:
1507
+
1508
+ ``` ruby
1509
+ before do
1510
+ expires 500, :public, :must_revalidate
1511
+ end
1512
+ ```
1513
+
1514
+ Para usar cachés adecuadamente, deberías considerar usar `etag` o
1515
+ `last_modified`. Es recomendable que llames a estos asistentes *antes* de hacer
1516
+ cualquier trabajo pesado, ya que van a enviar la respuesta inmediatamente si
1517
+ el cliente ya tiene la versión actual en su caché:
1518
+
1519
+ ``` ruby
1520
+ get '/articulo/:id' do
1521
+ @articulo = Articulo.find params[:id]
1522
+ last_modified @articulo.updated_at
1523
+ etag @articulo.sha1
1524
+ erb :articulo
1525
+ end
1526
+ ```
1527
+
1528
+ También es posible usar una
1529
+ [weak ETag](http://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation):
1530
+
1531
+ ``` ruby
1532
+ etag @articulo.sha1, :weak
1533
+ ```
1534
+
1535
+ Estos helpers no van a cachear nada por vos, sino que van a facilitar la
1536
+ información necesaria para poder hacerlo. Si estás buscando soluciones rápidas
1537
+ de cacheo con proxys reversos, mirá
1538
+ [rack-cache](https://github.com/rtomayko/rack-cache):
1539
+
1540
+ ``` ruby
1541
+ require "rack/cache"
1542
+ require "sinatra"
1543
+
1544
+ use Rack::Cache
1545
+
1546
+ get '/' do
1547
+ cache_control :public, :max_age => 36000
1548
+ sleep 5
1549
+ "hola"
1550
+ end
1551
+ ```
1552
+
1553
+ Usá la configuración `:static_cache_control` para agregar el encabezado
1554
+ `Cache-Control` a archivos estáticos (ver la sección de configuración
1555
+ para más detalles).
1556
+
1557
+ De acuerdo con la RFC 2616 tu aplicación debería comportarse diferente si a las
1558
+ cabeceras If-Match o If-None-Match se le asigna el valor `*` cuando el
1559
+ recurso solicitado ya existe. Sinatra asume para peticiones seguras (como get)
1560
+ y potentes (como put) que el recurso existe, mientras que para el resto
1561
+ (como post) asume que no. Podés cambiar este comportamiento con la opción
1562
+ `:new_resource`:
1563
+
1564
+ ``` ruby
1565
+ get '/crear' do
1566
+ etag '', :new_resource => true
1567
+ Articulo.create
1568
+ erb :nuevo_articulo
1569
+ end
1570
+ ```
1571
+
1572
+ Si querés seguir usando una weak ETag, indicalo con la opción `:kind`:
1573
+
1574
+ ``` ruby
1575
+ etag '', :new_resource => true, :kind => :weak
1576
+ ```
1577
+
1578
+ ### Enviando Archivos
1579
+
1580
+ Para enviar archivos, podés usar el método `send_file`:
1581
+
1582
+ ``` ruby
1583
+ get '/' do
1584
+ send_file 'foo.png'
1585
+ end
1586
+ ```
1587
+
1588
+ Además acepta un par de opciones:
1589
+
1590
+ ``` ruby
1591
+ send_file 'foo.png', :type => :jpg
1592
+ ```
1593
+
1594
+ Estas opciones son:
1595
+
1596
+ [filename]
1597
+ nombre del archivo devuelto, por defecto es el nombre real del archivo.
1598
+
1599
+ [last_modified]
1600
+ valor para el encabezado Last-Modified, por defecto toma el mtime del archivo.
1601
+
1602
+ [type]
1603
+ el content type que se va a utilizar, si no está presente se intenta adivinar
1604
+ a partir de la extensión del archivo.
1605
+
1606
+ [disposition]
1607
+ se utiliza para el encabezado Content-Disposition, y puede tomar alguno de los
1608
+ siguientes valores: `nil` (por defecto), `:attachment` e
1609
+ `:inline`
1610
+
1611
+ [length]
1612
+ encabezado Content-Length, por defecto toma el tamaño del archivo.
1613
+
1614
+ [status]
1615
+ código de estado devuelto. Resulta útil al enviar un archivo estático como una
1616
+ página de error.
1617
+
1618
+ Si el Rack handler lo soporta, se intentará no transmitir directamente desde el
1619
+ proceso de Ruby. Si usás este método, Sinatra se va a encargar automáticamente de las
1620
+ peticiones de rango.
1621
+
1622
+ ### Accediendo al objeto de la petición
1623
+
1624
+ El objeto de la petición entrante puede ser accedido desde el nivel de la
1625
+ petición (filtros, rutas y manejadores de errores) a través del método
1626
+ `request`:
1627
+
1628
+ ``` ruby
1629
+ # app corriendo en http://ejemplo.com/ejemplo
1630
+ get '/foo' do
1631
+ t = %w[text/css text/html application/javascript]
1632
+ request.accept # ['text/html', '*/*']
1633
+ request.accept? 'text/xml' # true
1634
+ request.preferred_type(t) # 'text/html'
1635
+ request.body # cuerpo de la petición enviado por el cliente (ver más abajo)
1636
+ request.scheme # "http"
1637
+ request.script_name # "/ejemplo"
1638
+ request.path_info # "/foo"
1639
+ request.port # 80
1640
+ request.request_method # "GET"
1641
+ request.query_string # ""
1642
+ request.content_length # longitud de request.body
1643
+ request.media_type # tipo de medio de request.body
1644
+ request.host # "ejemplo.com"
1645
+ request.get? # true (hay métodos análogos para los otros verbos)
1646
+ request.form_data? # false
1647
+ request["UNA_CABECERA"] # valor de la cabecera UNA_CABECERA
1648
+ request.referrer # la referencia del cliente o '/'
1649
+ request.user_agent # user agent (usado por la condición :agent)
1650
+ request.cookies # hash de las cookies del navegador
1651
+ request.xhr? # es una petición ajax?
1652
+ request.url # "http://ejemplo.com/ejemplo/foo"
1653
+ request.path # "/ejemplo/foo"
1654
+ request.ip # dirección IP del cliente
1655
+ request.secure? # false (sería true sobre ssl)
1656
+ request.forwarded? # true (si se está corriendo atrás de un proxy reverso)
1657
+ requuest.env # hash de entorno directamente entregado por Rack
1658
+ end
1659
+ ```
1660
+
1661
+ Algunas opciones, como `script_name` o `path_info` pueden
1662
+ también ser escritas:
1663
+
1664
+ ``` ruby
1665
+ before { request.path_info = "/" }
1666
+
1667
+ get "/" do
1668
+ "todas las peticiones llegan acá"
1669
+ end
1670
+ ```
1671
+
1672
+ El objeto `request.body` es una instancia de IO o StringIO:
1673
+
1674
+ ``` ruby
1675
+ post "/api" do
1676
+ request.body.rewind # en caso de que alguien ya lo haya leído
1677
+ datos = JSON.parse request.body.read
1678
+ "Hola #{datos['nombre']}!"
1679
+ end
1680
+ ```
1681
+
1682
+ ### Archivos Adjuntos
1683
+
1684
+ Podés usar el helper `attachment` para indicarle al navegador que
1685
+ almacene la respuesta en el disco en lugar de mostrarla en pantalla:
1686
+
1687
+ ``` ruby
1688
+ get '/' do
1689
+ attachment
1690
+ "guardalo!"
1691
+ end
1692
+ ```
1693
+
1694
+ También podés pasarle un nombre de archivo:
1695
+
1696
+ ``` ruby
1697
+ get '/' do
1698
+ attachment "info.txt"
1699
+ "guardalo!"
1700
+ end
1701
+ ```
1702
+
1703
+ ### Fecha y Hora
1704
+
1705
+ Sinatra pone a tu disposición el helper `time_for`, que genera un objeto `Time`
1706
+ a partir del valor que recibe como argumento. Este valor puede ser un
1707
+ `String`, pero también es capaz de convertir objetos `DateTime`, `Date` y de
1708
+ otras clases similares:
1709
+
1710
+ ``` ruby
1711
+ get '/' do
1712
+ pass if Time.now > time_for('Dec 23, 2012')
1713
+ "todavía hay tiempo"
1714
+ end
1715
+ ```
1716
+
1717
+ Este método es usado internamente por métodos como `expires` y `last_modified`,
1718
+ entre otros. Por lo tanto, es posible extender el comportamiento de estos
1719
+ métodos sobreescribiendo `time_for` en tu aplicación:
1720
+
1721
+ ``` ruby
1722
+ helpers do
1723
+ def time_for(value)
1724
+ case value
1725
+ when :ayer then Time.now - 24*60*60
1726
+ when :mañana then Time.now + 24*60*60
1727
+ else super
1728
+ end
1729
+ end
1730
+ end
1731
+
1732
+ get '/' do
1733
+ last_modified :ayer
1734
+ expires :mañana
1735
+ "hola"
1736
+ end
1737
+ ```
1738
+
1739
+ ### Buscando los Archivos de las Plantillas
1740
+
1741
+ El helper `find_template` se utiliza para encontrar los archivos de las
1742
+ plantillas que se van a renderizar:
1743
+
1744
+ ``` ruby
1745
+ find_template settings.views, 'foo', Tilt[:haml] do |archivo|
1746
+ puts "podría ser #{archivo}"
1747
+ end
1748
+ ```
1749
+
1750
+ Si bien esto no es muy útil, lo interesante es que podés sobreescribir este
1751
+ método, y así enganchar tu propio mecanismo de búsqueda. Por ejemplo, para
1752
+ poder utilizar más de un directorio de vistas:
1753
+
1754
+ ``` ruby
1755
+ set :views, ['vistas', 'plantillas']
1756
+
1757
+ helpers do
1758
+ def find_template(views, name, engine, &block)
1759
+ Array(views).each { |v| super(v, name, engine, &block) }
1760
+ end
1761
+ end
1762
+ ```
1763
+
1764
+ Otro ejemplo consiste en usar directorios diferentes para los distintos motores
1765
+ de renderizado:
1766
+
1767
+ ``` ruby
1768
+ set :views, :sass => 'vistas/sass', :haml => 'plantillas', :defecto => 'vistas'
1769
+
1770
+ helpers do
1771
+ def find_template(views, name, engine, &block)
1772
+ _, folder = views.detect { |k,v| engine == Tilt[k] }
1773
+ folder ||= views[:defecto]
1774
+ super(folder, name, engine, &block)
1775
+ end
1776
+ end
1777
+ ```
1778
+
1779
+ ¡Es muy fácil convertir estos ejemplos en una extensión y compartirla!
1780
+
1781
+ Notá que `find_template` no verifica si un archivo existe realmente, sino
1782
+ que llama al bloque que recibe para cada path posible. Esto no representa un
1783
+ problema de rendimiento debido a que `render` va a usar `break` ni bien
1784
+ encuentre un archivo que exista. Además, las ubicaciones de las plantillas (y
1785
+ su contenido) se cachean cuando no estás en el modo de desarrollo. Es bueno
1786
+ tener en cuenta lo anterior si escribís un método extraño.
1787
+
1788
+ ## Configuración
1789
+
1790
+ Ejecutar una vez, en el inicio, en cualquier entorno:
1791
+
1792
+ ``` ruby
1793
+ configure do
1794
+ # asignando una opción
1795
+ set :opcion, 'valor'
1796
+
1797
+ # asignando varias opciones
1798
+ set :a => 1, :b => 2
1799
+
1800
+ # atajo para `set :opcion, true`
1801
+ enable :opcion
1802
+
1803
+ # atajo para `set :opcion, false`
1804
+ disable :opcion
1805
+
1806
+ # también podés tener configuraciones dinámicas usando bloques
1807
+ set(:css_dir) { File.join(views, 'css') }
1808
+ end
1809
+ ```
1810
+
1811
+ Ejecutar únicamente cuando el entorno (la variable de entorno RACK_ENV) es
1812
+ `:production`:
1813
+
1814
+ ``` ruby
1815
+ configure :production do
1816
+ ...
1817
+ end
1818
+ ```
1819
+
1820
+ Ejecutar cuando el entorno es `:production` o `:test`:
1821
+
1822
+ ``` ruby
1823
+ configure :production, :test do
1824
+ ...
1825
+ end
1826
+ ```
1827
+
1828
+ Podés acceder a estas opciones utilizando el método `settings`:
1829
+
1830
+ ``` ruby
1831
+ configure do
1832
+ set :foo, 'bar'
1833
+ end
1834
+
1835
+ get '/' do
1836
+ settings.foo? # => true
1837
+ settings.foo # => 'bar'
1838
+ ...
1839
+ end
1840
+ ```
1841
+
1842
+ ### Configurando la Protección de Ataques
1843
+
1844
+ Sinatra usa [Rack::Protection](https://github.com/rkh/rack-protection#readme)
1845
+ para defender a tu aplicación de los ataques más comunes. Si por algún motivo,
1846
+ querés desactivar esta funcionalidad, podés hacerlo como se indica a
1847
+ continuación (ten en cuenta que tu aplicación va a quedar expuesta a un
1848
+ montón de vulnerabilidades bien conocidas):
1849
+
1850
+ ``` ruby
1851
+ disable :protection
1852
+ ```
1853
+
1854
+ También es posible desactivar una única capa de defensa:
1855
+
1856
+ ``` ruby
1857
+ set :protection, :except => :path_traversal
1858
+ ```
1859
+
1860
+ O varias:
1861
+
1862
+ ``` ruby
1863
+ set :protection, :except => [:path_traversal, :session_hijacking]
1864
+ ```
1865
+
1866
+ ### Configuraciones Disponibles
1867
+
1868
+ <dl>
1869
+ <dt>absolute_redirects</dt>
1870
+ <dd>
1871
+ Si está deshabilitada, Sinatra va a permitir
1872
+ redirecciones relativas, sin embargo, como consecuencia
1873
+ de esto, va a dejar de cumplir con el RFC 2616 (HTTP
1874
+ 1.1), que solamente permite redirecciones absolutas.
1875
+
1876
+ Activalo si tu apliación está corriendo atrás de un proxy
1877
+ reverso que no se ha configurado adecuadamente. Notá que
1878
+ el helper <tt>url</tt> va a seguir produciendo URLs absolutas, a
1879
+ menos que le pasés <tt>false</tt> como segundo parámetro.
1880
+
1881
+ Deshabilitada por defecto.
1882
+ </dd>
1883
+
1884
+ <dt>add_charsets</dt>
1885
+ <dd>
1886
+ Tipos mime a los que el helper <tt>content_type</tt> les
1887
+ añade automáticamente el charset.
1888
+
1889
+ En general, no deberías asignar directamente esta opción,
1890
+ sino añadirle los charsets que quieras:
1891
+ <tt>settings.add_charsets &lt;&lt; "application/foobar"</tt>
1892
+ </dd>
1893
+
1894
+ <dt>app_file</dt>
1895
+ <dd>
1896
+ Path del archivo principal de la aplicación, se utiliza
1897
+ para detectar la raíz del proyecto, el directorio de las
1898
+ vistas y el público, así como las plantillas inline.
1899
+ </dd>
1900
+
1901
+ <dt>bind</dt>
1902
+ <dd>
1903
+ Dirección IP que utilizará el servidor integrado (por
1904
+ defecto: 0.0.0.0).
1905
+ </dd>
1906
+
1907
+ <dt>default_encoding</dt>
1908
+ <dd>
1909
+ Encoding utilizado cuando el mismo se desconoce (por
1910
+ defecto <tt>"utf-8"</tt>).
1911
+ </dd>
1912
+
1913
+ <dt>dump_errors</dt>
1914
+ <dd>
1915
+ Mostrar errores en el log.
1916
+ </dd>
1917
+
1918
+ <dt>environment</dt>
1919
+ <dd>
1920
+ Entorno actual, por defecto toma el valor de
1921
+ <tt>ENV['RACK_ENV']</tt>, o <tt>"development"</tt> si no
1922
+ está disponible.
1923
+ </dd>
1924
+
1925
+ <dt>logging</dt>
1926
+ <dd>
1927
+ Define si se utiliza el logger.
1928
+ </dd>
1929
+
1930
+ <dt>lock</dt>
1931
+ <dd>
1932
+ Coloca un lock alrededor de cada petición, procesando
1933
+ solamente una por proceso.
1934
+
1935
+ Habilitá esta opción si tu aplicación no es thread-safe.
1936
+ Se encuentra deshabilitada por defecto.
1937
+ </dd>
1938
+
1939
+ <dt>method_override</dt>
1940
+ <dd>
1941
+ Utiliza el parámetro <tt>_method</tt> para permtir
1942
+ formularios put/delete en navegadores que no los
1943
+ soportan.
1944
+ </dd>
1945
+
1946
+ <dt>port</dt>
1947
+ <dd>
1948
+ Puerto en el que escuchará el servidor integrado.
1949
+ </dd>
1950
+
1951
+ <dt>prefixed_redirects</dt>
1952
+ <dd>
1953
+ Define si inserta <tt>request.script_name</tt> en las
1954
+ redirecciones cuando no se proporciona un path absoluto.
1955
+ De esta manera, cuando está habilitada,
1956
+ <tt>redirect '/foo'</tt> se comporta de la misma manera
1957
+ que <tt>redirect to('/foo')</tt>. Se encuentra
1958
+ deshabilitada por defecto.
1959
+ </dd>
1960
+
1961
+ <dt>protection</dt>
1962
+ <dd>
1963
+ Define si deben activarse las protecciones para los
1964
+ ataques web más comunes. Para más detalles mirá la
1965
+ sección sobre la configuración de protección de ataques
1966
+ más arriba.
1967
+ </dd>
1968
+
1969
+ <dt>public_dir</dt>
1970
+ <dd>
1971
+ Alias para <tt>public_folder</tt>, que se encuentra a
1972
+ continuación.
1973
+ </dd>
1974
+
1975
+ <dt>public_folder</dt>
1976
+ <dd>
1977
+ Lugar del directorio desde donde se sirven los archivos
1978
+ públicos. Solo se utiliza cuando se sirven archivos
1979
+ estáticos (ver la opción <tt>static</tt>). Si no
1980
+ está presente, se infiere del valor de la opción
1981
+ <tt>app_file</tt>.
1982
+ </dd>
1983
+
1984
+ <dt>reload_templates</dt>
1985
+ <dd>
1986
+ Define si se recargan las plantillas entre peticiones.
1987
+
1988
+ Se encuentra activado en el entorno de desarrollo.
1989
+ </dd>
1990
+
1991
+ <dt>root</dt>
1992
+ <dd>
1993
+ Lugar del directorio raíz del proyecto. Si no está
1994
+ presente, se infiere del valor de la opción
1995
+ <tt>app_file</tt>.
1996
+ </dd>
1997
+
1998
+ <dt>raise_errors</dt>
1999
+ <dd>
2000
+ Elevar excepciones (detiene la aplicación). Se
2001
+ encuentra activada por defecto cuando el valor de
2002
+ <tt>environment</tt> es <tt>"test"</tt>. En caso
2003
+ contrario estará desactivada.
2004
+ </dd>
2005
+
2006
+ <dt>run</dt>
2007
+ <dd>
2008
+ Cuando está habilitada, Sinatra se va a encargar de
2009
+ iniciar el servidor web, no la habilites cuando estés
2010
+ usando rackup o algún otro medio.
2011
+ </dd>
2012
+
2013
+ <dt>running</dt>
2014
+ <dd>
2015
+ Indica si el servidor integrado está ejecutándose, ¡no
2016
+ cambiés esta configuración!.
2017
+ </dd>
2018
+
2019
+ <dt>server</dt>
2020
+ <dd>
2021
+ Servidor, o lista de servidores, para usar como servidor
2022
+ integrado. Por defecto: <tt>['thin', 'mongrel', 'webrick']</tt>,
2023
+ el orden establece la prioridad.
2024
+ </dd>
2025
+
2026
+ <dt>sessions</dt>
2027
+ <dd>
2028
+ Habilita el soporte de sesiones basadas en cookies a
2029
+ través de <tt>Rack::Session::Cookie</tt>. Ver la
2030
+ sección 'Usando Sesiones' para más información.
2031
+ </dd>
2032
+
2033
+ <dt>show_exceptions</dt>
2034
+ <dd>
2035
+ Muestra un stack trace en el navegador cuando ocurre una
2036
+ excepción. Se encuentra activada por defecto cuando el
2037
+ valor de <tt>environment</tt> es <tt>"development"</tt>.
2038
+ En caso contrario estará desactivada.
2039
+ </dd>
2040
+
2041
+ <dt>static</dt>
2042
+ <dd>
2043
+ Define si Sinatra debe encargarse de servir archivos
2044
+ estáticos.
2045
+
2046
+ Deshabilitala cuando uses un servidor capaz de
2047
+ hacerlo por sí solo, porque mejorará el
2048
+ rendimiento. Se encuentra habilitada por
2049
+ defecto en el estilo clásico y desactivado en el
2050
+ el modular.
2051
+ </dd>
2052
+
2053
+ <dt>static_cache_control</dt>
2054
+ <dd>
2055
+ Cuando Sinatra está sirviendo archivos estáticos, y
2056
+ esta opción está habilitada, les va a agregar encabezados
2057
+ <tt>Cache-Control</tt> a las respuestas. Para esto
2058
+ utiliza el helper <tt>cache_control</tt>. Se encuentra
2059
+ deshabilitada por defecto. Notar que es necesario
2060
+ utilizar un array cuando se asignan múltiples valores:
2061
+ <tt>set :static_cache_control, [:public, :max_age => 300]</tt>.
2062
+ </dd>
2063
+
2064
+ <dt>views</dt>
2065
+ <dd>
2066
+ Path del directorio de las vistas. Si no está presente,
2067
+ se infiere del valor de la opción <tt>app_file</tt>.
2068
+ </dd>
2069
+ </dl>
2070
+
2071
+ ## Entornos
2072
+
2073
+ Existen tres entornos (`environments`) predefinidos: `development`,
2074
+ `production` y `test`. El entorno por defecto es
2075
+ `development` y tiene algunas particularidades:
2076
+
2077
+ * Se recargan las plantillas entre una petición y la siguiente, a diferencia
2078
+ de `production` y `test`, donde se cachean.
2079
+ * Se instalan manejadores de errores `not_found` y `error`
2080
+ especiales que muestran un stack trace en el navegador cuando son disparados.
2081
+
2082
+ Para utilizar alguno de los otros entornos puede asignarse el valor
2083
+ correspondiente a la variable de entorno `RACK_ENV`, o bien utilizar la opción
2084
+ `-e` al ejecutar la aplicación:
2085
+
2086
+ ``` shell
2087
+ ruby mi_app.rb -e <ENTORNO>
2088
+ ```
2089
+
2090
+ Los métodos `development?`, `test?` y `production?` te permiten conocer el
2091
+ entorno actual.
2092
+
2093
+ ## Manejo de Errores
2094
+
2095
+ Los manejadores de errores se ejecutan dentro del mismo contexto que las rutas
2096
+ y los filtros `before`, lo que significa que podés usar, por ejemplo,
2097
+ `haml`, `erb`, `halt`, etc.
2098
+
2099
+ ### No encontrado <em>(Not Found)</em>
2100
+
2101
+ Cuando se eleva una excepción `Sinatra::NotFound`, o el código de
2102
+ estado de la respuesta es 404, el manejador `not_found` es invocado:
2103
+
2104
+ ``` ruby
2105
+ not_found do
2106
+ 'No existo'
2107
+ end
2108
+ ```
2109
+
2110
+ ### Error
2111
+
2112
+ El manejador `error` es invocado cada vez que una excepción es elevada
2113
+ desde un bloque de ruta o un filtro. El objeto de la excepción se puede
2114
+ obtener de la variable Rack `sinatra.error`:
2115
+
2116
+ ``` ruby
2117
+ error do
2118
+ 'Disculpá, ocurrió un error horrible - ' + env['sinatra.error'].name
2119
+ end
2120
+ ```
2121
+
2122
+ Errores personalizados:
2123
+
2124
+ ``` ruby
2125
+ error MiErrorPersonalizado do
2126
+ 'Lo que pasó fue...' + env['sinatra.error'].message
2127
+ end
2128
+ ```
2129
+
2130
+ Entonces, si pasa esto:
2131
+
2132
+ ``` ruby
2133
+ get '/' do
2134
+ raise MiErrorPersonalizado, 'algo malo'
2135
+ end
2136
+ ```
2137
+
2138
+ Obtenés esto:
2139
+
2140
+ Lo que pasó fue... algo malo
2141
+
2142
+ También, podés instalar un manejador de errores para un código de estado:
2143
+
2144
+ ``` ruby
2145
+ error 403 do
2146
+ 'Acceso prohibido'
2147
+ end
2148
+
2149
+ get '/secreto' do
2150
+ 403
2151
+ end
2152
+ ```
2153
+
2154
+ O un rango:
2155
+
2156
+ ``` ruby
2157
+ error 400..510 do
2158
+ 'Boom'
2159
+ end
2160
+ ```
2161
+
2162
+ Sinatra instala manejadores `not_found` y `error` especiales
2163
+ cuando se ejecuta dentro del entorno de desarrollo "development".
2164
+
2165
+ ## Rack Middleware
2166
+
2167
+ Sinatra corre sobre Rack[http://rack.rubyforge.org/], una interfaz minimalista
2168
+ que es un estándar para frameworks webs escritos en Ruby. Una de las
2169
+ características más interesantes de Rack para los desarrolladores de aplicaciones
2170
+ es el soporte de "middleware" -- componentes que se ubican entre el servidor y
2171
+ tu aplicación, supervisando y/o manipulando la petición/respuesta HTTP para
2172
+ proporcionar varios tipos de funcionalidades comunes.
2173
+
2174
+ Sinatra hace muy sencillo construir tuberías de Rack middleware a través del
2175
+ método top-level `use`:
2176
+
2177
+ ``` ruby
2178
+ require 'sinatra'
2179
+ require 'mi_middleware_personalizado'
2180
+
2181
+ use Rack::Lint
2182
+ use MiMiddlewarePersonalizado
2183
+
2184
+ get '/hola' do
2185
+ 'Hola Mundo'
2186
+ end
2187
+ ```
2188
+
2189
+ La semántica de `use` es idéntica a la definida para el DSL
2190
+ Rack::Builder[http://rack.rubyforge.org/doc/classes/Rack/Builder.html] (más
2191
+ frecuentemente usado en archivos rackup). Por ejemplo, el método `use`
2192
+ acepta argumentos múltiples/variables así como bloques:
2193
+
2194
+ ``` ruby
2195
+ use Rack::Auth::Basic do |nombre_de_usuario, password|
2196
+ nombre_de_usuario == 'admin' && password == 'secreto'
2197
+ end
2198
+ ```
2199
+
2200
+ Rack es distribuido con una variedad de middleware estándar para logging,
2201
+ debugging, enrutamiento URL, autenticación y manejo de sesiones. Sinatra
2202
+ usa muchos de estos componentes automáticamente de acuerdo a su configuración
2203
+ para que usualmente no tengas que usarlas (con `use`) explícitamente.
2204
+
2205
+ Podés encontrar middleware útil en
2206
+ [rack](https://github.com/rack/rack/tree/master/lib/rack),
2207
+ [rack-contrib](https://github.com/rack/rack-contrib#readme),
2208
+ o en la [Rack wiki](https://github.com/rack/rack/wiki/List-of-Middleware).
2209
+
2210
+ ## Pruebas
2211
+
2212
+ Las pruebas para las aplicaciones Sinatra pueden ser escritas utilizando
2213
+ cualquier framework o librería de pruebas basada en Rack. Se recomienda usar
2214
+ [Rack::Test](http://rdoc.info/github/brynary/rack-test/master/frames):
2215
+
2216
+ ``` ruby
2217
+ require 'mi_app_sinatra'
2218
+ require 'test/unit'
2219
+ require 'rack/test'
2220
+
2221
+ class MiAppTest < Test::Unit::TestCase
2222
+ include Rack::Test::Methods
2223
+
2224
+ def app
2225
+ Sinatra::Application
2226
+ end
2227
+
2228
+ def test_mi_defecto
2229
+ get '/'
2230
+ assert_equal 'Hola Mundo!', last_response.body
2231
+ end
2232
+
2233
+ def test_con_parametros
2234
+ get '/saludar', :name => 'Franco'
2235
+ assert_equal 'Hola Frank!', last_response.body
2236
+ end
2237
+
2238
+ def test_con_entorno_rack
2239
+ get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
2240
+ assert_equal "Estás usando Songbird!", last_response.body
2241
+ end
2242
+ end
2243
+ ```
2244
+
2245
+ ## Sinatra::Base - Middleware, Librerías, y Aplicaciones Modulares
2246
+
2247
+ Definir tu aplicación en el nivel superior funciona bien para micro-aplicaciones
2248
+ pero trae inconvenientes considerables a la hora de construir componentes
2249
+ reutilizables como Rack middleware, Rails metal, librerías simples con un
2250
+ componente de servidor o incluso extensiones de Sinatra. El DSL de alto nivel
2251
+ asume una configuración apropiada para micro-aplicaciones (por ejemplo, un
2252
+ único archivo de aplicación, los directorios `./public` y
2253
+ `./views`, logging, página con detalles de excepción, etc.). Ahí es
2254
+ donde `Sinatra::Base` entra en el juego:
2255
+
2256
+ ``` ruby
2257
+ require 'sinatra/base'
2258
+
2259
+ class MiApp < Sinatra::Base
2260
+ set :sessions, true
2261
+ set :foo, 'bar'
2262
+
2263
+ get '/' do
2264
+ 'Hola Mundo!'
2265
+ end
2266
+ end
2267
+ ```
2268
+
2269
+ Las subclases de `Sinatra::Base` tienen disponibles exactamente los
2270
+ mismos métodos que los provistos por el DSL de top-level. La mayoría de las
2271
+ aplicaciones top-level se pueden convertir en componentes
2272
+ `Sinatra::Base` con dos modificaciones:
2273
+
2274
+ * Tu archivo debe requerir `sinatra/base` en lugar de `sinatra`; de otra
2275
+ manera, todos los métodos del DSL de sinatra son importados dentro del
2276
+ espacio de nombres principal.
2277
+ * Poné las rutas, manejadores de errores, filtros y opciones de tu aplicación
2278
+ en una subclase de `Sinatra::Base`.
2279
+
2280
+ `Sinatra::Base` es una pizarra en blanco. La mayoría de las opciones están
2281
+ desactivadas por defecto, incluyendo el servidor incorporado. Mirá
2282
+ [Opciones y Configuraciones](http://sinatra.github.com/configuration.html)
2283
+ para detalles sobre las opciones disponibles y su comportamiento.
2284
+
2285
+ ### Estilo Modular vs. Clásico
2286
+
2287
+ Contrariamente a la creencia popular, no hay nada de malo con el estilo clásico.
2288
+ Si se ajusta a tu aplicación, no es necesario que la cambies a una modular.
2289
+
2290
+ La desventaja de usar el estilo clásico en lugar del modular consiste en que
2291
+ solamente podés tener una aplicación Sinatra por proceso Ruby. Si tenés
2292
+ planificado usar más, cambiá al estilo modular. Al mismo tiempo, ten en
2293
+ cuenta que no hay ninguna razón por la cuál no puedas mezclar los estilos
2294
+ clásico y modular.
2295
+
2296
+ A continuación se detallan las diferencias (sútiles) entre las configuraciones
2297
+ de ambos estilos:
2298
+
2299
+ <table>
2300
+ <tr>
2301
+ <td>Configuración</td>
2302
+ <td>Clásica</td>
2303
+ <td>Modular</td>
2304
+ </tr>
2305
+
2306
+ <tr>
2307
+ <td>app_file</td>
2308
+ <td>archivo que carga sinatra</td>
2309
+ <td>archivo con la subclase de Sinatra::Base</td>
2310
+ </tr>
2311
+
2312
+ <tr>
2313
+ <td>run</td>
2314
+ <td>$0 == app_file</td>
2315
+ <td>false</td>
2316
+ </tr>
2317
+
2318
+ <tr>
2319
+ <td>logging</td>
2320
+ <td>true</td>
2321
+ <td>false</td>
2322
+ </tr>
2323
+
2324
+ <tr>
2325
+ <td>method_override</td>
2326
+ <td>true</td>
2327
+ <td>false</td>
2328
+ </tr>
2329
+
2330
+ <tr>
2331
+ <td>inline_templates</td>
2332
+ <td>true</td>
2333
+ <td>false</td>
2334
+ </tr>
2335
+
2336
+ <tr>
2337
+ <td>static</td>
2338
+ <td>true</td>
2339
+ <td>false</td>
2340
+ </tr>
2341
+ </table>
2342
+
2343
+ ### Sirviendo una Aplicación Modular
2344
+
2345
+ Las dos opciones más comunes para iniciar una aplicación modular son, iniciarla
2346
+ activamente con `run!`:
2347
+
2348
+ ``` ruby
2349
+ # mi_app.rb
2350
+ require 'sinatra/base'
2351
+
2352
+ class MiApp < Sinatra::Base
2353
+ # ... código de la app ...
2354
+
2355
+ # iniciar el servidor si el archivo fue ejecutado directamente
2356
+ run! if app_file == $0
2357
+ end
2358
+ ```
2359
+
2360
+ Iniciar con:
2361
+
2362
+ ``` shell
2363
+ ruby mi_app.rb
2364
+ ```
2365
+
2366
+ O, con un archivo `config.ru`, que permite usar cualquier handler Rack:
2367
+
2368
+ ``` ruby
2369
+ # config.ru
2370
+ require './mi_app'
2371
+ run MiApp
2372
+ ```
2373
+
2374
+ Después ejecutar:
2375
+
2376
+ ``` shell
2377
+ rackup -p 4567
2378
+ ```
2379
+
2380
+ ### Usando una Aplicación Clásica con un Archivo config.ru
2381
+
2382
+ Escribí el archivo de tu aplicación:
2383
+
2384
+ ``` ruby
2385
+ # app.rb
2386
+ require 'sinatra'
2387
+
2388
+ get '/' do
2389
+ 'Hola mundo!'
2390
+ end
2391
+ ```
2392
+
2393
+ Y el `config.ru` correspondiente:
2394
+
2395
+ ``` ruby
2396
+ require './app'
2397
+ run Sinatra::Application
2398
+ ```
2399
+
2400
+ ### ¿Cuándo usar config.ru?
2401
+
2402
+ Indicadores de que probablemente querés usar `config.ru`:
2403
+
2404
+ * Querés realizar el deploy con un handler Rack distinto (Passenger, Unicorn,
2405
+ Heroku, ...).
2406
+ * Querés usar más de una subclase de `Sinatra::Base`.
2407
+ * Querés usar Sinatra únicamente para middleware, pero no como un endpoint.
2408
+
2409
+ <b>No hay necesidad de utilizar un archivo `config.ru` exclusivamente
2410
+ porque tenés una aplicación modular, y no necesitás una aplicación modular para
2411
+ iniciarla con `config.ru`.</b>
2412
+
2413
+ ### Utilizando Sinatra como Middleware
2414
+
2415
+ Sinatra no solo es capaz de usar otro Rack middleware, sino que a su vez,
2416
+ cualquier aplicación Sinatra puede ser agregada delante de un endpoint Rack
2417
+ como middleware. Este endpoint puede ser otra aplicación Sinatra, o cualquier
2418
+ aplicación basada en Rack (Rails/Ramaze/Camping/...):
2419
+
2420
+ ``` ruby
2421
+ require 'sinatra/base'
2422
+
2423
+ class PantallaDeLogin < Sinatra::Base
2424
+ enable :sessions
2425
+
2426
+ get('/login') { haml :login }
2427
+
2428
+ post('/login') do
2429
+ if params[:nombre] == 'admin' && params[:password] == 'admin'
2430
+ session['nombre_de_usuario'] = params[:nombre]
2431
+ else
2432
+ redirect '/login'
2433
+ end
2434
+ end
2435
+ end
2436
+
2437
+ class MiApp < Sinatra::Base
2438
+ # el middleware se ejecutará antes que los filtros
2439
+ use PantallaDeLogin
2440
+
2441
+ before do
2442
+ unless session['nombre_de_usuario']
2443
+ halt "Acceso denegado, por favor <a href='/login'>iniciá sesión</a>."
2444
+ end
2445
+ end
2446
+
2447
+ get('/') { "Hola #{session['nombre_de_usuario']}." }
2448
+ end
2449
+ ```
2450
+
2451
+ ### Creación Dinámica de Aplicaciones
2452
+
2453
+ Puede que en algunas ocasiones quieras crear nuevas aplicaciones en
2454
+ tiempo de ejecución sin tener que asignarlas a una constante. Para
2455
+ esto tenés `Sinatra.new`:
2456
+
2457
+ ``` ruby
2458
+ require 'sinatra/base'
2459
+ mi_app = Sinatra.new { get('/') { "hola" } }
2460
+ mi_app.run!
2461
+ ```
2462
+
2463
+ Acepta como argumento opcional una aplicación desde la que se
2464
+ heredará:
2465
+
2466
+ ``` ruby
2467
+ # config.ru
2468
+ require 'sinatra/base'
2469
+
2470
+ controller = Sinatra.new do
2471
+ enable :logging
2472
+ helpers MisHelpers
2473
+ end
2474
+
2475
+ map('/a') do
2476
+ run Sinatra.new(controller) { get('/') { 'a' } }
2477
+ end
2478
+
2479
+ map('/b') do
2480
+ run Sinatra.new(controller) { get('/') { 'b' } }
2481
+ end
2482
+ ```
2483
+
2484
+ Construir aplicaciones de esta forma resulta especialmente útil para
2485
+ testear extensiones Sinatra o para usar Sinatra en tus librerías.
2486
+
2487
+ Por otro lado, hace extremadamente sencillo usar Sinatra como
2488
+ middleware:
2489
+
2490
+ ``` ruby
2491
+ require 'sinatra/base'
2492
+
2493
+ use Sinatra do
2494
+ get('/') { ... }
2495
+ end
2496
+
2497
+ run ProyectoRails::Application
2498
+ ```
2499
+
2500
+ ## Ámbitos y Ligaduras
2501
+
2502
+ El ámbito en el que te encontrás determina que métodos y variables están
2503
+ disponibles.
2504
+
2505
+ ### Ámbito de Aplicación/Clase
2506
+
2507
+ Cada aplicación Sinatra es una subclase de `Sinatra::Base`. Si estás
2508
+ usando el DSL de top-level (`require 'sinatra'`), entonces esta clase es
2509
+ `Sinatra::Application`, de otra manera es la subclase que creaste
2510
+ explícitamente. Al nivel de la clase tenés métodos como `get` o `before`, pero
2511
+ no podés acceder a los objetos `request` o `session`, ya que hay una única
2512
+ clase de la aplicación para todas las peticiones.
2513
+
2514
+ Las opciones creadas utilizando `set` son métodos al nivel de la clase:
2515
+
2516
+ ``` ruby
2517
+ class MiApp < Sinatra::Base
2518
+ # Ey, estoy en el ámbito de la aplicación!
2519
+ set :foo, 42
2520
+ foo # => 42
2521
+
2522
+ get '/foo' do
2523
+ # Hey, ya no estoy en el ámbito de la aplicación!
2524
+ end
2525
+ end
2526
+ ```
2527
+
2528
+ Tenés la ligadura al ámbito de la aplicación dentro de:
2529
+
2530
+ * El cuerpo de la clase de tu aplicación
2531
+ * Métodos definidos por extensiones
2532
+ * El bloque pasado a `helpers`
2533
+ * Procs/bloques usados como el valor para `set`
2534
+
2535
+ Este ámbito puede alcanzarse de las siguientes maneras:
2536
+
2537
+ * A través del objeto pasado a los bloques de configuración (`configure { |c| ...}`)
2538
+ * Llamando a `settings` desde dentro del ámbito de la petición
2539
+
2540
+ ### Ámbito de Petición/Instancia
2541
+
2542
+ Para cada petición entrante, una nueva instancia de la clase de tu aplicación
2543
+ es creada y todos los bloques de rutas son ejecutados en ese ámbito. Desde este
2544
+ ámbito podés acceder a los objetos `request` y `session` o llamar a los métodos
2545
+ de renderización como `erb` o `haml`. Podés acceder al ámbito de la aplicación
2546
+ desde el ámbito de la petición utilizando `settings`:
2547
+
2548
+ ``` ruby
2549
+ class MiApp < Sinatra::Base
2550
+ # Ey, estoy en el ámbito de la aplicación!
2551
+ get '/definir_ruta/:nombre' do
2552
+ # Ámbito de petición para '/definir_ruta/:nombre'
2553
+ @valor = 42
2554
+
2555
+ settings.get("/#{params[:nombre]}") do
2556
+ # Ámbito de petición para "/#{params[:nombre]}"
2557
+ @valor # => nil (no es la misma petición)
2558
+ end
2559
+
2560
+ "Ruta definida!"
2561
+ end
2562
+ end
2563
+ ```
2564
+
2565
+ Tenés la ligadura al ámbito de la petición dentro de:
2566
+
2567
+ * bloques pasados a get/head/post/put/delete/options
2568
+ * filtros before/after
2569
+ * métodos ayudantes
2570
+ * plantillas/vistas
2571
+
2572
+ ### Ámbito de Delegación
2573
+
2574
+ El ámbito de delegación solo reenvía métodos al ámbito de clase. De cualquier
2575
+ manera, no se comporta 100% como el ámbito de clase porque no tenés la ligadura
2576
+ de la clase: únicamente métodos marcados explícitamente para delegación están
2577
+ disponibles y no compartís variables/estado con el ámbito de clase (léase:
2578
+ tenés un `self` diferente). Podés agregar delegaciones de método llamando a
2579
+ `Sinatra::Delegator.delegate :nombre_del_metodo`.
2580
+
2581
+ Tenés la ligadura al ámbito de delegación dentro de:
2582
+
2583
+ * La ligadura del top-level, si hiciste `require "sinatra"`
2584
+ * Un objeto extendido con el mixin `Sinatra::Delegator`
2585
+
2586
+ Hechale un vistazo al código: acá está el
2587
+ [Sinatra::Delegator mixin](https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/base.rb#L1609-1633)
2588
+ que [extiende el objeto main](https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/main.rb#L28-30).
2589
+
2590
+ ## Línea de Comandos
2591
+
2592
+ Las aplicaciones Sinatra pueden ser ejecutadas directamente:
2593
+
2594
+ ``` shell
2595
+ ruby miapp.rb [-h] [-x] [-e ENTORNO] [-p PUERTO] [-o HOST] [-s MANEJADOR]
2596
+ ```
2597
+
2598
+ Las opciones son:
2599
+
2600
+ ```
2601
+ -h # ayuda
2602
+ -p # asigna el puerto (4567 es usado por defecto)
2603
+ -o # asigna el host (0.0.0.0 es usado por defecto)
2604
+ -e # asigna el entorno (development es usado por defecto)
2605
+ -s # especifica el servidor/manejador rack (thin es usado por defecto)
2606
+ -x # activa el mutex lock (está desactivado por defecto)
2607
+ ```
2608
+
2609
+ ## Versiones de Ruby Soportadas
2610
+
2611
+ Las siguientes versiones de Ruby son soportadas oficialmente:
2612
+
2613
+ <dl>
2614
+ <dt>Ruby 1.8.7</dt>
2615
+ <dd>
2616
+ 1.8.7 es soportado completamente. Sin embargo, si no hay nada que te lo
2617
+ prohiba, te recomendamos que uses 1.9.2 o cambies a JRuby o Rubinius. No se
2618
+ dejará de dar soporte a 1.8.7 hasta Sinatra 2.0 y Ruby 2.0, aunque si se
2619
+ libera la versión 1.8.8 de Ruby las cosas podrían llegar a cambiar. Sin
2620
+ embargo, que eso ocurra es muy poco probable, e incluso el caso de que lo
2621
+ haga, puede que se siga dando soporte a 1.8.7. <b>Hemos dejado de soportar
2622
+ Ruby 1.8.6.</b> Si querés ejecutar Sinatra sobre 1.8.6, podés utilizar la
2623
+ versión 1.2, pero ten en cuenta que una vez que Sinatra 1.4.0 sea liberado,
2624
+ ya no se corregirán errores por más que se reciban reportes de los mismos.
2625
+ </dd>
2626
+
2627
+ <dt>Ruby 1.9.2</dt>
2628
+ <dd>
2629
+ 1.9.2 es soportado y recomendado. No uses 1.9.2p0, porque se producen fallos
2630
+ de segmentación cuando se ejecuta Sinatra. El soporte se mantendrá al menos
2631
+ hasta que se libere la versión 1.9.4/2.0 de Ruby. El soporte para la última
2632
+ versión de la serie 1.9 se mantendrá mientras lo haga el equipo principal de Ruby.
2633
+ </dd>
2634
+
2635
+ <dt>Ruby 1.9.3</dt>
2636
+ <dd>
2637
+ 1.9.3 es soportado y recomendado. Ten en cuenta que el cambio a 1.9.3 desde
2638
+ una versión anterior va a invalidar todas las sesiones.
2639
+ </dd>
2640
+
2641
+ <dt>Rubinius</dt>
2642
+ <dd>
2643
+ Rubinius es soportado oficialmente (Rubinius >= 1.2.4). Todo funciona
2644
+ correctamente, incluyendo los lenguajes de plantillas. La próxima versión,
2645
+ 2.0, también es soportada, incluyendo el modo 1.9.
2646
+ </dd>
2647
+
2648
+ <dt>JRuby</dt>
2649
+ <dd>
2650
+ JRuby es soportado oficialmente (JRuby >= 1.6.7). No se conocen problemas
2651
+ con librerías de plantillas de terceras partes. Sin embargo, si elegís usar
2652
+ JRuby, deberías examinar sus Rack handlers porque el servidor web Thin no es
2653
+ soportado completamente. El soporte de JRuby para extensiones C se encuentra
2654
+ en una etapa experimental, sin embargo, de momento, solamente RDiscount,
2655
+ Redcarpet, RedCloth y Yajl, así como Thin y Mongrel se ven afectadas.
2656
+ </dd>
2657
+ </dl>
2658
+
2659
+ Siempre le prestamos atención a las nuevas versiones de Ruby.
2660
+
2661
+ Las siguientes implementaciones de Ruby no se encuentran soportadas
2662
+ oficialmente. De cualquier manera, pueden ejecutar Sinatra:
2663
+
2664
+ * Versiones anteriores de JRuby y Rubinius
2665
+ * Ruby Enterprise Edition
2666
+ * MacRuby, Maglev e IronRuby
2667
+ * Ruby 1.9.0 y 1.9.1 (pero no te recomendamos que los uses)
2668
+
2669
+ No ser soportada oficialmente, significa que si las cosas se rompen
2670
+ ahí y no en una plataforma soportada, asumimos que no es nuestro problema sino
2671
+ el suyo.
2672
+
2673
+ Nuestro servidor CI también se ejecuta sobre ruby-head (que será la próxima
2674
+ versión 2.1.0) y la rama 1.9.4. Como están en movimiento constante, no podemos
2675
+ garantizar nada. De todas formas, podés contar con que tanto 1.9.4-p0 como
2676
+ 2.1.0-p0 sea soportadas.
2677
+
2678
+ Sinatra debería funcionar en cualquier sistema operativo soportado por la
2679
+ implementación de Ruby elegida.
2680
+
2681
+ En este momento, no vas a poder ejecutar Sinatra en Cardinal, SmallRuby,
2682
+ BlueRuby o cualquier versión de Ruby anterior a 1.8.7.
2683
+
2684
+ ## A la Vanguardia
2685
+
2686
+ Si querés usar el código de Sinatra más reciente, sentite libre de ejecutar
2687
+ tu aplicación sobre la rama master, en general es bastante estable.
2688
+
2689
+ También liberamos prereleases de vez en cuando, así, podés hacer:
2690
+
2691
+ ``` shell
2692
+ gem install sinatra --pre
2693
+ ```
2694
+
2695
+ Para obtener algunas de las últimas características.
2696
+
2697
+ ### Con Bundler
2698
+
2699
+ Esta es la manera recomendada para ejecutar tu aplicación sobre la última
2700
+ versión de Sinatra usando [Bundler](http://gembundler.com/).
2701
+
2702
+ Primero, instalá Bundler si no lo hiciste todavía:
2703
+
2704
+ ``` shell
2705
+ gem install bundler
2706
+ ```
2707
+
2708
+ Después, en el directorio de tu proyecto, creá un archivo `Gemfile`:
2709
+
2710
+ ``` ruby
2711
+ source :rubygems
2712
+ gem 'sinatra', :git => "git://github.com/sinatra/sinatra.git"
2713
+
2714
+ # otras dependencias
2715
+ gem 'haml' # por ejemplo, si usás haml
2716
+ gem 'activerecord', '~> 3.0' # quizás también necesités ActiveRecord 3.x
2717
+ ```
2718
+
2719
+ Tené en cuenta que tenés que listar todas las dependencias directas de tu
2720
+ aplicación. No es necesario listar las dependencias de Sinatra (Rack y Tilt)
2721
+ porque Bundler las agrega directamente.
2722
+
2723
+ Ahora podés arrancar tu aplicación así:
2724
+
2725
+ ``` shell
2726
+ bundle exec ruby miapp.rb
2727
+ ```
2728
+
2729
+ ### Con Git
2730
+
2731
+ Cloná el repositorio localmente y ejecutá tu aplicación, asegurándote que el
2732
+ directorio `sinatra/lib` esté en el `$LOAD_PATH`:
2733
+
2734
+ ``` shell
2735
+ cd miapp
2736
+ git clone git://github.com/sinatra/sinatra.git
2737
+ ruby -Isinatra/lib miapp.rb
2738
+ ```
2739
+
2740
+ Para actualizar el código fuente de Sinatra en el futuro:
2741
+
2742
+ ``` shell
2743
+ cd miapp/sinatra
2744
+ git pull
2745
+ ```
2746
+
2747
+ ### Instalación Global
2748
+
2749
+ Podés construir la gem vos mismo:
2750
+
2751
+ ``` shell
2752
+ git clone git://github.com/sinatra/sinatra.git
2753
+ cd sinatra
2754
+ rake sinatra.gemspec
2755
+ rake install
2756
+ ```
2757
+
2758
+ Si instalás tus gems como root, el último paso debería ser
2759
+
2760
+ ``` shell
2761
+ sudo rake install
2762
+ ```
2763
+
2764
+ ## Versionado
2765
+
2766
+ Sinatra utiliza el [Versionado Semántico](http://semver.org/),
2767
+ siguiendo las especificaciones SemVer y SemVerTag.
2768
+
2769
+ ## Lecturas Recomendadas
2770
+
2771
+ * [Sito web del proyecto](http://www.sinatrarb.com/) - Documentación
2772
+ adicional, noticias, y enlaces a otros recursos.
2773
+ * [Contribuyendo](http://www.sinatrarb.com/contributing) - ¿Encontraste un
2774
+ error?. ¿Necesitás ayuda?. ¿Tenés un parche?.
2775
+ * [Seguimiento de problemas](http://github.com/sinatra/sinatra/issues)
2776
+ * [Twitter](http://twitter.com/sinatra)
2777
+ * [Lista de Correo](http://groups.google.com/group/sinatrarb/topics)
2778
+ * [IRC: #sinatra](irc://chat.freenode.net/#sinatra) en http://freenode.net
2779
+ * [Sinatra Book](http://sinatra-book.gittr.com) Tutorial (en inglés).
2780
+ * [Sinatra Recipes](http://recipes.sinatrarb.com/) Recetas contribuidas
2781
+ por la comunidad (en inglés).
2782
+ * Documentación de la API para la
2783
+ [última versión liberada](http://rubydoc.info/gems/sinatra) o para la
2784
+ [rama de desarrollo actual](http://rubydoc.info/github/sinatra/sinatra)
2785
+ en http://rubydoc.info/
2786
+ * [Servidor de CI](http://travis-ci.org/sinatra/sinatra)