sinatra 1.4.6 → 1.4.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sinatra might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/AUTHORS.md +5 -2
- data/{CHANGES → CHANGELOG.md} +17 -1
- data/CONTRIBUTING.md +100 -0
- data/LICENSE +2 -2
- data/README.de.md +78 -41
- data/README.es.md +200 -165
- data/README.fr.md +364 -338
- data/README.hu.md +7 -7
- data/README.ja.md +199 -167
- data/README.ko.md +222 -183
- data/README.md +218 -179
- data/README.pt-br.md +146 -112
- data/README.pt-pt.md +63 -63
- data/README.ru.md +158 -35
- data/README.zh.md +1941 -1235
- data/Rakefile +2 -2
- data/lib/sinatra/base.rb +16 -24
- data/lib/sinatra/ext.rb +17 -0
- data/lib/sinatra/show_exceptions.rb +13 -7
- data/lib/sinatra/version.rb +1 -1
- data/sinatra.gemspec +1 -1
- data/test/public/hello+world.txt +1 -0
- data/test/routing_test.rb +44 -0
- data/test/static_test.rb +30 -0
- metadata +9 -6
data/README.pt-br.md
CHANGED
@@ -9,10 +9,10 @@ Alguns dos trechos de código a seguir utilizam caracteres UTF-8. Então, caso e
|
|
9
9
|
# encoding: utf-8
|
10
10
|
```
|
11
11
|
|
12
|
-
Sinatra é uma [DSL](
|
12
|
+
Sinatra é uma [DSL](https://pt.wikipedia.org/wiki/Linguagem_de_domínio_específico) para
|
13
13
|
criar aplicações web em Ruby com o mínimo de esforço e rapidez:
|
14
14
|
|
15
|
-
```
|
15
|
+
```ruby
|
16
16
|
# minha_app.rb
|
17
17
|
require 'sinatra'
|
18
18
|
|
@@ -23,17 +23,17 @@ end
|
|
23
23
|
|
24
24
|
Instale a gem:
|
25
25
|
|
26
|
-
```
|
26
|
+
```shell
|
27
27
|
gem install sinatra
|
28
28
|
```
|
29
29
|
|
30
30
|
Em seguida execute:
|
31
31
|
|
32
|
-
```
|
32
|
+
```shell
|
33
33
|
ruby minha_app.rb
|
34
34
|
```
|
35
35
|
|
36
|
-
Acesse: [localhost:4567](http://localhost:4567)
|
36
|
+
Acesse: [http://localhost:4567](http://localhost:4567)
|
37
37
|
|
38
38
|
É recomendado também executar `gem install thin`. Caso esta gem esteja disponível, o
|
39
39
|
Sinatra irá utilizá-la.
|
@@ -93,6 +93,7 @@ Sinatra irá utilizá-la.
|
|
93
93
|
* [Testando](#testando)
|
94
94
|
* [Sinatra::Base - Middleware, Bibliotecas e aplicativos modulares](#sinatrabase---middleware-bibliotecas-e-aplicativos-modulares)
|
95
95
|
* [Linha de comando](#linha-de-comando)
|
96
|
+
* [Multi-threading](#multi-threading)
|
96
97
|
* [A última versão](#a-última-versão)
|
97
98
|
* [Mais](#mais)
|
98
99
|
|
@@ -101,7 +102,7 @@ Sinatra irá utilizá-la.
|
|
101
102
|
No Sinatra, uma rota é um método HTTP emparelhado com um padrão de URL.
|
102
103
|
Cada rota possui um bloco de execução:
|
103
104
|
|
104
|
-
```
|
105
|
+
```ruby
|
105
106
|
get '/' do
|
106
107
|
.. mostrando alguma coisa ..
|
107
108
|
end
|
@@ -133,7 +134,7 @@ rota encontrada responde a requisição.
|
|
133
134
|
Padrões de rota podem conter parâmetros nomeados, acessíveis por meio do
|
134
135
|
hash `params`:
|
135
136
|
|
136
|
-
```
|
137
|
+
```ruby
|
137
138
|
get '/ola/:nome' do
|
138
139
|
# corresponde a "GET /ola/foo" e "GET /ola/bar"
|
139
140
|
# params['nome'] é 'foo' ou 'bar'
|
@@ -144,7 +145,7 @@ end
|
|
144
145
|
Você também pode acessar parâmetros nomeados por meio dos parâmetros de
|
145
146
|
um bloco:
|
146
147
|
|
147
|
-
```
|
148
|
+
```ruby
|
148
149
|
get '/ola/:nome' do |n|
|
149
150
|
# corresponde a "GET /ola/foo" e "GET /ola/bar"
|
150
151
|
# params['nome'] é 'foo' ou 'bar'
|
@@ -156,7 +157,7 @@ end
|
|
156
157
|
Padrões de rota também podem conter parâmetros splat (curinga),
|
157
158
|
acessível por meio do array `params['splat']`:
|
158
159
|
|
159
|
-
```
|
160
|
+
```ruby
|
160
161
|
get '/diga/*/para/*' do
|
161
162
|
# corresponde a /diga/ola/para/mundo
|
162
163
|
params['splat'] # => ["ola", "mundo"]
|
@@ -170,7 +171,7 @@ end
|
|
170
171
|
|
171
172
|
Ou com parâmetros de um bloco:
|
172
173
|
|
173
|
-
```
|
174
|
+
```ruby
|
174
175
|
get '/download/*.*' do |caminho, ext|
|
175
176
|
[caminho, ext] # => ["caminho/do/arquivo", "xml"]
|
176
177
|
end
|
@@ -178,7 +179,7 @@ end
|
|
178
179
|
|
179
180
|
Rotas podem casar com expressões regulares:
|
180
181
|
|
181
|
-
```
|
182
|
+
```ruby
|
182
183
|
get /\A\/ola\/([\w]+)\z/ do
|
183
184
|
"Olá, #{params['captures'].first}!"
|
184
185
|
end
|
@@ -186,7 +187,7 @@ end
|
|
186
187
|
|
187
188
|
Ou com parâmetros de um bloco:
|
188
189
|
|
189
|
-
```
|
190
|
+
```ruby
|
190
191
|
get %r{/ola/([\w]+)} do |c|
|
191
192
|
# corresponde a "GET /meta/ola/mundo", "GET /ola/mundo/1234" etc.
|
192
193
|
"Olá, #{c}!"
|
@@ -195,15 +196,15 @@ end
|
|
195
196
|
|
196
197
|
Padrões de rota podem contar com parâmetros opcionais:
|
197
198
|
|
198
|
-
```
|
199
|
-
get '/posts
|
200
|
-
# corresponde a "GET /posts" e qualquer extensão "GET /posts
|
199
|
+
```ruby
|
200
|
+
get '/posts/:formato?' do
|
201
|
+
# corresponde a "GET /posts/" e qualquer extensão "GET /posts/json", "GET /posts/xml", etc.
|
201
202
|
end
|
202
203
|
```
|
203
204
|
|
204
205
|
Rotas também podem utilizar query strings:
|
205
206
|
|
206
|
-
```
|
207
|
+
```ruby
|
207
208
|
get '/posts' do
|
208
209
|
# corresponde a "GET /posts?titulo=foo&autor=bar"
|
209
210
|
titulo = params['titulo']
|
@@ -220,7 +221,7 @@ comparação com as suas rotas.
|
|
220
221
|
|
221
222
|
Rotas podem incluir uma variedade de condições, tal como o `user agent`:
|
222
223
|
|
223
|
-
```
|
224
|
+
```ruby
|
224
225
|
get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
|
225
226
|
"Você está usando o Songbird versão #{params['agent'][0]}"
|
226
227
|
end
|
@@ -232,7 +233,7 @@ end
|
|
232
233
|
|
233
234
|
Outras condições disponíveis são `host_name` e `provides`:
|
234
235
|
|
235
|
-
```
|
236
|
+
```ruby
|
236
237
|
get '/', :host_name => /^admin\./ do
|
237
238
|
"Área administrativa. Acesso negado!"
|
238
239
|
end
|
@@ -249,7 +250,7 @@ end
|
|
249
250
|
|
250
251
|
Você pode facilmente definir suas próprias condições:
|
251
252
|
|
252
|
-
```
|
253
|
+
```ruby
|
253
254
|
set(:probabilidade) { |valor| condition { rand <= valor } }
|
254
255
|
|
255
256
|
get '/ganha_um_carro', :probabilidade => 0.1 do
|
@@ -263,7 +264,7 @@ end
|
|
263
264
|
|
264
265
|
Use splat, para uma condição que leva vários valores:
|
265
266
|
|
266
|
-
```
|
267
|
+
```ruby
|
267
268
|
set(:auth) do |*roles| # <- observe o splat aqui
|
268
269
|
condition do
|
269
270
|
unless logged_in? && roles.any? {|role| current_user.in_role? role }
|
@@ -305,7 +306,7 @@ retornar um código de status HTTP.
|
|
305
306
|
|
306
307
|
Dessa forma, podemos implementar facilmente um exemplo de streaming:
|
307
308
|
|
308
|
-
```
|
309
|
+
```ruby
|
309
310
|
class Stream
|
310
311
|
def each
|
311
312
|
100.times { |i| yield "#{i}\n" }
|
@@ -325,7 +326,7 @@ embutido para uso de padrões de String e expressões regulares como
|
|
325
326
|
validadores de rota. No entanto, ele não pára por aí. Você pode
|
326
327
|
facilmente definir os seus próprios validadores:
|
327
328
|
|
328
|
-
```
|
329
|
+
```ruby
|
329
330
|
class AllButPattern
|
330
331
|
Match = Struct.new(:captures)
|
331
332
|
|
@@ -351,7 +352,7 @@ end
|
|
351
352
|
Note que o exemplo acima pode ser robusto e complicado em excesso. Pode
|
352
353
|
também ser implementado como:
|
353
354
|
|
354
|
-
```
|
355
|
+
```ruby
|
355
356
|
get // do
|
356
357
|
pass if request.path_info == "/index"
|
357
358
|
# ...
|
@@ -360,7 +361,7 @@ end
|
|
360
361
|
|
361
362
|
Ou, usando algo mais denso à frente:
|
362
363
|
|
363
|
-
```
|
364
|
+
```ruby
|
364
365
|
get %r{^(?!/index$)} do
|
365
366
|
# ...
|
366
367
|
end
|
@@ -372,7 +373,7 @@ Arquivos estáticos são disponibilizados a partir do diretório
|
|
372
373
|
`./public`. Você pode especificar um local diferente pela opção
|
373
374
|
`:public_folder`
|
374
375
|
|
375
|
-
```
|
376
|
+
```ruby
|
376
377
|
set :public_folder, File.dirname(__FILE__) + '/estatico'
|
377
378
|
```
|
378
379
|
|
@@ -384,7 +385,7 @@ Note que o nome do diretório público não é incluido na URL. Um arquivo
|
|
384
385
|
|
385
386
|
Cada linguagem de template é exposta através de seu próprio método de renderização. Estes metodos simplesmente retornam uma string:
|
386
387
|
|
387
|
-
```
|
388
|
+
```ruby
|
388
389
|
get '/' do
|
389
390
|
erb :index
|
390
391
|
end
|
@@ -403,7 +404,7 @@ end
|
|
403
404
|
|
404
405
|
Templates também aceitam um segundo argumento, um hash de opções:
|
405
406
|
|
406
|
-
```
|
407
|
+
```ruby
|
407
408
|
get '/' do
|
408
409
|
erb :index, :layout => :post
|
409
410
|
end
|
@@ -413,7 +414,7 @@ Isto irá renderizar a `views/index.erb` inclusa dentro da `views/post.erb` (o p
|
|
413
414
|
|
414
415
|
Qualquer opção não reconhecida pelo Sinatra será passada adiante para o engine de template:
|
415
416
|
|
416
|
-
```
|
417
|
+
```ruby
|
417
418
|
get '/' do
|
418
419
|
haml :index, :format => :html5
|
419
420
|
end
|
@@ -421,7 +422,7 @@ end
|
|
421
422
|
|
422
423
|
Você também pode definir opções padrões para um tipo de template:
|
423
424
|
|
424
|
-
```
|
425
|
+
```ruby
|
425
426
|
set :haml, :format => :html5
|
426
427
|
|
427
428
|
get '/' do
|
@@ -476,7 +477,7 @@ Opções disponíveis:
|
|
476
477
|
<dd>
|
477
478
|
A engine de template utilizada para renderizar seu layout.
|
478
479
|
Útil para linguagens que não suportam templates de outra
|
479
|
-
forma. O padrão é a engine do template utilizado. Exemplo:
|
480
|
+
forma. O padrão é a engine do template utilizado. Exemplo:
|
480
481
|
<tt>set :rdoc, :layout_engine => :erb</tt>
|
481
482
|
</dd>
|
482
483
|
|
@@ -497,14 +498,14 @@ set :views, settings.root + '/templates'
|
|
497
498
|
Uma coisa importante para se lembrar é que você sempre deve
|
498
499
|
referenciar os templates utilizando *symbols*, mesmo que
|
499
500
|
eles estejam em um subdiretório (neste caso use:
|
500
|
-
`:'subdir/template'` or `'subdir/template'.to_sym`). Você deve
|
501
|
+
`:'subdir/template'` or `'subdir/template'.to_sym`). Você deve
|
501
502
|
utilizar um *symbol* porque senão o método de renderização irá
|
502
503
|
renderizar qualquer outra string que você passe diretamente
|
503
504
|
para ele
|
504
505
|
|
505
506
|
### Literal Templates
|
506
507
|
|
507
|
-
```
|
508
|
+
```ruby
|
508
509
|
get '/' do
|
509
510
|
haml '%div.title Olá Mundo'
|
510
511
|
end
|
@@ -516,7 +517,7 @@ Renderiza um template string.
|
|
516
517
|
|
517
518
|
Algumas linguagens possuem multiplas implementações. Para especificar qual implementação deverá ser utilizada (e para ser *thread-safe*), você deve simplesmente requere-la primeiro:
|
518
519
|
|
519
|
-
```
|
520
|
+
```ruby
|
520
521
|
require 'rdiscount' # ou require 'bluecloth'
|
521
522
|
get('/') { markdown :index }
|
522
523
|
```
|
@@ -584,7 +585,7 @@ It also takes a block for inline templates (see exemplo).
|
|
584
585
|
<table>
|
585
586
|
<tr>
|
586
587
|
<td>Dependencia</td>
|
587
|
-
<td><a href="http://nokogiri.org/" title="nokogiri">nokogiri</a></td>
|
588
|
+
<td><a href="http://www.nokogiri.org/" title="nokogiri">nokogiri</a></td>
|
588
589
|
</tr>
|
589
590
|
<tr>
|
590
591
|
<td>Extencao do Arquivo</td>
|
@@ -637,7 +638,7 @@ It also takes a block for inline templates (see exemplo).
|
|
637
638
|
<table>
|
638
639
|
<tr>
|
639
640
|
<td>Dependencia</td>
|
640
|
-
<td><a href="http://
|
641
|
+
<td><a href="http://lesscss.org/" title="less">less</a></td>
|
641
642
|
</tr>
|
642
643
|
<tr>
|
643
644
|
<td>Extencao do Arquivo</td>
|
@@ -654,7 +655,7 @@ It also takes a block for inline templates (see exemplo).
|
|
654
655
|
<table>
|
655
656
|
<tr>
|
656
657
|
<td>Dependencia</td>
|
657
|
-
<td><a href="http://
|
658
|
+
<td><a href="http://liquidmarkup.org/" title="liquid">liquid</a></td>
|
658
659
|
</tr>
|
659
660
|
<tr>
|
660
661
|
<td>Extencao do Arquivo</td>
|
@@ -676,7 +677,7 @@ você quase sempre precisará passar o `locals` para ele.
|
|
676
677
|
<td>Dependencia</td>
|
677
678
|
<td>
|
678
679
|
Anyone of:
|
679
|
-
<a href="https://github.com/
|
680
|
+
<a href="https://github.com/davidfstr/rdiscount" title="RDiscount">RDiscount</a>,
|
680
681
|
<a href="https://github.com/vmg/redcarpet" title="RedCarpet">RedCarpet</a>,
|
681
682
|
<a href="http://deveiate.org/projects/BlueCloth" title="BlueCloth">BlueCloth</a>,
|
682
683
|
<a href="http://kramdown.gettalong.org/" title="kramdown">kramdown</a>,
|
@@ -695,20 +696,20 @@ você quase sempre precisará passar o `locals` para ele.
|
|
695
696
|
|
696
697
|
Não é possível chamar métodos por este template, nem passar *locals* para o mesmo. Portanto normalmente é utilizado junto a outra engine de renderização:
|
697
698
|
|
698
|
-
```
|
699
|
+
```ruby
|
699
700
|
erb :overview, :locals => { :text => markdown(:introducao) }
|
700
701
|
```
|
701
702
|
|
702
703
|
Note que vcoê também pode chamar o método `markdown` dentro de outros templates:
|
703
704
|
|
704
|
-
```
|
705
|
+
```ruby
|
705
706
|
%h1 Olá do Haml!
|
706
707
|
%p= markdown(:saudacoes)
|
707
708
|
```
|
708
709
|
|
709
710
|
Já que você não pode chamar o Ruby pelo Markdown, você não
|
710
711
|
pode utilizar um layout escrito em Markdown. Contudo é
|
711
|
-
possível utilizar outra engine de renderização como template,
|
712
|
+
possível utilizar outra engine de renderização como template,
|
712
713
|
deve-se passar a `:layout_engine` como opção.
|
713
714
|
|
714
715
|
<table>
|
@@ -728,20 +729,20 @@ deve-se passar a `:layout_engine` como opção.
|
|
728
729
|
|
729
730
|
Não é possível chamar métodos por este template, nem passar *locals* para o mesmo. Portanto normalmente é utilizado junto a outra engine de renderização:
|
730
731
|
|
731
|
-
```
|
732
|
+
```ruby
|
732
733
|
erb :overview, :locals => { :text => textile(:introducao) }
|
733
734
|
```
|
734
735
|
|
735
736
|
Note que vcoê também pode chamar o método `textile` dentro de outros templates:
|
736
737
|
|
737
|
-
```
|
738
|
+
```ruby
|
738
739
|
%h1 Olá do Haml!
|
739
740
|
%p= textile(:saudacoes)
|
740
741
|
```
|
741
742
|
|
742
743
|
Já que você não pode chamar o Ruby pelo Textile, você não
|
743
744
|
pode utilizar um layout escrito em Textile. Contudo é
|
744
|
-
possível utilizar outra engine de renderização como template,
|
745
|
+
possível utilizar outra engine de renderização como template,
|
745
746
|
deve-se passar a `:layout_engine` como opção.
|
746
747
|
|
747
748
|
#### RDoc Templates
|
@@ -763,20 +764,20 @@ deve-se passar a `:layout_engine` como opção.
|
|
763
764
|
|
764
765
|
Não é possível chamar métodos por este template, nem passar *locals* para o mesmo. Portanto normalmente é utilizado junto a outra engine de renderização:
|
765
766
|
|
766
|
-
```
|
767
|
+
```ruby
|
767
768
|
erb :overview, :locals => { :text => rdoc(:introducao) }
|
768
769
|
```
|
769
770
|
|
770
771
|
Note que vcoê também pode chamar o método `rdoc` dentro de outros templates:
|
771
772
|
|
772
|
-
```
|
773
|
+
```ruby
|
773
774
|
%h1 Olá do Haml!
|
774
775
|
%p= rdoc(:saudacoes)
|
775
776
|
```
|
776
777
|
|
777
778
|
Já que você não pode chamar o Ruby pelo RDoc, você não
|
778
779
|
pode utilizar um layout escrito em RDoc. Contudo é
|
779
|
-
possível utilizar outra engine de renderização como template,
|
780
|
+
possível utilizar outra engine de renderização como template,
|
780
781
|
deve-se passar a `:layout_engine` como opção.
|
781
782
|
|
782
783
|
#### AsciiDoc Templates
|
@@ -824,7 +825,7 @@ você quase sempre precisará passar o `locals` para ele.
|
|
824
825
|
<table>
|
825
826
|
<tr>
|
826
827
|
<td>Dependencia</td>
|
827
|
-
<td><a href="http://markaby.github.
|
828
|
+
<td><a href="http://markaby.github.io/" title="Markaby">Markaby</a></td>
|
828
829
|
</tr>
|
829
830
|
<tr>
|
830
831
|
<td>Extencao do Arquivo</td>
|
@@ -891,20 +892,20 @@ Este também recebe um bloco para templates (veja o exemplo).
|
|
891
892
|
|
892
893
|
Não é possível chamar métodos por este template, nem passar *locals* para o mesmo. Portanto normalmente é utilizado junto a outra engine de renderização:
|
893
894
|
|
894
|
-
```
|
895
|
+
```ruby
|
895
896
|
erb :overview, :locals => { :text => creole(:introduction) }
|
896
897
|
```
|
897
898
|
|
898
899
|
Note que vcoê também pode chamar o método `creole` dentro de outros templates:
|
899
900
|
|
900
|
-
```
|
901
|
+
```ruby
|
901
902
|
%h1 Olá do Haml!
|
902
903
|
%p= creole(:saudacoes)
|
903
904
|
```
|
904
905
|
|
905
906
|
Já que você não pode chamar o Ruby pelo Creole, você não
|
906
907
|
pode utilizar um layout escrito em Creole. Contudo é
|
907
|
-
possível utilizar outra engine de renderização como template,
|
908
|
+
possível utilizar outra engine de renderização como template,
|
908
909
|
deve-se passar a `:layout_engine` como opção.
|
909
910
|
|
910
911
|
#### MediaWiki Templates
|
@@ -928,20 +929,20 @@ It is not possible to call methods from MediaWiki markup, nor to pass locals to
|
|
928
929
|
it. You therefore will usually use it in combination with another rendering
|
929
930
|
engine:
|
930
931
|
|
931
|
-
```
|
932
|
+
```ruby
|
932
933
|
erb :overview, :locals => { :text => mediawiki(:introduction) }
|
933
934
|
```
|
934
935
|
|
935
936
|
Note that you may also call the `mediawiki` method from within other templates:
|
936
937
|
|
937
|
-
```
|
938
|
+
```ruby
|
938
939
|
%h1 Hello From Haml!
|
939
940
|
%p= mediawiki(:greetings)
|
940
941
|
```
|
941
942
|
|
942
943
|
Já que você não pode chamar o Ruby pelo MediaWiki, você não
|
943
944
|
pode utilizar um layout escrito em MediaWiki. Contudo é
|
944
|
-
possível utilizar outra engine de renderização como template,
|
945
|
+
possível utilizar outra engine de renderização como template,
|
945
946
|
deve-se passar a `:layout_engine` como opção.
|
946
947
|
|
947
948
|
#### CoffeeScript Templates
|
@@ -974,7 +975,7 @@ deve-se passar a `:layout_engine` como opção.
|
|
974
975
|
<tr>
|
975
976
|
<td>Dependencia</td>
|
976
977
|
<td>
|
977
|
-
<a href="https://github.com/
|
978
|
+
<a href="https://github.com/forgecrafted/ruby-stylus" title="Ruby Stylus">
|
978
979
|
Stylus
|
979
980
|
</a> and a
|
980
981
|
<a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
|
@@ -994,7 +995,7 @@ deve-se passar a `:layout_engine` como opção.
|
|
994
995
|
|
995
996
|
Antes que vcoê possa utilizar o template Stylus primeiro você deve carregar `stylus` e `stylus/tilt`:
|
996
997
|
|
997
|
-
```
|
998
|
+
```ruby
|
998
999
|
require 'sinatra'
|
999
1000
|
require 'stylus'
|
1000
1001
|
require 'stylus/tilt'
|
@@ -1030,14 +1031,14 @@ end
|
|
1030
1031
|
|
1031
1032
|
O código-fonte do template é executado como uma string Ruby e a variável resultante em json é convertida utilizando `#to_json`:
|
1032
1033
|
|
1033
|
-
```
|
1034
|
+
```ruby
|
1034
1035
|
json = { :foo => 'bar' }
|
1035
1036
|
json[:baz] = key
|
1036
1037
|
```
|
1037
1038
|
|
1038
1039
|
O `:callback` e `:variable` são opções que podem ser utilizadas para o objeto de renderização:
|
1039
1040
|
|
1040
|
-
```
|
1041
|
+
```javascript
|
1041
1042
|
var resource = {"foo":"bar","baz":"qux"};
|
1042
1043
|
present(resource);
|
1043
1044
|
```
|
@@ -1069,7 +1070,7 @@ Templates são avaliados dentro do mesmo contexto como manipuladores de
|
|
1069
1070
|
rota. Variáveis de instância setadas em rotas manipuladas são
|
1070
1071
|
diretamente acessadas por templates:
|
1071
1072
|
|
1072
|
-
```
|
1073
|
+
```ruby
|
1073
1074
|
get '/:id' do
|
1074
1075
|
@foo = Foo.find(params['id'])
|
1075
1076
|
haml '%h1= @foo.nome'
|
@@ -1078,7 +1079,7 @@ end
|
|
1078
1079
|
|
1079
1080
|
Ou, especifique um hash explícito para variáveis locais:
|
1080
1081
|
|
1081
|
-
```
|
1082
|
+
```ruby
|
1082
1083
|
get '/:id' do
|
1083
1084
|
foo = Foo.find(params['id'])
|
1084
1085
|
haml '%h1= foo.nome', :locals => { :foo => foo }
|
@@ -1090,10 +1091,10 @@ partials dentro de outros templates.
|
|
1090
1091
|
|
1091
1092
|
### Templates com `yield` e layouts aninhados
|
1092
1093
|
|
1093
|
-
O layout geralmente é apenas um template que executa `yield`.
|
1094
|
+
O layout geralmente é apenas um template que executa `yield`.
|
1094
1095
|
Tal template pode ser utilizado pela opção `:template` descrita acima ou pode ser renderizado através de um bloco, como a seguir:
|
1095
1096
|
|
1096
|
-
```
|
1097
|
+
```ruby
|
1097
1098
|
erb :post, :layout => false do
|
1098
1099
|
erb :index
|
1099
1100
|
end
|
@@ -1103,7 +1104,7 @@ Este código é quase equivalente a `erb :index, :layout => :post`
|
|
1103
1104
|
|
1104
1105
|
Passando blocos para os métodos de renderização é útil para criar layouts aninhados:
|
1105
1106
|
|
1106
|
-
```
|
1107
|
+
```ruby
|
1107
1108
|
erb :main_layout, :layout => false do
|
1108
1109
|
erb :admin_layout do
|
1109
1110
|
erb :user
|
@@ -1113,7 +1114,7 @@ end
|
|
1113
1114
|
|
1114
1115
|
Também pode ser feito com menos linhas de código:
|
1115
1116
|
|
1116
|
-
```
|
1117
|
+
```ruby
|
1117
1118
|
erb :admin_layout, :layout => :main_layout do
|
1118
1119
|
erb :user
|
1119
1120
|
end
|
@@ -1126,7 +1127,7 @@ Atualmente os métodos listados aceitam blocos: `erb`, `haml`,
|
|
1126
1127
|
|
1127
1128
|
Templates podem ser definidos no final do arquivo fonte(.rb):
|
1128
1129
|
|
1129
|
-
```
|
1130
|
+
```ruby
|
1130
1131
|
require 'sinatra'
|
1131
1132
|
|
1132
1133
|
get '/' do
|
@@ -1152,7 +1153,7 @@ tem templates inline no outro arquivo fonte.
|
|
1152
1153
|
Templates também podem ser definidos utilizando o método top-level
|
1153
1154
|
`template`:
|
1154
1155
|
|
1155
|
-
```
|
1156
|
+
```ruby
|
1156
1157
|
template :layout do
|
1157
1158
|
"%html\n =yield\n"
|
1158
1159
|
end
|
@@ -1170,7 +1171,7 @@ Se existir um template com nome “layout”, ele será utilizado toda vez
|
|
1170
1171
|
que um template for renderizado. Você pode desabilitar layouts passando
|
1171
1172
|
`:layout => false`.
|
1172
1173
|
|
1173
|
-
```
|
1174
|
+
```ruby
|
1174
1175
|
get '/' do
|
1175
1176
|
haml :index, :layout => !request.xhr?
|
1176
1177
|
end
|
@@ -1180,7 +1181,7 @@ end
|
|
1180
1181
|
|
1181
1182
|
Para associar uma extensão de arquivo com um engine de template use o método `Tilt.register`. Por exemplo, se você quiser usar a extensão `tt` para os templates Textile você pode fazer o seguinte:
|
1182
1183
|
|
1183
|
-
```
|
1184
|
+
```ruby
|
1184
1185
|
Tilt.register :tt, Tilt[:textile]
|
1185
1186
|
```
|
1186
1187
|
|
@@ -1188,7 +1189,7 @@ Tilt.register :tt, Tilt[:textile]
|
|
1188
1189
|
|
1189
1190
|
Primeiro registre seu engine utilizando o Tilt, e então crie um método de renderização:
|
1190
1191
|
|
1191
|
-
```
|
1192
|
+
```ruby
|
1192
1193
|
Tilt.register :myat, MyAwesomeTemplateEngine
|
1193
1194
|
|
1194
1195
|
helpers do
|
@@ -1207,7 +1208,7 @@ https://github.com/rtomayko/tilt para saber mais sobre Tilt.
|
|
1207
1208
|
|
1208
1209
|
Para implementar sua própria lógica para busca de templates você pode escrever seu próprio método `#find_template`
|
1209
1210
|
|
1210
|
-
```
|
1211
|
+
```ruby
|
1211
1212
|
configure do
|
1212
1213
|
set :views [ './views/a', './views/b' ]
|
1213
1214
|
end
|
@@ -1226,7 +1227,7 @@ da requisição e podem modificar a requisição e a reposta. Variáveis de
|
|
1226
1227
|
instância setadas nos filtros são acessadas através de rotas e
|
1227
1228
|
templates:
|
1228
1229
|
|
1229
|
-
```
|
1230
|
+
```ruby
|
1230
1231
|
before do
|
1231
1232
|
@nota = 'Oi!'
|
1232
1233
|
request.path_info = '/foo/bar/baz'
|
@@ -1243,7 +1244,7 @@ requisição e também podem modificar a requisição e a resposta. Variáveis d
|
|
1243
1244
|
instância e rotas definidas nos filtros before são acessadas através dos
|
1244
1245
|
filtros after:
|
1245
1246
|
|
1246
|
-
```
|
1247
|
+
```ruby
|
1247
1248
|
after do
|
1248
1249
|
puts response.status
|
1249
1250
|
end
|
@@ -1252,7 +1253,7 @@ end
|
|
1252
1253
|
Filtros opcionalmente têm um padrão, fazendo com que sejam avaliados
|
1253
1254
|
somente se o caminho do pedido coincidir com esse padrão:
|
1254
1255
|
|
1255
|
-
```
|
1256
|
+
```ruby
|
1256
1257
|
before '/protected/*' do
|
1257
1258
|
authenticate!
|
1258
1259
|
end
|
@@ -1267,7 +1268,7 @@ end
|
|
1267
1268
|
Use o método de alto nível `helpers` para definir métodos auxiliares
|
1268
1269
|
para utilizar em manipuladores de rotas e modelos:
|
1269
1270
|
|
1270
|
-
```
|
1271
|
+
```ruby
|
1271
1272
|
helpers do
|
1272
1273
|
def bar(nome)
|
1273
1274
|
"#{nome}bar"
|
@@ -1283,7 +1284,7 @@ end
|
|
1283
1284
|
|
1284
1285
|
Sessões são usadas para manter um estado durante uma requisição. Se ativa, você terá disponível um hash de sessão para cada sessão de usuário:
|
1285
1286
|
|
1286
|
-
```
|
1287
|
+
```ruby
|
1287
1288
|
enable :sessions
|
1288
1289
|
|
1289
1290
|
get '/' do
|
@@ -1297,7 +1298,7 @@ end
|
|
1297
1298
|
|
1298
1299
|
Note que `enable :sessions` utilizará um cookie para guardar todos os dados da sessão. Isso nem sempre pode ser o que você quer (guardar muitos dados irá aumentar o seu tráfego, por exemplo). Você pode utilizar qualquer Rack middleware de sessão: para fazer isso **não** utilize o método `enable :sessions`, ao invés disso utilize seu middleware de sessão como utilizaria qualquer outro:
|
1299
1300
|
|
1300
|
-
```
|
1301
|
+
```ruby
|
1301
1302
|
use Rack::Session::Pool, :expire_after => 2592000
|
1302
1303
|
|
1303
1304
|
get '/' do
|
@@ -1311,19 +1312,19 @@ end
|
|
1311
1312
|
|
1312
1313
|
Para melhorar a segurança, os dados da sessão guardados no cookie é assinado com uma chave secreta da sessão. Uma chave aleatória é gerada para você pelo Sinatra. Contudo, já que a chave mudará cada vez que você inicia sua aplicação, você talvez queira defini-la você mesmo para que todas as instâncias da aplicação compartilhe-a:
|
1313
1314
|
|
1314
|
-
```
|
1315
|
+
```ruby
|
1315
1316
|
set :session_secret, 'super secret'
|
1316
1317
|
```
|
1317
1318
|
|
1318
1319
|
Se você quiser fazer outras configurações, você também pode guardar um hash com as opções nas configurações da `session`:
|
1319
1320
|
|
1320
|
-
```
|
1321
|
+
```ruby
|
1321
1322
|
set :sessions, :domain => 'foo.com'
|
1322
1323
|
```
|
1323
1324
|
|
1324
1325
|
Para compartilhar sua sessão entre outros aplicativos em um subdomínio de foo.com, utilize o prefixo *.*:
|
1325
1326
|
|
1326
|
-
```
|
1327
|
+
```ruby
|
1327
1328
|
set :sessions, :domain => '.foo.com'
|
1328
1329
|
```
|
1329
1330
|
|
@@ -1331,37 +1332,37 @@ set :sessions, :domain => '.foo.com'
|
|
1331
1332
|
|
1332
1333
|
Para parar imediatamente uma requisição com um filtro ou rota utilize:
|
1333
1334
|
|
1334
|
-
```
|
1335
|
+
```ruby
|
1335
1336
|
halt
|
1336
1337
|
```
|
1337
1338
|
|
1338
1339
|
Você também pode especificar o status quando parar…
|
1339
1340
|
|
1340
|
-
```
|
1341
|
+
```ruby
|
1341
1342
|
halt 410
|
1342
1343
|
```
|
1343
1344
|
|
1344
1345
|
Ou com corpo de texto…
|
1345
1346
|
|
1346
|
-
```
|
1347
|
+
```ruby
|
1347
1348
|
halt 'isso será o corpo do texto'
|
1348
1349
|
```
|
1349
1350
|
|
1350
1351
|
Ou também…
|
1351
1352
|
|
1352
|
-
```
|
1353
|
+
```ruby
|
1353
1354
|
halt 401, 'vamos embora!'
|
1354
1355
|
```
|
1355
1356
|
|
1356
1357
|
Com cabeçalhos…
|
1357
1358
|
|
1358
|
-
```
|
1359
|
+
```ruby
|
1359
1360
|
halt 402, {'Content-Type' => 'text/plain'}, 'revanche'
|
1360
1361
|
```
|
1361
1362
|
|
1362
1363
|
É obviamente possivel combinar um template com o `halt`:
|
1363
1364
|
|
1364
|
-
```
|
1365
|
+
```ruby
|
1365
1366
|
halt erb(:error)
|
1366
1367
|
```
|
1367
1368
|
|
@@ -1370,7 +1371,7 @@ halt erb(:error)
|
|
1370
1371
|
Uma rota pode processar aposta para a próxima rota correspondente usando
|
1371
1372
|
`pass`:
|
1372
1373
|
|
1373
|
-
```
|
1374
|
+
```ruby
|
1374
1375
|
get '/adivinhar/:quem' do
|
1375
1376
|
pass unless params['quem'] == 'Frank'
|
1376
1377
|
'Você me pegou!'
|
@@ -1389,7 +1390,7 @@ próxima rota de parâmetro. Se o parâmetro da rota não for encontrado, um
|
|
1389
1390
|
|
1390
1391
|
As vezes o `pass` não é o que você quer, ao invés dele talvez você queira obter o resultado chamando outra rota. Utilize o método `call` neste caso:
|
1391
1392
|
|
1392
|
-
```
|
1393
|
+
```ruby
|
1393
1394
|
get '/foo' do
|
1394
1395
|
status, headers, body = call env.merge("PATH_INFO" => '/bar')
|
1395
1396
|
[status, headers, body.map(&:upcase)]
|
@@ -1410,7 +1411,7 @@ Veja a especificação do Rack se você quer aprender mais sobre o `call`.
|
|
1410
1411
|
|
1411
1412
|
Rodando uma vez, na inicialização, em qualquer ambiente:
|
1412
1413
|
|
1413
|
-
```
|
1414
|
+
```ruby
|
1414
1415
|
configure do
|
1415
1416
|
...
|
1416
1417
|
end
|
@@ -1419,7 +1420,7 @@ end
|
|
1419
1420
|
Rodando somente quando o ambiente (`RACK_ENV` environment variável) é
|
1420
1421
|
setado para `:production`:
|
1421
1422
|
|
1422
|
-
```
|
1423
|
+
```ruby
|
1423
1424
|
configure :production do
|
1424
1425
|
...
|
1425
1426
|
end
|
@@ -1427,7 +1428,7 @@ end
|
|
1427
1428
|
|
1428
1429
|
Rodando quando o ambiente é setado para `:production` ou `:test`:
|
1429
1430
|
|
1430
|
-
```
|
1431
|
+
```ruby
|
1431
1432
|
configure :production, :test do
|
1432
1433
|
...
|
1433
1434
|
end
|
@@ -1444,7 +1445,7 @@ oferecer, como `haml`, `erb`, `halt`, etc.
|
|
1444
1445
|
Quando um `Sinatra::NotFound` exception é levantado, ou o código de
|
1445
1446
|
status da reposta é 404, o manipulador `not_found` é invocado:
|
1446
1447
|
|
1447
|
-
```
|
1448
|
+
```ruby
|
1448
1449
|
not_found do
|
1449
1450
|
'Isto está longe de ser encontrado'
|
1450
1451
|
end
|
@@ -1456,7 +1457,7 @@ O manipulador `error` é invocado toda a vez que uma exceção é lançada a
|
|
1456
1457
|
partir de um bloco de rota ou um filtro. O objeto da exceção pode ser
|
1457
1458
|
obtido a partir da variável Rack `sinatra.error`:
|
1458
1459
|
|
1459
|
-
```
|
1460
|
+
```ruby
|
1460
1461
|
error do
|
1461
1462
|
'Desculpe, houve um erro desagradável - ' + env['sinatra.error'].message
|
1462
1463
|
end
|
@@ -1464,7 +1465,7 @@ end
|
|
1464
1465
|
|
1465
1466
|
Erros customizados:
|
1466
1467
|
|
1467
|
-
```
|
1468
|
+
```ruby
|
1468
1469
|
error MeuErroCustomizado do
|
1469
1470
|
'Então que aconteceu foi...' + env['sinatra.error'].message
|
1470
1471
|
end
|
@@ -1472,7 +1473,7 @@ end
|
|
1472
1473
|
|
1473
1474
|
Então, se isso acontecer:
|
1474
1475
|
|
1475
|
-
```
|
1476
|
+
```ruby
|
1476
1477
|
get '/' do
|
1477
1478
|
raise MeuErroCustomizado, 'alguma coisa ruim'
|
1478
1479
|
end
|
@@ -1485,7 +1486,7 @@ Você receberá isso:
|
|
1485
1486
|
Alternativamente, você pode instalar manipulador de erro para um código
|
1486
1487
|
de status:
|
1487
1488
|
|
1488
|
-
```
|
1489
|
+
```ruby
|
1489
1490
|
error 403 do
|
1490
1491
|
'Accesso negado'
|
1491
1492
|
end
|
@@ -1497,7 +1498,7 @@ end
|
|
1497
1498
|
|
1498
1499
|
Ou um range:
|
1499
1500
|
|
1500
|
-
```
|
1501
|
+
```ruby
|
1501
1502
|
error 400..510 do
|
1502
1503
|
'Boom'
|
1503
1504
|
end
|
@@ -1512,13 +1513,13 @@ Quando utilizamos `send_file` ou arquivos estáticos você pode ter mime
|
|
1512
1513
|
types Sinatra não entendidos. Use `mime_type` para registrar eles por
|
1513
1514
|
extensão de arquivos:
|
1514
1515
|
|
1515
|
-
```
|
1516
|
+
```ruby
|
1516
1517
|
mime_type :foo, 'text/foo'
|
1517
1518
|
```
|
1518
1519
|
|
1519
1520
|
Você também pode utilizar isto com o helper `content_type`:
|
1520
1521
|
|
1521
|
-
```
|
1522
|
+
```ruby
|
1522
1523
|
content_type :foo
|
1523
1524
|
```
|
1524
1525
|
|
@@ -1534,7 +1535,7 @@ vários tipos de funcionalidades comuns.
|
|
1534
1535
|
O Sinatra faz construtores pipelines do middleware Rack facilmente em um
|
1535
1536
|
nível superior utilizando o método `use`:
|
1536
1537
|
|
1537
|
-
```
|
1538
|
+
```ruby
|
1538
1539
|
require 'sinatra'
|
1539
1540
|
require 'meu_middleware_customizado'
|
1540
1541
|
|
@@ -1547,11 +1548,11 @@ end
|
|
1547
1548
|
```
|
1548
1549
|
|
1549
1550
|
A semântica de `use` é idêntica aquela definida para a DSL
|
1550
|
-
[Rack::Builder](http://rubydoc.info/github/rack/rack/master/Rack/Builder)
|
1551
|
+
[Rack::Builder](http://www.rubydoc.info/github/rack/rack/master/Rack/Builder)
|
1551
1552
|
(mais frequentemente utilizada para arquivos rackup). Por exemplo, o
|
1552
1553
|
método `use` aceita múltiplos argumentos/variáveis bem como blocos:
|
1553
1554
|
|
1554
|
-
```
|
1555
|
+
```ruby
|
1555
1556
|
use Rack::Auth::Basic do |usuario, senha|
|
1556
1557
|
usuario == 'admin' && senha == 'secreto'
|
1557
1558
|
end
|
@@ -1568,7 +1569,7 @@ Testes no Sinatra podem ser escritos utilizando qualquer biblioteca ou
|
|
1568
1569
|
framework de teste baseados no Rack.
|
1569
1570
|
[Rack::Test](http://gitrdoc.com/brynary/rack-test) é recomendado:
|
1570
1571
|
|
1571
|
-
```
|
1572
|
+
```ruby
|
1572
1573
|
require 'minha_aplicacao_sinatra'
|
1573
1574
|
require 'rack/test'
|
1574
1575
|
|
@@ -1610,7 +1611,7 @@ estilo de configuração de micro aplicativos (exemplo: uma simples
|
|
1610
1611
|
arquivo de aplicação, diretórios `./public` e `./views`, logs, página de
|
1611
1612
|
detalhes de exceção, etc.). É onde o `Sinatra::Base` entra em jogo:
|
1612
1613
|
|
1613
|
-
```
|
1614
|
+
```ruby
|
1614
1615
|
require 'sinatra/base'
|
1615
1616
|
|
1616
1617
|
class MinhaApp < Sinatra::Base
|
@@ -1628,7 +1629,7 @@ um middleware Rack, uma aplicação Rack, ou metal Rails. Você pode
|
|
1628
1629
|
utilizar ou executar esta classe com um arquivo rackup `config.ru`;
|
1629
1630
|
ou, controlar um componente de servidor fornecendo como biblioteca:
|
1630
1631
|
|
1631
|
-
```
|
1632
|
+
```ruby
|
1632
1633
|
MinhaApp.run! :host => 'localhost', :port => 9090
|
1633
1634
|
```
|
1634
1635
|
|
@@ -1646,7 +1647,7 @@ modificações:
|
|
1646
1647
|
|
1647
1648
|
`Sinatra::Base` é um quadro branco. Muitas opções são desabilitadas por
|
1648
1649
|
padrão, incluindo o servidor embutido. Veja [Opções e
|
1649
|
-
Configurações](http://
|
1650
|
+
Configurações](http://www.sinatrarb.com/configuration.html) para
|
1650
1651
|
detalhes de opções disponíveis e seus comportamentos.
|
1651
1652
|
|
1652
1653
|
SIDEBAR: A DSL de alto nível do Sinatra é implementada utilizando um simples
|
@@ -1663,7 +1664,7 @@ principal](http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854
|
|
1663
1664
|
|
1664
1665
|
Aplicações Sinatra podem ser executadas diretamente:
|
1665
1666
|
|
1666
|
-
```
|
1667
|
+
```shell
|
1667
1668
|
ruby minhaapp.rb [-h] [-x] [-e AMBIENTE] [-p PORTA] [-o HOST] [-s SERVIDOR]
|
1668
1669
|
```
|
1669
1670
|
|
@@ -1678,13 +1679,46 @@ As opções são:
|
|
1678
1679
|
-x # ativa o bloqueio (padrão é desligado)
|
1679
1680
|
```
|
1680
1681
|
|
1682
|
+
### Multi-threading
|
1683
|
+
|
1684
|
+
_Parafraseando [esta resposta no StackOverflow](resposta-so) por Konstantin_
|
1685
|
+
|
1686
|
+
Sinatra não impõe nenhum modelo de concorrencia, mas deixa isso como responsabilidade
|
1687
|
+
do Rack (servidor) subjacente como o Thin, Puma ou WEBrick. Sinatra por si só é thread-safe,
|
1688
|
+
então não há nenhum problema se um Rack handler usar um modelo de thread de concorrência. Isso
|
1689
|
+
significaria que ao iniciar o servidor, você teria que espeficiar o método de invocação correto
|
1690
|
+
para o Rack handler específico. Os seguintes exemplos é uma demonstração de como iniciar um
|
1691
|
+
servidor Thin multi-thread:
|
1692
|
+
|
1693
|
+
```ruby
|
1694
|
+
# app.rb
|
1695
|
+
|
1696
|
+
require 'sinatra/base'
|
1697
|
+
|
1698
|
+
class App < Sinatra::Base
|
1699
|
+
get '/' do
|
1700
|
+
'Olá mundo'
|
1701
|
+
end
|
1702
|
+
end
|
1703
|
+
|
1704
|
+
App.run!
|
1705
|
+
```
|
1706
|
+
|
1707
|
+
Para iniciar o servidor seria:
|
1708
|
+
|
1709
|
+
```shell
|
1710
|
+
thin --threaded start
|
1711
|
+
```
|
1712
|
+
|
1713
|
+
[resposrta-so]: http://stackoverflow.com/questions/6278817/is-sinatra-multi-threaded/6282999#6282999)
|
1714
|
+
|
1681
1715
|
## A última versão
|
1682
1716
|
|
1683
1717
|
Se você gostaria de utilizar o código da última versão do Sinatra, crie
|
1684
1718
|
um clone local e execute sua aplicação com o diretório `sinatra/lib` no
|
1685
1719
|
`LOAD_PATH`:
|
1686
1720
|
|
1687
|
-
```
|
1721
|
+
```shell
|
1688
1722
|
cd minhaapp
|
1689
1723
|
git clone git://github.com/sinatra/sinatra.git
|
1690
1724
|
ruby -I sinatra/lib minhaapp.rb
|
@@ -1693,7 +1727,7 @@ ruby -I sinatra/lib minhaapp.rb
|
|
1693
1727
|
Alternativamente, você pode adicionar o diretório do `sinatra/lib` no
|
1694
1728
|
`LOAD_PATH` do seu aplicativo:
|
1695
1729
|
|
1696
|
-
```
|
1730
|
+
```ruby
|
1697
1731
|
$LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
|
1698
1732
|
require 'rubygems'
|
1699
1733
|
require 'sinatra'
|
@@ -1705,7 +1739,7 @@ end
|
|
1705
1739
|
|
1706
1740
|
Para atualizar o código do Sinatra no futuro:
|
1707
1741
|
|
1708
|
-
```
|
1742
|
+
```shell
|
1709
1743
|
cd meuprojeto/sinatra
|
1710
1744
|
git pull
|
1711
1745
|
```
|
@@ -1716,11 +1750,11 @@ git pull
|
|
1716
1750
|
adicional, novidades e links para outros recursos.
|
1717
1751
|
* [Contribuir](http://www.sinatrarb.com/contributing) - Encontrar um
|
1718
1752
|
bug? Precisa de ajuda? Tem um patch?
|
1719
|
-
* [Acompanhar Questões](
|
1720
|
-
* [Twitter](
|
1753
|
+
* [Acompanhar Questões](https://github.com/sinatra/sinatra/issues)
|
1754
|
+
* [Twitter](https://twitter.com/sinatra)
|
1721
1755
|
* [Lista de Email](http://groups.google.com/group/sinatrarb/topics)
|
1722
1756
|
* [Sinatra Book](https://github.com/sinatra/sinatra-book/) Livro de Receitas
|
1723
|
-
* Documentação da API para a [última release](http://rubydoc.info/gems/sinatra)
|
1757
|
+
* Documentação da API para a [última release](http://www.rubydoc.info/gems/sinatra)
|
1724
1758
|
* [IRC: \#sinatra](irc://chat.freenode.net/#sinatra) em
|
1725
1759
|
[freenode.net](http://freenode.net)
|
1726
|
-
* [Servidor de CI](
|
1760
|
+
* [Servidor de CI](https://travis-ci.org/sinatra/sinatra)
|