devcenter 0.0.3 → 0.0.4

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