sinatra 1.2.0.c → 1.2.0.d
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.
- data/AUTHORS +10 -1
- data/Gemfile +24 -6
- data/README.de.rdoc +696 -72
- data/README.es.rdoc +545 -61
- data/README.fr.rdoc +2 -2
- data/README.jp.rdoc +2 -2
- data/README.rdoc +281 -74
- data/README.ru.rdoc +2 -2
- data/README.zh.rdoc +2 -2
- data/Rakefile +10 -7
- data/lib/sinatra/base.rb +48 -20
- data/sinatra.gemspec +4 -5
- data/test/encoding_test.rb +4 -3
- data/test/helper.rb +2 -0
- data/test/helpers_test.rb +48 -13
- data/test/rdoc_test.rb +1 -1
- data/test/routing_test.rb +5 -0
- data/test/views/{ascii.haml → ascii.erb} +1 -1
- data/test/views/{utf8.haml → utf8.erb} +1 -1
- metadata +6 -7
- data/Gemfile.lock +0 -74
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.
|
@@ -126,7 +129,7 @@ Podés definir tus propias condiciones fácilmente:
|
|
126
129
|
"Lo siento, perdiste."
|
127
130
|
end
|
128
131
|
|
129
|
-
=== Valores de
|
132
|
+
=== Valores de Retorno
|
130
133
|
|
131
134
|
El valor de retorno de un bloque de ruta determina al menos el cuerpo de la
|
132
135
|
respuesta que se le pasa al cliente HTTP o al siguiente middleware en la pila
|
@@ -151,6 +154,47 @@ De esa manera podemos, por ejemplo, implementar fácilmente un streaming:
|
|
151
154
|
|
152
155
|
get('/') { Stream.new }
|
153
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
|
+
|
154
198
|
== Archivos Estáticos
|
155
199
|
|
156
200
|
Los archivos estáticos son servidos desde el directorio público
|
@@ -372,7 +416,7 @@ plantillas:
|
|
372
416
|
|
373
417
|
Como no podés utilizar Ruby desde Markdown, no podés usar layouts escritos en
|
374
418
|
Markdown. De todos modos, es posible usar un motor de renderizado para el
|
375
|
-
layout distinto al de la plantilla pasando la opción
|
419
|
+
layout distinto al de la plantilla pasando la opción <tt>:layout_engine</tt>:
|
376
420
|
|
377
421
|
get '/' do
|
378
422
|
markdown :index, :layout_engine => :erb
|
@@ -432,7 +476,7 @@ plantillas:
|
|
432
476
|
|
433
477
|
Como no podés utilizar Ruby desde Textile, no podés usar layouts escritos en
|
434
478
|
Textile. De todos modos, es posible usar un motor de renderizado para el
|
435
|
-
layout distinto al de la plantilla pasando la opción
|
479
|
+
layout distinto al de la plantilla pasando la opción <tt>:layout_engine</tt>:
|
436
480
|
|
437
481
|
get '/' do
|
438
482
|
textile :index, :layout_engine => :erb
|
@@ -456,8 +500,8 @@ con el layout <tt>./views/post.haml</tt>.
|
|
456
500
|
|
457
501
|
La gem/librería <tt>rdoc</tt> es necesaria para renderizar plantillas RDoc:
|
458
502
|
|
459
|
-
# Vas a necesitar requerir rdoc en tu app
|
460
|
-
require "rdoc"
|
503
|
+
# Vas a necesitar requerir rdoc/markup/to_html en tu app
|
504
|
+
require "rdoc/markup/to_html"
|
461
505
|
|
462
506
|
get '/' do
|
463
507
|
rdoc :index
|
@@ -478,7 +522,7 @@ plantillas:
|
|
478
522
|
|
479
523
|
Como no podés utilizar Ruby desde RDoc, no podés usar layouts escritos en RDoc.
|
480
524
|
De todos modos, es posible usar un motor de renderizado para el layout distinto
|
481
|
-
al de la plantilla pasando la opción
|
525
|
+
al de la plantilla pasando la opción <tt>:layout_engine</tt>:
|
482
526
|
|
483
527
|
get '/' do
|
484
528
|
rdoc :index, :layout_engine => :erb
|
@@ -676,10 +720,10 @@ para aprender más de Tilt.
|
|
676
720
|
|
677
721
|
== Filtros
|
678
722
|
|
679
|
-
Los filtros before son evaluados antes de cada petición dentro del mismo
|
680
|
-
contexto que las rutas
|
681
|
-
|
682
|
-
|
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:
|
683
727
|
|
684
728
|
before do
|
685
729
|
@nota = 'Hey!'
|
@@ -691,16 +735,16 @@ por las rutas y las plantillas:
|
|
691
735
|
params[:splat] #=> 'bar/baz'
|
692
736
|
end
|
693
737
|
|
694
|
-
Los filtros after son evaluados después de cada petición dentro del mismo
|
695
|
-
contexto y también pueden modificar la petición y la respuesta.
|
696
|
-
de instancia asignadas en los filtros before y rutas son accesibles por
|
697
|
-
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+:
|
698
742
|
|
699
743
|
after do
|
700
744
|
puts response.status
|
701
745
|
end
|
702
746
|
|
703
|
-
Nota: A menos que usés el método
|
747
|
+
Nota: A menos que usés el método +body+ en lugar de simplemente devolver un
|
704
748
|
string desde una ruta, el cuerpo de la respuesta no va a estar disponible en
|
705
749
|
un filtro after, debido a que todavía no se ha generado.
|
706
750
|
|
@@ -716,7 +760,7 @@ patrón:
|
|
716
760
|
session[:ultimo_slug] = slug
|
717
761
|
end
|
718
762
|
|
719
|
-
Al igual que las rutas, los filtros también
|
763
|
+
Al igual que las rutas, los filtros también pueden aceptar condiciones:
|
720
764
|
|
721
765
|
before :agent => /Songbird/ do
|
722
766
|
# ...
|
@@ -741,6 +785,37 @@ pueden ser utilizados dentro de los manejadores de rutas y las plantillas:
|
|
741
785
|
bar(params[:nombre])
|
742
786
|
end
|
743
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
|
+
|
744
819
|
=== Interrupción
|
745
820
|
|
746
821
|
Para detener inmediatamente una petición dentro de un filtro o una ruta usá:
|
@@ -780,12 +855,36 @@ la petición usando <tt>pass</tt>:
|
|
780
855
|
Se sale inmediatamente del bloque de la ruta y se le pasa el control a la
|
781
856
|
siguiente ruta que coincida. Si no coincide ninguna ruta, se devuelve un 404.
|
782
857
|
|
783
|
-
===
|
858
|
+
=== Ejecutando Otra Ruta
|
859
|
+
|
860
|
+
Cuando querés obtener el resultado de la llamada a una ruta, +pass+ no te va a
|
861
|
+
servir. Para lograr esto, podés usar +call+:
|
862
|
+
|
863
|
+
get '/foo' do
|
864
|
+
status, headers, body = call request.env.merge("PATH_INFO" => '/bar')
|
865
|
+
[status, body.upcase]
|
866
|
+
end
|
867
|
+
|
868
|
+
get '/bar' do
|
869
|
+
"bar"
|
870
|
+
end
|
871
|
+
|
872
|
+
Notá que en el ejemplo anterior, es conveniente mover <tt>"bar"</tt> a un
|
873
|
+
helper, y llamarlo desde <tt>/foo</tt> y <tt>/bar</tt>. Así, vas a simplificar
|
874
|
+
las pruebas y a mejorar el rendimiento.
|
875
|
+
|
876
|
+
Si querés que la petición se envíe a la misma instancia de la aplicación en
|
877
|
+
lugar de a otra, usá <tt>call!</tt> en lugar de <tt>call</tt>.
|
878
|
+
|
879
|
+
En la especificación de Rack podés encontrar más información sobre
|
880
|
+
<tt>call</tt>.
|
881
|
+
|
882
|
+
=== Asignando el Código de Estado, los Encabezados y el Cuerpo de una Respuesta
|
784
883
|
|
785
884
|
Es posible, y se recomienda, asignar el código de estado y el cuerpo de una
|
786
885
|
respuesta con el valor de retorno de una ruta. De cualquier manera, en varios
|
787
886
|
escenarios, puede que sea conveniente asignar el cuerpo en un punto arbitrario
|
788
|
-
del flujo de ejecución con el método
|
887
|
+
del flujo de ejecución con el método +body+. A partir de ahí, podés usar ese
|
789
888
|
mismo método para acceder al cuerpo de la respuesta:
|
790
889
|
|
791
890
|
get '/foo' do
|
@@ -796,35 +895,78 @@ mismo método para acceder al cuerpo de la respuesta:
|
|
796
895
|
puts body
|
797
896
|
end
|
798
897
|
|
799
|
-
También es posible pasarle un bloque a body
|
800
|
-
handler (podés usar esto para implementar streaming, mirá
|
801
|
-
[Valores de retorno](#Valores%20de%20retorno)).
|
898
|
+
También es posible pasarle un bloque a +body+, que será ejecutado por el Rack
|
899
|
+
handler (podés usar esto para implementar streaming, mirá "Valores de retorno").
|
802
900
|
|
803
|
-
De manera similar, también podés asignar el código de estado:
|
901
|
+
De manera similar, también podés asignar el código de estado y encabezados:
|
804
902
|
|
805
903
|
get '/foo' do
|
806
904
|
status 418
|
807
|
-
|
905
|
+
headers \
|
906
|
+
"Allow" => "BREW, POST, GET, PROPFIND, WHEN"
|
907
|
+
"Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
|
908
|
+
body "I'm a tea pot!"
|
909
|
+
end
|
910
|
+
|
911
|
+
También, al igual que +body+, tanto +status+ como +headers+ pueden utilizarse
|
912
|
+
para obtener sus valores cuando no se les pasa argumentos.
|
913
|
+
|
914
|
+
=== Tipos Mime
|
915
|
+
|
916
|
+
Cuando usás <tt>send_file</tt> o archivos estáticos tal vez tengas tipos mime
|
917
|
+
que Sinatra no entiende. Usá +mime_type+ para registrarlos a través de la
|
918
|
+
extensión de archivo:
|
919
|
+
|
920
|
+
mime_type :foo, 'text/foo'
|
921
|
+
|
922
|
+
También lo podés usar con el ayudante +content_type+:
|
923
|
+
|
924
|
+
get '/' do
|
925
|
+
content_type :foo
|
926
|
+
"foo foo foo"
|
808
927
|
end
|
809
928
|
|
929
|
+
=== Generando URLs
|
930
|
+
|
931
|
+
Para generar URLs deberías usar el método +url+. Por ejemplo, en Haml:
|
932
|
+
|
933
|
+
%a{:href => url('/foo')} foo
|
934
|
+
|
935
|
+
Tiene en cuenta proxies inversos y encaminadores de Rack, si están presentes.
|
936
|
+
|
937
|
+
Este método también puede invocarse mediante su alias +to+ (mirá un ejemplo
|
938
|
+
a continuación).
|
939
|
+
|
810
940
|
=== Redirección del Navegador
|
811
941
|
|
812
|
-
Podés redireccionar al navegador con el método
|
942
|
+
Podés redireccionar al navegador con el método +redirect+:
|
813
943
|
|
814
944
|
get '/foo' do
|
815
|
-
redirect '/bar'
|
945
|
+
redirect to('/bar')
|
816
946
|
end
|
817
947
|
|
818
948
|
Cualquier parámetro adicional se utiliza de la misma manera que los argumentos
|
819
|
-
pasados a
|
949
|
+
pasados a +halt+:
|
950
|
+
|
951
|
+
redirect to('/bar'), 303
|
952
|
+
redirect 'http://google.com', 'te confundiste de lugar, compañero'
|
820
953
|
|
821
|
-
|
822
|
-
|
954
|
+
También podés redireccionar fácilmente de vuelta hacia la página desde donde
|
955
|
+
vino el usuario con +redirect back+:
|
823
956
|
|
824
|
-
|
957
|
+
get '/foo' do
|
958
|
+
"<a href='/bar'>hacer algo</a>"
|
959
|
+
end
|
960
|
+
|
961
|
+
get '/bar' do
|
962
|
+
hacer_algo
|
963
|
+
redirect back
|
964
|
+
end
|
965
|
+
|
966
|
+
Para pasar argumentos con una redirección, podés agregarlos a la cadena de
|
825
967
|
búsqueda:
|
826
968
|
|
827
|
-
redirect '/bar?suma=42'
|
969
|
+
redirect to('/bar?suma=42')
|
828
970
|
|
829
971
|
O usar una sesión:
|
830
972
|
|
@@ -832,18 +974,111 @@ O usar una sesión:
|
|
832
974
|
|
833
975
|
get '/foo' do
|
834
976
|
session[:secreto] = 'foo'
|
835
|
-
redirect '/bar'
|
977
|
+
redirect to('/bar')
|
836
978
|
end
|
837
979
|
|
838
980
|
get '/bar' do
|
839
981
|
session[:secreto]
|
840
982
|
end
|
841
983
|
|
984
|
+
=== Cache Control
|
985
|
+
|
986
|
+
Asignar tus encabezados correctamente es el cimiento para realizar un cacheo
|
987
|
+
HTTP correcto.
|
988
|
+
|
989
|
+
Podés asignar el encabezado Cache-Control fácilmente:
|
990
|
+
|
991
|
+
get '/' do
|
992
|
+
cache_control :public
|
993
|
+
"cachealo!"
|
994
|
+
end
|
995
|
+
|
996
|
+
Pro tip: configurar el cacheo en un filtro +before+.
|
997
|
+
|
998
|
+
before do
|
999
|
+
cache_control :public, :must_revalidate, :max_age => 60
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
Si estás usando el helper +expires+ para definir el encabezado correspondiente,
|
1003
|
+
<tt>Cache-Control</tt> se va a definir automáticamente:
|
1004
|
+
|
1005
|
+
before do
|
1006
|
+
expires 500, :public, :must_revalidate
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
Para usar cachés adecuadamente, deberías considerar usar +etag+ y
|
1010
|
+
+last_modified+. Es recomendable que llames a estos helpers *antes* de hacer
|
1011
|
+
cualquier trabajo pesado, ya que van a enviar la respuesta inmediatamente si
|
1012
|
+
el cliente ya tiene la versión actual en su caché.
|
1013
|
+
|
1014
|
+
get '/articulo/:id' do
|
1015
|
+
@articulo = Articulo.find params[:id]
|
1016
|
+
last_modified @articulo.updated_at
|
1017
|
+
etag @articulo.sha1
|
1018
|
+
erb :articulo
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
También es posible usar una
|
1022
|
+
{weak ETag}[http://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation]:
|
1023
|
+
|
1024
|
+
etag @articulo.sha1, :weak
|
1025
|
+
|
1026
|
+
Estos helpers no van a cachear nada por vos, sino que van a facilitar la
|
1027
|
+
información necesaria para poder hacerlo. Si estás buscando soluciones rápidas
|
1028
|
+
de cacheo, mirá {rack-cache}[http://rtomayko.github.com/rack-cache/]:
|
1029
|
+
|
1030
|
+
require "rack/cache"
|
1031
|
+
require "sinatra"
|
1032
|
+
|
1033
|
+
use Rack::Cache
|
1034
|
+
|
1035
|
+
get '/' do
|
1036
|
+
cache_control :public, :max_age => 36000
|
1037
|
+
sleep 5
|
1038
|
+
"hola"
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
=== Enviando Archivos
|
1042
|
+
|
1043
|
+
Para enviar archivos, podés usar el método <tt>send_file</tt>:
|
1044
|
+
|
1045
|
+
get '/' do
|
1046
|
+
send_file 'foo.png'
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
Además acepta un par de opciones:
|
1050
|
+
|
1051
|
+
send_file 'foo.png', :type => :jpg
|
1052
|
+
|
1053
|
+
Estas opciones son:
|
1054
|
+
|
1055
|
+
[filename]
|
1056
|
+
nombre del archivo respondido, por defecto es el nombre real del archivo.
|
1057
|
+
|
1058
|
+
[last_modified]
|
1059
|
+
valor para el encabezado Last-Modified, por defecto toma el mtime del archivo.
|
1060
|
+
|
1061
|
+
[type]
|
1062
|
+
el content type que se va a utilizar, si no está presente se intenta adivinar
|
1063
|
+
a partir de la extensión del archivo.
|
1064
|
+
|
1065
|
+
[disposition]
|
1066
|
+
se utiliza para el encabezado Content-Disposition, y puede tomar alguno de los
|
1067
|
+
siguientes valores: +nil+ (por defecto), <tt>:attachment</tt> e
|
1068
|
+
<tt>:inline</tt>
|
1069
|
+
|
1070
|
+
[length]
|
1071
|
+
encabezado Content-Length, por defecto toma el tamaño del archivo.
|
1072
|
+
|
1073
|
+
Si el Rack handler lo soporta, se intentará no transmitir directamente desde el
|
1074
|
+
proceso de Ruby. Si usás este método, Sinatra se va a encargar automáticamente
|
1075
|
+
peticiones de rango.
|
1076
|
+
|
842
1077
|
=== Accediendo al objeto de la petición
|
843
1078
|
|
844
1079
|
El objeto de la petición entrante puede ser accedido desde el nivel de la
|
845
1080
|
petición (filtros, rutas y manejadores de errores) a través del método
|
846
|
-
|
1081
|
+
<tt>request</tt>:
|
847
1082
|
|
848
1083
|
# app corriendo en http://ejemplo.com/ejemplo
|
849
1084
|
get '/foo' do
|
@@ -860,14 +1095,15 @@ petición (filtros, rutas y manejadores de errores) a través del método
|
|
860
1095
|
request.get? # verdadero (hay métodos análogos para los otros verbos)
|
861
1096
|
request.form_data? # falso
|
862
1097
|
request["UNA_CABECERA"] # valor de la cabecera UNA_CABECERA
|
863
|
-
request.
|
1098
|
+
request.referrer # la referencia del cliente o '/'
|
864
1099
|
request.user_agent # user agent (usado por la condición :agent)
|
865
1100
|
request.cookies # hash de las cookies del browser
|
866
1101
|
request.xhr? # es una petición ajax?
|
867
1102
|
request.url # "http://ejemplo.com/ejemplo/foo"
|
868
1103
|
request.path # "/ejemplo/foo"
|
869
1104
|
request.ip # dirección IP del cliente
|
870
|
-
request.secure? # falso
|
1105
|
+
request.secure? # falso (sería verdadero sobre ssl)
|
1106
|
+
request.forwarded? # verdadero (si se está corriendo atrás de un proxy inverso)
|
871
1107
|
requuest.env # hash de entorno directamente entregado por Rack
|
872
1108
|
end
|
873
1109
|
|
@@ -888,12 +1124,85 @@ El objeto <tt>request.body</tt> es una instancia de IO o StringIO:
|
|
888
1124
|
"Hola #{datos['nombre']}!"
|
889
1125
|
end
|
890
1126
|
|
1127
|
+
=== Archivos Adjuntos
|
1128
|
+
|
1129
|
+
Podés usar el método helper +attachment+ para indicarle al navegador que
|
1130
|
+
almacene la respuesta en el disco en lugar de mostrarla en pantalla.
|
1131
|
+
|
1132
|
+
get '/' do
|
1133
|
+
attachment
|
1134
|
+
"guardalo!"
|
1135
|
+
end
|
1136
|
+
|
1137
|
+
También podés pasarle un nombre de archivo:
|
1138
|
+
|
1139
|
+
get '/' do
|
1140
|
+
attachment "info.txt"
|
1141
|
+
"guardalo!"
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
=== Buscando los Archivos de las Plantillas
|
1145
|
+
|
1146
|
+
El helper <tt>find_template</tt> se utiliza para encontrar los archivos de las
|
1147
|
+
plantillas que se van a renderizar:
|
1148
|
+
|
1149
|
+
find_template settings.views, 'foo', Tilt[:haml] do |archivo|
|
1150
|
+
puts "podría ser #{archivo}"
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
Si bien esto no es muy útil, lo interesante es que podés sobreescribir este
|
1154
|
+
método, y así enganchar tu propio mecanismo de búsqueda. Por ejemplo, para
|
1155
|
+
poder utilizar más de un directorio de vistas:
|
1156
|
+
|
1157
|
+
set :views, ['vistas', 'plantillas']
|
1158
|
+
|
1159
|
+
helpers do
|
1160
|
+
def find_template(views, name, engine, &block)
|
1161
|
+
Array(views).each { |v| super(v, name, engine, &block) }
|
1162
|
+
end
|
1163
|
+
end
|
1164
|
+
|
1165
|
+
Otro ejemplo consiste en usar directorios diferentes para los distintos motores
|
1166
|
+
de renderizado:
|
1167
|
+
|
1168
|
+
set :views, :sass => 'vistas/sass', :haml => 'plantillas', :defecto => 'vistas'
|
1169
|
+
|
1170
|
+
helpers do
|
1171
|
+
def find_template(views, name, engine, &block)
|
1172
|
+
_, folder = views.detect { |k,v| engine == Tilt[k] }
|
1173
|
+
folder ||= views[:defecto]
|
1174
|
+
super(folder, name, engine, &block)
|
1175
|
+
end
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
¡Es muy fácil convertir estos ejemplos en una extensión y compartirla!.
|
1179
|
+
|
1180
|
+
Notá que <tt>find_template</tt> no verifica si un archivo existe realmente, sino
|
1181
|
+
que llama al bloque que recibe para cada path posible. Esto no representa un
|
1182
|
+
problema de rendimiento debido a que +render+ va a usar +break+ ni bien
|
1183
|
+
encuentre un archivo que exista. Además, las ubicaciones de las plantillas (y
|
1184
|
+
su contenido) se cachean cuando no estás en el modo de desarrollo. Es bueno
|
1185
|
+
tener en cuenta lo anteiror si escribís un método medio loco.
|
1186
|
+
|
891
1187
|
== Configuración
|
892
1188
|
|
893
1189
|
Ejecutar una vez, en el inicio, en cualquier entorno:
|
894
1190
|
|
895
1191
|
configure do
|
896
|
-
|
1192
|
+
# asignando una opción
|
1193
|
+
set :opcion, 'valor'
|
1194
|
+
|
1195
|
+
# asignando varias opciones
|
1196
|
+
set :a => 1, :b => 2
|
1197
|
+
|
1198
|
+
# atajo para `set :opcion, true`
|
1199
|
+
enable :opcion
|
1200
|
+
|
1201
|
+
# atajo para `set :opcion, false`
|
1202
|
+
disable :opcion
|
1203
|
+
|
1204
|
+
# también podés tener configuraciones dinámicas usando bloques
|
1205
|
+
set(:css_dir) { File.join(views, 'css') }
|
897
1206
|
end
|
898
1207
|
|
899
1208
|
Ejecutar únicamente cuando el entorno (la variable de entorno RACK_ENV) es
|
@@ -909,10 +1218,116 @@ Ejecutar cuando el entorno es <tt>:production</tt> o <tt>:test</tt>:
|
|
909
1218
|
...
|
910
1219
|
end
|
911
1220
|
|
1221
|
+
Podés acceder a estas opciones utilizando el método <tt>settings</tt>:
|
1222
|
+
|
1223
|
+
configure do
|
1224
|
+
set :foo, 'bar'
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
get '/' do
|
1228
|
+
settings.foo? # => true
|
1229
|
+
settings.foo # => 'bar'
|
1230
|
+
...
|
1231
|
+
end
|
1232
|
+
|
1233
|
+
=== Configuraciones Disponibles
|
1234
|
+
|
1235
|
+
[absolute_redirects] si está deshabilitada, Sinatra va a permitir redirecciones
|
1236
|
+
relativas, sin embargo, como consecuencia de esto, va a
|
1237
|
+
dejar de cumplir con el RFC 2616 (HTTP 1.1), que solamente
|
1238
|
+
permite redirecciones absolutas.
|
1239
|
+
|
1240
|
+
Activalo si tu apliación está corriendo atrás de un proxy
|
1241
|
+
inverso que no se ha configurado adecuadamente. Notá que
|
1242
|
+
el helper +url+ va a seguir produciendo URLs absolutas, a
|
1243
|
+
menos que le pasés +false+ como segundo parámetro.
|
1244
|
+
|
1245
|
+
Deshabilitada por defecto.
|
1246
|
+
|
1247
|
+
[add_charsets] tipos mime a los que el helper <tt>content_type</tt> les
|
1248
|
+
añade automáticamente el charset.
|
1249
|
+
|
1250
|
+
En general, no deberías asignar directamente esta opción,
|
1251
|
+
sino añadirle los charsets que quieras:
|
1252
|
+
|
1253
|
+
settings.add_charsets << "application/foobar"
|
1254
|
+
|
1255
|
+
[app_file] archivo principal de la aplicación, se utiliza para
|
1256
|
+
detectar la raíz del proyecto, el directorio de las vistas
|
1257
|
+
y el público así como las plantillas inline.
|
1258
|
+
|
1259
|
+
[bind] dirección IP que utilizará el servidor integrado (por
|
1260
|
+
defecto: 0.0.0.0).
|
1261
|
+
|
1262
|
+
[default_encoding] encoding utilizado cuando el mismo se desconoce (por
|
1263
|
+
defecto <tt>"utf-8"</tt>).
|
1264
|
+
|
1265
|
+
[dump_errors] mostrar errores en el log.
|
1266
|
+
|
1267
|
+
[environment] entorno actual, por defecto toma el valor de
|
1268
|
+
<tt>ENV['RACK_ENV']</tt>, o <tt>"development"</tt> si no
|
1269
|
+
está disponible.
|
1270
|
+
|
1271
|
+
[logging] define si se utiliza el logger.
|
1272
|
+
|
1273
|
+
[lock] coloca un lock alrededor de cada petición, procesando
|
1274
|
+
solamente una por proceso.
|
1275
|
+
|
1276
|
+
Habilitá esta opción si tu aplicación no es thread-safe.
|
1277
|
+
Se encuentra deshabilitada por defecto.
|
1278
|
+
|
1279
|
+
[method_override] utiliza el parámetro <tt>_method</tt> para permtir
|
1280
|
+
formularios put/delete en navegadores que no los soportan.
|
1281
|
+
|
1282
|
+
[port] puerto en el que escuchará el servidor integrado.
|
1283
|
+
|
1284
|
+
[prefixed_redirects] define si inserta <tt>request.script_name</tt> en las
|
1285
|
+
redirecciones cuando no se proporciona un path absoluto.
|
1286
|
+
De esta manera, cuando está habilitada,
|
1287
|
+
<tt>redirect '/foo'</tt> se comporta de la misma manera
|
1288
|
+
que <tt>redirect to('/foo')</tt>. Se encuentra
|
1289
|
+
deshabilitada por defecto.
|
1290
|
+
|
1291
|
+
[public] directorio desde donde se sirven los archivos públicos.
|
1292
|
+
|
1293
|
+
[reload_templates] define si se recargan las plantillas entre peticiones.
|
1294
|
+
|
1295
|
+
Se encuentra activado en el entorno de desarrollo y en
|
1296
|
+
Ruby 1.8.6 (para compoensar un bug en Ruby que provoca una
|
1297
|
+
pérdida de memoria).
|
1298
|
+
|
1299
|
+
[root] directorio raíz del proyecto.
|
1300
|
+
|
1301
|
+
[raise_errors] elevar excepciones (detiene la aplicación).
|
1302
|
+
|
1303
|
+
[run] cuando está habilitada, Sinatra se va a encargar de
|
1304
|
+
iniciar el servidor web, no la habilités cuando estés
|
1305
|
+
usando rackup o algún otro medio.
|
1306
|
+
|
1307
|
+
[running] indica si el servidor integrado está ejecutandose, ¡no
|
1308
|
+
cambiés esta configuración!.
|
1309
|
+
|
1310
|
+
[server] servidor, o lista de servidores, para usar como servidor
|
1311
|
+
integrado. Por defecto: ['thin', 'mongrel', 'webrick'],
|
1312
|
+
el orden establece la prioridad.
|
1313
|
+
|
1314
|
+
[sessions] habilita sesiones basadas en cookies.
|
1315
|
+
|
1316
|
+
[show_exceptions] muestra un stack trace en el navegador.
|
1317
|
+
|
1318
|
+
[static] define si Sinatra debe encargarse de servir archivos
|
1319
|
+
estáticos.
|
1320
|
+
|
1321
|
+
Deshabilitala cuando usés un servidor capaz de hacerlo
|
1322
|
+
por sí solo, porque mejorará el rendimiento. Se encuentra
|
1323
|
+
habilitada por defecto.
|
1324
|
+
|
1325
|
+
[views] directorio de las vistas.
|
1326
|
+
|
912
1327
|
== Manejo de Errores
|
913
1328
|
|
914
1329
|
Los manejadores de errores se ejecutan dentro del mismo contexto que las rutas
|
915
|
-
y los filtros before
|
1330
|
+
y los filtros +before+, lo que significa que podés usar, por ejemplo,
|
916
1331
|
<tt>haml</tt>, <tt>erb</tt>, <tt>halt</tt>, etc.
|
917
1332
|
|
918
1333
|
=== No encontrado <em>(Not Found)</em>
|
@@ -969,18 +1384,6 @@ O un rango:
|
|
969
1384
|
Sinatra instala manejadores <tt>not_found</tt> y <tt>error</ttt> especiales
|
970
1385
|
cuando se ejecuta dentro del entorno de desarrollo "development".
|
971
1386
|
|
972
|
-
== Tipos Mime
|
973
|
-
|
974
|
-
Cuando usás <tt>send_file</tt> o archivos estáticos tal vez tengas tipos mime
|
975
|
-
que Sinatra no entiende. Usá +mime_type+ para registrarlos a través de la
|
976
|
-
extensión de archivo:
|
977
|
-
|
978
|
-
mime_type :foo, 'text/foo'
|
979
|
-
|
980
|
-
También lo podés usar con el ayudante +content_type+:
|
981
|
-
|
982
|
-
content_type :foo
|
983
|
-
|
984
1387
|
== Rack Middleware
|
985
1388
|
|
986
1389
|
Sinatra corre sobre Rack[http://rack.rubyforge.org/], una interfaz minimalista
|
@@ -1080,7 +1483,7 @@ métodos que los provistos por el DSL de top-level. La mayoría de las
|
|
1080
1483
|
aplicaciones top-level se pueden convertir en componentes Sinatra::Base con
|
1081
1484
|
dos modificaciones:
|
1082
1485
|
|
1083
|
-
* Tu archivo debe requerir
|
1486
|
+
* Tu archivo debe requerir <tt>sinatra/base</tt> en lugar de +sinatra+; de otra
|
1084
1487
|
manera, todos los métodos del DSL de sinatra son importados dentro del
|
1085
1488
|
espacio de nombres principal.
|
1086
1489
|
* Poné las rutas, manejadores de errores, filtros y opciones de tu aplicación
|
@@ -1091,6 +1494,34 @@ desactivadas por defecto, incluyendo el servidor incorporado. Mirá
|
|
1091
1494
|
{Opciones y Configuraciones}[http://sinatra.github.com/configuration.html]
|
1092
1495
|
para detalles sobre las opciones disponibles y su comportamiento.
|
1093
1496
|
|
1497
|
+
=== Estilo Modular vs. Clásico
|
1498
|
+
|
1499
|
+
Contrariamente a la creencia popular, no hay nada de malo con el estilo clásico.
|
1500
|
+
Si se ajusta a tu aplicación, no es necesario que la cambies a una modular.
|
1501
|
+
|
1502
|
+
Existen tan solo dos desventajas en comparación con el estilo modular:
|
1503
|
+
|
1504
|
+
* Solamente podés tener una aplicación Sinatra por proceso Ruby - si tenés
|
1505
|
+
planificado usar más, cambiá al estilo modular.
|
1506
|
+
|
1507
|
+
* El estilo clásico contamina Object con métodos delegadores - si tenés
|
1508
|
+
planificado empaquetar tu aplicación en una librería/gem, cambiá al estilo
|
1509
|
+
modular.
|
1510
|
+
|
1511
|
+
No hay ninguna razón por la cuál no puedas mezclar los estilos modular y
|
1512
|
+
clásico.
|
1513
|
+
|
1514
|
+
Cuando cambiés de un estilo al otro, tené en cuenta las sutiles diferencias
|
1515
|
+
entre sus configuraciones:
|
1516
|
+
|
1517
|
+
Configuración Clásica Modular
|
1518
|
+
|
1519
|
+
app_file archivo que carga sinatra nil
|
1520
|
+
run $0 == app_file false
|
1521
|
+
logging true false
|
1522
|
+
method_override true false
|
1523
|
+
inline_templates true false
|
1524
|
+
|
1094
1525
|
=== Sirviendo una Aplicación Modular
|
1095
1526
|
|
1096
1527
|
Las dos opciones más comunes para iniciar una aplicación modular son, iniciarla
|
@@ -1195,11 +1626,11 @@ disponibles.
|
|
1195
1626
|
Cada aplicación Sinatra es una subclase de Sinatra::Base. Si estás usando el
|
1196
1627
|
DSL de top-level (<tt>require 'sinatra'</tt>), entonces esta clase es
|
1197
1628
|
Sinatra::Application, de otra manera es la subclase que creaste explícitamente.
|
1198
|
-
Al nivel de la clase tenés métodos como
|
1199
|
-
a los objetos
|
1629
|
+
Al nivel de la clase tenés métodos como +get+ o +before+, pero no podés acceder
|
1630
|
+
a los objetos +request+ o +session+, ya que hay una única clase de la
|
1200
1631
|
aplicación para todas las peticiones.
|
1201
1632
|
|
1202
|
-
Las opciones creadas utilizando
|
1633
|
+
Las opciones creadas utilizando +set+ son métodos al nivel de la clase:
|
1203
1634
|
|
1204
1635
|
class MiApp < Sinatra::Base
|
1205
1636
|
# Ey, estoy en el ámbito de la aplicación!
|
@@ -1215,21 +1646,21 @@ Tenés la ligadura al ámbito de la aplicación dentro de:
|
|
1215
1646
|
|
1216
1647
|
* El cuerpo de la clase de tu aplicación
|
1217
1648
|
* Métodos definidos por extensiones
|
1218
|
-
* El bloque pasado a
|
1219
|
-
* Procs/bloques usados como el valor para
|
1649
|
+
* El bloque pasado a +helpers+
|
1650
|
+
* Procs/bloques usados como el valor para +set+
|
1220
1651
|
|
1221
1652
|
Este ámbito puede alcanzarse de las siguientes maneras:
|
1222
1653
|
|
1223
1654
|
* A través del objeto pasado a los bloques de configuración (<tt>configure { |c| ...}</tt>)
|
1224
|
-
* Llamando a
|
1655
|
+
* Llamando a +settings+ desde dentro del ámbito de la petición
|
1225
1656
|
|
1226
1657
|
=== Ámbito de Petición/Instancia
|
1227
1658
|
|
1228
1659
|
Para cada petición entrante, una nueva instancia de la clase de tu aplicación
|
1229
1660
|
es creada y todos los bloques de rutas son ejecutados en ese ámbito. Desde este
|
1230
|
-
ámbito podés acceder a los objetos
|
1231
|
-
de renderización como
|
1232
|
-
desde el ámbito de la petición utilizando
|
1661
|
+
ámbito podés acceder a los objetos +request+ y +session+ o llamar a los métodos
|
1662
|
+
de renderización como +erb+ o +haml+. Podés acceder al ámbito de la aplicación
|
1663
|
+
desde el ámbito de la petición utilizando +settings+:
|
1233
1664
|
|
1234
1665
|
class MiApp < Sinatra::Base
|
1235
1666
|
# Ey, estoy en el ámbito de la aplicación!
|
@@ -1259,13 +1690,13 @@ El ámbito de delegación solo reenvía métodos al ámbito de clase. De cualqui
|
|
1259
1690
|
manera, no se comporta 100% como el ámbito de clase porque no tenés la ligadura
|
1260
1691
|
de la clase: únicamente métodos marcados explícitamente para delegación están
|
1261
1692
|
disponibles y no compartís variables/estado con el ámbito de clase (léase:
|
1262
|
-
tenés un
|
1693
|
+
tenés un +self+ diferente). Podés agregar delegaciones de método llamando a
|
1263
1694
|
<tt>Sinatra::Delegator.delegate :nombre_del_metodo</tt>.
|
1264
1695
|
|
1265
1696
|
Tenés la ligadura al ámbito de delegación dentro de:
|
1266
1697
|
|
1267
1698
|
* La ligadura del top-level, si hiciste <tt>require "sinatra"</tt>
|
1268
|
-
* Un objeto extendido con el mixin
|
1699
|
+
* Un objeto extendido con el mixin <tt>Sinatra::Delegator</tt>
|
1269
1700
|
|
1270
1701
|
Pegale una mirada al código: acá está el
|
1271
1702
|
{Sinatra::Delegator mixin}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/base.rb#L1128]
|
@@ -1286,6 +1717,59 @@ Las opciones son:
|
|
1286
1717
|
-s # especifica el servidor/manejador rack (thin es usado por defecto)
|
1287
1718
|
-x # activa el mutex lock (está desactivado por defecto)
|
1288
1719
|
|
1720
|
+
== Requerimientos
|
1721
|
+
|
1722
|
+
Se recomienda instalar Sinatra en Ruby 1.8.7, 1.9.2, JRuby o Rubinius.
|
1723
|
+
|
1724
|
+
Las siguientes versiones de Ruby son soportadas oficialmente:
|
1725
|
+
|
1726
|
+
[ Ruby 1.8.6 ]
|
1727
|
+
No se recomienda utilizar Sinatra en 1.8.6. Sin embargo, esta versión será
|
1728
|
+
soportada oficialmente hasta que se libere Sinatra 1.3.0. RDoc y CoffeeScript
|
1729
|
+
no son soportadas por esta versión de Ruby. 1.8.6 contiene una falla
|
1730
|
+
importante de pérdida de memoria en su implementación de Hash, que afecta a
|
1731
|
+
las versiones de Sinatra anteriores a 1.1.1. La versión actual evita
|
1732
|
+
explícitamente esta falla a expensas de una disminución del rendimiento. Por
|
1733
|
+
último, Rack >= 1.2 dejó de soportar 1.8.6, por lo que vas a tener que usar
|
1734
|
+
alguna versión 1.1.x.
|
1735
|
+
|
1736
|
+
[ Ruby 1.8.7 ]
|
1737
|
+
1.8.7 es soportado completamente. Sin embargo, si no hay nada que te lo
|
1738
|
+
prohíba, te recomendamos que usés 1.9.2 o cambies a JRuby o Rubinius.
|
1739
|
+
|
1740
|
+
[ Ruby 1.9.2 ]
|
1741
|
+
1.9.2 es soportado y recomendado. Tené en cuenta que Radius y Markaby no
|
1742
|
+
son compatibles con 1.9 actualmente. Además, no usés 1.9.2p0, porque produce
|
1743
|
+
fallos de segmentación cuando se utiliza Sinatra.
|
1744
|
+
|
1745
|
+
[ Rubinius ]
|
1746
|
+
Rubinius es soportado oficialmente (Rubinius >= 1.2.2), con la excepción de
|
1747
|
+
las plantillas Textile.
|
1748
|
+
|
1749
|
+
[ JRuby ]
|
1750
|
+
JRuby es soportado oficialmente (JRuby >= 1.5.6). No se conocen problemas con
|
1751
|
+
librerías de plantillas de terceras partes. Sin embargo, si elegís usar
|
1752
|
+
JRuby, deberías examinar sus Rack handlers porque el servidor web Thin no es
|
1753
|
+
soportado actualmente.
|
1754
|
+
|
1755
|
+
Siempre le prestamos atención a las nuevas versiones de Ruby.
|
1756
|
+
|
1757
|
+
Las siguientes implementaciones de Ruby no se encuentran soportadas
|
1758
|
+
oficialmente. De cualquier manera, pueden ejecutar Sinatra:
|
1759
|
+
|
1760
|
+
* Versiones anteriores de JRuby y Rubinius
|
1761
|
+
* MacRuby
|
1762
|
+
* Maglev
|
1763
|
+
* IronRuby
|
1764
|
+
* Ruby 1.9.0 y 1.9.1
|
1765
|
+
|
1766
|
+
No estar soportada oficialmente, significa que si las cosas solamente se rompen
|
1767
|
+
ahí y no en una plataforma soportada, asumimos que no es nuestro problema sino
|
1768
|
+
el suyo.
|
1769
|
+
|
1770
|
+
Sinatra debería funcionar en cualquier sistema operativo soportado por la
|
1771
|
+
implementación de Ruby elegida.
|
1772
|
+
|
1289
1773
|
== A la Vanguardia
|
1290
1774
|
|
1291
1775
|
Si querés usar el código de Sinatra más reciente, sentite libre de ejecutar
|
@@ -1326,7 +1810,7 @@ Ahora podés arrancar tu aplicación así:
|
|
1326
1810
|
=== Con Git
|
1327
1811
|
|
1328
1812
|
Cloná el repositorio localmente y ejecutá tu aplicación, asegurándote que el
|
1329
|
-
directorio <tt>sinatra/lib</tt> esté en el <tt
|
1813
|
+
directorio <tt>sinatra/lib</tt> esté en el <tt>$LOAD_PATH</tt>:
|
1330
1814
|
|
1331
1815
|
cd miapp
|
1332
1816
|
git clone git://github.com/sinatra/sinatra.git
|