sinatra 1.1.4 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +5 -1
- data/CHANGES +47 -2
- data/Gemfile +53 -0
- data/README.de.rdoc +732 -85
- data/README.es.rdoc +725 -75
- data/README.fr.rdoc +29 -16
- data/README.hu.rdoc +4 -4
- data/README.jp.rdoc +29 -16
- data/README.pt-br.rdoc +6 -6
- data/README.rdoc +664 -91
- data/README.ru.rdoc +257 -75
- data/README.zh.rdoc +889 -111
- data/Rakefile +7 -32
- data/lib/sinatra/base.rb +133 -66
- data/lib/sinatra/showexceptions.rb +25 -0
- data/sinatra.gemspec +10 -18
- data/test/builder_test.rb +6 -0
- data/test/coffee_test.rb +1 -1
- data/test/encoding_test.rb +4 -3
- data/test/erubis_test.rb +6 -0
- data/test/filter_test.rb +105 -1
- data/test/haml_test.rb +2 -1
- data/test/helper.rb +2 -0
- data/test/helpers_test.rb +105 -13
- data/test/less_test.rb +6 -0
- data/test/liquid_test.rb +2 -1
- data/test/markaby_test.rb +23 -1
- data/test/markdown_test.rb +3 -2
- data/test/nokogiri_test.rb +2 -1
- data/test/radius_test.rb +3 -2
- data/test/rdoc_test.rb +3 -2
- data/test/routing_test.rb +38 -1
- data/test/sass_test.rb +1 -1
- data/test/scss_test.rb +1 -1
- data/test/slim_test.rb +98 -0
- data/test/templates_test.rb +53 -0
- data/test/textile_test.rb +2 -1
- data/test/views/a/in_a.str +1 -0
- data/test/views/{ascii.haml → ascii.erb} +1 -1
- data/test/views/b/in_b.str +1 -0
- data/test/views/hello.slim +1 -0
- data/test/views/layout2.slim +3 -0
- data/test/views/{utf8.haml → utf8.erb} +1 -1
- metadata +42 -161
data/README.es.rdoc
CHANGED
|
@@ -18,6 +18,9 @@ Instalá la gem y ejecutá la aplicación con:
|
|
|
18
18
|
|
|
19
19
|
Podés verla en: http://localhost:4567
|
|
20
20
|
|
|
21
|
+
Es recomendable además ejecutar <tt>gem install thin</tt>, ya que Sinatra lo va
|
|
22
|
+
a utilizar cuando esté disponible.
|
|
23
|
+
|
|
21
24
|
== Rutas
|
|
22
25
|
|
|
23
26
|
En Sinatra, una ruta está compuesta por un método HTTP y un patrón de una URL.
|
|
@@ -39,6 +42,11 @@ Cada ruta se asocia con un bloque:
|
|
|
39
42
|
.. aniquilar algo ..
|
|
40
43
|
end
|
|
41
44
|
|
|
45
|
+
options '/' do
|
|
46
|
+
.. informar algo ..
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
|
|
42
50
|
Las rutas son comparadas en el orden en el que son definidas. La primer ruta
|
|
43
51
|
que coincide con la petición es invocada.
|
|
44
52
|
|
|
@@ -121,7 +129,7 @@ Podés definir tus propias condiciones fácilmente:
|
|
|
121
129
|
"Lo siento, perdiste."
|
|
122
130
|
end
|
|
123
131
|
|
|
124
|
-
=== Valores de
|
|
132
|
+
=== Valores de Retorno
|
|
125
133
|
|
|
126
134
|
El valor de retorno de un bloque de ruta determina al menos el cuerpo de la
|
|
127
135
|
respuesta que se le pasa al cliente HTTP o al siguiente middleware en la pila
|
|
@@ -146,6 +154,47 @@ De esa manera podemos, por ejemplo, implementar fácilmente un streaming:
|
|
|
146
154
|
|
|
147
155
|
get('/') { Stream.new }
|
|
148
156
|
|
|
157
|
+
=== Comparadores de Rutas Personalizados
|
|
158
|
+
|
|
159
|
+
Como se mostró anteriormente, Sinatra permite utilizar Strings y expresiones
|
|
160
|
+
regulares para definir las rutas. Sin embargo, la cosa no termina ahí. Podés
|
|
161
|
+
definir tus propios comparadores muy fácilmente:
|
|
162
|
+
|
|
163
|
+
class PattronCualquieraMenos
|
|
164
|
+
Match = Struct.new(:captures)
|
|
165
|
+
|
|
166
|
+
def initialize(excepto)
|
|
167
|
+
@excepto = excepto
|
|
168
|
+
@caputras = Match.new([])
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def match(str)
|
|
172
|
+
@caputras unless @excepto === str
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def cualquiera_menos(patron)
|
|
177
|
+
PatronCualquieraMenos.new(patron)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
get cualquiera_menos("/index") do
|
|
181
|
+
# ...
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
Tené en cuenta que el ejemplo anterior es un poco rebuscado. Un resultado
|
|
185
|
+
similar puede conseguirse más sencillamente:
|
|
186
|
+
|
|
187
|
+
get // do
|
|
188
|
+
pass if request.path_info == "/index"
|
|
189
|
+
# ...
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
O, usando un lookahead negativo:
|
|
193
|
+
|
|
194
|
+
get %r{^(?!/index$)} do
|
|
195
|
+
# ...
|
|
196
|
+
end
|
|
197
|
+
|
|
149
198
|
== Archivos Estáticos
|
|
150
199
|
|
|
151
200
|
Los archivos estáticos son servidos desde el directorio público
|
|
@@ -175,7 +224,7 @@ les pase como argumento.
|
|
|
175
224
|
|
|
176
225
|
La gem/librería <tt>haml</tt> es necesaria para para renderizar plantillas HAML:
|
|
177
226
|
|
|
178
|
-
|
|
227
|
+
# Vas a necesitar requerir haml en tu app
|
|
179
228
|
require 'haml'
|
|
180
229
|
|
|
181
230
|
get '/' do
|
|
@@ -197,7 +246,7 @@ y reemplazadas individualmente.
|
|
|
197
246
|
|
|
198
247
|
=== Plantillas Erb
|
|
199
248
|
|
|
200
|
-
|
|
249
|
+
# Vas a necesitar requerir erb en tu app
|
|
201
250
|
require 'erb'
|
|
202
251
|
|
|
203
252
|
get '/' do
|
|
@@ -210,7 +259,7 @@ Renderiza <tt>./views/index.erb</tt>
|
|
|
210
259
|
|
|
211
260
|
La gem/librería <tt>erubis</tt> es necesaria para renderizar plantillas Erubis:
|
|
212
261
|
|
|
213
|
-
|
|
262
|
+
# Vas a necesitar requerir erubis en tu app
|
|
214
263
|
require 'erubis'
|
|
215
264
|
|
|
216
265
|
get '/' do
|
|
@@ -235,7 +284,7 @@ Renderiza <tt>./views/index.erb</tt> con Erubis.
|
|
|
235
284
|
La gem/librería <tt>builder</tt> es necesaria para renderizar plantillas
|
|
236
285
|
builder:
|
|
237
286
|
|
|
238
|
-
|
|
287
|
+
# Vas a necesitar requerir builder en tu app
|
|
239
288
|
require 'builder'
|
|
240
289
|
|
|
241
290
|
get '/' do
|
|
@@ -249,7 +298,7 @@ Renderiza <tt>./views/index.builder</tt>.
|
|
|
249
298
|
La gem/librería <tt>nokogiri</tt> es necesaria para renderizar plantillas
|
|
250
299
|
nokogiri:
|
|
251
300
|
|
|
252
|
-
|
|
301
|
+
# Vas a necesitar requerir nokogiri en tu app
|
|
253
302
|
require 'nokogiri'
|
|
254
303
|
|
|
255
304
|
get '/' do
|
|
@@ -263,7 +312,7 @@ Renderiza <tt>./views/index.nokogiri</tt>.
|
|
|
263
312
|
La gem/librería <tt>haml</tt> o <tt>sass</tt> es necesaria para renderizar
|
|
264
313
|
plantillas Sass:
|
|
265
314
|
|
|
266
|
-
|
|
315
|
+
# Vas a necesitar requerir haml o sass en tu app
|
|
267
316
|
require 'sass'
|
|
268
317
|
|
|
269
318
|
get '/stylesheet.css' do
|
|
@@ -288,7 +337,7 @@ y reemplazadas individualmente.
|
|
|
288
337
|
La gem/librería <tt>haml</tt> o <tt>sass</tt>es necesaria para renderizar
|
|
289
338
|
plantillas Scss:
|
|
290
339
|
|
|
291
|
-
|
|
340
|
+
# Vas a necesitar requerir haml o sass en tu app
|
|
292
341
|
require 'sass'
|
|
293
342
|
|
|
294
343
|
get '/stylesheet.css' do
|
|
@@ -312,7 +361,7 @@ y reemplazadas individualmente.
|
|
|
312
361
|
|
|
313
362
|
La gem/librería <tt>less</tt> es necesaria para renderizar plantillas Less:
|
|
314
363
|
|
|
315
|
-
|
|
364
|
+
# Vas a necesitar requerir less en tu app
|
|
316
365
|
require 'less'
|
|
317
366
|
|
|
318
367
|
get '/stylesheet.css' do
|
|
@@ -325,7 +374,7 @@ Renderiza <tt>./views/stylesheet.less</tt>.
|
|
|
325
374
|
|
|
326
375
|
La gem/librería <tt>liquid</tt> es necesaria para renderizar plantillas Liquid:
|
|
327
376
|
|
|
328
|
-
|
|
377
|
+
# Vas a necesitar requerir liquid en tu app
|
|
329
378
|
require 'liquid'
|
|
330
379
|
|
|
331
380
|
get '/' do
|
|
@@ -344,7 +393,7 @@ plantilla Liquid, casi siempre vas a querer pasarle locales:
|
|
|
344
393
|
La gem/librería <tt>rdiscount</tt> es necesaria para renderizar plantillas
|
|
345
394
|
Markdown:
|
|
346
395
|
|
|
347
|
-
|
|
396
|
+
# Vas a necesitar requerir rdiscount en tu app
|
|
348
397
|
require "rdiscount"
|
|
349
398
|
|
|
350
399
|
get '/' do
|
|
@@ -365,6 +414,27 @@ plantillas:
|
|
|
365
414
|
%h1 Hola Desde Haml!
|
|
366
415
|
%p= markdown(:saludos)
|
|
367
416
|
|
|
417
|
+
Como no podés utilizar Ruby desde Markdown, no podés usar layouts escritos en
|
|
418
|
+
Markdown. De todos modos, es posible usar un motor de renderizado para el
|
|
419
|
+
layout distinto al de la plantilla pasando la opción <tt>:layout_engine</tt>:
|
|
420
|
+
|
|
421
|
+
get '/' do
|
|
422
|
+
markdown :index, :layout_engine => :erb
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
Renderiza <tt>./views/index.md</tt> con el layout <tt>./views/layout.erb</tt>.
|
|
426
|
+
|
|
427
|
+
Recordá que podés asignar las opciones de renderizado globalmente:
|
|
428
|
+
|
|
429
|
+
set :markdown, :layout_engine => :haml, :layout => :post
|
|
430
|
+
|
|
431
|
+
get '/' do
|
|
432
|
+
markdown :index
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
Renderiza <tt>./views/index.md</tt> (o cualquier otra plantilla Markdown) con
|
|
436
|
+
el layout <tt>./views/post.haml</tt>.
|
|
437
|
+
|
|
368
438
|
También es posible parsear Markdown con BlueCloth en lugar de RDiscount:
|
|
369
439
|
|
|
370
440
|
require 'bluecloth'
|
|
@@ -384,7 +454,7 @@ Renderiza <tt>./views/index.md</tt> con BlueCloth.
|
|
|
384
454
|
La gem/librería <tt>RedCloth</tt> es necesaria para renderizar plantillas
|
|
385
455
|
Textile:
|
|
386
456
|
|
|
387
|
-
|
|
457
|
+
# Vas a necesitar requerir redcloth en tu app
|
|
388
458
|
require "redcloth"
|
|
389
459
|
|
|
390
460
|
get '/' do
|
|
@@ -404,12 +474,34 @@ plantillas:
|
|
|
404
474
|
%h1 Hola Desde Haml!
|
|
405
475
|
%p= textile(:saludos)
|
|
406
476
|
|
|
477
|
+
Como no podés utilizar Ruby desde Textile, no podés usar layouts escritos en
|
|
478
|
+
Textile. De todos modos, es posible usar un motor de renderizado para el
|
|
479
|
+
layout distinto al de la plantilla pasando la opción <tt>:layout_engine</tt>:
|
|
480
|
+
|
|
481
|
+
get '/' do
|
|
482
|
+
textile :index, :layout_engine => :erb
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
Renderiza <tt>./views/index.textile</tt> con el layout
|
|
486
|
+
<tt>./views/layout.erb</tt>.
|
|
487
|
+
|
|
488
|
+
Recordá que podés asignar las opciones de renderizado globalmente:
|
|
489
|
+
|
|
490
|
+
set :textile, :layout_engine => :haml, :layout => :post
|
|
491
|
+
|
|
492
|
+
get '/' do
|
|
493
|
+
textile :index
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
Renderiza <tt>./views/index.textile</tt> (o cualquier otra plantilla Textile)
|
|
497
|
+
con el layout <tt>./views/post.haml</tt>.
|
|
498
|
+
|
|
407
499
|
=== Plantillas RDoc
|
|
408
500
|
|
|
409
501
|
La gem/librería <tt>rdoc</tt> es necesaria para renderizar plantillas RDoc:
|
|
410
502
|
|
|
411
|
-
|
|
412
|
-
require "rdoc"
|
|
503
|
+
# Vas a necesitar requerir rdoc/markup/to_html en tu app
|
|
504
|
+
require "rdoc/markup/to_html"
|
|
413
505
|
|
|
414
506
|
get '/' do
|
|
415
507
|
rdoc :index
|
|
@@ -428,11 +520,32 @@ plantillas:
|
|
|
428
520
|
%h1 Hola Desde Haml!
|
|
429
521
|
%p= rdoc(:saludos)
|
|
430
522
|
|
|
523
|
+
Como no podés utilizar Ruby desde RDoc, no podés usar layouts escritos en RDoc.
|
|
524
|
+
De todos modos, es posible usar un motor de renderizado para el layout distinto
|
|
525
|
+
al de la plantilla pasando la opción <tt>:layout_engine</tt>:
|
|
526
|
+
|
|
527
|
+
get '/' do
|
|
528
|
+
rdoc :index, :layout_engine => :erb
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
Renderiza <tt>./views/index.rdoc</tt> con el layout <tt>./views/layout.erb</tt>.
|
|
532
|
+
|
|
533
|
+
Recordá que podés asignar las opciones de renderizado globalmente:
|
|
534
|
+
|
|
535
|
+
set :rdoc, :layout_engine => :haml, :layout => :post
|
|
536
|
+
|
|
537
|
+
get '/' do
|
|
538
|
+
rdoc :index
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
Renderiza <tt>./views/index.rdoc</tt> (o cualquier otra plantilla RDoc) con el
|
|
542
|
+
layout <tt>./views/post.haml</tt>.
|
|
543
|
+
|
|
431
544
|
=== Plantillas Radius
|
|
432
545
|
|
|
433
546
|
La gem/librería <tt>radius</tt> es necesaria para renderizar plantillas Radius:
|
|
434
547
|
|
|
435
|
-
|
|
548
|
+
# Vas a necesitar requerir radius en tu app
|
|
436
549
|
require 'radius'
|
|
437
550
|
|
|
438
551
|
get '/' do
|
|
@@ -451,7 +564,7 @@ plantilla Radius, casi siempre vas a querer pasarle locales:
|
|
|
451
564
|
La gem/librería <tt>markaby</tt> es necesaria para renderizar plantillas
|
|
452
565
|
Markaby:
|
|
453
566
|
|
|
454
|
-
|
|
567
|
+
# Vas a necesitar requerir markaby en tu app
|
|
455
568
|
require 'markaby'
|
|
456
569
|
|
|
457
570
|
get '/' do
|
|
@@ -460,6 +573,26 @@ Markaby:
|
|
|
460
573
|
|
|
461
574
|
Renderiza <tt>./views/index.mab</tt>.
|
|
462
575
|
|
|
576
|
+
También podés usar Markaby inline:
|
|
577
|
+
|
|
578
|
+
get '/' do
|
|
579
|
+
markaby { h1 "Bienvenido!" }
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
=== Plantillas Slim
|
|
584
|
+
|
|
585
|
+
La gem/librería <tt>slim</tt> es necesaria para renderizar plantillas Slim:
|
|
586
|
+
|
|
587
|
+
# Vas a necesitar requerir slim en tu app
|
|
588
|
+
require 'slim'
|
|
589
|
+
|
|
590
|
+
get '/' do
|
|
591
|
+
slim :index
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
Renderiza <tt>./views/index.slim</tt>.
|
|
595
|
+
|
|
463
596
|
=== Plantillas CoffeeScript
|
|
464
597
|
|
|
465
598
|
La gem/librería <tt>coffee-script</tt> y al menos <b>una</b> de las siguientes
|
|
@@ -471,7 +604,7 @@ opciones para ejecutar JavaScript:
|
|
|
471
604
|
|
|
472
605
|
son necesarios para renderizar plantillas CoffeeScript:
|
|
473
606
|
|
|
474
|
-
|
|
607
|
+
# Vas a necesitar requerir coffee-script en tu app
|
|
475
608
|
require 'coffee-script'
|
|
476
609
|
|
|
477
610
|
get '/application.js' do
|
|
@@ -585,27 +718,12 @@ Primero, registrá tu motor con Tilt, y después, creá tu método de renderizad
|
|
|
585
718
|
Renderiza <tt>./views/index.mypg</tt>. Mirá https://github.com/rtomayko/tilt
|
|
586
719
|
para aprender más de Tilt.
|
|
587
720
|
|
|
588
|
-
== Ayudantes
|
|
589
|
-
|
|
590
|
-
Usá el método top-level <tt>helpers</tt> para definir métodos ayudantes que
|
|
591
|
-
pueden ser utilizados dentro de los manejadores de rutas y las plantillas:
|
|
592
|
-
|
|
593
|
-
helpers do
|
|
594
|
-
def bar(nombre)
|
|
595
|
-
"#{nombre}bar"
|
|
596
|
-
end
|
|
597
|
-
end
|
|
598
|
-
|
|
599
|
-
get '/:nombre' do
|
|
600
|
-
bar(params[:nombre])
|
|
601
|
-
end
|
|
602
|
-
|
|
603
721
|
== Filtros
|
|
604
722
|
|
|
605
|
-
Los filtros before son evaluados antes de cada petición dentro del mismo
|
|
606
|
-
contexto que las rutas
|
|
607
|
-
|
|
608
|
-
|
|
723
|
+
Los filtros +before+ son evaluados antes de cada petición dentro del mismo
|
|
724
|
+
contexto que las rutas. Pueden modificar la petición y la respuesta. Las
|
|
725
|
+
variables de instancia asignadas en los filtros son accesibles por las rutas y
|
|
726
|
+
las plantillas:
|
|
609
727
|
|
|
610
728
|
before do
|
|
611
729
|
@nota = 'Hey!'
|
|
@@ -617,15 +735,19 @@ por las rutas y las plantillas:
|
|
|
617
735
|
params[:splat] #=> 'bar/baz'
|
|
618
736
|
end
|
|
619
737
|
|
|
620
|
-
Los filtros after son evaluados después de cada petición dentro del mismo
|
|
621
|
-
contexto y también pueden modificar la petición y la respuesta.
|
|
622
|
-
de instancia asignadas en los filtros before y rutas son accesibles por
|
|
623
|
-
filtros after
|
|
738
|
+
Los filtros +after+ son evaluados después de cada petición dentro del mismo
|
|
739
|
+
contexto y también pueden modificar la petición y la respuesta. Las variables
|
|
740
|
+
de instancia asignadas en los filtros +before+ y en las rutas son accesibles por
|
|
741
|
+
los filtros +after+:
|
|
624
742
|
|
|
625
743
|
after do
|
|
626
744
|
puts response.status
|
|
627
745
|
end
|
|
628
746
|
|
|
747
|
+
Nota: A menos que usés el método +body+ en lugar de simplemente devolver un
|
|
748
|
+
string desde una ruta, el cuerpo de la respuesta no va a estar disponible en
|
|
749
|
+
un filtro after, debido a que todavía no se ha generado.
|
|
750
|
+
|
|
629
751
|
Los filtros aceptan un patrón opcional, que cuando está presente causa que los
|
|
630
752
|
mismos sean evaluados únicamente si el path de la petición coincide con ese
|
|
631
753
|
patrón:
|
|
@@ -638,7 +760,63 @@ patrón:
|
|
|
638
760
|
session[:ultimo_slug] = slug
|
|
639
761
|
end
|
|
640
762
|
|
|
641
|
-
|
|
763
|
+
Al igual que las rutas, los filtros también pueden aceptar condiciones:
|
|
764
|
+
|
|
765
|
+
before :agent => /Songbird/ do
|
|
766
|
+
# ...
|
|
767
|
+
end
|
|
768
|
+
|
|
769
|
+
after '/blog/*', :host_name => 'ejemplo.com' do
|
|
770
|
+
# ...
|
|
771
|
+
end
|
|
772
|
+
|
|
773
|
+
== Ayudantes
|
|
774
|
+
|
|
775
|
+
Usá el método top-level <tt>helpers</tt> para definir métodos ayudantes que
|
|
776
|
+
pueden ser utilizados dentro de los manejadores de rutas y las plantillas:
|
|
777
|
+
|
|
778
|
+
helpers do
|
|
779
|
+
def bar(nombre)
|
|
780
|
+
"#{nombre}bar"
|
|
781
|
+
end
|
|
782
|
+
end
|
|
783
|
+
|
|
784
|
+
get '/:nombre' do
|
|
785
|
+
bar(params[:nombre])
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
=== Usando Sesiones
|
|
789
|
+
|
|
790
|
+
Una sesión es usada para mantener el estado a través de distintas peticiones.
|
|
791
|
+
Cuando están activadas, tenés un hash de sesión para cada sesión de usuario:
|
|
792
|
+
|
|
793
|
+
enable :sessions
|
|
794
|
+
|
|
795
|
+
get '/' do
|
|
796
|
+
"valor = " << session[:valor].inspect
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
get '/:valor' do
|
|
800
|
+
session[:valor] = params[:valor]
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
Tené en cuenta que <tt>enable :sessions</tt> guarda todos los datos en una
|
|
804
|
+
cookie, lo que no es siempre deseable (guardar muchos datos va a incrementar
|
|
805
|
+
tu tráfico, por citar un ejemplo). Podés usar cualquier middleware Rack para
|
|
806
|
+
manejar sesiones, de la misma manera que usarías cualquier otro middleware,
|
|
807
|
+
pero con la salvedad de que *no* tenés que llamar a <tt>enable :sessions</tt>:
|
|
808
|
+
|
|
809
|
+
use Rack::Session::Pool, :expire_after => 2592000
|
|
810
|
+
|
|
811
|
+
get '/' do
|
|
812
|
+
"valor = " << session[:valor].inspect
|
|
813
|
+
end
|
|
814
|
+
|
|
815
|
+
get '/:valor' do
|
|
816
|
+
session[:valor] = params[:valor]
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
=== Interrupción
|
|
642
820
|
|
|
643
821
|
Para detener inmediatamente una petición dentro de un filtro o una ruta usá:
|
|
644
822
|
|
|
@@ -660,7 +838,11 @@ Con cabeceras:
|
|
|
660
838
|
|
|
661
839
|
halt 402, { 'Content-Type' => 'text/plain' }, 'venganza'
|
|
662
840
|
|
|
663
|
-
|
|
841
|
+
Obviamente, es posible utilizar +halt+ con una plantilla:
|
|
842
|
+
|
|
843
|
+
halt erb(:error)
|
|
844
|
+
|
|
845
|
+
=== Paso
|
|
664
846
|
|
|
665
847
|
Una ruta puede pasarle el procesamiento a la siguiente ruta que coincida con
|
|
666
848
|
la petición usando <tt>pass</tt>:
|
|
@@ -677,11 +859,230 @@ la petición usando <tt>pass</tt>:
|
|
|
677
859
|
Se sale inmediatamente del bloque de la ruta y se le pasa el control a la
|
|
678
860
|
siguiente ruta que coincida. Si no coincide ninguna ruta, se devuelve un 404.
|
|
679
861
|
|
|
680
|
-
|
|
862
|
+
=== Ejecutando Otra Ruta
|
|
863
|
+
|
|
864
|
+
Cuando querés obtener el resultado de la llamada a una ruta, +pass+ no te va a
|
|
865
|
+
servir. Para lograr esto, podés usar +call+:
|
|
866
|
+
|
|
867
|
+
get '/foo' do
|
|
868
|
+
status, headers, body = call request.env.merge("PATH_INFO" => '/bar')
|
|
869
|
+
[status, body.upcase]
|
|
870
|
+
end
|
|
871
|
+
|
|
872
|
+
get '/bar' do
|
|
873
|
+
"bar"
|
|
874
|
+
end
|
|
875
|
+
|
|
876
|
+
Notá que en el ejemplo anterior, es conveniente mover <tt>"bar"</tt> a un
|
|
877
|
+
helper, y llamarlo desde <tt>/foo</tt> y <tt>/bar</tt>. Así, vas a simplificar
|
|
878
|
+
las pruebas y a mejorar el rendimiento.
|
|
879
|
+
|
|
880
|
+
Si querés que la petición se envíe a la misma instancia de la aplicación en
|
|
881
|
+
lugar de a otra, usá <tt>call!</tt> en lugar de <tt>call</tt>.
|
|
882
|
+
|
|
883
|
+
En la especificación de Rack podés encontrar más información sobre
|
|
884
|
+
<tt>call</tt>.
|
|
885
|
+
|
|
886
|
+
=== Asignando el Código de Estado, los Encabezados y el Cuerpo de una Respuesta
|
|
887
|
+
|
|
888
|
+
Es posible, y se recomienda, asignar el código de estado y el cuerpo de una
|
|
889
|
+
respuesta con el valor de retorno de una ruta. De cualquier manera, en varios
|
|
890
|
+
escenarios, puede que sea conveniente asignar el cuerpo en un punto arbitrario
|
|
891
|
+
del flujo de ejecución con el método +body+. A partir de ahí, podés usar ese
|
|
892
|
+
mismo método para acceder al cuerpo de la respuesta:
|
|
893
|
+
|
|
894
|
+
get '/foo' do
|
|
895
|
+
body "bar"
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
after do
|
|
899
|
+
puts body
|
|
900
|
+
end
|
|
901
|
+
|
|
902
|
+
También es posible pasarle un bloque a +body+, que será ejecutado por el Rack
|
|
903
|
+
handler (podés usar esto para implementar streaming, mirá "Valores de retorno").
|
|
904
|
+
|
|
905
|
+
De manera similar, también podés asignar el código de estado y encabezados:
|
|
906
|
+
|
|
907
|
+
get '/foo' do
|
|
908
|
+
status 418
|
|
909
|
+
headers \
|
|
910
|
+
"Allow" => "BREW, POST, GET, PROPFIND, WHEN"
|
|
911
|
+
"Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
|
|
912
|
+
body "I'm a tea pot!"
|
|
913
|
+
end
|
|
914
|
+
|
|
915
|
+
También, al igual que +body+, tanto +status+ como +headers+ pueden utilizarse
|
|
916
|
+
para obtener sus valores cuando no se les pasa argumentos.
|
|
917
|
+
|
|
918
|
+
=== Tipos Mime
|
|
919
|
+
|
|
920
|
+
Cuando usás <tt>send_file</tt> o archivos estáticos tal vez tengas tipos mime
|
|
921
|
+
que Sinatra no entiende. Usá +mime_type+ para registrarlos a través de la
|
|
922
|
+
extensión de archivo:
|
|
923
|
+
|
|
924
|
+
mime_type :foo, 'text/foo'
|
|
925
|
+
|
|
926
|
+
También lo podés usar con el ayudante +content_type+:
|
|
927
|
+
|
|
928
|
+
get '/' do
|
|
929
|
+
content_type :foo
|
|
930
|
+
"foo foo foo"
|
|
931
|
+
end
|
|
932
|
+
|
|
933
|
+
=== Generando URLs
|
|
934
|
+
|
|
935
|
+
Para generar URLs deberías usar el método +url+. Por ejemplo, en Haml:
|
|
936
|
+
|
|
937
|
+
%a{:href => url('/foo')} foo
|
|
938
|
+
|
|
939
|
+
Tiene en cuenta proxies inversos y encaminadores de Rack, si están presentes.
|
|
940
|
+
|
|
941
|
+
Este método también puede invocarse mediante su alias +to+ (mirá un ejemplo
|
|
942
|
+
a continuación).
|
|
943
|
+
|
|
944
|
+
=== Redirección del Navegador
|
|
945
|
+
|
|
946
|
+
Podés redireccionar al navegador con el método +redirect+:
|
|
947
|
+
|
|
948
|
+
get '/foo' do
|
|
949
|
+
redirect to('/bar')
|
|
950
|
+
end
|
|
951
|
+
|
|
952
|
+
Cualquier parámetro adicional se utiliza de la misma manera que los argumentos
|
|
953
|
+
pasados a +halt+:
|
|
954
|
+
|
|
955
|
+
redirect to('/bar'), 303
|
|
956
|
+
redirect 'http://google.com', 'te confundiste de lugar, compañero'
|
|
957
|
+
|
|
958
|
+
También podés redireccionar fácilmente de vuelta hacia la página desde donde
|
|
959
|
+
vino el usuario con +redirect back+:
|
|
960
|
+
|
|
961
|
+
get '/foo' do
|
|
962
|
+
"<a href='/bar'>hacer algo</a>"
|
|
963
|
+
end
|
|
964
|
+
|
|
965
|
+
get '/bar' do
|
|
966
|
+
hacer_algo
|
|
967
|
+
redirect back
|
|
968
|
+
end
|
|
969
|
+
|
|
970
|
+
Para pasar argumentos con una redirección, podés agregarlos a la cadena de
|
|
971
|
+
búsqueda:
|
|
972
|
+
|
|
973
|
+
redirect to('/bar?suma=42')
|
|
974
|
+
|
|
975
|
+
O usar una sesión:
|
|
976
|
+
|
|
977
|
+
enable :session
|
|
978
|
+
|
|
979
|
+
get '/foo' do
|
|
980
|
+
session[:secreto] = 'foo'
|
|
981
|
+
redirect to('/bar')
|
|
982
|
+
end
|
|
983
|
+
|
|
984
|
+
get '/bar' do
|
|
985
|
+
session[:secreto]
|
|
986
|
+
end
|
|
987
|
+
|
|
988
|
+
=== Cache Control
|
|
989
|
+
|
|
990
|
+
Asignar tus encabezados correctamente es el cimiento para realizar un cacheo
|
|
991
|
+
HTTP correcto.
|
|
992
|
+
|
|
993
|
+
Podés asignar el encabezado Cache-Control fácilmente:
|
|
994
|
+
|
|
995
|
+
get '/' do
|
|
996
|
+
cache_control :public
|
|
997
|
+
"cachealo!"
|
|
998
|
+
end
|
|
999
|
+
|
|
1000
|
+
Pro tip: configurar el cacheo en un filtro +before+.
|
|
1001
|
+
|
|
1002
|
+
before do
|
|
1003
|
+
cache_control :public, :must_revalidate, :max_age => 60
|
|
1004
|
+
end
|
|
1005
|
+
|
|
1006
|
+
Si estás usando el helper +expires+ para definir el encabezado correspondiente,
|
|
1007
|
+
<tt>Cache-Control</tt> se va a definir automáticamente:
|
|
1008
|
+
|
|
1009
|
+
before do
|
|
1010
|
+
expires 500, :public, :must_revalidate
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
Para usar cachés adecuadamente, deberías considerar usar +etag+ y
|
|
1014
|
+
+last_modified+. Es recomendable que llames a estos helpers *antes* de hacer
|
|
1015
|
+
cualquier trabajo pesado, ya que van a enviar la respuesta inmediatamente si
|
|
1016
|
+
el cliente ya tiene la versión actual en su caché.
|
|
1017
|
+
|
|
1018
|
+
get '/articulo/:id' do
|
|
1019
|
+
@articulo = Articulo.find params[:id]
|
|
1020
|
+
last_modified @articulo.updated_at
|
|
1021
|
+
etag @articulo.sha1
|
|
1022
|
+
erb :articulo
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
También es posible usar una
|
|
1026
|
+
{weak ETag}[http://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation]:
|
|
1027
|
+
|
|
1028
|
+
etag @articulo.sha1, :weak
|
|
1029
|
+
|
|
1030
|
+
Estos helpers no van a cachear nada por vos, sino que van a facilitar la
|
|
1031
|
+
información necesaria para poder hacerlo. Si estás buscando soluciones rápidas
|
|
1032
|
+
de cacheo, mirá {rack-cache}[http://rtomayko.github.com/rack-cache/]:
|
|
1033
|
+
|
|
1034
|
+
require "rack/cache"
|
|
1035
|
+
require "sinatra"
|
|
1036
|
+
|
|
1037
|
+
use Rack::Cache
|
|
1038
|
+
|
|
1039
|
+
get '/' do
|
|
1040
|
+
cache_control :public, :max_age => 36000
|
|
1041
|
+
sleep 5
|
|
1042
|
+
"hola"
|
|
1043
|
+
end
|
|
1044
|
+
|
|
1045
|
+
=== Enviando Archivos
|
|
1046
|
+
|
|
1047
|
+
Para enviar archivos, podés usar el método <tt>send_file</tt>:
|
|
1048
|
+
|
|
1049
|
+
get '/' do
|
|
1050
|
+
send_file 'foo.png'
|
|
1051
|
+
end
|
|
1052
|
+
|
|
1053
|
+
Además acepta un par de opciones:
|
|
1054
|
+
|
|
1055
|
+
send_file 'foo.png', :type => :jpg
|
|
1056
|
+
|
|
1057
|
+
Estas opciones son:
|
|
1058
|
+
|
|
1059
|
+
[filename]
|
|
1060
|
+
nombre del archivo respondido, por defecto es el nombre real del archivo.
|
|
1061
|
+
|
|
1062
|
+
[last_modified]
|
|
1063
|
+
valor para el encabezado Last-Modified, por defecto toma el mtime del archivo.
|
|
1064
|
+
|
|
1065
|
+
[type]
|
|
1066
|
+
el content type que se va a utilizar, si no está presente se intenta adivinar
|
|
1067
|
+
a partir de la extensión del archivo.
|
|
1068
|
+
|
|
1069
|
+
[disposition]
|
|
1070
|
+
se utiliza para el encabezado Content-Disposition, y puede tomar alguno de los
|
|
1071
|
+
siguientes valores: +nil+ (por defecto), <tt>:attachment</tt> e
|
|
1072
|
+
<tt>:inline</tt>
|
|
1073
|
+
|
|
1074
|
+
[length]
|
|
1075
|
+
encabezado Content-Length, por defecto toma el tamaño del archivo.
|
|
1076
|
+
|
|
1077
|
+
Si el Rack handler lo soporta, se intentará no transmitir directamente desde el
|
|
1078
|
+
proceso de Ruby. Si usás este método, Sinatra se va a encargar automáticamente
|
|
1079
|
+
peticiones de rango.
|
|
1080
|
+
|
|
1081
|
+
=== Accediendo al objeto de la petición
|
|
681
1082
|
|
|
682
1083
|
El objeto de la petición entrante puede ser accedido desde el nivel de la
|
|
683
1084
|
petición (filtros, rutas y manejadores de errores) a través del método
|
|
684
|
-
|
|
1085
|
+
<tt>request</tt>:
|
|
685
1086
|
|
|
686
1087
|
# app corriendo en http://ejemplo.com/ejemplo
|
|
687
1088
|
get '/foo' do
|
|
@@ -698,14 +1099,15 @@ petición (filtros, rutas y manejadores de errores) a través del método
|
|
|
698
1099
|
request.get? # verdadero (hay métodos análogos para los otros verbos)
|
|
699
1100
|
request.form_data? # falso
|
|
700
1101
|
request["UNA_CABECERA"] # valor de la cabecera UNA_CABECERA
|
|
701
|
-
request.
|
|
1102
|
+
request.referrer # la referencia del cliente o '/'
|
|
702
1103
|
request.user_agent # user agent (usado por la condición :agent)
|
|
703
1104
|
request.cookies # hash de las cookies del browser
|
|
704
1105
|
request.xhr? # es una petición ajax?
|
|
705
1106
|
request.url # "http://ejemplo.com/ejemplo/foo"
|
|
706
1107
|
request.path # "/ejemplo/foo"
|
|
707
1108
|
request.ip # dirección IP del cliente
|
|
708
|
-
request.secure? # falso
|
|
1109
|
+
request.secure? # falso (sería verdadero sobre ssl)
|
|
1110
|
+
request.forwarded? # verdadero (si se está corriendo atrás de un proxy inverso)
|
|
709
1111
|
requuest.env # hash de entorno directamente entregado por Rack
|
|
710
1112
|
end
|
|
711
1113
|
|
|
@@ -726,12 +1128,85 @@ El objeto <tt>request.body</tt> es una instancia de IO o StringIO:
|
|
|
726
1128
|
"Hola #{datos['nombre']}!"
|
|
727
1129
|
end
|
|
728
1130
|
|
|
1131
|
+
=== Archivos Adjuntos
|
|
1132
|
+
|
|
1133
|
+
Podés usar el método helper +attachment+ para indicarle al navegador que
|
|
1134
|
+
almacene la respuesta en el disco en lugar de mostrarla en pantalla.
|
|
1135
|
+
|
|
1136
|
+
get '/' do
|
|
1137
|
+
attachment
|
|
1138
|
+
"guardalo!"
|
|
1139
|
+
end
|
|
1140
|
+
|
|
1141
|
+
También podés pasarle un nombre de archivo:
|
|
1142
|
+
|
|
1143
|
+
get '/' do
|
|
1144
|
+
attachment "info.txt"
|
|
1145
|
+
"guardalo!"
|
|
1146
|
+
end
|
|
1147
|
+
|
|
1148
|
+
=== Buscando los Archivos de las Plantillas
|
|
1149
|
+
|
|
1150
|
+
El helper <tt>find_template</tt> se utiliza para encontrar los archivos de las
|
|
1151
|
+
plantillas que se van a renderizar:
|
|
1152
|
+
|
|
1153
|
+
find_template settings.views, 'foo', Tilt[:haml] do |archivo|
|
|
1154
|
+
puts "podría ser #{archivo}"
|
|
1155
|
+
end
|
|
1156
|
+
|
|
1157
|
+
Si bien esto no es muy útil, lo interesante es que podés sobreescribir este
|
|
1158
|
+
método, y así enganchar tu propio mecanismo de búsqueda. Por ejemplo, para
|
|
1159
|
+
poder utilizar más de un directorio de vistas:
|
|
1160
|
+
|
|
1161
|
+
set :views, ['vistas', 'plantillas']
|
|
1162
|
+
|
|
1163
|
+
helpers do
|
|
1164
|
+
def find_template(views, name, engine, &block)
|
|
1165
|
+
Array(views).each { |v| super(v, name, engine, &block) }
|
|
1166
|
+
end
|
|
1167
|
+
end
|
|
1168
|
+
|
|
1169
|
+
Otro ejemplo consiste en usar directorios diferentes para los distintos motores
|
|
1170
|
+
de renderizado:
|
|
1171
|
+
|
|
1172
|
+
set :views, :sass => 'vistas/sass', :haml => 'plantillas', :defecto => 'vistas'
|
|
1173
|
+
|
|
1174
|
+
helpers do
|
|
1175
|
+
def find_template(views, name, engine, &block)
|
|
1176
|
+
_, folder = views.detect { |k,v| engine == Tilt[k] }
|
|
1177
|
+
folder ||= views[:defecto]
|
|
1178
|
+
super(folder, name, engine, &block)
|
|
1179
|
+
end
|
|
1180
|
+
end
|
|
1181
|
+
|
|
1182
|
+
¡Es muy fácil convertir estos ejemplos en una extensión y compartirla!.
|
|
1183
|
+
|
|
1184
|
+
Notá que <tt>find_template</tt> no verifica si un archivo existe realmente, sino
|
|
1185
|
+
que llama al bloque que recibe para cada path posible. Esto no representa un
|
|
1186
|
+
problema de rendimiento debido a que +render+ va a usar +break+ ni bien
|
|
1187
|
+
encuentre un archivo que exista. Además, las ubicaciones de las plantillas (y
|
|
1188
|
+
su contenido) se cachean cuando no estás en el modo de desarrollo. Es bueno
|
|
1189
|
+
tener en cuenta lo anteiror si escribís un método medio loco.
|
|
1190
|
+
|
|
729
1191
|
== Configuración
|
|
730
1192
|
|
|
731
1193
|
Ejecutar una vez, en el inicio, en cualquier entorno:
|
|
732
1194
|
|
|
733
1195
|
configure do
|
|
734
|
-
|
|
1196
|
+
# asignando una opción
|
|
1197
|
+
set :opcion, 'valor'
|
|
1198
|
+
|
|
1199
|
+
# asignando varias opciones
|
|
1200
|
+
set :a => 1, :b => 2
|
|
1201
|
+
|
|
1202
|
+
# atajo para `set :opcion, true`
|
|
1203
|
+
enable :opcion
|
|
1204
|
+
|
|
1205
|
+
# atajo para `set :opcion, false`
|
|
1206
|
+
disable :opcion
|
|
1207
|
+
|
|
1208
|
+
# también podés tener configuraciones dinámicas usando bloques
|
|
1209
|
+
set(:css_dir) { File.join(views, 'css') }
|
|
735
1210
|
end
|
|
736
1211
|
|
|
737
1212
|
Ejecutar únicamente cuando el entorno (la variable de entorno RACK_ENV) es
|
|
@@ -747,10 +1222,116 @@ Ejecutar cuando el entorno es <tt>:production</tt> o <tt>:test</tt>:
|
|
|
747
1222
|
...
|
|
748
1223
|
end
|
|
749
1224
|
|
|
1225
|
+
Podés acceder a estas opciones utilizando el método <tt>settings</tt>:
|
|
1226
|
+
|
|
1227
|
+
configure do
|
|
1228
|
+
set :foo, 'bar'
|
|
1229
|
+
end
|
|
1230
|
+
|
|
1231
|
+
get '/' do
|
|
1232
|
+
settings.foo? # => true
|
|
1233
|
+
settings.foo # => 'bar'
|
|
1234
|
+
...
|
|
1235
|
+
end
|
|
1236
|
+
|
|
1237
|
+
=== Configuraciones Disponibles
|
|
1238
|
+
|
|
1239
|
+
[absolute_redirects] si está deshabilitada, Sinatra va a permitir redirecciones
|
|
1240
|
+
relativas, sin embargo, como consecuencia de esto, va a
|
|
1241
|
+
dejar de cumplir con el RFC 2616 (HTTP 1.1), que solamente
|
|
1242
|
+
permite redirecciones absolutas.
|
|
1243
|
+
|
|
1244
|
+
Activalo si tu apliación está corriendo atrás de un proxy
|
|
1245
|
+
inverso que no se ha configurado adecuadamente. Notá que
|
|
1246
|
+
el helper +url+ va a seguir produciendo URLs absolutas, a
|
|
1247
|
+
menos que le pasés +false+ como segundo parámetro.
|
|
1248
|
+
|
|
1249
|
+
Deshabilitada por defecto.
|
|
1250
|
+
|
|
1251
|
+
[add_charsets] tipos mime a los que el helper <tt>content_type</tt> les
|
|
1252
|
+
añade automáticamente el charset.
|
|
1253
|
+
|
|
1254
|
+
En general, no deberías asignar directamente esta opción,
|
|
1255
|
+
sino añadirle los charsets que quieras:
|
|
1256
|
+
|
|
1257
|
+
settings.add_charsets << "application/foobar"
|
|
1258
|
+
|
|
1259
|
+
[app_file] archivo principal de la aplicación, se utiliza para
|
|
1260
|
+
detectar la raíz del proyecto, el directorio de las vistas
|
|
1261
|
+
y el público así como las plantillas inline.
|
|
1262
|
+
|
|
1263
|
+
[bind] dirección IP que utilizará el servidor integrado (por
|
|
1264
|
+
defecto: 0.0.0.0).
|
|
1265
|
+
|
|
1266
|
+
[default_encoding] encoding utilizado cuando el mismo se desconoce (por
|
|
1267
|
+
defecto <tt>"utf-8"</tt>).
|
|
1268
|
+
|
|
1269
|
+
[dump_errors] mostrar errores en el log.
|
|
1270
|
+
|
|
1271
|
+
[environment] entorno actual, por defecto toma el valor de
|
|
1272
|
+
<tt>ENV['RACK_ENV']</tt>, o <tt>"development"</tt> si no
|
|
1273
|
+
está disponible.
|
|
1274
|
+
|
|
1275
|
+
[logging] define si se utiliza el logger.
|
|
1276
|
+
|
|
1277
|
+
[lock] coloca un lock alrededor de cada petición, procesando
|
|
1278
|
+
solamente una por proceso.
|
|
1279
|
+
|
|
1280
|
+
Habilitá esta opción si tu aplicación no es thread-safe.
|
|
1281
|
+
Se encuentra deshabilitada por defecto.
|
|
1282
|
+
|
|
1283
|
+
[method_override] utiliza el parámetro <tt>_method</tt> para permtir
|
|
1284
|
+
formularios put/delete en navegadores que no los soportan.
|
|
1285
|
+
|
|
1286
|
+
[port] puerto en el que escuchará el servidor integrado.
|
|
1287
|
+
|
|
1288
|
+
[prefixed_redirects] define si inserta <tt>request.script_name</tt> en las
|
|
1289
|
+
redirecciones cuando no se proporciona un path absoluto.
|
|
1290
|
+
De esta manera, cuando está habilitada,
|
|
1291
|
+
<tt>redirect '/foo'</tt> se comporta de la misma manera
|
|
1292
|
+
que <tt>redirect to('/foo')</tt>. Se encuentra
|
|
1293
|
+
deshabilitada por defecto.
|
|
1294
|
+
|
|
1295
|
+
[public] directorio desde donde se sirven los archivos públicos.
|
|
1296
|
+
|
|
1297
|
+
[reload_templates] define si se recargan las plantillas entre peticiones.
|
|
1298
|
+
|
|
1299
|
+
Se encuentra activado en el entorno de desarrollo y en
|
|
1300
|
+
Ruby 1.8.6 (para compoensar un bug en Ruby que provoca una
|
|
1301
|
+
pérdida de memoria).
|
|
1302
|
+
|
|
1303
|
+
[root] directorio raíz del proyecto.
|
|
1304
|
+
|
|
1305
|
+
[raise_errors] elevar excepciones (detiene la aplicación).
|
|
1306
|
+
|
|
1307
|
+
[run] cuando está habilitada, Sinatra se va a encargar de
|
|
1308
|
+
iniciar el servidor web, no la habilités cuando estés
|
|
1309
|
+
usando rackup o algún otro medio.
|
|
1310
|
+
|
|
1311
|
+
[running] indica si el servidor integrado está ejecutandose, ¡no
|
|
1312
|
+
cambiés esta configuración!.
|
|
1313
|
+
|
|
1314
|
+
[server] servidor, o lista de servidores, para usar como servidor
|
|
1315
|
+
integrado. Por defecto: ['thin', 'mongrel', 'webrick'],
|
|
1316
|
+
el orden establece la prioridad.
|
|
1317
|
+
|
|
1318
|
+
[sessions] habilita sesiones basadas en cookies.
|
|
1319
|
+
|
|
1320
|
+
[show_exceptions] muestra un stack trace en el navegador.
|
|
1321
|
+
|
|
1322
|
+
[static] define si Sinatra debe encargarse de servir archivos
|
|
1323
|
+
estáticos.
|
|
1324
|
+
|
|
1325
|
+
Deshabilitala cuando usés un servidor capaz de hacerlo
|
|
1326
|
+
por sí solo, porque mejorará el rendimiento. Se encuentra
|
|
1327
|
+
habilitada por defecto.
|
|
1328
|
+
|
|
1329
|
+
[views] directorio de las vistas.
|
|
1330
|
+
|
|
750
1331
|
== Manejo de Errores
|
|
751
1332
|
|
|
752
1333
|
Los manejadores de errores se ejecutan dentro del mismo contexto que las rutas
|
|
753
|
-
y los filtros before
|
|
1334
|
+
y los filtros +before+, lo que significa que podés usar, por ejemplo,
|
|
754
1335
|
<tt>haml</tt>, <tt>erb</tt>, <tt>halt</tt>, etc.
|
|
755
1336
|
|
|
756
1337
|
=== No encontrado <em>(Not Found)</em>
|
|
@@ -807,18 +1388,6 @@ O un rango:
|
|
|
807
1388
|
Sinatra instala manejadores <tt>not_found</tt> y <tt>error</ttt> especiales
|
|
808
1389
|
cuando se ejecuta dentro del entorno de desarrollo "development".
|
|
809
1390
|
|
|
810
|
-
== Tipos Mime
|
|
811
|
-
|
|
812
|
-
Cuando usás <tt>send_file</tt> o archivos estáticos tal vez tengas tipos mime
|
|
813
|
-
que Sinatra no entiende. Usá +mime_type+ para registrarlos a través de la
|
|
814
|
-
extensión de archivo:
|
|
815
|
-
|
|
816
|
-
mime_type :foo, 'text/foo'
|
|
817
|
-
|
|
818
|
-
También lo podés usar con el ayudante +content_type+:
|
|
819
|
-
|
|
820
|
-
content_type :foo
|
|
821
|
-
|
|
822
1391
|
== Rack Middleware
|
|
823
1392
|
|
|
824
1393
|
Sinatra corre sobre Rack[http://rack.rubyforge.org/], una interfaz minimalista
|
|
@@ -918,7 +1487,7 @@ métodos que los provistos por el DSL de top-level. La mayoría de las
|
|
|
918
1487
|
aplicaciones top-level se pueden convertir en componentes Sinatra::Base con
|
|
919
1488
|
dos modificaciones:
|
|
920
1489
|
|
|
921
|
-
* Tu archivo debe requerir
|
|
1490
|
+
* Tu archivo debe requerir <tt>sinatra/base</tt> en lugar de +sinatra+; de otra
|
|
922
1491
|
manera, todos los métodos del DSL de sinatra son importados dentro del
|
|
923
1492
|
espacio de nombres principal.
|
|
924
1493
|
* Poné las rutas, manejadores de errores, filtros y opciones de tu aplicación
|
|
@@ -929,6 +1498,34 @@ desactivadas por defecto, incluyendo el servidor incorporado. Mirá
|
|
|
929
1498
|
{Opciones y Configuraciones}[http://sinatra.github.com/configuration.html]
|
|
930
1499
|
para detalles sobre las opciones disponibles y su comportamiento.
|
|
931
1500
|
|
|
1501
|
+
=== Estilo Modular vs. Clásico
|
|
1502
|
+
|
|
1503
|
+
Contrariamente a la creencia popular, no hay nada de malo con el estilo clásico.
|
|
1504
|
+
Si se ajusta a tu aplicación, no es necesario que la cambies a una modular.
|
|
1505
|
+
|
|
1506
|
+
Existen tan solo dos desventajas en comparación con el estilo modular:
|
|
1507
|
+
|
|
1508
|
+
* Solamente podés tener una aplicación Sinatra por proceso Ruby - si tenés
|
|
1509
|
+
planificado usar más, cambiá al estilo modular.
|
|
1510
|
+
|
|
1511
|
+
* El estilo clásico contamina Object con métodos delegadores - si tenés
|
|
1512
|
+
planificado empaquetar tu aplicación en una librería/gem, cambiá al estilo
|
|
1513
|
+
modular.
|
|
1514
|
+
|
|
1515
|
+
No hay ninguna razón por la cuál no puedas mezclar los estilos modular y
|
|
1516
|
+
clásico.
|
|
1517
|
+
|
|
1518
|
+
Cuando cambiés de un estilo al otro, tené en cuenta las sutiles diferencias
|
|
1519
|
+
entre sus configuraciones:
|
|
1520
|
+
|
|
1521
|
+
Configuración Clásica Modular
|
|
1522
|
+
|
|
1523
|
+
app_file archivo que carga sinatra nil
|
|
1524
|
+
run $0 == app_file false
|
|
1525
|
+
logging true false
|
|
1526
|
+
method_override true false
|
|
1527
|
+
inline_templates true false
|
|
1528
|
+
|
|
932
1529
|
=== Sirviendo una Aplicación Modular
|
|
933
1530
|
|
|
934
1531
|
Las dos opciones más comunes para iniciar una aplicación modular son, iniciarla
|
|
@@ -996,7 +1593,7 @@ aplicación basada en Rack (Rails/Ramaze/Camping/...).
|
|
|
996
1593
|
|
|
997
1594
|
require 'sinatra/base'
|
|
998
1595
|
|
|
999
|
-
class PantallaDeLogin< Sinatra::Base
|
|
1596
|
+
class PantallaDeLogin < Sinatra::Base
|
|
1000
1597
|
enable :sessions
|
|
1001
1598
|
|
|
1002
1599
|
get('/login') { haml :login }
|
|
@@ -1033,11 +1630,11 @@ disponibles.
|
|
|
1033
1630
|
Cada aplicación Sinatra es una subclase de Sinatra::Base. Si estás usando el
|
|
1034
1631
|
DSL de top-level (<tt>require 'sinatra'</tt>), entonces esta clase es
|
|
1035
1632
|
Sinatra::Application, de otra manera es la subclase que creaste explícitamente.
|
|
1036
|
-
Al nivel de la clase tenés métodos como
|
|
1037
|
-
a los objetos
|
|
1633
|
+
Al nivel de la clase tenés métodos como +get+ o +before+, pero no podés acceder
|
|
1634
|
+
a los objetos +request+ o +session+, ya que hay una única clase de la
|
|
1038
1635
|
aplicación para todas las peticiones.
|
|
1039
1636
|
|
|
1040
|
-
Las opciones creadas utilizando
|
|
1637
|
+
Las opciones creadas utilizando +set+ son métodos al nivel de la clase:
|
|
1041
1638
|
|
|
1042
1639
|
class MiApp < Sinatra::Base
|
|
1043
1640
|
# Ey, estoy en el ámbito de la aplicación!
|
|
@@ -1053,21 +1650,21 @@ Tenés la ligadura al ámbito de la aplicación dentro de:
|
|
|
1053
1650
|
|
|
1054
1651
|
* El cuerpo de la clase de tu aplicación
|
|
1055
1652
|
* Métodos definidos por extensiones
|
|
1056
|
-
* El bloque pasado a
|
|
1057
|
-
* Procs/bloques usados como el valor para
|
|
1653
|
+
* El bloque pasado a +helpers+
|
|
1654
|
+
* Procs/bloques usados como el valor para +set+
|
|
1058
1655
|
|
|
1059
1656
|
Este ámbito puede alcanzarse de las siguientes maneras:
|
|
1060
1657
|
|
|
1061
1658
|
* A través del objeto pasado a los bloques de configuración (<tt>configure { |c| ...}</tt>)
|
|
1062
|
-
* Llamando a
|
|
1659
|
+
* Llamando a +settings+ desde dentro del ámbito de la petición
|
|
1063
1660
|
|
|
1064
1661
|
=== Ámbito de Petición/Instancia
|
|
1065
1662
|
|
|
1066
1663
|
Para cada petición entrante, una nueva instancia de la clase de tu aplicación
|
|
1067
1664
|
es creada y todos los bloques de rutas son ejecutados en ese ámbito. Desde este
|
|
1068
|
-
ámbito podés acceder a los objetos
|
|
1069
|
-
de renderización como
|
|
1070
|
-
desde el ámbito de la petición utilizando
|
|
1665
|
+
ámbito podés acceder a los objetos +request+ y +session+ o llamar a los métodos
|
|
1666
|
+
de renderización como +erb+ o +haml+. Podés acceder al ámbito de la aplicación
|
|
1667
|
+
desde el ámbito de la petición utilizando +settings+:
|
|
1071
1668
|
|
|
1072
1669
|
class MiApp < Sinatra::Base
|
|
1073
1670
|
# Ey, estoy en el ámbito de la aplicación!
|
|
@@ -1086,7 +1683,7 @@ desde el ámbito de la petición utilizando `settings`:
|
|
|
1086
1683
|
|
|
1087
1684
|
Tenés la ligadura al ámbito de la petición dentro de:
|
|
1088
1685
|
|
|
1089
|
-
* bloques pasados a get/head/post/put/delete
|
|
1686
|
+
* bloques pasados a get/head/post/put/delete/options
|
|
1090
1687
|
* filtros before/after
|
|
1091
1688
|
* métodos ayudantes
|
|
1092
1689
|
* plantillas/vistas
|
|
@@ -1097,13 +1694,13 @@ El ámbito de delegación solo reenvía métodos al ámbito de clase. De cualqui
|
|
|
1097
1694
|
manera, no se comporta 100% como el ámbito de clase porque no tenés la ligadura
|
|
1098
1695
|
de la clase: únicamente métodos marcados explícitamente para delegación están
|
|
1099
1696
|
disponibles y no compartís variables/estado con el ámbito de clase (léase:
|
|
1100
|
-
tenés un
|
|
1697
|
+
tenés un +self+ diferente). Podés agregar delegaciones de método llamando a
|
|
1101
1698
|
<tt>Sinatra::Delegator.delegate :nombre_del_metodo</tt>.
|
|
1102
1699
|
|
|
1103
1700
|
Tenés la ligadura al ámbito de delegación dentro de:
|
|
1104
1701
|
|
|
1105
1702
|
* La ligadura del top-level, si hiciste <tt>require "sinatra"</tt>
|
|
1106
|
-
* Un objeto extendido con el mixin
|
|
1703
|
+
* Un objeto extendido con el mixin <tt>Sinatra::Delegator</tt>
|
|
1107
1704
|
|
|
1108
1705
|
Pegale una mirada al código: acá está el
|
|
1109
1706
|
{Sinatra::Delegator mixin}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/base.rb#L1128]
|
|
@@ -1124,6 +1721,59 @@ Las opciones son:
|
|
|
1124
1721
|
-s # especifica el servidor/manejador rack (thin es usado por defecto)
|
|
1125
1722
|
-x # activa el mutex lock (está desactivado por defecto)
|
|
1126
1723
|
|
|
1724
|
+
== Requerimientos
|
|
1725
|
+
|
|
1726
|
+
Se recomienda instalar Sinatra en Ruby 1.8.7, 1.9.2, JRuby o Rubinius.
|
|
1727
|
+
|
|
1728
|
+
Las siguientes versiones de Ruby son soportadas oficialmente:
|
|
1729
|
+
|
|
1730
|
+
[ Ruby 1.8.6 ]
|
|
1731
|
+
No se recomienda utilizar Sinatra en 1.8.6. Sin embargo, esta versión será
|
|
1732
|
+
soportada oficialmente hasta que se libere Sinatra 1.3.0. RDoc y CoffeeScript
|
|
1733
|
+
no son soportadas por esta versión de Ruby. 1.8.6 contiene una falla
|
|
1734
|
+
importante de pérdida de memoria en su implementación de Hash, que afecta a
|
|
1735
|
+
las versiones de Sinatra anteriores a 1.1.1. La versión actual evita
|
|
1736
|
+
explícitamente esta falla a expensas de una disminución del rendimiento. Por
|
|
1737
|
+
último, Rack >= 1.2 dejó de soportar 1.8.6, por lo que vas a tener que usar
|
|
1738
|
+
alguna versión 1.1.x.
|
|
1739
|
+
|
|
1740
|
+
[ Ruby 1.8.7 ]
|
|
1741
|
+
1.8.7 es soportado completamente. Sin embargo, si no hay nada que te lo
|
|
1742
|
+
prohíba, te recomendamos que usés 1.9.2 o cambies a JRuby o Rubinius.
|
|
1743
|
+
|
|
1744
|
+
[ Ruby 1.9.2 ]
|
|
1745
|
+
1.9.2 es soportado y recomendado. Tené en cuenta que Radius y Markaby no
|
|
1746
|
+
son compatibles con 1.9 actualmente. Además, no usés 1.9.2p0, porque produce
|
|
1747
|
+
fallos de segmentación cuando se utiliza Sinatra.
|
|
1748
|
+
|
|
1749
|
+
[ Rubinius ]
|
|
1750
|
+
Rubinius es soportado oficialmente (Rubinius >= 1.2.2), con la excepción de
|
|
1751
|
+
las plantillas Textile.
|
|
1752
|
+
|
|
1753
|
+
[ JRuby ]
|
|
1754
|
+
JRuby es soportado oficialmente (JRuby >= 1.5.6). No se conocen problemas con
|
|
1755
|
+
librerías de plantillas de terceras partes. Sin embargo, si elegís usar
|
|
1756
|
+
JRuby, deberías examinar sus Rack handlers porque el servidor web Thin no es
|
|
1757
|
+
soportado actualmente.
|
|
1758
|
+
|
|
1759
|
+
Siempre le prestamos atención a las nuevas versiones de Ruby.
|
|
1760
|
+
|
|
1761
|
+
Las siguientes implementaciones de Ruby no se encuentran soportadas
|
|
1762
|
+
oficialmente. De cualquier manera, pueden ejecutar Sinatra:
|
|
1763
|
+
|
|
1764
|
+
* Versiones anteriores de JRuby y Rubinius
|
|
1765
|
+
* MacRuby
|
|
1766
|
+
* Maglev
|
|
1767
|
+
* IronRuby
|
|
1768
|
+
* Ruby 1.9.0 y 1.9.1
|
|
1769
|
+
|
|
1770
|
+
No estar soportada oficialmente, significa que si las cosas solamente se rompen
|
|
1771
|
+
ahí y no en una plataforma soportada, asumimos que no es nuestro problema sino
|
|
1772
|
+
el suyo.
|
|
1773
|
+
|
|
1774
|
+
Sinatra debería funcionar en cualquier sistema operativo soportado por la
|
|
1775
|
+
implementación de Ruby elegida.
|
|
1776
|
+
|
|
1127
1777
|
== A la Vanguardia
|
|
1128
1778
|
|
|
1129
1779
|
Si querés usar el código de Sinatra más reciente, sentite libre de ejecutar
|
|
@@ -1164,7 +1814,7 @@ Ahora podés arrancar tu aplicación así:
|
|
|
1164
1814
|
=== Con Git
|
|
1165
1815
|
|
|
1166
1816
|
Cloná el repositorio localmente y ejecutá tu aplicación, asegurándote que el
|
|
1167
|
-
directorio <tt>sinatra/lib</tt> esté en el <tt
|
|
1817
|
+
directorio <tt>sinatra/lib</tt> esté en el <tt>$LOAD_PATH</tt>:
|
|
1168
1818
|
|
|
1169
1819
|
cd miapp
|
|
1170
1820
|
git clone git://github.com/sinatra/sinatra.git
|