sinatra 1.0 → 1.1.a

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

Potentially problematic release.


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

Files changed (57) hide show
  1. data/CHANGES +108 -1
  2. data/LICENSE +1 -1
  3. data/README.de.rdoc +1024 -0
  4. data/README.es.rdoc +1047 -0
  5. data/README.fr.rdoc +1038 -0
  6. data/README.hu.rdoc +607 -0
  7. data/README.jp.rdoc +473 -15
  8. data/README.rdoc +429 -41
  9. data/Rakefile +17 -6
  10. data/lib/sinatra/base.rb +357 -158
  11. data/lib/sinatra/showexceptions.rb +9 -1
  12. data/sinatra.gemspec +52 -9
  13. data/test/builder_test.rb +25 -1
  14. data/test/coffee_test.rb +88 -0
  15. data/test/encoding_test.rb +18 -0
  16. data/test/filter_test.rb +61 -2
  17. data/test/hello.mab +1 -0
  18. data/test/helper.rb +1 -0
  19. data/test/helpers_test.rb +141 -37
  20. data/test/less_test.rb +26 -2
  21. data/test/liquid_test.rb +58 -0
  22. data/test/markaby_test.rb +58 -0
  23. data/test/markdown_test.rb +35 -0
  24. data/test/nokogiri_test.rb +69 -0
  25. data/test/radius_test.rb +59 -0
  26. data/test/rdoc_test.rb +34 -0
  27. data/test/request_test.rb +12 -0
  28. data/test/routing_test.rb +35 -1
  29. data/test/sass_test.rb +46 -16
  30. data/test/scss_test.rb +88 -0
  31. data/test/settings_test.rb +32 -0
  32. data/test/sinatra_test.rb +4 -0
  33. data/test/static_test.rb +64 -0
  34. data/test/templates_test.rb +55 -1
  35. data/test/textile_test.rb +34 -0
  36. data/test/views/ascii.haml +2 -0
  37. data/test/views/explicitly_nested.str +1 -0
  38. data/test/views/hello.coffee +1 -0
  39. data/test/views/hello.liquid +1 -0
  40. data/test/views/hello.mab +1 -0
  41. data/test/views/hello.md +1 -0
  42. data/test/views/hello.nokogiri +1 -0
  43. data/test/views/hello.radius +1 -0
  44. data/test/views/hello.rdoc +1 -0
  45. data/test/views/hello.sass +1 -1
  46. data/test/views/hello.scss +3 -0
  47. data/test/views/hello.str +1 -0
  48. data/test/views/hello.textile +1 -0
  49. data/test/views/layout2.liquid +2 -0
  50. data/test/views/layout2.mab +2 -0
  51. data/test/views/layout2.nokogiri +3 -0
  52. data/test/views/layout2.radius +2 -0
  53. data/test/views/layout2.str +2 -0
  54. data/test/views/nested.str +1 -0
  55. data/test/views/utf8.haml +2 -0
  56. metadata +240 -33
  57. data/lib/sinatra/tilt.rb +0 -746
