sinatra 1.4.6 → 1.4.7
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.
- checksums.yaml +4 -4
- data/AUTHORS.md +5 -2
- data/{CHANGES → CHANGELOG.md} +17 -1
- data/CONTRIBUTING.md +100 -0
- data/LICENSE +2 -2
- data/README.de.md +78 -41
- data/README.es.md +200 -165
- data/README.fr.md +364 -338
- data/README.hu.md +7 -7
- data/README.ja.md +199 -167
- data/README.ko.md +222 -183
- data/README.md +218 -179
- data/README.pt-br.md +146 -112
- data/README.pt-pt.md +63 -63
- data/README.ru.md +158 -35
- data/README.zh.md +1941 -1235
- data/Rakefile +2 -2
- data/lib/sinatra/base.rb +16 -24
- data/lib/sinatra/ext.rb +17 -0
- data/lib/sinatra/show_exceptions.rb +13 -7
- data/lib/sinatra/version.rb +1 -1
- data/sinatra.gemspec +1 -1
- data/test/public/hello+world.txt +1 -0
- data/test/routing_test.rb +44 -0
- data/test/static_test.rb +30 -0
- metadata +9 -6
data/README.es.md
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
*Atención: Este documento es una traducción de la versión en inglés y puede estar desactualizado.*
|
4
4
|
|
5
5
|
Sinatra es un
|
6
|
-
[DSL](
|
6
|
+
[DSL](https://es.wikipedia.org/wiki/Lenguaje_específico_del_dominio) para
|
7
7
|
crear aplicaciones web rápidamente en Ruby con un mínimo esfuerzo:
|
8
8
|
|
9
|
-
```
|
9
|
+
```ruby
|
10
10
|
# miapp.rb
|
11
11
|
require 'sinatra'
|
12
12
|
|
@@ -17,12 +17,12 @@ end
|
|
17
17
|
|
18
18
|
Instalar la gema y correr la aplicación con:
|
19
19
|
|
20
|
-
```
|
20
|
+
```shell
|
21
21
|
gem install sinatra
|
22
22
|
ruby miapp.rb
|
23
23
|
```
|
24
24
|
|
25
|
-
Ver en
|
25
|
+
Ver en [http://localhost:4567](http://localhost:4567).
|
26
26
|
|
27
27
|
Se recomienda ejecutar `gem install thin`, porque Sinatra lo utilizará si está disponible.
|
28
28
|
|
@@ -31,7 +31,7 @@ Se recomienda ejecutar `gem install thin`, porque Sinatra lo utilizará si está
|
|
31
31
|
En Sinatra, una ruta es un método HTTP junto a un patrón de un URL.
|
32
32
|
Cada ruta está asociada a un bloque:
|
33
33
|
|
34
|
-
```
|
34
|
+
```ruby
|
35
35
|
get '/' do
|
36
36
|
.. mostrar algo ..
|
37
37
|
end
|
@@ -72,7 +72,7 @@ que coincide con la petición es escogida.
|
|
72
72
|
Los patrones de las rutas pueden incluir parámetros nombrados, accesibles a
|
73
73
|
través del hash `params`:
|
74
74
|
|
75
|
-
```
|
75
|
+
```ruby
|
76
76
|
get '/hola/:nombre' do
|
77
77
|
# coincide con "GET /hola/foo" y "GET /hola/bar"
|
78
78
|
# params['nombre'] es 'foo' o 'bar'
|
@@ -82,7 +82,7 @@ end
|
|
82
82
|
|
83
83
|
También puede acceder a los parámetros nombrados usando parámetros de bloque:
|
84
84
|
|
85
|
-
```
|
85
|
+
```ruby
|
86
86
|
get '/hola/:nombre' do |n|
|
87
87
|
# coincide con "GET /hola/foo" y "GET /hola/bar"
|
88
88
|
# params['nombre'] es 'foo' o 'bar'
|
@@ -94,7 +94,7 @@ end
|
|
94
94
|
Los patrones de ruta también pueden incluir parámetros splat (o wildcard),
|
95
95
|
accesibles a través del arreglo `params['splat']`:
|
96
96
|
|
97
|
-
```
|
97
|
+
```ruby
|
98
98
|
get '/decir/*/al/*' do
|
99
99
|
# coincide con /decir/hola/al/mundo
|
100
100
|
params['splat'] # => ["hola", "mundo"]
|
@@ -108,7 +108,7 @@ end
|
|
108
108
|
|
109
109
|
O, con parámetros de bloque:
|
110
110
|
|
111
|
-
```
|
111
|
+
```ruby
|
112
112
|
get '/descargar/*.*' do |path, ext|
|
113
113
|
[path, ext] # => ["path/al/archivo", "xml"]
|
114
114
|
end
|
@@ -116,7 +116,7 @@ end
|
|
116
116
|
|
117
117
|
Rutas con Expresiones Regulares:
|
118
118
|
|
119
|
-
```
|
119
|
+
```ruby
|
120
120
|
get /\A\/hola\/([\w]+)\z/ do
|
121
121
|
"Hola, #{params['captures'].first}!"
|
122
122
|
end
|
@@ -124,7 +124,7 @@ end
|
|
124
124
|
|
125
125
|
O con un parámetro de bloque:
|
126
126
|
|
127
|
-
```
|
127
|
+
```ruby
|
128
128
|
get %r{/hola/([\w]+)} do |c|
|
129
129
|
"Hola, #{c}!"
|
130
130
|
end
|
@@ -132,10 +132,10 @@ end
|
|
132
132
|
|
133
133
|
Los patrones de ruta pueden contener parámetros opcionales:
|
134
134
|
|
135
|
-
```
|
136
|
-
get '/posts
|
137
|
-
# coincide con "GET /posts" y además admite cualquier extensión, por
|
138
|
-
# ejemplo, "GET /posts
|
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
139
|
end
|
140
140
|
```
|
141
141
|
|
@@ -148,7 +148,7 @@ antes de que se compare con los de tus rutas.
|
|
148
148
|
Las rutas pueden incluir una variedad de condiciones de selección, como por
|
149
149
|
ejemplo el user agent:
|
150
150
|
|
151
|
-
```
|
151
|
+
```ruby
|
152
152
|
get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
|
153
153
|
"Estás usando la versión de Songbird #{params['agent'][0]}"
|
154
154
|
end
|
@@ -160,7 +160,7 @@ end
|
|
160
160
|
|
161
161
|
Otras condiciones disponibles son `host_name` y `provides`:
|
162
162
|
|
163
|
-
```
|
163
|
+
```ruby
|
164
164
|
get '/', :host_name => /^admin\./ do
|
165
165
|
"Área de Administración, Acceso denegado!"
|
166
166
|
end
|
@@ -176,7 +176,7 @@ end
|
|
176
176
|
|
177
177
|
Puede definir sus propias condiciones fácilmente:
|
178
178
|
|
179
|
-
```
|
179
|
+
```ruby
|
180
180
|
set(:probabilidad) { |valor| condition { rand <= valor } }
|
181
181
|
|
182
182
|
get '/gana_un_auto', :probabilidad => 0.1 do
|
@@ -192,7 +192,7 @@ Si su condición acepta más de un argumento, puede pasarle un arreglo. Al
|
|
192
192
|
definir la condición, se puede utilizar el operador splat en
|
193
193
|
la lista de parámetros:
|
194
194
|
|
195
|
-
```
|
195
|
+
```ruby
|
196
196
|
set(:autorizar) do |*roles| # <- mirá el splat
|
197
197
|
condition do
|
198
198
|
unless sesion_iniciada? && roles.any? {|rol| usuario_actual.tiene_rol? rol }
|
@@ -230,7 +230,7 @@ que represente el cuerpo de una respuesta Rack o un código de estado HTTP:
|
|
230
230
|
|
231
231
|
De esa manera, podemos fácilmente implementar un ejemplo de streaming:
|
232
232
|
|
233
|
-
```
|
233
|
+
```ruby
|
234
234
|
class Stream
|
235
235
|
def each
|
236
236
|
100.times { |i| yield "#{i}\n" }
|
@@ -246,7 +246,7 @@ Como se mostró anteriormente, Sinatra permite utilizar strings y expresiones
|
|
246
246
|
regulares para definir las rutas. Sin embargo, la cosa no termina ahí. Podés
|
247
247
|
definir tus propios comparadores muy fácilmente:
|
248
248
|
|
249
|
-
```
|
249
|
+
```ruby
|
250
250
|
class PatronCualquieraMenos
|
251
251
|
Match = Struct.new(:captures)
|
252
252
|
|
@@ -272,7 +272,7 @@ end
|
|
272
272
|
Tenga en cuenta que el ejemplo anterior es un poco rebuscado. Un resultado
|
273
273
|
similar puede conseguirse más sencillamente:
|
274
274
|
|
275
|
-
```
|
275
|
+
```ruby
|
276
276
|
get // do
|
277
277
|
pass if request.path_info == "/index"
|
278
278
|
# ...
|
@@ -281,7 +281,7 @@ end
|
|
281
281
|
|
282
282
|
O, usando un lookahead negativo:
|
283
283
|
|
284
|
-
```
|
284
|
+
```ruby
|
285
285
|
get %r{^(?!/index$)} do
|
286
286
|
# ...
|
287
287
|
end
|
@@ -293,7 +293,7 @@ Los archivos estáticos son servidos desde el directorio público
|
|
293
293
|
`./public`. Puede especificar una ubicación diferente ajustando la
|
294
294
|
opción `:public_folder`:
|
295
295
|
|
296
|
-
```
|
296
|
+
```ruby
|
297
297
|
set :public_folder, File.dirname(__FILE__) + '/estaticos'
|
298
298
|
```
|
299
299
|
|
@@ -309,7 +309,7 @@ Use la configuración `:static_cache_control` para agregar el encabezado
|
|
309
309
|
Cada lenguaje de plantilla se expone a través de un método de renderizado que
|
310
310
|
lleva su nombre. Estos métodos simplemente devuelven un string:
|
311
311
|
|
312
|
-
```
|
312
|
+
```ruby
|
313
313
|
get '/' do
|
314
314
|
erb :index
|
315
315
|
end
|
@@ -320,7 +320,7 @@ Renderiza `views/index.erb`.
|
|
320
320
|
En lugar del nombre de la plantilla podés proporcionar directamente el
|
321
321
|
contenido de la misma:
|
322
322
|
|
323
|
-
```
|
323
|
+
```ruby
|
324
324
|
get '/' do
|
325
325
|
codigo = "<%= Time.now %>"
|
326
326
|
erb codigo
|
@@ -330,7 +330,7 @@ end
|
|
330
330
|
Los métodos de renderizado, aceptan además un segundo argumento, el hash de
|
331
331
|
opciones:
|
332
332
|
|
333
|
-
```
|
333
|
+
```ruby
|
334
334
|
get '/' do
|
335
335
|
erb :index, :layout => :post
|
336
336
|
end
|
@@ -343,7 +343,7 @@ cuando este último archivo exista).
|
|
343
343
|
Cualquier opción que Sinatra no entienda le será pasada al motor de renderizado
|
344
344
|
de la plantilla:
|
345
345
|
|
346
|
-
```
|
346
|
+
```ruby
|
347
347
|
get '/' do
|
348
348
|
haml :index, :format => :html5
|
349
349
|
end
|
@@ -352,7 +352,7 @@ end
|
|
352
352
|
Además, puede definir las opciones para un lenguaje de plantillas de forma
|
353
353
|
general:
|
354
354
|
|
355
|
-
```
|
355
|
+
```ruby
|
356
356
|
set :haml, :format => :html5
|
357
357
|
|
358
358
|
get '/' do
|
@@ -435,7 +435,7 @@ Algunos lenguajes tienen varias implementaciones. Para especificar que
|
|
435
435
|
implementación usar (y para ser thread-safe), deberías requerirla antes de
|
436
436
|
usarla:
|
437
437
|
|
438
|
-
```
|
438
|
+
```ruby
|
439
439
|
require 'rdiscount' # o require 'bluecloth'
|
440
440
|
get('/') { markdown :index }
|
441
441
|
```
|
@@ -503,7 +503,7 @@ Además, acepta un bloque con la definición de la plantilla (ver ejemplo).
|
|
503
503
|
<table>
|
504
504
|
<tr>
|
505
505
|
<td>Dependencias</td>
|
506
|
-
<td><a href="http://nokogiri.org/" title="nokogiri">nokogiri</a></td>
|
506
|
+
<td><a href="http://www.nokogiri.org/" title="nokogiri">nokogiri</a></td>
|
507
507
|
</tr>
|
508
508
|
<tr>
|
509
509
|
<td>Extensiones de Archivo</td>
|
@@ -556,7 +556,7 @@ Además, acepta un bloque con la definición de la plantilla (ver ejemplo).
|
|
556
556
|
<table>
|
557
557
|
<tr>
|
558
558
|
<td>Dependencias</td>
|
559
|
-
<td><a href="http://
|
559
|
+
<td><a href="http://lesscss.org/" title="less">less</a></td>
|
560
560
|
</tr>
|
561
561
|
<tr>
|
562
562
|
<td>Extensiones de Archivo</td>
|
@@ -573,7 +573,7 @@ Además, acepta un bloque con la definición de la plantilla (ver ejemplo).
|
|
573
573
|
<table>
|
574
574
|
<tr>
|
575
575
|
<td>Dependencias</td>
|
576
|
-
<td><a href="http://
|
576
|
+
<td><a href="http://liquidmarkup.org/" title="liquid">liquid</a></td>
|
577
577
|
</tr>
|
578
578
|
<tr>
|
579
579
|
<td>Extensiones de Archivo</td>
|
@@ -594,7 +594,7 @@ plantilla Liquid, casi siempre va a querer pasarle locales.
|
|
594
594
|
<tr>
|
595
595
|
<td>Dependencias</td>
|
596
596
|
<td>
|
597
|
-
<a href="https://github.com/
|
597
|
+
<a href="https://github.com/davidfstr/rdiscount" title="RDiscount">RDiscount</a>,
|
598
598
|
<a href="https://github.com/vmg/redcarpet" title="RedCarpet">RedCarpet</a>,
|
599
599
|
<a href="http://deveiate.org/projects/BlueCloth" title="BlueCloth">BlueCloth</a>,
|
600
600
|
<a href="http://kramdown.gettalong.org/" title="kramdown">kramdown</a> o
|
@@ -614,14 +614,14 @@ plantilla Liquid, casi siempre va a querer pasarle locales.
|
|
614
614
|
No es posible llamar métodos desde markdown, ni pasarle locales. Por lo tanto,
|
615
615
|
generalmente va a usarlo en combinación con otro motor de renderizado:
|
616
616
|
|
617
|
-
```
|
617
|
+
```ruby
|
618
618
|
erb :resumen, :locals => { :texto => markdown(:introduccion) }
|
619
619
|
```
|
620
620
|
|
621
621
|
Tenga en cuenta que también podés llamar al método `markdown` desde otras
|
622
622
|
plantillas:
|
623
623
|
|
624
|
-
```
|
624
|
+
```ruby
|
625
625
|
%h1 Hola Desde Haml!
|
626
626
|
%p= markdown(:saludos)
|
627
627
|
```
|
@@ -650,14 +650,14 @@ layout distinto al de la plantilla pasando la opción `:layout_engine`.
|
|
650
650
|
No es posible llamar métodos desde textile, ni pasarle locales. Por lo tanto,
|
651
651
|
generalmente vas a usarlo en combinación con otro motor de renderizado:
|
652
652
|
|
653
|
-
```
|
653
|
+
```ruby
|
654
654
|
erb :resumen, :locals => { :texto => textile(:introduccion) }
|
655
655
|
```
|
656
656
|
|
657
657
|
Tené en cuenta que también podés llamar al método `textile` desde otras
|
658
658
|
plantillas:
|
659
659
|
|
660
|
-
```
|
660
|
+
```ruby
|
661
661
|
%h1 Hola Desde Haml!
|
662
662
|
%p= textile(:saludos)
|
663
663
|
```
|
@@ -686,14 +686,14 @@ layout distinto al de la plantilla pasando la opción `:layout_engine`.
|
|
686
686
|
No es posible llamar métodos desde rdoc, ni pasarle locales. Por lo tanto,
|
687
687
|
generalmente vas a usarlo en combinación con otro motor de renderizado:
|
688
688
|
|
689
|
-
```
|
689
|
+
```ruby
|
690
690
|
erb :resumen, :locals => { :texto => rdoc(:introduccion) }
|
691
691
|
```
|
692
692
|
|
693
693
|
Tené en cuenta que también podés llamar al método `rdoc` desde otras
|
694
694
|
plantillas:
|
695
695
|
|
696
|
-
```
|
696
|
+
```ruby
|
697
697
|
%h1 Hola Desde Haml!
|
698
698
|
%p= rdoc(:saludos)
|
699
699
|
```
|
@@ -727,7 +727,7 @@ plantilla Radius, casi siempre se necesita pasar locales.
|
|
727
727
|
<table>
|
728
728
|
<tr>
|
729
729
|
<td>Dependencias</td>
|
730
|
-
<td><a href="http://markaby.github.
|
730
|
+
<td><a href="http://markaby.github.io/" title="Markaby">Markaby</a></td>
|
731
731
|
</tr>
|
732
732
|
<tr>
|
733
733
|
<td>Extensiones de Archivo</td>
|
@@ -795,14 +795,14 @@ Además, acepta un bloque con la definición de la plantilla (ver ejemplo).
|
|
795
795
|
No es posible llamar métodos desde creole, ni pasarle locales. Por lo tanto,
|
796
796
|
generalmente va a usarlo en combinación con otro motor de renderizado:
|
797
797
|
|
798
|
-
```
|
798
|
+
```ruby
|
799
799
|
erb :resumen, :locals => { :texto => cerole(:introduccion) }
|
800
800
|
```
|
801
801
|
|
802
802
|
Debe tomar en cuenta que también puede llamar al método `creole` desde otras
|
803
803
|
plantillas:
|
804
804
|
|
805
|
-
```
|
805
|
+
```ruby
|
806
806
|
%h1 Hola Desde Haml!
|
807
807
|
%p= creole(:saludos)
|
808
808
|
```
|
@@ -841,7 +841,7 @@ distinto al de la plantilla pasando la opción `:layout_engine`.
|
|
841
841
|
<tr>
|
842
842
|
<td>Dependencias</td>
|
843
843
|
<td>
|
844
|
-
<a href="https://github.com/
|
844
|
+
<a href="https://github.com/forgecrafted/ruby-stylus" title="Ruby Stylus">
|
845
845
|
Stylus
|
846
846
|
</a> y un
|
847
847
|
<a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
|
@@ -885,14 +885,14 @@ distinto al de la plantilla pasando la opción `:layout_engine`.
|
|
885
885
|
|
886
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
887
|
|
888
|
-
```
|
888
|
+
```ruby
|
889
889
|
json = { :foo => 'bar' }
|
890
890
|
json[:baz] = key
|
891
891
|
```
|
892
892
|
|
893
893
|
Las opciones `:callback` y `:variable` se pueden utilizar para decorar el objeto renderizado:
|
894
894
|
|
895
|
-
```
|
895
|
+
```ruby
|
896
896
|
var resource = {"foo":"bar","baz":"qux"}; present(resource);
|
897
897
|
```
|
898
898
|
|
@@ -918,7 +918,7 @@ plantilla WLang, casi siempre vas a querer pasarle locales.
|
|
918
918
|
|
919
919
|
### Plantillas Embebidas
|
920
920
|
|
921
|
-
```
|
921
|
+
```ruby
|
922
922
|
get '/' do
|
923
923
|
haml '%div.titulo Hola Mundo'
|
924
924
|
end
|
@@ -932,7 +932,7 @@ Las plantillas son evaluadas dentro del mismo contexto que los manejadores de
|
|
932
932
|
ruta. Las variables de instancia asignadas en los manejadores de ruta son
|
933
933
|
accesibles directamente por las plantillas:
|
934
934
|
|
935
|
-
```
|
935
|
+
```ruby
|
936
936
|
get '/:id' do
|
937
937
|
@foo = Foo.find(params['id'])
|
938
938
|
haml '%h1= @foo.nombre'
|
@@ -941,7 +941,7 @@ end
|
|
941
941
|
|
942
942
|
O es posible especificar un Hash de variables locales explícitamente:
|
943
943
|
|
944
|
-
```
|
944
|
+
```ruby
|
945
945
|
get '/:id' do
|
946
946
|
foo = Foo.find(params['id'])
|
947
947
|
haml '%h1= bar.nombre', :locals => { :bar => foo }
|
@@ -955,7 +955,7 @@ adentro de otras plantillas.
|
|
955
955
|
|
956
956
|
Las plantillas pueden ser definidas al final del archivo fuente:
|
957
957
|
|
958
|
-
```
|
958
|
+
```ruby
|
959
959
|
require 'rubygems'
|
960
960
|
require 'sinatra'
|
961
961
|
|
@@ -983,7 +983,7 @@ archivos fuente.
|
|
983
983
|
Las plantillas también pueden ser definidas usando el método top-level
|
984
984
|
`template`:
|
985
985
|
|
986
|
-
```
|
986
|
+
```ruby
|
987
987
|
template :layout do
|
988
988
|
"%html\n =yield\n"
|
989
989
|
end
|
@@ -1002,7 +1002,7 @@ una plantilla es renderizada. Podés desactivar los layouts individualmente
|
|
1002
1002
|
pasando `:layout => false` o globalmente con
|
1003
1003
|
`set :haml, :layout => false`:
|
1004
1004
|
|
1005
|
-
```
|
1005
|
+
```ruby
|
1006
1006
|
get '/' do
|
1007
1007
|
haml :index, :layout => !request.xhr?
|
1008
1008
|
end
|
@@ -1014,7 +1014,7 @@ Para asociar una extensión de archivo con un motor de renderizado, usá
|
|
1014
1014
|
`Tilt.register`. Por ejemplo, si querés usar la extensión `tt` para
|
1015
1015
|
las plantillas Textile, podés hacer lo siguiente:
|
1016
1016
|
|
1017
|
-
```
|
1017
|
+
```ruby
|
1018
1018
|
Tilt.register :tt, Tilt[:textile]
|
1019
1019
|
```
|
1020
1020
|
|
@@ -1022,7 +1022,7 @@ Tilt.register :tt, Tilt[:textile]
|
|
1022
1022
|
|
1023
1023
|
Primero, registrá tu motor con Tilt, y después, creá tu método de renderizado:
|
1024
1024
|
|
1025
|
-
```
|
1025
|
+
```ruby
|
1026
1026
|
Tilt.register :mipg, MiMotorParaPlantillaGenial
|
1027
1027
|
|
1028
1028
|
helpers do
|
@@ -1044,7 +1044,7 @@ contexto que las rutas. Pueden modificar la petición y la respuesta. Las
|
|
1044
1044
|
variables de instancia asignadas en los filtros son accesibles por las rutas y
|
1045
1045
|
las plantillas:
|
1046
1046
|
|
1047
|
-
```
|
1047
|
+
```ruby
|
1048
1048
|
before do
|
1049
1049
|
@nota = 'Hey!'
|
1050
1050
|
request.path_info = '/foo/bar/baz'
|
@@ -1061,7 +1061,7 @@ contexto y también pueden modificar la petición y la respuesta. Las variables
|
|
1061
1061
|
de instancia asignadas en los filtros `before` y en las rutas son accesibles por
|
1062
1062
|
los filtros `after`:
|
1063
1063
|
|
1064
|
-
```
|
1064
|
+
```ruby
|
1065
1065
|
after do
|
1066
1066
|
puts response.status
|
1067
1067
|
end
|
@@ -1075,7 +1075,7 @@ Los filtros aceptan un patrón opcional, que cuando está presente causa que los
|
|
1075
1075
|
mismos sean evaluados únicamente si el path de la petición coincide con ese
|
1076
1076
|
patrón:
|
1077
1077
|
|
1078
|
-
```
|
1078
|
+
```ruby
|
1079
1079
|
before '/protegido/*' do
|
1080
1080
|
autenticar!
|
1081
1081
|
end
|
@@ -1087,7 +1087,7 @@ end
|
|
1087
1087
|
|
1088
1088
|
Al igual que las rutas, los filtros también pueden aceptar condiciones:
|
1089
1089
|
|
1090
|
-
```
|
1090
|
+
```ruby
|
1091
1091
|
before :agent => /Songbird/ do
|
1092
1092
|
# ...
|
1093
1093
|
end
|
@@ -1102,7 +1102,7 @@ end
|
|
1102
1102
|
Usá el método top-level *helpers* para definir métodos ayudantes que
|
1103
1103
|
pueden ser utilizados dentro de los manejadores de rutas y las plantillas:
|
1104
1104
|
|
1105
|
-
```
|
1105
|
+
```ruby
|
1106
1106
|
helpers do
|
1107
1107
|
def bar(nombre)
|
1108
1108
|
"#{nombre}bar"
|
@@ -1117,7 +1117,7 @@ end
|
|
1117
1117
|
Por cuestiones organizativas, puede resultar conveniente organizar los métodos
|
1118
1118
|
ayudantes en distintos módulos:
|
1119
1119
|
|
1120
|
-
```
|
1120
|
+
```ruby
|
1121
1121
|
module FooUtils
|
1122
1122
|
def foo(nombre) "#{nombre}foo" end
|
1123
1123
|
end
|
@@ -1137,7 +1137,7 @@ incluir los módulos en la clase de la aplicación.
|
|
1137
1137
|
Una sesión es usada para mantener el estado a través de distintas peticiones.
|
1138
1138
|
Cuando están activadas, proporciona un hash de sesión para cada sesión de usuario:
|
1139
1139
|
|
1140
|
-
```
|
1140
|
+
```ruby
|
1141
1141
|
enable :sessions
|
1142
1142
|
|
1143
1143
|
get '/' do
|
@@ -1155,7 +1155,7 @@ el tráfico, por citar un ejemplo). Podés usar cualquier middleware Rack para
|
|
1155
1155
|
manejar sesiones, de la misma manera que usarías cualquier otro middleware,
|
1156
1156
|
pero con la salvedad de que *no* tenés que llamar a `enable :sessions`:
|
1157
1157
|
|
1158
|
-
```
|
1158
|
+
```ruby
|
1159
1159
|
use Rack::Session::Pool, :expire_after => 2592000
|
1160
1160
|
|
1161
1161
|
get '/' do
|
@@ -1174,14 +1174,14 @@ tener en cuenta que cada vez que inicies la aplicación se va a generar
|
|
1174
1174
|
uno nuevo. Así, si querés que todas las instancias de tu aplicación
|
1175
1175
|
compartan un único secreto, tenés que definirlo vos:
|
1176
1176
|
|
1177
|
-
```
|
1177
|
+
```ruby
|
1178
1178
|
set :session_secret, 'super secreto'
|
1179
1179
|
```
|
1180
1180
|
|
1181
1181
|
Si necesitás una configuración más específica, `sessions` acepta un
|
1182
1182
|
Hash con opciones:
|
1183
1183
|
|
1184
|
-
```
|
1184
|
+
```ruby
|
1185
1185
|
set :sessions, :domain => 'foo.com'
|
1186
1186
|
```
|
1187
1187
|
|
@@ -1189,37 +1189,37 @@ set :sessions, :domain => 'foo.com'
|
|
1189
1189
|
|
1190
1190
|
Para detener inmediatamente una petición dentro de un filtro o una ruta usá:
|
1191
1191
|
|
1192
|
-
```
|
1192
|
+
```ruby
|
1193
1193
|
halt
|
1194
1194
|
```
|
1195
1195
|
|
1196
1196
|
También podés especificar el estado:
|
1197
1197
|
|
1198
|
-
```
|
1198
|
+
```ruby
|
1199
1199
|
halt 410
|
1200
1200
|
```
|
1201
1201
|
|
1202
1202
|
O el cuerpo:
|
1203
1203
|
|
1204
|
-
```
|
1204
|
+
```ruby
|
1205
1205
|
halt 'esto va a ser el cuerpo'
|
1206
1206
|
```
|
1207
1207
|
|
1208
1208
|
O los dos:
|
1209
1209
|
|
1210
|
-
```
|
1210
|
+
```ruby
|
1211
1211
|
halt 401, 'salí de acá!'
|
1212
1212
|
```
|
1213
1213
|
|
1214
1214
|
Con cabeceras:
|
1215
1215
|
|
1216
|
-
```
|
1216
|
+
```ruby
|
1217
1217
|
halt 402, { 'Content-Type' => 'text/plain' }, 'venganza'
|
1218
1218
|
```
|
1219
1219
|
|
1220
1220
|
Obviamente, es posible utilizar `halt` con una plantilla:
|
1221
1221
|
|
1222
|
-
```
|
1222
|
+
```ruby
|
1223
1223
|
halt erb(:error)
|
1224
1224
|
```
|
1225
1225
|
|
@@ -1228,7 +1228,7 @@ halt erb(:error)
|
|
1228
1228
|
Una ruta puede pasarle el procesamiento a la siguiente ruta que coincida con
|
1229
1229
|
la petición usando `pass`:
|
1230
1230
|
|
1231
|
-
```
|
1231
|
+
```ruby
|
1232
1232
|
get '/adivina/:quien' do
|
1233
1233
|
pass unless params['quien'] == 'Franco'
|
1234
1234
|
'Adivinaste!'
|
@@ -1247,7 +1247,7 @@ siguiente ruta que coincida. Si no coincide ninguna ruta, se devuelve 404.
|
|
1247
1247
|
Cuando querés obtener el resultado de la llamada a una ruta, `pass` no te va a
|
1248
1248
|
servir. Para lograr esto, podés usar `call`:
|
1249
1249
|
|
1250
|
-
```
|
1250
|
+
```ruby
|
1251
1251
|
get '/foo' do
|
1252
1252
|
status, headers, body = call env.merge("PATH_INFO" => '/bar')
|
1253
1253
|
[status, headers, body.map(&:upcase)]
|
@@ -1276,7 +1276,7 @@ escenarios, puede que sea conveniente asignar el cuerpo en un punto arbitrario
|
|
1276
1276
|
del flujo de ejecución con el método `body`. A partir de ahí, podés usar ese
|
1277
1277
|
mismo método para acceder al cuerpo de la respuesta:
|
1278
1278
|
|
1279
|
-
```
|
1279
|
+
```ruby
|
1280
1280
|
get '/foo' do
|
1281
1281
|
body "bar"
|
1282
1282
|
end
|
@@ -1291,7 +1291,7 @@ handler (podés usar esto para implementar streaming, mirá "Valores de retorno"
|
|
1291
1291
|
|
1292
1292
|
De manera similar, también podés asignar el código de estado y encabezados:
|
1293
1293
|
|
1294
|
-
```
|
1294
|
+
```ruby
|
1295
1295
|
get '/foo' do
|
1296
1296
|
status 418
|
1297
1297
|
headers \
|
@@ -1311,7 +1311,7 @@ terminaste de generar su cuerpo. También es posible que, en algunos casos,
|
|
1311
1311
|
quieras seguir enviando información hasta que el cliente cierre la conexión.
|
1312
1312
|
Cuando esto ocurra, el helper `stream` te va a ser de gran ayuda:
|
1313
1313
|
|
1314
|
-
```
|
1314
|
+
```ruby
|
1315
1315
|
get '/' do
|
1316
1316
|
stream do |out|
|
1317
1317
|
out << "Esto va a ser legen -\n"
|
@@ -1324,17 +1324,17 @@ end
|
|
1324
1324
|
```
|
1325
1325
|
|
1326
1326
|
Podés implementar APIs de streaming,
|
1327
|
-
[Server-Sent Events](
|
1328
|
-
como base para [WebSockets](
|
1327
|
+
[Server-Sent Events](https://w3c.github.io/eventsource/) y puede ser usado
|
1328
|
+
como base para [WebSockets](https://es.wikipedia.org/wiki/WebSockets). También
|
1329
1329
|
puede ser usado para incrementar el throughput si solo una parte del contenido
|
1330
1330
|
depende de un recurso lento.
|
1331
1331
|
|
1332
1332
|
Hay que tener en cuenta que el comportamiento del streaming, especialmente el
|
1333
1333
|
número de peticiones concurrentes, depende del servidor web utilizado para
|
1334
|
-
alojar la aplicación. Puede que algunos servidores
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1334
|
+
alojar la aplicación. Puede que algunos servidores no soporten streaming
|
1335
|
+
directamente, así el cuerpo de la respuesta será enviado completamente de una
|
1336
|
+
vez cuando el bloque pasado a `stream` finalice su ejecución. Si estás usando
|
1337
|
+
Shotgun, el streaming no va a funcionar.
|
1338
1338
|
|
1339
1339
|
Cuando se pasa `keep_open` como parámetro, no se va a enviar el mensaje
|
1340
1340
|
`close` al objeto de stream. Queda en vos cerrarlo en el punto de ejecución
|
@@ -1342,7 +1342,7 @@ que quieras. Nuevamente, hay que tener en cuenta que este comportamiento es
|
|
1342
1342
|
posible solo en servidores que soporten eventos, como Thin o Rainbows. El
|
1343
1343
|
resto de los servidores van a cerrar el stream de todos modos:
|
1344
1344
|
|
1345
|
-
```
|
1345
|
+
```ruby
|
1346
1346
|
set :server, :thin
|
1347
1347
|
conexiones = []
|
1348
1348
|
|
@@ -1363,7 +1363,7 @@ end
|
|
1363
1363
|
En el ámbito de la petición, el helper `logger` (registrador) expone
|
1364
1364
|
una instancia de `Logger`:
|
1365
1365
|
|
1366
|
-
```
|
1366
|
+
```ruby
|
1367
1367
|
get '/' do
|
1368
1368
|
logger.info "cargando datos"
|
1369
1369
|
# ...
|
@@ -1379,7 +1379,7 @@ Tené en cuenta que el logueo está habilitado por defecto únicamente
|
|
1379
1379
|
para `Sinatra::Application`. Si heredaste de
|
1380
1380
|
`Sinatra::Base`, probablemente quieras habilitarlo manualmente:
|
1381
1381
|
|
1382
|
-
```
|
1382
|
+
```ruby
|
1383
1383
|
class MiApp < Sinatra::Base
|
1384
1384
|
configure :production, :development do
|
1385
1385
|
enable :logging
|
@@ -1398,7 +1398,7 @@ Cuando usás `send_file` o archivos estáticos tal vez tengas tipos mime
|
|
1398
1398
|
que Sinatra no entiende. Usá `mime_type` para registrarlos a través de la
|
1399
1399
|
extensión de archivo:
|
1400
1400
|
|
1401
|
-
```
|
1401
|
+
```ruby
|
1402
1402
|
configure do
|
1403
1403
|
mime_type :foo, 'text/foo'
|
1404
1404
|
end
|
@@ -1406,7 +1406,7 @@ end
|
|
1406
1406
|
|
1407
1407
|
También lo podés usar con el ayudante `content_type`:
|
1408
1408
|
|
1409
|
-
```
|
1409
|
+
```ruby
|
1410
1410
|
get '/' do
|
1411
1411
|
content_type :foo
|
1412
1412
|
"foo foo foo"
|
@@ -1417,7 +1417,7 @@ end
|
|
1417
1417
|
|
1418
1418
|
Para generar URLs deberías usar el método `url`. Por ejemplo, en Haml:
|
1419
1419
|
|
1420
|
-
```
|
1420
|
+
```ruby
|
1421
1421
|
%a{:href => url('/foo')} foo
|
1422
1422
|
```
|
1423
1423
|
|
@@ -1430,7 +1430,7 @@ a continuación).
|
|
1430
1430
|
|
1431
1431
|
Podés redireccionar al navegador con el método `redirect`:
|
1432
1432
|
|
1433
|
-
```
|
1433
|
+
```ruby
|
1434
1434
|
get '/foo' do
|
1435
1435
|
redirect to('/bar')
|
1436
1436
|
end
|
@@ -1439,15 +1439,15 @@ end
|
|
1439
1439
|
Cualquier parámetro adicional se utiliza de la misma manera que los argumentos
|
1440
1440
|
pasados a `halt`:
|
1441
1441
|
|
1442
|
-
```
|
1442
|
+
```ruby
|
1443
1443
|
redirect to('/bar'), 303
|
1444
|
-
redirect 'http://google.com', 'te confundiste de lugar, compañero'
|
1444
|
+
redirect 'http://www.google.com/', 'te confundiste de lugar, compañero'
|
1445
1445
|
```
|
1446
1446
|
|
1447
1447
|
También podés redireccionar fácilmente de vuelta hacia la página desde donde
|
1448
1448
|
vino el usuario con `redirect back`:
|
1449
1449
|
|
1450
|
-
```
|
1450
|
+
```ruby
|
1451
1451
|
get '/foo' do
|
1452
1452
|
"<a href='/bar'>hacer algo</a>"
|
1453
1453
|
end
|
@@ -1461,13 +1461,13 @@ end
|
|
1461
1461
|
Para pasar argumentos con una redirección, podés agregarlos a la cadena de
|
1462
1462
|
búsqueda:
|
1463
1463
|
|
1464
|
-
```
|
1464
|
+
```ruby
|
1465
1465
|
redirect to('/bar?suma=42')
|
1466
1466
|
```
|
1467
1467
|
|
1468
1468
|
O usar una sesión:
|
1469
1469
|
|
1470
|
-
```
|
1470
|
+
```ruby
|
1471
1471
|
enable :sessions
|
1472
1472
|
|
1473
1473
|
get '/foo' do
|
@@ -1487,7 +1487,7 @@ HTTP correcto.
|
|
1487
1487
|
|
1488
1488
|
Podés asignar el encabezado Cache-Control fácilmente:
|
1489
1489
|
|
1490
|
-
```
|
1490
|
+
```ruby
|
1491
1491
|
get '/' do
|
1492
1492
|
cache_control :public
|
1493
1493
|
"cachealo!"
|
@@ -1496,7 +1496,7 @@ end
|
|
1496
1496
|
|
1497
1497
|
Pro tip: configurar el cacheo en un filtro `before`:
|
1498
1498
|
|
1499
|
-
```
|
1499
|
+
```ruby
|
1500
1500
|
before do
|
1501
1501
|
cache_control :public, :must_revalidate, :max_age => 60
|
1502
1502
|
end
|
@@ -1505,7 +1505,7 @@ end
|
|
1505
1505
|
Si estás usando el helper `expires` para definir el encabezado correspondiente,
|
1506
1506
|
`Cache-Control` se va a definir automáticamente:
|
1507
1507
|
|
1508
|
-
```
|
1508
|
+
```ruby
|
1509
1509
|
before do
|
1510
1510
|
expires 500, :public, :must_revalidate
|
1511
1511
|
end
|
@@ -1516,7 +1516,7 @@ Para usar cachés adecuadamente, deberías considerar usar `etag` o
|
|
1516
1516
|
cualquier trabajo pesado, ya que van a enviar la respuesta inmediatamente si
|
1517
1517
|
el cliente ya tiene la versión actual en su caché:
|
1518
1518
|
|
1519
|
-
```
|
1519
|
+
```ruby
|
1520
1520
|
get '/articulo/:id' do
|
1521
1521
|
@articulo = Articulo.find params['id']
|
1522
1522
|
last_modified @articulo.updated_at
|
@@ -1526,9 +1526,9 @@ end
|
|
1526
1526
|
```
|
1527
1527
|
|
1528
1528
|
También es posible usar una
|
1529
|
-
[weak ETag](
|
1529
|
+
[weak ETag](https://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation):
|
1530
1530
|
|
1531
|
-
```
|
1531
|
+
```ruby
|
1532
1532
|
etag @articulo.sha1, :weak
|
1533
1533
|
```
|
1534
1534
|
|
@@ -1537,7 +1537,7 @@ información necesaria para poder hacerlo. Si estás buscando soluciones rápida
|
|
1537
1537
|
de cacheo con proxys reversos, mirá
|
1538
1538
|
[rack-cache](https://github.com/rtomayko/rack-cache):
|
1539
1539
|
|
1540
|
-
```
|
1540
|
+
```ruby
|
1541
1541
|
require "rack/cache"
|
1542
1542
|
require "sinatra"
|
1543
1543
|
|
@@ -1561,7 +1561,7 @@ y potentes (como put) que el recurso existe, mientras que para el resto
|
|
1561
1561
|
(como post) asume que no. Podés cambiar este comportamiento con la opción
|
1562
1562
|
`:new_resource`:
|
1563
1563
|
|
1564
|
-
```
|
1564
|
+
```ruby
|
1565
1565
|
get '/crear' do
|
1566
1566
|
etag '', :new_resource => true
|
1567
1567
|
Articulo.create
|
@@ -1571,7 +1571,7 @@ end
|
|
1571
1571
|
|
1572
1572
|
Si querés seguir usando una weak ETag, indicalo con la opción `:kind`:
|
1573
1573
|
|
1574
|
-
```
|
1574
|
+
```ruby
|
1575
1575
|
etag '', :new_resource => true, :kind => :weak
|
1576
1576
|
```
|
1577
1577
|
|
@@ -1579,7 +1579,7 @@ etag '', :new_resource => true, :kind => :weak
|
|
1579
1579
|
|
1580
1580
|
Para enviar archivos, podés usar el método `send_file`:
|
1581
1581
|
|
1582
|
-
```
|
1582
|
+
```ruby
|
1583
1583
|
get '/' do
|
1584
1584
|
send_file 'foo.png'
|
1585
1585
|
end
|
@@ -1587,7 +1587,7 @@ end
|
|
1587
1587
|
|
1588
1588
|
Además acepta un par de opciones:
|
1589
1589
|
|
1590
|
-
```
|
1590
|
+
```ruby
|
1591
1591
|
send_file 'foo.png', :type => :jpg
|
1592
1592
|
```
|
1593
1593
|
|
@@ -1625,7 +1625,7 @@ El objeto de la petición entrante puede ser accedido desde el nivel de la
|
|
1625
1625
|
petición (filtros, rutas y manejadores de errores) a través del método
|
1626
1626
|
`request`:
|
1627
1627
|
|
1628
|
-
```
|
1628
|
+
```ruby
|
1629
1629
|
# app corriendo en http://ejemplo.com/ejemplo
|
1630
1630
|
get '/foo' do
|
1631
1631
|
t = %w[text/css text/html application/javascript]
|
@@ -1661,7 +1661,7 @@ end
|
|
1661
1661
|
Algunas opciones, como `script_name` o `path_info` pueden
|
1662
1662
|
también ser escritas:
|
1663
1663
|
|
1664
|
-
```
|
1664
|
+
```ruby
|
1665
1665
|
before { request.path_info = "/" }
|
1666
1666
|
|
1667
1667
|
get "/" do
|
@@ -1671,7 +1671,7 @@ end
|
|
1671
1671
|
|
1672
1672
|
El objeto `request.body` es una instancia de IO o StringIO:
|
1673
1673
|
|
1674
|
-
```
|
1674
|
+
```ruby
|
1675
1675
|
post "/api" do
|
1676
1676
|
request.body.rewind # en caso de que alguien ya lo haya leído
|
1677
1677
|
datos = JSON.parse request.body.read
|
@@ -1684,7 +1684,7 @@ end
|
|
1684
1684
|
Podés usar el helper `attachment` para indicarle al navegador que
|
1685
1685
|
almacene la respuesta en el disco en lugar de mostrarla en pantalla:
|
1686
1686
|
|
1687
|
-
```
|
1687
|
+
```ruby
|
1688
1688
|
get '/' do
|
1689
1689
|
attachment
|
1690
1690
|
"guardalo!"
|
@@ -1693,7 +1693,7 @@ end
|
|
1693
1693
|
|
1694
1694
|
También podés pasarle un nombre de archivo:
|
1695
1695
|
|
1696
|
-
```
|
1696
|
+
```ruby
|
1697
1697
|
get '/' do
|
1698
1698
|
attachment "info.txt"
|
1699
1699
|
"guardalo!"
|
@@ -1707,7 +1707,7 @@ a partir del valor que recibe como argumento. Este valor puede ser un
|
|
1707
1707
|
`String`, pero también es capaz de convertir objetos `DateTime`, `Date` y de
|
1708
1708
|
otras clases similares:
|
1709
1709
|
|
1710
|
-
```
|
1710
|
+
```ruby
|
1711
1711
|
get '/' do
|
1712
1712
|
pass if Time.now > time_for('Dec 23, 2012')
|
1713
1713
|
"todavía hay tiempo"
|
@@ -1718,7 +1718,7 @@ Este método es usado internamente por métodos como `expires` y `last_modified`
|
|
1718
1718
|
entre otros. Por lo tanto, es posible extender el comportamiento de estos
|
1719
1719
|
métodos sobreescribiendo `time_for` en tu aplicación:
|
1720
1720
|
|
1721
|
-
```
|
1721
|
+
```ruby
|
1722
1722
|
helpers do
|
1723
1723
|
def time_for(value)
|
1724
1724
|
case value
|
@@ -1741,7 +1741,7 @@ end
|
|
1741
1741
|
El helper `find_template` se utiliza para encontrar los archivos de las
|
1742
1742
|
plantillas que se van a renderizar:
|
1743
1743
|
|
1744
|
-
```
|
1744
|
+
```ruby
|
1745
1745
|
find_template settings.views, 'foo', Tilt[:haml] do |archivo|
|
1746
1746
|
puts "podría ser #{archivo}"
|
1747
1747
|
end
|
@@ -1751,7 +1751,7 @@ Si bien esto no es muy útil, lo interesante es que podés sobreescribir este
|
|
1751
1751
|
método, y así enganchar tu propio mecanismo de búsqueda. Por ejemplo, para
|
1752
1752
|
poder utilizar más de un directorio de vistas:
|
1753
1753
|
|
1754
|
-
```
|
1754
|
+
```ruby
|
1755
1755
|
set :views, ['vistas', 'plantillas']
|
1756
1756
|
|
1757
1757
|
helpers do
|
@@ -1764,7 +1764,7 @@ end
|
|
1764
1764
|
Otro ejemplo consiste en usar directorios diferentes para los distintos motores
|
1765
1765
|
de renderizado:
|
1766
1766
|
|
1767
|
-
```
|
1767
|
+
```ruby
|
1768
1768
|
set :views, :sass => 'vistas/sass', :haml => 'plantillas', :defecto => 'vistas'
|
1769
1769
|
|
1770
1770
|
helpers do
|
@@ -1789,7 +1789,7 @@ tener en cuenta lo anterior si escribís un método extraño.
|
|
1789
1789
|
|
1790
1790
|
Ejecutar una vez, en el inicio, en cualquier entorno:
|
1791
1791
|
|
1792
|
-
```
|
1792
|
+
```ruby
|
1793
1793
|
configure do
|
1794
1794
|
# asignando una opción
|
1795
1795
|
set :opcion, 'valor'
|
@@ -1811,7 +1811,7 @@ end
|
|
1811
1811
|
Ejecutar únicamente cuando el entorno (la variable de entorno RACK_ENV) es
|
1812
1812
|
`:production`:
|
1813
1813
|
|
1814
|
-
```
|
1814
|
+
```ruby
|
1815
1815
|
configure :production do
|
1816
1816
|
...
|
1817
1817
|
end
|
@@ -1819,7 +1819,7 @@ end
|
|
1819
1819
|
|
1820
1820
|
Ejecutar cuando el entorno es `:production` o `:test`:
|
1821
1821
|
|
1822
|
-
```
|
1822
|
+
```ruby
|
1823
1823
|
configure :production, :test do
|
1824
1824
|
...
|
1825
1825
|
end
|
@@ -1827,7 +1827,7 @@ end
|
|
1827
1827
|
|
1828
1828
|
Podés acceder a estas opciones utilizando el método `settings`:
|
1829
1829
|
|
1830
|
-
```
|
1830
|
+
```ruby
|
1831
1831
|
configure do
|
1832
1832
|
set :foo, 'bar'
|
1833
1833
|
end
|
@@ -1841,25 +1841,25 @@ end
|
|
1841
1841
|
|
1842
1842
|
### Configurando la Protección de Ataques
|
1843
1843
|
|
1844
|
-
Sinatra usa [Rack::Protection](https://github.com/
|
1844
|
+
Sinatra usa [Rack::Protection](https://github.com/sinatra/rack-protection#readme)
|
1845
1845
|
para defender a tu aplicación de los ataques más comunes. Si por algún motivo,
|
1846
1846
|
querés desactivar esta funcionalidad, podés hacerlo como se indica a
|
1847
1847
|
continuación (ten en cuenta que tu aplicación va a quedar expuesta a un
|
1848
1848
|
montón de vulnerabilidades bien conocidas):
|
1849
1849
|
|
1850
|
-
```
|
1850
|
+
```ruby
|
1851
1851
|
disable :protection
|
1852
1852
|
```
|
1853
1853
|
|
1854
1854
|
También es posible desactivar una única capa de defensa:
|
1855
1855
|
|
1856
|
-
```
|
1856
|
+
```ruby
|
1857
1857
|
set :protection, :except => :path_traversal
|
1858
1858
|
```
|
1859
1859
|
|
1860
1860
|
O varias:
|
1861
1861
|
|
1862
|
-
```
|
1862
|
+
```ruby
|
1863
1863
|
set :protection, :except => [:path_traversal, :session_hijacking]
|
1864
1864
|
```
|
1865
1865
|
|
@@ -2083,7 +2083,7 @@ Para utilizar alguno de los otros entornos puede asignarse el valor
|
|
2083
2083
|
correspondiente a la variable de entorno `RACK_ENV`, o bien utilizar la opción
|
2084
2084
|
`-e` al ejecutar la aplicación:
|
2085
2085
|
|
2086
|
-
```
|
2086
|
+
```shell
|
2087
2087
|
ruby mi_app.rb -e <ENTORNO>
|
2088
2088
|
```
|
2089
2089
|
|
@@ -2101,7 +2101,7 @@ y los filtros `before`, lo que significa que podés usar, por ejemplo,
|
|
2101
2101
|
Cuando se eleva una excepción `Sinatra::NotFound`, o el código de
|
2102
2102
|
estado de la respuesta es 404, el manejador `not_found` es invocado:
|
2103
2103
|
|
2104
|
-
```
|
2104
|
+
```ruby
|
2105
2105
|
not_found do
|
2106
2106
|
'No existo'
|
2107
2107
|
end
|
@@ -2113,7 +2113,7 @@ El manejador `error` es invocado cada vez que una excepción es elevada
|
|
2113
2113
|
desde un bloque de ruta o un filtro. El objeto de la excepción se puede
|
2114
2114
|
obtener de la variable Rack `sinatra.error`:
|
2115
2115
|
|
2116
|
-
```
|
2116
|
+
```ruby
|
2117
2117
|
error do
|
2118
2118
|
'Disculpá, ocurrió un error horrible - ' + env['sinatra.error'].message
|
2119
2119
|
end
|
@@ -2121,7 +2121,7 @@ end
|
|
2121
2121
|
|
2122
2122
|
Errores personalizados:
|
2123
2123
|
|
2124
|
-
```
|
2124
|
+
```ruby
|
2125
2125
|
error MiErrorPersonalizado do
|
2126
2126
|
'Lo que pasó fue...' + env['sinatra.error'].message
|
2127
2127
|
end
|
@@ -2129,7 +2129,7 @@ end
|
|
2129
2129
|
|
2130
2130
|
Entonces, si pasa esto:
|
2131
2131
|
|
2132
|
-
```
|
2132
|
+
```ruby
|
2133
2133
|
get '/' do
|
2134
2134
|
raise MiErrorPersonalizado, 'algo malo'
|
2135
2135
|
end
|
@@ -2141,7 +2141,7 @@ Obtenés esto:
|
|
2141
2141
|
|
2142
2142
|
También, podés instalar un manejador de errores para un código de estado:
|
2143
2143
|
|
2144
|
-
```
|
2144
|
+
```ruby
|
2145
2145
|
error 403 do
|
2146
2146
|
'Acceso prohibido'
|
2147
2147
|
end
|
@@ -2153,7 +2153,7 @@ end
|
|
2153
2153
|
|
2154
2154
|
O un rango:
|
2155
2155
|
|
2156
|
-
```
|
2156
|
+
```ruby
|
2157
2157
|
error 400..510 do
|
2158
2158
|
'Boom'
|
2159
2159
|
end
|
@@ -2174,7 +2174,7 @@ proporcionar varios tipos de funcionalidades comunes.
|
|
2174
2174
|
Sinatra hace muy sencillo construir tuberías de Rack middleware a través del
|
2175
2175
|
método top-level `use`:
|
2176
2176
|
|
2177
|
-
```
|
2177
|
+
```ruby
|
2178
2178
|
require 'sinatra'
|
2179
2179
|
require 'mi_middleware_personalizado'
|
2180
2180
|
|
@@ -2187,11 +2187,11 @@ end
|
|
2187
2187
|
```
|
2188
2188
|
|
2189
2189
|
La semántica de `use` es idéntica a la definida para el DSL
|
2190
|
-
Rack::Builder[http://rubydoc.info/github/rack/rack/master/Rack/Builder] (más
|
2190
|
+
Rack::Builder[http://www.rubydoc.info/github/rack/rack/master/Rack/Builder] (más
|
2191
2191
|
frecuentemente usado en archivos rackup). Por ejemplo, el método `use`
|
2192
2192
|
acepta argumentos múltiples/variables así como bloques:
|
2193
2193
|
|
2194
|
-
```
|
2194
|
+
```ruby
|
2195
2195
|
use Rack::Auth::Basic do |nombre_de_usuario, password|
|
2196
2196
|
nombre_de_usuario == 'admin' && password == 'secreto'
|
2197
2197
|
end
|
@@ -2211,9 +2211,9 @@ o en la [Rack wiki](https://github.com/rack/rack/wiki/List-of-Middleware).
|
|
2211
2211
|
|
2212
2212
|
Las pruebas para las aplicaciones Sinatra pueden ser escritas utilizando
|
2213
2213
|
cualquier framework o librería de pruebas basada en Rack. Se recomienda usar
|
2214
|
-
[Rack::Test](http://
|
2214
|
+
[Rack::Test](http://www.rubydoc.info/github/brynary/rack-test/master/frames):
|
2215
2215
|
|
2216
|
-
```
|
2216
|
+
```ruby
|
2217
2217
|
require 'mi_app_sinatra'
|
2218
2218
|
require 'minitest/autorun'
|
2219
2219
|
require 'rack/test'
|
@@ -2253,7 +2253,7 @@ asume una configuración apropiada para micro-aplicaciones (por ejemplo, un
|
|
2253
2253
|
`./views`, logging, página con detalles de excepción, etc.). Ahí es
|
2254
2254
|
donde `Sinatra::Base` entra en el juego:
|
2255
2255
|
|
2256
|
-
```
|
2256
|
+
```ruby
|
2257
2257
|
require 'sinatra/base'
|
2258
2258
|
|
2259
2259
|
class MiApp < Sinatra::Base
|
@@ -2279,7 +2279,7 @@ aplicaciones top-level se pueden convertir en componentes
|
|
2279
2279
|
|
2280
2280
|
`Sinatra::Base` es una pizarra en blanco. La mayoría de las opciones están
|
2281
2281
|
desactivadas por defecto, incluyendo el servidor incorporado. Mirá
|
2282
|
-
[Opciones y Configuraciones](http://
|
2282
|
+
[Opciones y Configuraciones](http://www.sinatrarb.com/configuration.html)
|
2283
2283
|
para detalles sobre las opciones disponibles y su comportamiento.
|
2284
2284
|
|
2285
2285
|
### Estilo Modular vs. Clásico
|
@@ -2336,7 +2336,7 @@ de ambos estilos:
|
|
2336
2336
|
<tr>
|
2337
2337
|
<td>static</td>
|
2338
2338
|
<td>true</td>
|
2339
|
-
<td>
|
2339
|
+
<td>File.exist?(public_folder)</td>
|
2340
2340
|
</tr>
|
2341
2341
|
</table>
|
2342
2342
|
|
@@ -2345,7 +2345,7 @@ de ambos estilos:
|
|
2345
2345
|
Las dos opciones más comunes para iniciar una aplicación modular son, iniciarla
|
2346
2346
|
activamente con `run!`:
|
2347
2347
|
|
2348
|
-
```
|
2348
|
+
```ruby
|
2349
2349
|
# mi_app.rb
|
2350
2350
|
require 'sinatra/base'
|
2351
2351
|
|
@@ -2359,13 +2359,13 @@ end
|
|
2359
2359
|
|
2360
2360
|
Iniciar con:
|
2361
2361
|
|
2362
|
-
```
|
2362
|
+
```shell
|
2363
2363
|
ruby mi_app.rb
|
2364
2364
|
```
|
2365
2365
|
|
2366
2366
|
O, con un archivo `config.ru`, que permite usar cualquier handler Rack:
|
2367
2367
|
|
2368
|
-
```
|
2368
|
+
```ruby
|
2369
2369
|
# config.ru
|
2370
2370
|
require './mi_app'
|
2371
2371
|
run MiApp
|
@@ -2373,7 +2373,7 @@ run MiApp
|
|
2373
2373
|
|
2374
2374
|
Después ejecutar:
|
2375
2375
|
|
2376
|
-
```
|
2376
|
+
```shell
|
2377
2377
|
rackup -p 4567
|
2378
2378
|
```
|
2379
2379
|
|
@@ -2381,7 +2381,7 @@ rackup -p 4567
|
|
2381
2381
|
|
2382
2382
|
Escribí el archivo de tu aplicación:
|
2383
2383
|
|
2384
|
-
```
|
2384
|
+
```ruby
|
2385
2385
|
# app.rb
|
2386
2386
|
require 'sinatra'
|
2387
2387
|
|
@@ -2392,7 +2392,7 @@ end
|
|
2392
2392
|
|
2393
2393
|
Y el `config.ru` correspondiente:
|
2394
2394
|
|
2395
|
-
```
|
2395
|
+
```ruby
|
2396
2396
|
require './app'
|
2397
2397
|
run Sinatra::Application
|
2398
2398
|
```
|
@@ -2417,7 +2417,7 @@ cualquier aplicación Sinatra puede ser agregada delante de un endpoint Rack
|
|
2417
2417
|
como middleware. Este endpoint puede ser otra aplicación Sinatra, o cualquier
|
2418
2418
|
aplicación basada en Rack (Rails/Ramaze/Camping/...):
|
2419
2419
|
|
2420
|
-
```
|
2420
|
+
```ruby
|
2421
2421
|
require 'sinatra/base'
|
2422
2422
|
|
2423
2423
|
class PantallaDeLogin < Sinatra::Base
|
@@ -2454,7 +2454,7 @@ Puede que en algunas ocasiones quieras crear nuevas aplicaciones en
|
|
2454
2454
|
tiempo de ejecución sin tener que asignarlas a una constante. Para
|
2455
2455
|
esto tenés `Sinatra.new`:
|
2456
2456
|
|
2457
|
-
```
|
2457
|
+
```ruby
|
2458
2458
|
require 'sinatra/base'
|
2459
2459
|
mi_app = Sinatra.new { get('/') { "hola" } }
|
2460
2460
|
mi_app.run!
|
@@ -2463,7 +2463,7 @@ mi_app.run!
|
|
2463
2463
|
Acepta como argumento opcional una aplicación desde la que se
|
2464
2464
|
heredará:
|
2465
2465
|
|
2466
|
-
```
|
2466
|
+
```ruby
|
2467
2467
|
# config.ru
|
2468
2468
|
require 'sinatra/base'
|
2469
2469
|
|
@@ -2487,7 +2487,7 @@ testear extensiones Sinatra o para usar Sinatra en tus librerías.
|
|
2487
2487
|
Por otro lado, hace extremadamente sencillo usar Sinatra como
|
2488
2488
|
middleware:
|
2489
2489
|
|
2490
|
-
```
|
2490
|
+
```ruby
|
2491
2491
|
require 'sinatra/base'
|
2492
2492
|
|
2493
2493
|
use Sinatra do
|
@@ -2513,7 +2513,7 @@ clase de la aplicación para todas las peticiones.
|
|
2513
2513
|
|
2514
2514
|
Las opciones creadas utilizando `set` son métodos al nivel de la clase:
|
2515
2515
|
|
2516
|
-
```
|
2516
|
+
```ruby
|
2517
2517
|
class MiApp < Sinatra::Base
|
2518
2518
|
# Ey, estoy en el ámbito de la aplicación!
|
2519
2519
|
set :foo, 42
|
@@ -2545,7 +2545,7 @@ es creada y todos los bloques de rutas son ejecutados en ese ámbito. Desde este
|
|
2545
2545
|
de renderización como `erb` o `haml`. Podés acceder al ámbito de la aplicación
|
2546
2546
|
desde el ámbito de la petición utilizando `settings`:
|
2547
2547
|
|
2548
|
-
```
|
2548
|
+
```ruby
|
2549
2549
|
class MiApp < Sinatra::Base
|
2550
2550
|
# Ey, estoy en el ámbito de la aplicación!
|
2551
2551
|
get '/definir_ruta/:nombre' do
|
@@ -2591,7 +2591,7 @@ que [extiende el objeto main](https://github.com/sinatra/sinatra/blob/ca06364/li
|
|
2591
2591
|
|
2592
2592
|
Las aplicaciones Sinatra pueden ser ejecutadas directamente:
|
2593
2593
|
|
2594
|
-
```
|
2594
|
+
```shell
|
2595
2595
|
ruby miapp.rb [-h] [-x] [-e ENTORNO] [-p PUERTO] [-o HOST] [-s MANEJADOR]
|
2596
2596
|
```
|
2597
2597
|
|
@@ -2606,6 +2606,41 @@ Las opciones son:
|
|
2606
2606
|
-x # activa el mutex lock (está desactivado por defecto)
|
2607
2607
|
```
|
2608
2608
|
|
2609
|
+
### Multi-threading
|
2610
|
+
|
2611
|
+
_Basado en [esta respuesta en StackOverflow][so-answer] escrita por Konstantin_
|
2612
|
+
|
2613
|
+
Sinatra no impone ningún modelo de concurrencia, sino que lo deja en manos del
|
2614
|
+
handler Rack que se esté usando (Thin, Puma, WEBrick). Sinatra en sí mismo es
|
2615
|
+
thread-safe, así que no hay problema en que el Rack handler use un modelo de
|
2616
|
+
concurrencia basado en hilos.
|
2617
|
+
|
2618
|
+
Esto significa que, cuando estemos arrancando el servidor, tendríamos que
|
2619
|
+
especificar la opción adecuada para el handler Rack específico. En este ejemplo
|
2620
|
+
vemos cómo arrancar un servidor Thin multihilo:
|
2621
|
+
|
2622
|
+
```ruby
|
2623
|
+
# app.rb
|
2624
|
+
|
2625
|
+
require 'sinatra/base'
|
2626
|
+
|
2627
|
+
class App < Sinatra::Base
|
2628
|
+
get '/' do
|
2629
|
+
"¡Hola, Mundo!"
|
2630
|
+
end
|
2631
|
+
end
|
2632
|
+
|
2633
|
+
App.run!
|
2634
|
+
```
|
2635
|
+
|
2636
|
+
Para arrancar el servidor, el comando sería:
|
2637
|
+
|
2638
|
+
```shell
|
2639
|
+
thin --threaded start
|
2640
|
+
```
|
2641
|
+
|
2642
|
+
[so-answer]: http://stackoverflow.com/questions/6278817/is-sinatra-multi-threaded/6282999#6282999)
|
2643
|
+
|
2609
2644
|
## Versiones de Ruby Soportadas
|
2610
2645
|
|
2611
2646
|
Las siguientes versiones de Ruby son soportadas oficialmente:
|
@@ -2688,7 +2723,7 @@ tu aplicación sobre la rama master, en general es bastante estable.
|
|
2688
2723
|
|
2689
2724
|
También liberamos prereleases de vez en cuando, así, podés hacer:
|
2690
2725
|
|
2691
|
-
```
|
2726
|
+
```shell
|
2692
2727
|
gem install sinatra --pre
|
2693
2728
|
```
|
2694
2729
|
|
@@ -2697,17 +2732,17 @@ Para obtener algunas de las últimas características.
|
|
2697
2732
|
### Con Bundler
|
2698
2733
|
|
2699
2734
|
Esta es la manera recomendada para ejecutar tu aplicación sobre la última
|
2700
|
-
versión de Sinatra usando [Bundler](http://
|
2735
|
+
versión de Sinatra usando [Bundler](http://bundler.io).
|
2701
2736
|
|
2702
2737
|
Primero, instalá Bundler si no lo hiciste todavía:
|
2703
2738
|
|
2704
|
-
```
|
2739
|
+
```shell
|
2705
2740
|
gem install bundler
|
2706
2741
|
```
|
2707
2742
|
|
2708
2743
|
Después, en el directorio de tu proyecto, creá un archivo `Gemfile`:
|
2709
2744
|
|
2710
|
-
```
|
2745
|
+
```ruby
|
2711
2746
|
source :rubygems
|
2712
2747
|
gem 'sinatra', :git => "git://github.com/sinatra/sinatra.git"
|
2713
2748
|
|
@@ -2722,7 +2757,7 @@ porque Bundler las agrega directamente.
|
|
2722
2757
|
|
2723
2758
|
Ahora podés arrancar tu aplicación así:
|
2724
2759
|
|
2725
|
-
```
|
2760
|
+
```shell
|
2726
2761
|
bundle exec ruby miapp.rb
|
2727
2762
|
```
|
2728
2763
|
|
@@ -2731,7 +2766,7 @@ bundle exec ruby miapp.rb
|
|
2731
2766
|
Cloná el repositorio localmente y ejecutá tu aplicación, asegurándote que el
|
2732
2767
|
directorio `sinatra/lib` esté en el `$LOAD_PATH`:
|
2733
2768
|
|
2734
|
-
```
|
2769
|
+
```shell
|
2735
2770
|
cd miapp
|
2736
2771
|
git clone git://github.com/sinatra/sinatra.git
|
2737
2772
|
ruby -Isinatra/lib miapp.rb
|
@@ -2739,7 +2774,7 @@ ruby -Isinatra/lib miapp.rb
|
|
2739
2774
|
|
2740
2775
|
Para actualizar el código fuente de Sinatra en el futuro:
|
2741
2776
|
|
2742
|
-
```
|
2777
|
+
```shell
|
2743
2778
|
cd miapp/sinatra
|
2744
2779
|
git pull
|
2745
2780
|
```
|
@@ -2748,7 +2783,7 @@ git pull
|
|
2748
2783
|
|
2749
2784
|
Podés construir la gem vos mismo:
|
2750
2785
|
|
2751
|
-
```
|
2786
|
+
```shell
|
2752
2787
|
git clone git://github.com/sinatra/sinatra.git
|
2753
2788
|
cd sinatra
|
2754
2789
|
rake sinatra.gemspec
|
@@ -2757,7 +2792,7 @@ rake install
|
|
2757
2792
|
|
2758
2793
|
Si instalás tus gems como root, el último paso debería ser
|
2759
2794
|
|
2760
|
-
```
|
2795
|
+
```shell
|
2761
2796
|
sudo rake install
|
2762
2797
|
```
|
2763
2798
|
|
@@ -2772,15 +2807,15 @@ siguiendo las especificaciones SemVer y SemVerTag.
|
|
2772
2807
|
adicional, noticias, y enlaces a otros recursos.
|
2773
2808
|
* [Contribuyendo](http://www.sinatrarb.com/contributing) - ¿Encontraste un
|
2774
2809
|
error?. ¿Necesitás ayuda?. ¿Tenés un parche?.
|
2775
|
-
* [Seguimiento de problemas](
|
2776
|
-
* [Twitter](
|
2810
|
+
* [Seguimiento de problemas](https://github.com/sinatra/sinatra/issues)
|
2811
|
+
* [Twitter](https://twitter.com/sinatra)
|
2777
2812
|
* [Lista de Correo](http://groups.google.com/group/sinatrarb/topics)
|
2778
2813
|
* [IRC: #sinatra](irc://chat.freenode.net/#sinatra) en http://freenode.net
|
2779
2814
|
* [Sinatra Book](https://github.com/sinatra/sinatra-book/) Tutorial (en inglés).
|
2780
2815
|
* [Sinatra Recipes](http://recipes.sinatrarb.com/) Recetas contribuidas
|
2781
2816
|
por la comunidad (en inglés).
|
2782
2817
|
* 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](
|
2818
|
+
[última versión liberada](http://www.rubydoc.info/gems/sinatra) o para la
|
2819
|
+
[rama de desarrollo actual](http://www.rubydoc.info/github/sinatra/sinatra)
|
2820
|
+
en http://www.rubydoc.info/
|
2821
|
+
* [Servidor de CI](https://travis-ci.org/sinatra/sinatra)
|