@@ -0,0 +1,1047 @@
1
+ = Sinatra
2
+ <i>Atención: Este documento es una traducción de la versión en inglés y puede estar desactualizado.</i>
3
+
4
+ Sinatra es un DSL para crear aplicaciones web rápidamente en Ruby con un mínimo
5
+ esfuerzo:
6
+
7
+ # miapp.rb
8
+ require 'sinatra'
9
+
10
+ get '/' do
11
+ 'Hola mundo!'
12
+ end
13
+
14
+ Instalá la gem y ejecutá la aplicación con:
15
+
16
+ gem install sinatra
17
+ ruby -rubygems miapp.rb
18
+
19
+ Podés verla en: http://localhost:4567
20
+
21
+ == Rutas
22
+
23
+ En Sinatra, una ruta está compuesta por un método HTTP y un patrón de una URL.
24
+ Cada ruta se asocia con un bloque:
25
+
26
+ get '/' do
27
+ .. mostrar algo ..
28
+ end
29
+
30
+ post '/' do
31
+ .. crear algo ..
32
+ end
33
+
34
+ put '/' do
35
+ .. actualizar algo ..
36
+ end
37
+
38
+ delete '/' do
39
+ .. aniquilar algo ..
40
+ end
41
+
42
+ Las rutas son comparadas en el orden en el que son definidas. La primer ruta
43
+ que coincide con la petición es invocada.
44
+
45
+ Los patrones de las rutas pueden incluir parámetros nombrados, accesibles a
46
+ través de el hash <tt>params</tt>:
47
+
48
+ get '/hola/:nombre' do
49
+ # coincide con "GET /hola/foo" y "GET /hola/bar"
50
+ # params[:nombre] es 'foo' o 'bar'
51
+ "Hola #{params[:nombre]}!"
52
+ end
53
+
54
+ También podés acceder a los parámetros nombrados usando parámetros de bloque:
55
+
56
+ get '/hola/:nombre' do |n|
57
+ "Hola #{n}!"
58
+ end
59
+
60
+ Los patrones de ruta también pueden incluir parámetros splat (o wildcard),
61
+ accesibles a través del arreglo <tt>params[:splat]</tt>.
62
+
63
+ get '/decir/*/al/*' do
64
+ # coincide con /decir/hola/al/mundo
65
+ params[:splat] # => ["hola", "mundo"]
66
+ end
67
+
68
+ get '/descargar/*.*' do
69
+ # coincide con /descargar/path/al/archivo.xml
70
+ params[:splat] # => ["path/al/archivo", "xml"]
71
+ end
72
+
73
+ Rutas con Expresiones Regulares:
74
+
75
+ get %r{/hola/([\w]+)} do
76
+ "Hola, #{params[:captures].first}!"
77
+ end
78
+
79
+ O con un parámetro de bloque:
80
+
81
+ get %r{/hola/([\w]+)} do |c|
82
+ "Hola, #{c}!"
83
+ end
84
+
85
+ === Condiciones
86
+
87
+ Las rutas pueden incluir una variedad de condiciones de selección, como por
88
+ ejemplo el user agent:
89
+
90
+ get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
91
+ "Estás usando la versión de Songbird #{params[:agent][0]}"
92
+ end
93
+
94
+ get '/foo' do
95
+ # Coincide con browsers que no sean songbird
96
+ end
97
+
98
+ Otras condiciones disponibles son +host_name+ y +provides+:
99
+
100
+ get '/', :host_name => /^admin\./ do
101
+ "Área de Administración, Acceso denegado!"
102
+ end
103
+
104
+ get '/', :provides => 'html' do
105
+ haml :index
106
+ end
107
+
108
+ get '/', :provides => ['rss', 'atom', 'xml'] do
109
+ builder :feed
110
+ end
111
+
112
+ Podés definir tus propias condiciones fácilmente:
113
+
114
+ set(:probabilidad) { |valor| condition { rand <= valor } }
115
+
116
+ get '/gana_un_auto', :probabilidad => 0.1 do
117
+ "Ganaste!"
118
+ end
119
+
120
+ get '/gana_un_auto' do
121
+ "Lo siento, perdiste."
122
+ end
123
+
124
+ === Valores de retorno
125
+
126
+ El valor de retorno de un bloque de ruta determina al menos el cuerpo de la
127
+ respuesta que se le pasa al cliente HTTP o al siguiente middleware en la pila
128
+ de Rack. Lo más común es que sea un string, como en los ejemplos anteriores.
129
+ Sin embargo, otros valor también son aceptados.
130
+
131
+ Podés devolver cualquier objeto que sea una respuesta Rack válida, un objeto
132
+ que represente el cuerpo de una respuesta Rack o un código de estado HTTP:
133
+
134
+ * Un arreglo con tres elementos: <tt>[estado (Fixnum), cabeceras (Hash), cuerpo de la respuesta (responde a #each)]</tt>
135
+ * Un arreglo con dos elementos: <tt>[estado (Fixnum), cuerpo de la respuesta (responde a #each)]</tt>
136
+ * Un objeto que responde a <tt>#each</tt> y que le pasa únicamente strings al bloque dado
137
+ * Un Fixnum representando el código de estado
138
+
139
+ De esa manera podemos, por ejemplo, implementar fácilmente un streaming:
140
+
141
+ class Stream
142
+ def each
143
+ 100.times { |i| yield "#{i}\n" }
144
+ end
145
+ end
146
+
147
+ get('/') { Stream.new }
148
+
149
+ == Archivos estáticos
150
+
151
+ Los archivos estáticos son servidos desde el directorio público
152
+ <tt>./public</tt>. Podés especificar una ubicación diferente ajustando la
153
+ opción <tt>:public</tt>:
154
+
155
+ set :public, File.dirname(__FILE__) + '/estaticos'
156
+
157
+ Notá que el nombre del directorio público no está incluido en la URL. Por
158
+ ejemplo, el archivo <tt>./public/css/style.css</tt> se accede a través de
159
+ <tt>http://ejemplo.com/css/style.css</tt>.
160
+
161
+ == Vistas / Plantillas
162
+
163
+ Se asume que las plantillas están ubicadas directamente bajo el directorio
164
+ <tt>./views</tt>. Para usar un directorio de vistas diferente:
165
+
166
+ set :views, File.dirname(__FILE__) + '/plantillas'
167
+
168
+ Es importante acordarse que siempre tenés que referenciar a las plantillas con
169
+ símbolos, incluso cuando se encuentran en un subdirectorio (en este caso tenés
170
+ que usar <tt>:'subdir/plantilla'</tt>). Tenés que usar un símbolo porque los
171
+ métodos de renderización van a renderizar directamente cualquier string que se
172
+ les pase como argumento.
173
+
174
+ === Plantillas Haml
175
+
176
+ La gem/librería haml es necesaria para para renderizar plantillas HAML:
177
+
178
+ ## Vas a necesitar requerir haml en tu app
179
+ require 'haml'
180
+
181
+ get '/' do
182
+ haml :index
183
+ end
184
+
185
+ Renderiza <tt>./views/index.haml</tt>.
186
+
187
+ Las {opciones de Haml}[http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#options]
188
+ pueden ser ajustadas globalmente a través de las configuraciones de Sinatra,
189
+ ver {Opciones y Configuraciones}[http://www.sinatrarb.com/configuration.html],
190
+ y reemplazadas individualmente.
191
+
192
+ set :haml, :format => :html5 # el formato por defecto de Haml es :xhtml
193
+
194
+ get '/' do
195
+ haml :index, :format => :html4 # reemplazado
196
+ end
197
+
198
+ === Plantillas Erb
199
+
200
+ ## Vas a necesitar requerir erb en tu app
201
+ require 'erb'
202
+
203
+ get '/' do
204
+ erb :index
205
+ end
206
+
207
+ Renderiza <tt>./views/index.erb</tt>
208
+
209
+ === Erubis
210
+
211
+ La gem/librería erubis es necesaria para renderizar plantillas erubis:
212
+
213
+ ## Vas a necesitar requerir erubis en tu app
214
+ require 'erubis'
215
+
216
+ get '/' do
217
+ erubis :index
218
+ end
219
+
220
+ Renderiza <tt>./views/index.erubis</tt>
221
+
222
+ === Plantillas Builder
223
+
224
+ La gem/librería builder es necesaria para renderizar plantillas builder:
225
+
226
+ ## Vas a necesitar requerir builder en tu app
227
+ require 'builder'
228
+
229
+ get '/' do
230
+ builder :index
231
+ end
232
+
233
+ Renderiza <tt>./views/index.builder</tt>.
234
+
235
+ === Plantillas Nokogiri
236
+
237
+ La gem/librería nokogiri es necesaria para renderizar plantillas nokogiri:
238
+
239
+ ## Vas a necesitar requerir nokogiri en tu app
240
+ require 'nokogiri'
241
+
242
+ get '/' do
243
+ nokogiri :index
244
+ end
245
+
246
+ Renderiza <tt>./views/index.nokogiri</tt>.
247
+
248
+ === Plantillas Sass
249
+
250
+ La gem/librería sass es necesaria para renderizar plantillas Sass:
251
+
252
+ ## Vas a necesitar requerir haml o sass en tu app
253
+ require 'sass'
254
+
255
+ get '/stylesheet.css' do
256
+ sass :stylesheet
257
+ end
258
+
259
+ Renderiza <tt>./views/stylesheet.sass</tt>.
260
+
261
+ Las {opciones de Sass}[http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options]
262
+ pueden ser ajustadas globalmente a través de las configuraciones de Sinatra,
263
+ ver {Opciones y Configuraciones}[http://www.sinatrarb.com/configuration.html],
264
+ y reemplazadas individualmente.
265
+
266
+ set :sass, :style => :compact # el estilo por defecto de Sass es :nested
267
+
268
+ get '/stylesheet.css' do
269
+ sass :stylesheet, :style => :expanded # reemplazado
270
+ end
271
+
272
+ === Plantillas Scss
273
+
274
+ La gem/librería sass es necesaria para renderizar plantillas Scss:
275
+
276
+ ## Vas a necesitar requerir haml o sass en tu app
277
+ require 'sass'
278
+
279
+ get '/stylesheet.css' do
280
+ scss :stylesheet
281
+ end
282
+
283
+ Renderiza <tt>./views/stylesheet.scss</tt>.
284
+
285
+ Las {opciones de Scss}[http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options]
286
+ pueden ser ajustadas globalmente a través de las configuraciones de Sinatra,
287
+ ver {Opciones y Configuraciones}[http://www.sinatrarb.com/configuration.html],
288
+ y reemplazadas individualmente.
289
+
290
+ set :scss, :style => :compact # el estilo por defecto de Sass es :nested
291
+
292
+ get '/stylesheet.css' do
293
+ scss :stylesheet, :style => :expanded # reemplazado
294
+ end
295
+
296
+ === Plantillas Less
297
+
298
+ La gem/librería less es necesaria para renderizar plantillas Less:
299
+
300
+ ## Vas a necesitar requerir less en tu app
301
+ require 'less'
302
+
303
+ get '/stylesheet.css' do
304
+ less :stylesheet
305
+ end
306
+
307
+ Renderiza <tt>./views/stylesheet.less</tt>.
308
+
309
+ === Plantillas Liquid
310
+
311
+ La gem/librería liquid es necesaria para renderizar plantillas Liquid:
312
+
313
+ ## Vas a necesitar requerir liquid en tu app
314
+ require 'liquid'
315
+
316
+ get '/' do
317
+ liquid :index
318
+ end
319
+
320
+ Renderiza <tt>./views/index.liquid</tt>.
321
+
322
+ Como no vas a poder llamar a métodos de Ruby (excepto a +yield+) desde una
323
+ plantilla Liquid, casi siempre vas a querer pasarle locales:
324
+
325
+ liquid :index, :locals => { :clave => 'valor' }
326
+
327
+ === Plantillas Markdown
328
+
329
+ La gem/librería rdiscount es necesaria para renderizar plantillas Markdown:
330
+
331
+ ## Vas a necesitar requerir rdiscount en tu app
332
+ require "rdiscount"
333
+
334
+ get '/' do
335
+ markdown :index
336
+ end
337
+
338
+ Renderiza <tt>./views/index.markdown</tt> (+md+ y +mkd+ también son extensiones
339
+ de archivo válidas).
340
+
341
+ No es posible llamar métodos desde markdown, ni pasarle locales. Por lo tanto,
342
+ generalmente vas a usarlo en combinación con otro motor de renderizado:
343
+
344
+ erb :resumen, :locals => { :texto => markdown(:introduccion) }
345
+
346
+ Tené en cuenta que también podés llamar al método markdown desde otras
347
+ plantillas:
348
+
349
+ %h1 Hola Desde Haml!
350
+ %p= markdown(:saludos)
351
+
352
+ === Plantilla Textile
353
+
354
+ La gem/librería RedCloth es necesaria para renderizar plantillas Textile:
355
+
356
+ ## Vas a necesitar requerir redcloth en tu app
357
+ require "redcloth"
358
+
359
+ get '/' do
360
+ textile :index
361
+ end
362
+
363
+ Renderiza <tt>./views/index.textile</tt>.
364
+
365
+ No es posible llamar métodos desde textile, ni pasarle locales. Por lo tanto,
366
+ generalmente vas a usarlo en combinación con otro motor de renderizado:
367
+
368
+ erb :resumen, :locals => { :texto => textile(:introduccion) }
369
+
370
+ Tené en cuenta que también podés llamar al método textile desde otras
371
+ plantillas:
372
+
373
+ %h1 Hola Desde Haml!
374
+ %p= textile(:saludos)
375
+
376
+ === Plantillas RDoc
377
+
378
+ La gem/librería RDoc es necesaria para renderizar plantillas RDoc:
379
+
380
+ ## Vas a necesitar requerir rdoc en tu app
381
+ require "rdoc"
382
+
383
+ get '/' do
384
+ rdoc :index
385
+ end
386
+
387
+ Renderiza <tt>./views/index.rdoc</tt>.
388
+
389
+ No es posible llamar métodos desde rdoc, ni pasarle locales. Por lo tanto,
390
+ generalmente vas a usarlo en combinación con otro motor de renderizado:
391
+
392
+ erb :resumen, :locals => { :texto => rdoc(:introduccion) }
393
+
394
+ Tené en cuenta que también podés llamar al método rdoc desde otras
395
+ plantillas:
396
+
397
+ %h1 Hola Desde Haml!
398
+ %p= rdoc(:saludos)
399
+
400
+ === Plantillas Radius
401
+
402
+ La gem/librería radius es necesaria para renderizar plantillas Radius:
403
+
404
+ ## Vas a necesitar requerir radius en tu app
405
+ require 'radius'
406
+
407
+ get '/' do
408
+ radius :index
409
+ end
410
+
411
+ Renderiza <tt>./views/index.radius</tt>.
412
+
413
+ Como no vas a poder llamar a métodos de Ruby (excepto a +yield+) desde una
414
+ plantilla Radius, casi siempre vas a querer pasarle locales:
415
+
416
+ radius :index, :locals => { :clave => 'valor' }
417
+
418
+ === Plantillas Markaby
419
+
420
+ La gem/librería markaby es necesaria para renderizar plantillas Markaby:
421
+
422
+ ## Vas a necesitar requerir markaby en tu app
423
+ require 'markaby'
424
+
425
+ get '/' do
426
+ markaby :index
427
+ end
428
+
429
+ Renderiza <tt>./views/index.mab</tt>.
430
+
431
+ === Plantillas CoffeeScript
432
+
433
+ La gem/librería coffee-script y el binario `coffee` son necesarios para
434
+ renderizar plantillas CoffeeScript:
435
+
436
+ ## Vas a necesitar requerir coffee-script en tu app
437
+ require 'coffee-script'
438
+
439
+ get '/application.js' do
440
+ coffee :application
441
+ end
442
+
443
+ Renderiza <tt>./views/application.coffee</tt>.
444
+
445
+ === Plantillas Inline
446
+
447
+ get '/' do
448
+ haml '%div.titulo Hola Mundo'
449
+ end
450
+
451
+ Renderiza el template contenido en el string.
452
+
453
+ === Accediendo a Variables en Plantillas
454
+
455
+ Las plantillas son evaluadas dentro del mismo contexto que los manejadores de
456
+ ruta. Las variables de instancia asignadas en los manejadores de ruta son
457
+ accesibles directamente por las plantillas:
458
+
459
+ get '/:id' do
460
+ @foo = Foo.find(params[:id])
461
+ haml '%h1= @foo.nombre'
462
+ end
463
+
464
+ O es posible especificar un Hash de variables locales explícitamente:
465
+
466
+ get '/:id' do
467
+ foo = Foo.find(params[:id])
468
+ haml '%h1= foo.nombre', :locals => { :foo => foo }
469
+ end
470
+
471
+ Esto es usado típicamente cuando se renderizan plantillas como parciales desde
472
+ adentro de otras plantillas.
473
+
474
+ === Plantillas Inline
475
+
476
+ Las plantillas pueden ser definidas al final del archivo fuente:
477
+
478
+ require 'rubygems'
479
+ require 'sinatra'
480
+
481
+ get '/' do
482
+ haml :index
483
+ end
484
+
485
+ __END__
486
+
487
+ @@ layout
488
+ %html
489
+ = yield
490
+
491
+ @@ index
492
+ %div.titulo Hola mundo!!!!!
493
+
494
+ NOTA: únicamente las plantillas inline definidas en el archivo fuente que
495
+ requiere sinatra son cargadas automáticamente. Llamá <tt>enable
496
+ :inline_templates</tt> explícitamente si tenés plantillas inline en otros
497
+ archivos fuente.
498
+
499
+ === Plantillas Nombradas
500
+
501
+ Las plantillas también pueden ser definidas usando el método top-level
502
+ <tt>template</tt>:
503
+
504
+ template :layout do
505
+ "%html\n =yield\n"
506
+ end
507
+
508
+ template :index do
509
+ '%div.titulo Hola Mundo!'
510
+ end
511
+
512
+ get '/' do
513
+ haml :index
514
+ end
515
+
516
+ Si existe una plantilla con el nombre "layout", va a ser usada cada vez que
517
+ una plantilla es renderizada. Podés desactivar los layouts pasando
518
+ <tt>:layout => false</tt>.
519
+
520
+ get '/' do
521
+ haml :index, :layout => !request.xhr?
522
+ end
523
+
524
+ == Ayudantes
525
+
526
+ Usá el método top-level <tt>helpers</tt> para definir métodos ayudantes que
527
+ pueden ser utilizados dentro de los manejadores de rutas y las plantillas:
528
+
529
+ helpers do
530
+ def bar(nombre)
531
+ "#{nombre}bar"
532
+ end
533
+ end
534
+
535
+ get '/:nombre' do
536
+ bar(params[:nombre])
537
+ end
538
+
539
+ == Filtros
540
+
541
+ Los filtros before son evaluados antes de cada petición dentro del mismo
542
+ contexto que las rutas serán evaluadas y pueden modificar la petición y la
543
+ respuesta. Las variables de instancia asignadas en los filtros son accesibles
544
+ por las rutas y las plantillas:
545
+
546
+ before do
547
+ @nota = 'Hey!'
548
+ request.path_info = '/foo/bar/baz'
549
+ end
550
+
551
+ get '/foo/*' do
552
+ @nota #=> 'Hey!'
553
+ params[:splat] #=> 'bar/baz'
554
+ end
555
+
556
+ Los filtros after son evaluados después de cada petición dentro del mismo
557
+ contexto y también pueden modificar la petición y la respuesta. Las variables
558
+ de instancia asignadas en los filtros before y rutas son accesibles por los
559
+ filtros after:
560
+
561
+ after do
562
+ puts response.status
563
+ end
564
+
565
+ Los filtros aceptan un patrón opcional, que cuando está presente causa que los
566
+ mismos sean evaluados únicamente si el path de la petición coincide con ese
567
+ patrón:
568
+
569
+ before '/protegido/*' do
570
+ autenticar!
571
+ end
572
+
573
+ after '/crear/:slug' do |slug|
574
+ session[:ultimo_slug] = slug
575
+ end
576
+
577
+ == Interrupción
578
+
579
+ Para detener inmediatamente una petición dentro de un filtro o una ruta usá:
580
+
581
+ halt
582
+
583
+ También podés especificar el estado:
584
+
585
+ halt 410
586
+
587
+ O el cuerpo:
588
+
589
+ halt 'esto va a ser el cuerpo'
590
+
591
+ O los dos:
592
+
593
+ halt 401, 'salí de acá!'
594
+
595
+ Con cabeceras:
596
+
597
+ halt 402, { 'Content-Type' => 'text/plain' }, 'venganza'
598
+
599
+ == Paso
600
+
601
+ Una ruta puede pasarle el procesamiento a la siguiente ruta que coincida con
602
+ la petición usando <tt>pass</tt>:
603
+
604
+ get '/adivina/:quien' do
605
+ pass unless params[:quien] == 'Franco'
606
+ 'Adivinaste!'
607
+ end
608
+
609
+ get '/adivina/*' do
610
+ 'Erraste!'
611
+ end
612
+
613
+ Se sale inmediatamente del bloque de la ruta y se le pasa el control a la
614
+ siguiente ruta que coincida. Si no coincide ninguna ruta, se devuelve un 404.
615
+
616
+ == Accediendo al objeto de la petición
617
+
618
+ El objeto de la petición entrante puede ser accedido desde el nivel de la
619
+ petición (filtros, rutas y manejadores de errores) a través del método
620
+ `request`:
621
+
622
+ # app corriendo en http://ejemplo.com/ejemplo
623
+ get '/foo' do
624
+ request.body # cuerpo de la petición enviado por el cliente (ver más abajo)
625
+ request.scheme # "http"
626
+ request.script_name # "/ejemplo"
627
+ request.path_info # "/foo"
628
+ request.port # 80
629
+ request.request_method # "GET"
630
+ request.query_string # ""
631
+ request.content_length # longitud de request.body
632
+ request.media_type # tipo de medio de request.body
633
+ request.host # "ejemplo.com"
634
+ request.get? # verdadero (hay métodos análogos para los otros verbos)
635
+ request.form_data? # falso
636
+ request["UNA_CABECERA"] # valor de la cabecera UNA_CABECERA
637
+ request.referer # la referencia del cliente o '/'
638
+ request.user_agent # user agent (usado por la condición :agent)
639
+ request.cookies # hash de las cookies del browser
640
+ request.xhr? # es una petición ajax?
641
+ request.url # "http://ejemplo.com/ejemplo/foo"
642
+ request.path # "/ejemplo/foo"
643
+ request.ip # dirección IP del cliente
644
+ request.secure? # falso
645
+ requuest.env # hash de entorno directamente entregado por Rack
646
+ end
647
+
648
+ Algunas opciones, como <tt>script_name</tt> o <tt>path_info</tt> pueden
649
+ también ser escritas:
650
+
651
+ before { request.path_info = "/" }
652
+
653
+ get "/" do
654
+ "todas las peticiones llegan acá"
655
+ end
656
+
657
+ El objeto <tt>request.body</tt> es una instancia de IO o StringIO:
658
+
659
+ post "/api" do
660
+ request.body.rewind # en caso de que alguien ya lo haya leído
661
+ datos = JSON.parse request.body.read
662
+ "Hola #{datos['nombre']}!"
663
+ end
664
+
665
+ == Configuración
666
+
667
+ Ejecutar una vez, en el inicio, en cualquier entorno:
668
+
669
+ configure do
670
+ ...
671
+ end
672
+
673
+ Ejecutar únicamente cuando el entorno (la variable de entorno RACK_ENV) es
674
+ <tt>:production</tt>:
675
+
676
+ configure :production do
677
+ ...
678
+ end
679
+
680
+ Ejecutar cuando el entorno es <tt>:production</tt> o <tt>:test</tt>:
681
+
682
+ configure :production, :test do
683
+ ...
684
+ end
685
+
686
+ == Manejo de errores
687
+
688
+ Los manejadores de errores se ejecutan dentro del mismo contexto que las rutas
689
+ y los filtros before, lo que significa que podés usar, por ejemplo,
690
+ <tt>haml</tt>, <tt>erb</tt>, <tt>halt</tt>, etc.
691
+
692
+ === No encontrado <em>(Not Found)</em>
693
+
694
+ Cuando se eleva una excepción <tt>Sinatra::NotFound</tt>, o el código de
695
+ estado de la respuesta es 404, el manejador <tt>not_found</tt> es invocado:
696
+
697
+ not_found do
698
+ 'No existo'
699
+ end
700
+
701
+ === Error
702
+
703
+ El manejador +error+ es invocado cada vez que una excepción es elevada
704
+ desde un bloque de ruta o un filtro. El objeto de la excepción se puede
705
+ obtener de la variable Rack <tt>sinatra.error</tt>:
706
+
707
+ error do
708
+ 'Disculpá, ocurrió un error horrible - ' + env['sinatra.error'].name
709
+ end
710
+
711
+ Errores personalizados:
712
+
713
+ error MiErrorPersonalizado do
714
+ 'Lo que pasó fue...' request.env['sinatra.error'].message
715
+ end
716
+
717
+ Entonces, si pasa esto:
718
+
719
+ get '/' do
720
+ raise MiErrorPersonalizado, 'algo malo'
721
+ end
722
+
723
+ Obtenés esto:
724
+
725
+ Lo que pasó fue... algo malo
726
+
727
+ También, podés instalar un manejador de errores para un código de estado:
728
+
729
+ error 403 do
730
+ 'Acceso prohibido'
731
+ end
732
+
733
+ get '/secreto' do
734
+ 403
735
+ end
736
+
737
+ O un rango:
738
+
739
+ error 400..510 do
740
+ 'Boom'
741
+ end
742
+
743
+ Sinatra instala manejadores <tt>not_found</tt> y <tt>error</ttt> especiales
744
+ cuando se ejecuta dentro del entorno de desarrollo "development".
745
+
746
+ == Tipos Mime
747
+
748
+ Cuando usás <tt>send_file</tt> o archivos estáticos tal vez tengas tipos mime
749
+ que Sinatra no entiende. Usá +mime_type+ para registrarlos a través de la
750
+ extensión de archivo:
751
+
752
+ mime_type :foo, 'text/foo'
753
+
754
+ También lo podés usar con el ayudante +content_type+:
755
+
756
+ content_type :foo
757
+
758
+ == Rack Middleware
759
+
760
+ Sinatra corre sobre Rack[http://rack.rubyforge.org/], una interfaz minimalista
761
+ que es un estándar para frameworks webs escritos en Ruby. Una de las
762
+ capacidades más interesantes de Rack para los desarrolladores de aplicaciones
763
+ es el soporte de "middleware" -- componentes que se ubican entre el servidor y
764
+ tu aplicación, supervisando y/o manipulando la petición/respuesta HTTP para
765
+ proporcionar varios tipos de funcionalidades comunes.
766
+
767
+ Sinatra hace muy sencillo construir tuberías de Rack middleware a través del
768
+ método top-level +use+:
769
+
770
+ require 'sinatra'
771
+ require 'mi_middleware_personalizado'
772
+
773
+ use Rack::Lint
774
+ use MiMiddlewarePersonalizado
775
+
776
+ get '/hola' do
777
+ 'Hola Mundo'
778
+ end
779
+
780
+ Las semánticas de +use+ son idénticas a las definidas para el DSL
781
+ Rack::Builder[http://rack.rubyforge.org/doc/classes/Rack/Builder.html] (más
782
+ frecuentemente usado desde archivos rackup). Por ejemplo, el método +use+
783
+ acepta argumentos múltiples/variables así como bloques:
784
+
785
+ use Rack::Auth::Basic do |nombre_de_usuario, password|
786
+ nombre_de_usuario == 'admin' && password == 'secreto'
787
+ end
788
+
789
+ Rack es distribuido con una variedad de middleware estándar para logging,
790
+ debugging, enrutamiento URL, autenticación, y manejo de sesiones. Sinatra
791
+ usa muchos de estos componentes automáticamente de acuerdo a su configuración
792
+ para que típicamente no tengas que usarlas (con +use+) explícitamente.
793
+
794
+ == Pruebas
795
+
796
+ Las pruebas para las aplicaciones Sinatra pueden ser escritas utilizando
797
+ cualquier framework o librería de pruebas basada en Rack. Se recomienda usar
798
+ {Rack::Test}[http://gitrdoc.com/brynary/rack-test]:
799
+
800
+ require 'mi_app_sinatra'
801
+ require 'test/unit'
802
+ require 'rack/test'
803
+
804
+ class MiAppTest < Test::Unit::TestCase
805
+ include Rack::Test::Methods
806
+
807
+ def app
808
+ Sinatra::Application
809
+ end
810
+
811
+ def test_mi_defecto
812
+ get '/'
813
+ assert_equal 'Hola Mundo!', last_response.body
814
+ end
815
+
816
+ def test_con_parametros
817
+ get '/saludar', :name => 'Franco'
818
+ assert_equal 'Hola Frank!', last_response.body
819
+ end
820
+
821
+ def test_con_entorno_rack
822
+ get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
823
+ assert_equal "Estás usando Songbird!", last_response.body
824
+ end
825
+ end
826
+
827
+ NOTA: El módulo Sinatra::Test y la clase Sinatra::TestHarness están
828
+ deprecados a partir de la versión 0.9.2.
829
+
830
+ == Sinatra::Base - Middleware, Librerías, y Aplicaciones Modulares
831
+
832
+ Definir tu aplicación en el top-level funciona bien para micro-aplicaciones
833
+ pero trae inconvenientes considerables a la hora de construir componentes
834
+ reutilizables como Rack middleware, Rails metal, simple librerías con un
835
+ componente de servidor, o incluso extensiones de Sinatra. El DSL de top-level
836
+ contamina el espacio de nombres de Object y asume una configuración apropiada
837
+ para micro-aplicaciones (por ejemplo, un único archivo de aplicación, los
838
+ directorios ./public y ./views, logging, página con detalles de excepción,
839
+ etc.). Ahí es donde Sinatra::Base entra en el juego:
840
+
841
+ require 'sinatra/base'
842
+
843
+ class MiApp < Sinatra::Base
844
+ set :sessions, true
845
+ set :foo, 'bar'
846
+
847
+ get '/' do
848
+ 'Hola Mundo!'
849
+ end
850
+ end
851
+
852
+ La clase MiApp es un componente Rack independiente que puede actuar como Rack
853
+ middleware, una aplicación Rack, o Rails metal. Podés usar (con +use+) o
854
+ ejecutar (con +run+) esta clase desde un archivo rackup +config.ru+; o,
855
+ controlar un componente de servidor provisto como una librería:
856
+
857
+ MiApp.run! :host => 'localhost', :port => 9090
858
+
859
+ Las subclases de Sinatra::Base tienen disponibles exactamente los mismos
860
+ métodos que los provistos por el DSL de top-level. La mayoría de las
861
+ aplicaciones top-level se pueden convertir en componentes Sinatra::Base con
862
+ dos modificaciones:
863
+
864
+ * Tu archivo debe requerir +sinatra/base+ en lugar de +sinatra+; de otra
865
+ manera, todos los métodos del DSL de sinatra son importados dentro del
866
+ espacio de nombres principal.
867
+ * Poné las rutas, manejadores de errores, filtros y opciones de tu aplicación
868
+ en una subclase de Sinatra::Base.
869
+
870
+ <tt>Sinatra::Base</tt> es una pizarra en blanco. La mayoría de las opciones están
871
+ desactivadas por defecto, incluyendo el servidor incorporado. Mirá
872
+ {Opciones y Configuraciones}[http://sinatra.github.com/configuration.html]
873
+ para detalles sobre las opciones disponibles y su comportamiento.
874
+
875
+ === Utilizando Sinatra como Middleware
876
+
877
+ Sinatra no solo es capaz de usar otro Rack middleware, sino que a su vez,
878
+ cualquier aplicación Sinatra puede ser agregada delante de un endpoint Rack
879
+ como middleware. Este endpoint puede ser otra aplicación Sinatra, o cualquier
880
+ aplicación basada en Rack (Rails/Ramaze/Camping/...).
881
+
882
+ require 'sinatra/base'
883
+
884
+ class PantallaDeLogin< Sinatra::Base
885
+ enable :session
886
+
887
+ get('/login') { haml :login }
888
+
889
+ post('/login') do
890
+ if params[:nombre] = 'admin' and params[:password] = 'admin'
891
+ session['nombre_de_usuario'] = params[:nombre]
892
+ else
893
+ redirect '/login'
894
+ end
895
+ end
896
+ end
897
+
898
+ class MiApp < Sinatra::Base
899
+ # el middleware se ejecutará antes que los filtros
900
+ use PantallaDeLogin
901
+
902
+ before do
903
+ unless session['nombre_de_usuario']
904
+ halt "Acceso denegado, por favor <a href='/login'>iniciá sesión</a>."
905
+ end
906
+ end
907
+
908
+ get('/') { "Hola #{session['nombre_de_usuario']}." }
909
+ end
910
+
911
+ == Ámbitos y Ligaduras
912
+
913
+ El ámbito en el que te encontrás determina que métodos y variables están
914
+ disponibles.
915
+
916
+ === Ámbito de Aplicación/Clase
917
+
918
+ Cada aplicación Sinatra es una subclase de Sinatra::Base. Si estás usando el
919
+ DSL de top-level (<tt>require 'sinatra'</tt>), entonces esta clase es
920
+ Sinatra::Application, de otra manera es la subclase que creaste explícitamente.
921
+ Al nivel de la clase tenés métodos como `get` o `before`, pero no podés acceder
922
+ a los objetos `request` o `session`, ya que hay una única clase de la
923
+ aplicación para todas las peticiones.
924
+
925
+ Las opciones creadas utilizando `set` son métodos al nivel de la clase:
926
+
927
+ class MiApp << Sinatra::Base
928
+ # Ey, estoy en el ámbito de la aplicación!
929
+ set :foo, 42
930
+ foo # => 42
931
+
932
+ get '/foo' do
933
+ # Hey, ya no estoy en el ámbito de la aplicación!
934
+ end
935
+ end
936
+
937
+ Tenés la ligadura al ámbito de la aplicación dentro de:
938
+
939
+ * El cuerpo de la clase de tu aplicación
940
+ * Métodos definidos por extensiones
941
+ * El bloque pasado a `helpers`
942
+ * Procs/bloques usados como el valor para `set`
943
+
944
+ Este ámbito puede alcanzarse de las siguientes maneras:
945
+
946
+ * A través del objeto pasado a los bloques de configuración (<tt>configure { |c| ...}</tt>)
947
+ * Llamando a `settings` desde dentro del ámbito de la petición
948
+
949
+ === Ámbito de Petición/Instancia
950
+
951
+ Para cada petición entrante, una nueva instancia de la clase de tu aplicación
952
+ es creada y todos los bloques de rutas son ejecutados en ese ámbito. Desde este
953
+ ámbito podés acceder a los objetos `request` y `session` o llamar a los métodos
954
+ de renderización como `erb` o `haml`. Podés acceder al ámbito de la aplicación
955
+ desde el ámbito de la petición utilizando `settings`:
956
+
957
+ class MiApp << Sinatra::Base
958
+ # Ey, estoy en el ámbito de la aplicación!
959
+ get '/definir_ruta/:nombre' do
960
+ # Ámbito de petición para '/definir_ruta/:nombre'
961
+ @valor = 42
962
+
963
+ settings.get("/#{params[:nombre]}") do
964
+ # Ámbito de petición para "/#{params[:nombre]}"
965
+ @valor # => nil (no es la misma petición)
966
+ end
967
+
968
+ "Ruta definida!"
969
+ end
970
+ end
971
+
972
+ Tenés la ligadura al ámbito de la petición dentro de:
973
+
974
+ * bloques pasados a get/head/post/put/delete
975
+ * filtros before/after
976
+ * métodos ayudantes
977
+ * plantillas/vistas
978
+
979
+ === Ámbito de Delegación
980
+
981
+ El ámbito de delegación solo reenvía métodos al ámbito de clase. De cualquier
982
+ manera, no se comporta 100% como el ámbito de clase porque no tenés la ligadura
983
+ de la clase: únicamente métodos marcados explícitamente para delegación están
984
+ disponibles y no compartís variables/estado con el ámbito de clase (léase:
985
+ tenés un `self` diferente). Podés agregar delegaciones de método llamando a
986
+ <tt>Sinatra::Delegator.delegate :nombre_del_metodo</tt>.
987
+
988
+ Tenés la ligadura al ámbito de delegación dentro de:
989
+
990
+ * La ligadura del top-level, si hiciste <tt>require "sinatra"</tt>
991
+ * Un objeto extendido con el mixin `Sinatra::Delegator`
992
+
993
+ Pegale una mirada al código: acá está el
994
+ {Sinatra::Delegator mixin}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/base.rb#L1128]
995
+ que es {incluido en el espacio de nombres principal}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/main.rb#L28].
996
+
997
+ == Línea de comandos
998
+
999
+ Las aplicaciones Sinatra pueden ser ejecutadas directamente:
1000
+
1001
+ ruby miapp.rb [-h] [-x] [-e ENTORNO] [-p PUERTO] [-o HOST] [-s MANEJADOR]
1002
+
1003
+ Las opciones son:
1004
+
1005
+ -h # ayuda
1006
+ -p # asigna el puerto (4567 es usado por defecto)
1007
+ -o # asigna el host (0.0.0.0 es usado por defecto)
1008
+ -e # asigna el entorno (development es usado por defecto)
1009
+ -s # especifica el servidor/manejador rack (thin es usado por defecto)
1010
+ -x # activa el mutex lock (está desactivado por defecto)
1011
+
1012
+ == A la vanguardia
1013
+
1014
+ Si querés usar el código de Sinatra más reciente, cloná el repositorio
1015
+ localmente y ejecutá tu aplicación, asegurándote que el directorio
1016
+ <tt>sinatra/lib</tt> esté en el <tt>LOAD_PATH</tt>:
1017
+
1018
+ cd miapp
1019
+ git clone git://github.com/sinatra/sinatra.git
1020
+ ruby -Isinatra/lib miapp.rb
1021
+
1022
+ Otra opción consiste en agregar el directorio <tt>sinatra/lib</tt> al
1023
+ <tt>LOAD_PATH</tt> dentro de tu aplicación:
1024
+
1025
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
1026
+ require 'rubygems'
1027
+ require 'sinatra'
1028
+
1029
+ get '/acerca-de' do
1030
+ "Estoy usando la versión " + Sinatra::VERSION
1031
+ end
1032
+
1033
+ Para actualizar el código fuente de Sinatra en el futuro:
1034
+
1035
+ cd miproyecto/sinatra
1036
+ git pull
1037
+
1038
+ == Más
1039
+
1040
+ * {Sito web del proyecto}[http://www.sinatrarb.com/] - Documentación
1041
+ adicional, noticias, y enlaces a otros recursos.
1042
+ * {Contribuyendo}[http://www.sinatrarb.com/contributing] - ¿Encontraste un
1043
+ error?. ¿Necesitás ayuda?. ¿Tenés un parche?.
1044
+ * {Seguimiento de problemas}[http://github.com/sinatra/sinatra/issues]
1045
+ * {Twitter}[http://twitter.com/sinatra]
1046
+ * {Lista de Correo}[http://groups.google.com/group/sinatrarb/topics]
1047
+ * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] en http://freenode.net