sinatra 1.3.6 → 1.4.0.a

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.

Files changed (71) hide show
  1. data/CHANGES +96 -22
  2. data/Gemfile +11 -3
  3. data/README.de.md +2590 -0
  4. data/README.es.rdoc +66 -38
  5. data/README.fr.md +2630 -0
  6. data/README.hu.rdoc +3 -2
  7. data/README.jp.rdoc +16 -3
  8. data/README.ko.rdoc +11 -5
  9. data/README.md +2699 -0
  10. data/README.pt-br.rdoc +152 -21
  11. data/README.pt-pt.rdoc +3 -2
  12. data/README.ru.md +2724 -0
  13. data/README.zh.rdoc +3 -3
  14. data/Rakefile +3 -4
  15. data/examples/chat.rb +3 -3
  16. data/lib/sinatra/base.rb +433 -247
  17. data/lib/sinatra/main.rb +4 -2
  18. data/lib/sinatra/showexceptions.rb +6 -1
  19. data/lib/sinatra/version.rb +1 -1
  20. data/test/base_test.rb +21 -9
  21. data/test/builder_test.rb +15 -19
  22. data/test/coffee_test.rb +4 -6
  23. data/test/compile_test.rb +154 -0
  24. data/test/contest.rb +4 -6
  25. data/test/creole_test.rb +5 -5
  26. data/test/delegator_test.rb +1 -3
  27. data/test/erb_test.rb +32 -20
  28. data/test/extensions_test.rb +1 -3
  29. data/test/filter_test.rb +65 -56
  30. data/test/haml_test.rb +34 -26
  31. data/test/helpers_test.rb +331 -221
  32. data/test/integration_helper.rb +8 -0
  33. data/test/integration_test.rb +3 -1
  34. data/test/less_test.rb +10 -8
  35. data/test/liquid_test.rb +22 -4
  36. data/test/mapped_error_test.rb +122 -96
  37. data/test/markaby_test.rb +5 -5
  38. data/test/markdown_test.rb +5 -5
  39. data/test/middleware_test.rb +3 -3
  40. data/test/nokogiri_test.rb +4 -6
  41. data/test/rabl_test.rb +89 -0
  42. data/test/radius_test.rb +4 -4
  43. data/test/rdoc_test.rb +7 -7
  44. data/test/readme_test.rb +14 -30
  45. data/test/request_test.rb +15 -0
  46. data/test/response_test.rb +3 -4
  47. data/test/result_test.rb +11 -33
  48. data/test/route_added_hook_test.rb +10 -10
  49. data/test/routing_test.rb +123 -1
  50. data/test/sass_test.rb +26 -26
  51. data/test/scss_test.rb +16 -16
  52. data/test/server_test.rb +2 -2
  53. data/test/settings_test.rb +48 -4
  54. data/test/sinatra_test.rb +2 -7
  55. data/test/slim_test.rb +37 -23
  56. data/test/static_test.rb +56 -15
  57. data/test/streaming_test.rb +11 -2
  58. data/test/templates_test.rb +117 -45
  59. data/test/textile_test.rb +9 -9
  60. data/test/views/hello.rabl +2 -0
  61. data/test/views/hello.wlang +1 -0
  62. data/test/views/hello.yajl +1 -0
  63. data/test/views/layout2.rabl +3 -0
  64. data/test/views/layout2.wlang +2 -0
  65. data/test/wlang_test.rb +87 -0
  66. data/test/yajl_test.rb +86 -0
  67. metadata +27 -17
  68. data/README.de.rdoc +0 -2097
  69. data/README.fr.rdoc +0 -2036
  70. data/README.rdoc +0 -2017
  71. data/README.ru.rdoc +0 -1785
@@ -1,27 +1,29 @@
1
1
  = Sinatra
2
2
  <i>Atenção: Este documento é apenas uma tradução da versão em inglês e pode estar desatualizado.</i>
3
3
 
4
- Sinatra é uma DSL para criar rapidamente aplicações web em Ruby com o mínimo de
5
- esforço:
4
+ Sinatra é uma
5
+ {DSL}[http://pt.wikipedia.org/wiki/Linguagem_de_domínio_específico]
6
+ para criar aplicações web em Ruby com o mínimo de esforço e rapidez:
6
7
 
7
8
  # minhaapp.rb
8
- require 'rubygems'
9
9
  require 'sinatra'
10
+
10
11
  get '/' do
11
12
  'Olá Mundo!'
12
13
  end
13
14
 
14
15
  Instale a gem e execute como:
15
16
 
16
- sudo gem install sinatra
17
+ gem install sinatra
17
18
  ruby minhaapp.rb
18
19
 
19
20
  Acesse em: http://localhost:4567
20
21
 
22
+ Recomendamos a execução de <tt>gem install thin</tt>. Caso esteja disponível, o Sinatra irá usar.
23
+
21
24
  == Rotas
22
25
 
23
- No Sinatra, uma rota é um metodo HTTP associado a uma URL correspondente padrão.
24
- Cada rota é associada a um bloco:
26
+ No Sinatra, uma rota é um método HTTP emparelhado com um padrão de URL. Cada rota possui um bloco de execução:
25
27
 
26
28
  get '/' do
27
29
  .. mostrando alguma coisa ..
@@ -35,15 +37,21 @@ Cada rota é associada a um bloco:
35
37
  .. atualizando alguma coisa ..
36
38
  end
37
39
 
40
+ patch '/' do
41
+ .. modificando alguma coisa ..
42
+ end
43
+
38
44
  delete '/' do
39
- .. apagando alguma coisa ..
45
+ .. removendo alguma coisa ..
40
46
  end
41
47
 
42
- Rotas são encontradas na ordem em que são definidas. A primeira rota que
43
- é encontrada invoca o pedido.
48
+ options '/' do
49
+ .. estabelecendo alguma coisa ..
50
+ end
51
+
52
+ As rotas são interpretadas na ordem em que são definidos. A primeira rota encontrada responde ao pedido.
44
53
 
45
- Padrões de rota podem incluir parâmetros nomeados, acessáveis via a
46
- hash <tt>params</tt>:
54
+ Padrões de rota podem conter parâmetros nomeados, acessível através do hash <tt>params</tt>:
47
55
 
48
56
  get '/ola/:nome' do
49
57
  # corresponde a "GET /ola/foo" e "GET /ola/bar"
@@ -51,14 +59,13 @@ hash <tt>params</tt>:
51
59
  "Olá #{params[:nome]}!"
52
60
  end
53
61
 
54
- Você também pode acessar parâmetros nomeados via bloco de parâmetros:
62
+ Você também pode acessar parâmetros nomeados através dos parâmetros de um bloco:
55
63
 
56
64
  get '/ola/:nome' do |n|
57
65
  "Olá #{n}!"
58
66
  end
59
67
 
60
- Padrões de rota também podem incluir parâmetros splat (ou curingas), acessáveis
61
- via o array <tt>params[:splat]</tt>.
68
+ Padrões de rota também podem conter parâmetros splat (wildcard), acessível através do array <tt>params[: splat]</tt>:
62
69
 
63
70
  get '/diga/*/para/*' do
64
71
  # corresponde a /diga/ola/para/mundo
@@ -70,26 +77,150 @@ via o array <tt>params[:splat]</tt>.
70
77
  params[:splat] # => ["pasta/do/arquivo", "xml"]
71
78
  end
72
79
 
73
- Rotas se correspondem com expressões regulares:
80
+ Ou com parâmetros de um bloco:
81
+
82
+ get '/download/*.*' do |pasta, ext|
83
+ [pasta, ext] # => ["pasta/do/arquivo", "xml"]
84
+ end
85
+
86
+ Rotas podem corresponder com expressões regulares:
74
87
 
75
88
  get %r{/ola/([\w]+)} do
76
89
  "Olá, #{params[:captures].first}!"
77
90
  end
78
91
 
79
- Ou com um bloco de parâmetro:
92
+ Ou com parâmetros de um bloco:
80
93
 
81
94
  get %r{/ola/([\w]+)} do |c|
82
- "Hello, #{c}!"
95
+ "Olá, #{c}!"
96
+ end
97
+
98
+ Padrões de rota podem contar com parâmetros opcionais:
99
+
100
+ get '/posts.?:formato?' do
101
+ # corresponde a "GET /posts" e qualquer extensão "GET /posts.json", "GET /posts.xml", etc.
83
102
  end
84
103
 
85
- Rotas podem incluir uma variedade de condições correspondes, tal como o agente usuário:
104
+ A propósito, a menos que você desative a proteção contra ataques (veja abaixo), o caminho solicitado pode ser alterado antes de concluir a comparação com as suas rotas.
105
+
106
+ === Condições
107
+
108
+ Rotas podem incluir uma variedade de condições, tal como o <tt>user agent</tt>:
86
109
 
87
110
  get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
88
- "Você está utilizando a versão #{params[:agent][0]} do Songbird."
111
+ "Você está usando o Songbird versão #{params[:agent][0]}"
89
112
  end
90
113
 
91
114
  get '/foo' do
92
- # Corresponde a um navegador não Songbird
115
+ # Correspondente a navegadores que não sejam Songbird
116
+ end
117
+
118
+ Outras condições disponíveis são <tt>host_name</tt> e <tt>provides</tt>:
119
+
120
+ get '/', :host_name => /^admin\./ do
121
+ "Área administrativa. Acesso negado!"
122
+ end
123
+
124
+ get '/', :provides => 'html' do
125
+ haml :index
126
+ end
127
+
128
+ get '/', :provides => ['rss', 'atom', 'xml'] do
129
+ builder :feed
130
+ end
131
+
132
+ Você pode facilmente definir suas próprias condições:
133
+
134
+ set(:probabilidade) { |valor| condition { rand <= valor } }
135
+
136
+ get '/ganha_um_carro', :probabilidade => 0.1 do
137
+ "Você ganhou!"
138
+ end
139
+
140
+ get '/ganha_um_carro' do
141
+ "Sinto muito, você perdeu."
142
+ end
143
+
144
+ Use splat, para uma condição que levam vários valores:
145
+
146
+ set(:auth) do |*roles| # <- observe o splat aqui
147
+ condition do
148
+ unless logged_in? && roles.any? {|role| current_user.in_role? role }
149
+ redirect "/login/", 303
150
+ end
151
+ end
152
+ end
153
+
154
+ get "/minha/conta/", :auth => [:usuario, :administrador] do
155
+ "Detalhes da sua conta"
156
+ end
157
+
158
+ get "/apenas/administrador/", :auth => :administrador do
159
+ "Apenas administradores são permitidos aqui!"
160
+ end
161
+
162
+ === Retorno de valores
163
+
164
+ O valor de retorno do bloco de uma rota determina pelo menos o corpo da resposta passado para o cliente HTTP, ou pelo menos o próximo middleware na pilha Rack. Frequentemente, isto é uma <tt>string</tt>, tal como nos exemplos acima. Mas, outros valores também são aceitos.
165
+
166
+ Você pode retornar uma resposta válida ou um objeto para o Rack, sendo eles de qualquer tipo de objeto que queira. Além disto, é possível retornar um código de status HTTP.
167
+
168
+ * Um array com três elementros: [status (Fixnum), cabecalho (Hash), corpo da resposta (responde à #each)]
169
+
170
+ * Um array com dois elementros: [status (Fixnum), corpo da resposta (responde à #each)]
171
+
172
+ * Um objeto que responda à #each sem passar nada, mas, sim, <tt>strings</tt> para um dado bloco
173
+
174
+ * Um objeto <tt>Fixnum</tt> representando o código de status
175
+
176
+ Dessa forma, podemos implementar facilmente um exemplo de streaming:
177
+
178
+ class Stream
179
+ def each
180
+ 100.times { |i| yield "#{i}\n" }
181
+ end
182
+ end
183
+
184
+ get('/') { Stream.new }
185
+
186
+ Você também pode usar o método auxiliar <tt>stream</tt> (descrito abaixo) para incorporar a lógica de streaming na rota.
187
+
188
+ === Custom Route Matchers
189
+
190
+ Como apresentado acima, a estrutura do Sinatra conta com suporte embutido para uso de padrões de String e expressões regulares como validadores de rota. No entanto, ele não pára por aí. Você pode facilmente definir os seus próprios validadores:
191
+
192
+ class AllButPattern
193
+ Match = Struct.new(:captures)
194
+
195
+ def initialize(except)
196
+ @except = except
197
+ @captures = Match.new([])
198
+ end
199
+
200
+ def match(str)
201
+ @captures unless @except === str
202
+ end
203
+ end
204
+
205
+ def all_but(pattern)
206
+ AllButPattern.new(pattern)
207
+ end
208
+
209
+ get all_but("/index") do
210
+ # ...
211
+ end
212
+
213
+ Note que o exemplo acima pode ser robusto e complicado em excesso. Pode também ser implementado como:
214
+
215
+ get // do
216
+ pass if request.path_info == "/index"
217
+ # ...
218
+ end
219
+
220
+ Ou, usando algo mais denso à frente:
221
+
222
+ get %r{^(?!/index$)} do
223
+ # ...
93
224
  end
94
225
 
95
226
  == Arquivos estáticos
@@ -644,4 +775,4 @@ Para atualizar o código do Sinatra no futuro:
644
775
  * {Acompanhar Questões}[http://github.com/sinatra/sinatra/issues]
645
776
  * {Twitter}[http://twitter.com/sinatra]
646
777
  * {Lista de Email}[http://groups.google.com/group/sinatrarb/topics]
647
- * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] em http://freenode.net
778
+ * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] em http://freenode.net
@@ -1,8 +1,9 @@
1
1
  = Sinatra
2
2
  <i>Atenção: Este documento é apenas uma tradução da versão em inglês e pode estar desatualizado.</i>
3
3
 
4
- Sinatra é uma DSL para criar rapidamente aplicações web em Ruby com o mínimo de
5
- esforço:
4
+ Sinatra é uma
5
+ {DSL}[http://pt.wikipedia.org/wiki/Linguagem_de_domínio_específico]
6
+ para criar rapidamente aplicações web em Ruby com o mínimo de esforço:
6
7
 
7
8
  # minhaapp.rb
8
9
  require 'rubygems'
@@ -0,0 +1,2724 @@
1
+ # Sinatra
2
+
3
+ *Внимание: Этот документ является переводом английской версии и может быть
4
+ устаревшим*
5
+
6
+ Sinatra — это предметно-ориентированный каркас
7
+ ([DSL](http://ru.wikipedia.org/wiki/Предметно-ориентированный_язык_программирования))
8
+ для быстрого создания функциональных веб-приложений на Ruby с минимумом усилий:
9
+
10
+ ```ruby
11
+ # myapp.rb
12
+ require 'sinatra'
13
+
14
+ get '/' do
15
+ 'Hello world!'
16
+ end
17
+ ```
18
+
19
+ Установите gem:
20
+
21
+ ```
22
+ gem install sinatra
23
+ ```
24
+
25
+ и запустите приложение с помощью:
26
+
27
+ ```
28
+ ruby myapp.rb
29
+ ```
30
+
31
+ Оцените результат: http://localhost:4567
32
+
33
+ Рекомендуется также установить Thin, сделать это можно командой: `gem install
34
+ thin`. Thin — это более производительный и функциональный сервер для
35
+ разработки приложений на Sinatra.
36
+
37
+ ## Маршруты
38
+
39
+ В Sinatra маршрут — это пара: &lt;HTTP метод&gt; и &lt;шаблон URL&gt;. Каждый маршрут
40
+ связан с блоком кода:
41
+
42
+ ```ruby
43
+ get '/' do
44
+ # .. что-то показать ..
45
+ end
46
+
47
+ post '/' do
48
+ # .. что-то создать ..
49
+ end
50
+
51
+ put '/' do
52
+ # .. что-то заменить ..
53
+ end
54
+
55
+ patch '/' do
56
+ # .. что-то изменить ..
57
+ end
58
+
59
+ delete '/' do
60
+ # .. что-то удалить ..
61
+ end
62
+
63
+ options '/' do
64
+ # .. что-то ответить ..
65
+ end
66
+ ```
67
+
68
+ Маршруты сверяются с запросом в порядке очередности их записи в файле
69
+ приложения. Первый же совпавший с запросом маршрут и будет вызван.
70
+
71
+ Шаблоны маршрутов могут включать в себя именованные параметры, доступные в xэше
72
+ `params`:
73
+
74
+ ```ruby
75
+ get '/hello/:name' do
76
+ # соответствует "GET /hello/foo" и "GET /hello/bar",
77
+ # где params[:name] 'foo' или 'bar'
78
+ "Hello #{params[:name]}!"
79
+ end
80
+ ```
81
+
82
+ Также можно использовать именованные параметры в качестве переменных блока:
83
+
84
+ ```ruby
85
+ get '/hello/:name' do |n|
86
+ "Hello #{n}!"
87
+ end
88
+ ````
89
+
90
+ Шаблоны маршрутов также могут включать в себя splat (или '*' маску,
91
+ обозначающую любой символ) параметры, доступные в массиве `params[:splat]`:
92
+
93
+ ```ruby
94
+ get '/say/*/to/*' do
95
+ # соответствует /say/hello/to/world
96
+ params[:splat] # => ["hello", "world"]
97
+ end
98
+
99
+ get '/download/*.*' do
100
+ # соответствует /download/path/to/file.xml
101
+ params[:splat] # => ["path/to/file", "xml"]
102
+ end
103
+ ```
104
+
105
+ Или с параметрами блока:
106
+
107
+ ```ruby
108
+ get '/download/*.*' do |path, ext|
109
+ [path, ext] # => ["path/to/file", "xml"]
110
+ end
111
+ ```
112
+
113
+ Регулярные выражения в качестве шаблонов маршрутов:
114
+
115
+ ```ruby
116
+ get %r{/hello/([\w]+)} do
117
+ "Hello, #{params[:captures].first}!"
118
+ end
119
+ ```
120
+
121
+ Или с параметром блока:
122
+
123
+ ```ruby
124
+ get %r{/hello/([\w]+)} do |c|
125
+ "Hello, #{c}!"
126
+ end
127
+ ```
128
+
129
+ Шаблоны маршрутов могут иметь необязательные параметры:
130
+
131
+ ```ruby
132
+ get '/posts.?:format?' do
133
+ # соответствует "GET /posts", "GET /posts.json", "GET /posts.xml" и т.д.
134
+ end
135
+ ```
136
+
137
+ Кстати, если вы не отключите защиту от обратного пути в директориях (path
138
+ traversal, см. ниже), путь запроса может быть изменен до начала поиска
139
+ подходящего маршрута.
140
+
141
+ ### Условия
142
+
143
+ Маршруты могут включать различные условия совпадений, например, клиентское
144
+ приложение (user agent):
145
+
146
+ ```ruby
147
+ get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
148
+ "You're using Songbird version #{params[:agent][0]}"
149
+ end
150
+
151
+ get '/foo' do
152
+ # соответствует не-songbird браузерам
153
+ end
154
+ ```
155
+
156
+ Другими доступными условиями являются `host_name` и `provides`:
157
+
158
+ ```ruby
159
+ get '/', :host_name => /^admin\./ do
160
+ "Admin Area, Access denied!"
161
+ end
162
+
163
+ get '/', :provides => 'html' do
164
+ haml :index
165
+ end
166
+
167
+ get '/', :provides => ['rss', 'atom', 'xml'] do
168
+ builder :feed
169
+ end
170
+ ```
171
+
172
+ Вы можете задать собственные условия:
173
+
174
+ ```ruby
175
+ set(:probability) { |value| condition { rand <= value } }
176
+
177
+ get '/win_a_car', :probability => 0.1 do
178
+ "You won!"
179
+ end
180
+
181
+ get '/win_a_car' do
182
+ "Sorry, you lost."
183
+ end
184
+ ```
185
+
186
+ Для условия, которое принимает несколько параметров, используйте звездочку:
187
+
188
+ ```ruby
189
+ set(:auth) do |*roles| # <- обратите внимание на звездочку
190
+ condition do
191
+ unless logged_in? && roles.any? {|role| current_user.in_role? role }
192
+ redirect "/login/", 303
193
+ end
194
+ end
195
+ end
196
+
197
+ get "/my/account/", :auth => [:user, :admin] do
198
+ "Your Account Details"
199
+ end
200
+
201
+ get "/only/admin/", :auth => :admin do
202
+ "Only admins are allowed here!"
203
+ end
204
+ ```
205
+
206
+ ### Возвращаемые значения
207
+
208
+ Возвращаемое значение блока маршрута ограничивается телом ответа, которое
209
+ будет передано HTTP клиенту, или следующей "прослойкой" (middleware) в Rack
210
+ стеке. Чаще всего это строка, как в примерах выше. Но также приемлемы и
211
+ другие значения.
212
+
213
+ Вы можете вернуть любой объект, который будет либо корректным Rack ответом,
214
+ объектом Rack body, либо кодом состояния HTTP:
215
+
216
+ * массив с тремя переменными: `[код (Fixnum), заголовки (Hash), тело ответа
217
+ (должно отвечать на #each)]`;
218
+ * массив с двумя переменными: `[код (Fixnum), тело ответа (должно отвечать
219
+ на #each)]`;
220
+ * объект, отвечающий на `#each`, который передает только строковые типы
221
+ данных в этот блок;
222
+ * Fixnum, представляющий код состояния HTTP.
223
+
224
+
225
+ Таким образом, легко можно реализовать, например, поточный пример:
226
+
227
+ ```ruby
228
+ class Stream
229
+ def each
230
+ 100.times { |i| yield "#{i}\n" }
231
+ end
232
+ end
233
+
234
+ get('/') { Stream.new }
235
+ ```
236
+
237
+ Вы также можете использовать метод `stream` (описываемый ниже), чтобы
238
+ уменьшить количество дублируемого кода и держать логику стриминга прямо в
239
+ маршруте.
240
+
241
+ ### Собственные детекторы совпадений для маршрутов
242
+
243
+ Как показано выше, Sinatra поставляется со встроенной поддержкой строк и
244
+ регулярных выражений в качестве шаблонов URL. Но и это еще не все. Вы можете
245
+ легко определить свои собственные детекторы совпадений (matchers) для
246
+ маршрутов:
247
+
248
+ ```ruby
249
+ class AllButPattern
250
+ Match = Struct.new(:captures)
251
+
252
+ def initialize(except)
253
+ @except = except
254
+ @captures = Match.new([])
255
+ end
256
+
257
+ def match(str)
258
+ @captures unless @except === str
259
+ end
260
+ end
261
+
262
+ def all_but(pattern)
263
+ AllButPattern.new(pattern)
264
+ end
265
+
266
+ get all_but("/index") do
267
+ # ...
268
+ end
269
+ ```
270
+
271
+ Заметьте, что предыдущий пример, возможно, чересчур усложнен, потому что он
272
+ может быть реализован так:
273
+
274
+ ```ruby
275
+ get // do
276
+ pass if request.path_info == "/index"
277
+ # ...
278
+ end
279
+ ```
280
+
281
+ Или с использованием негативного просмотра вперед:
282
+
283
+ ```ruby
284
+ get %r{^(?!/index$)} do
285
+ # ...
286
+ end
287
+ ```
288
+
289
+ ## Статические файлы
290
+
291
+ Статические файлы отдаются из `./public` директории. Вы можете указать другое
292
+ место, используя опцию `:public_folder`:
293
+
294
+ ```ruby
295
+ set :public_folder, File.dirname(__FILE__) + '/static'
296
+ ```
297
+
298
+ Учтите, что имя директории со статическими файлами не включено в URL.
299
+ Например, файл `./public/css/style.css` будет доступен как
300
+ `http://example.com/css/style.css`.
301
+
302
+ Используйте опцию `:static_cache_control` (см. ниже), чтобы добавить заголовок
303
+ `Cache-Control`.
304
+
305
+ ## Представления / Шаблоны
306
+
307
+ Каждый шаблонизатор представлен своим собственным методом. Эти методы попросту
308
+ возвращают строку:
309
+
310
+ ```ruby
311
+ get '/' do
312
+ erb :index
313
+ end
314
+ ```
315
+
316
+ Отобразит `views/index.erb`.
317
+
318
+ Вместо имени шаблона вы так же можете передавать непосредственно само
319
+ содержимое шаблона:
320
+
321
+ ```ruby
322
+ get '/' do
323
+ code = "<%= Time.now %>"
324
+ erb code
325
+ end
326
+ ```
327
+
328
+ Эти методы принимают второй аргумент, хеш с опциями:
329
+
330
+ ```ruby
331
+ get '/' do
332
+ erb :index, :layout => :post
333
+ end
334
+ ```
335
+
336
+ Отобразит `views/index.erb`, вложенным в `views/post.erb` (по умолчанию:
337
+ `views/layout.erb`, если существует).
338
+
339
+ Любые опции, не понимаемые Sinatra, будут переданы в шаблонизатор:
340
+
341
+ ```ruby
342
+ get '/' do
343
+ haml :index, :format => :html5
344
+ end
345
+ ```
346
+
347
+ Вы также можете задавать опции для шаблонизаторов в общем:
348
+
349
+ ```ruby
350
+ set :haml, :format => :html5
351
+
352
+ get '/' do
353
+ haml :index
354
+ end
355
+ ```
356
+
357
+ Опции, переданные в метод, переопределяют опции, заданные с помощью `set`.
358
+
359
+ Доступные опции:
360
+
361
+ <dl>
362
+ <dt>locals</dt>
363
+ <dd>
364
+ Список локальных переменных, передаваемых в документ.
365
+ Например: <tt>erb "<%= foo %>", :locals => {:foo => "bar"}</tt>
366
+ </dd>
367
+
368
+ <dt>default_encoding</dt>
369
+ <dd>
370
+ Кодировка, которую следует использовать, если не удалось определить
371
+ оригинальную. По умолчанию: <tt>settings.default_encoding</tt>.
372
+ </dd>
373
+
374
+ <dt>views</dt>
375
+ <dd>
376
+ Директория с шаблонами. По умолчанию: <tt>settings.views</tt>.
377
+ </dd>
378
+
379
+ <dt>layout</dt>
380
+ <dd>
381
+ Использовать или нет лэйаут (<tt>true</tt> или <tt>false</tt>). Если же значение Symbol,
382
+ то указывает, какой шаблон использовать в качестве лэйаута. Например:
383
+ <tt>erb :index, :layout => !request.xhr?</tt>
384
+ </dd>
385
+
386
+ <dt>content_type</dt>
387
+ <dd>
388
+ Content-Type отображенного шаблона. По умолчанию: задается шаблонизатором.
389
+ </dd>
390
+
391
+ <dt>scope</dt>
392
+ <dd>
393
+ Область видимости, в которой рендерятся шаблоны. По умолчанию: экземпляр
394
+ приложения. Если вы измените эту опцию, то переменные экземпляра и
395
+ методы-помощники станут недоступными в ваших шаблонах.
396
+ </dd>
397
+
398
+ <dt>layout_engine</dt>
399
+ <dd>
400
+ Шаблонизатор, который следует использовать для отображения лэйаута.
401
+ Полезная опция для шаблонизаторов, в которых нет никакой поддержки
402
+ лэйаутов. По умолчанию: тот же шаблонизатор, что используется и для самого
403
+ шаблона. Пример: <tt>set :rdoc, :layout_engine => :erb</tt>
404
+ </dd>
405
+ </dl>
406
+
407
+ По умолчанию считается, что шаблоны находятся в директории `./views`. Чтобы
408
+ использовать другую директорию с шаблонами:
409
+
410
+ ```ruby
411
+ set :views, settings.root + '/templates'
412
+ ```
413
+
414
+ Важное замечание: вы всегда должны ссылаться на шаблоны с помощью символов
415
+ (Symbol), даже когда они в поддиректории (в этом случае используйте
416
+ `:'subdir/template'`). Вы должны использовать символы, потому что иначе
417
+ шаблонизаторы попросту отображают любые строки, переданные им.
418
+
419
+ #### Буквальные шаблоны
420
+
421
+ ```ruby
422
+ get '/' do
423
+ haml '%div.title Hello World'
424
+ end
425
+ ```
426
+
427
+ Отобразит шаблон, переданный строкой.
428
+
429
+ ### Доступные шаблонизаторы
430
+
431
+ Некоторые языки шаблонов имеют несколько реализаций. Чтобы указать, какую
432
+ реализацию использовать, вам следует просто подключить нужную библиотеку:
433
+
434
+ ```ruby
435
+ require 'rdiscount' # или require 'bluecloth'
436
+ get('/') { markdown :index }
437
+ ```
438
+
439
+ ### Haml шаблоны
440
+
441
+ <table>
442
+ <tr>
443
+ <td>Зависимости</td>
444
+ <td><a href="http://haml.info/" title="haml">haml</a></td>
445
+ </tr>
446
+ <tr>
447
+ <td>Расширения файлов</td>
448
+ <td><tt>.haml</tt></td>
449
+ </tr>
450
+ <tr>
451
+ <td>Пример</td>
452
+ <td><tt>haml :index, :format => :html5</tt></td>
453
+ </tr>
454
+ </table>
455
+
456
+ ### Erb шаблоны
457
+
458
+ <table>
459
+ <tr>
460
+ <td>Зависимости</td>
461
+ <td>
462
+ <a href="http://www.kuwata-lab.com/erubis/" title="erubis">erubis</a>
463
+ или erb (включен в Ruby)
464
+ </td>
465
+ </tr>
466
+ <tr>
467
+ <td>Расширения файлов</td>
468
+ <td><tt>.erb</tt>, <tt>.rhtml</tt> or <tt>.erubis</tt> (только Erubis)</td>
469
+ </tr>
470
+ <tr>
471
+ <td>Пример</td>
472
+ <td><tt>erb :index</tt></td>
473
+ </tr>
474
+ </table>
475
+
476
+ ### Builder шаблоны
477
+
478
+ <table>
479
+ <tr>
480
+ <td>Зависимости</td>
481
+ <td>
482
+ <a href="http://builder.rubyforge.org/" title="builder">builder</a>
483
+ </td>
484
+ </tr>
485
+ <tr>
486
+ <td>Расширения файлов</td>
487
+ <td><tt>.builder</tt></td>
488
+ </tr>
489
+ <tr>
490
+ <td>Пример</td>
491
+ <td><tt>builder { |xml| xml.em "hi" }</tt></td>
492
+ </tr>
493
+ </table>
494
+
495
+ Блок также используется и для встроенных шаблонов (см. пример).
496
+
497
+ ### Nokogiri шаблоны
498
+
499
+ <table>
500
+ <tr>
501
+ <td>Зависимости</td>
502
+ <td><a href="http://nokogiri.org/" title="nokogiri">nokogiri</a></td>
503
+ </tr>
504
+ <tr>
505
+ <td>Расширения файлов</td>
506
+ <td><tt>.nokogiri</tt></td>
507
+ </tr>
508
+ <tr>
509
+ <td>Пример</td>
510
+ <td><tt>nokogiri { |xml| xml.em "hi" }</tt></td>
511
+ </tr>
512
+ </table>
513
+
514
+ Блок также используется и для встроенных шаблонов (см. пример).
515
+
516
+ ### Sass шаблоны
517
+
518
+ <table>
519
+ <tr>
520
+ <td>Зависимости</td>
521
+ <td><a href="http://sass-lang.com/" title="sass">sass</a></td>
522
+ </tr>
523
+ <tr>
524
+ <td>Расширения файлов</td>
525
+ <td><tt>.sass</tt></td>
526
+ </tr>
527
+ <tr>
528
+ <td>Пример</td>
529
+ <td><tt>sass :stylesheet, :style => :expanded</tt></td>
530
+ </tr>
531
+ </table>
532
+
533
+ ### SCSS шаблоны
534
+
535
+ <table>
536
+ <tr>
537
+ <td>Зависимости</td>
538
+ <td><a href="http://sass-lang.com/" title="sass">sass</a></td>
539
+ </tr>
540
+ <tr>
541
+ <td>Расширения файлов</td>
542
+ <td><tt>.scss</tt></td>
543
+ </tr>
544
+ <tr>
545
+ <td>Пример</td>
546
+ <td><tt>scss :stylesheet, :style => :expanded</tt></td>
547
+ </tr>
548
+ </table>
549
+
550
+ ### Less шаблоны
551
+
552
+ <table>
553
+ <tr>
554
+ <td>Зависимости</td>
555
+ <td><a href="http://www.lesscss.org/" title="less">less</a></td>
556
+ </tr>
557
+ <tr>
558
+ <td>Расширения файлов</td>
559
+ <td><tt>.less</tt></td>
560
+ </tr>
561
+ <tr>
562
+ <td>Пример</td>
563
+ <td><tt>less :stylesheet</tt></td>
564
+ </tr>
565
+ </table>
566
+
567
+ ### Liquid шаблоны
568
+
569
+ <table>
570
+ <tr>
571
+ <td>Зависимости</td>
572
+ <td><a href="http://www.liquidmarkup.org/" title="liquid">liquid</a></td>
573
+ </tr>
574
+ <tr>
575
+ <td>Расширения файлов</td>
576
+ <td><tt>.liquid</tt></td>
577
+ </tr>
578
+ <tr>
579
+ <td>Пример</td>
580
+ <td><tt>liquid :index, :locals => { :key => 'value' }</tt></td>
581
+ </tr>
582
+ </table>
583
+
584
+ Так как в Liquid шаблонах невозможно вызывать методы из Ruby (кроме `yield`), то
585
+ вы почти всегда будете передавать в шаблон локальные переменные.
586
+
587
+ ### Markdown шаблоны
588
+
589
+ <table>
590
+ <tr>
591
+ <td>Зависимости</td>
592
+ <td>
593
+ Любая из библиотек:
594
+ <a href="https://github.com/rtomayko/rdiscount" title="RDiscount">RDiscount</a>,
595
+ <a href="https://github.com/vmg/redcarpet" title="RedCarpet">RedCarpet</a>,
596
+ <a href="http://deveiate.org/projects/BlueCloth" title="BlueCloth">BlueCloth</a>,
597
+ <a href="http://kramdown.rubyforge.org/" title="kramdown">kramdown</a>,
598
+ <a href="http://maruku.rubyforge.org/" title="maruku">maruku</a>
599
+ </td>
600
+ </tr>
601
+ <tr>
602
+ <td>Расширения файлов</td>
603
+ <td><tt>.markdown</tt>, <tt>.mkd</tt> and <tt>.md</tt></td>
604
+ </tr>
605
+ <tr>
606
+ <td>Пример</td>
607
+ <td><tt>markdown :index, :layout_engine => :erb</tt></td>
608
+ </tr>
609
+ </table>
610
+
611
+ В Markdown невозможно вызывать методы или передавать локальные переменные.
612
+ Следовательно, вам, скорее всего, придется использовать этот шаблон совместно
613
+ с другим шаблонизатором:
614
+
615
+ ```ruby
616
+ erb :overview, :locals => { :text => markdown(:introduction) }
617
+ ```
618
+
619
+ Заметьте, что вы можете вызывать метод `markdown` из других шаблонов:
620
+
621
+ ```ruby
622
+ %h1 Hello From Haml!
623
+ %p= markdown(:greetings)
624
+ ```
625
+
626
+ Вы не можете вызывать Ruby из Markdown, соответственно, вы не можете
627
+ использовать лэйауты на Markdown. Тем не менее, есть возможность использовать
628
+ один шаблонизатор для отображения шаблона, а другой для лэйаута с помощью
629
+ опции `:layout_engine`.
630
+
631
+ ### Textile шаблоны
632
+
633
+ <table>
634
+ <tr>
635
+ <td>Зависимости</td>
636
+ <td><a href="http://redcloth.org/" title="RedCloth">RedCloth</a></td>
637
+ </tr>
638
+ <tr>
639
+ <td>Расширения файлов</td>
640
+ <td><tt>.textile</tt></td>
641
+ </tr>
642
+ <tr>
643
+ <td>Пример</td>
644
+ <td><tt>textile :index, :layout_engine => :erb</tt></td>
645
+ </tr>
646
+ </table>
647
+
648
+ В Textile невозможно вызывать методы или передавать локальные переменные.
649
+ Следовательно, вам, скорее всего, придется использовать этот шаблон совместно
650
+ с другим шаблонизатором:
651
+
652
+ ```ruby
653
+ erb :overview, :locals => { :text => textile(:introduction) }
654
+ ```
655
+
656
+ Заметьте, что вы можете вызывать метод `textile` из других шаблонов:
657
+
658
+ ```ruby
659
+ %h1 Hello From Haml!
660
+ %p= textile(:greetings)
661
+ ```
662
+
663
+ Вы не можете вызывать Ruby из Textile, соответственно, вы не можете
664
+ использовать лэйауты на Textile. Тем не менее, есть возможность использовать
665
+ один шаблонизатор для отображения шаблона, а другой для лэйаута с помощью
666
+ опции `:layout_engine`.
667
+
668
+ ### RDoc шаблоны
669
+
670
+ <table>
671
+ <tr>
672
+ <td>Зависимости</td>
673
+ <td><a href="http://rdoc.rubyforge.org/" title="RDoc">RDoc</a></td>
674
+ </tr>
675
+ <tr>
676
+ <td>Расширения файлов</td>
677
+ <td><tt>.rdoc</tt></td>
678
+ </tr>
679
+ <tr>
680
+ <td>Пример</td>
681
+ <td><tt>rdoc :README, :layout_engine => :erb</tt></td>
682
+ </tr>
683
+ </table>
684
+
685
+ В RDoc невозможно вызывать методы или передавать локальные переменные.
686
+ Следовательно, вам, скорее всего, придется использовать этот шаблон совместно
687
+ с другим шаблонизатором:
688
+
689
+ ```ruby
690
+ erb :overview, :locals => { :text => rdoc(:introduction) }
691
+ ```
692
+
693
+ Заметьте, что вы можете вызывать метод `rdoc` из других шаблонов:
694
+
695
+ ```ruby
696
+ %h1 Hello From Haml!
697
+ %p= rdoc(:greetings)
698
+ ```
699
+
700
+ Вы не можете вызывать Ruby из RDoc, соответственно, вы не можете использовать
701
+ лэйауты на RDoc. Тем не менее, есть возможность использовать один шаблонизатор
702
+ для отображения шаблона, а другой для лэйаута с помощью опции
703
+ `:layout_engine`.
704
+
705
+ ### Radius шаблоны
706
+
707
+ <table>
708
+ <tr>
709
+ <td>Зависимости</td>
710
+ <td><a href="http://radius.rubyforge.org/" title="Radius">Radius</a></td>
711
+ </tr>
712
+ <tr>
713
+ <td>Расширения файлов</td>
714
+ <td><tt>.radius</tt></td>
715
+ </tr>
716
+ <tr>
717
+ <td>Пример</td>
718
+ <td><tt>radius :index, :locals => { :key => 'value' }</tt></td>
719
+ </tr>
720
+ </table>
721
+
722
+ Так как в Radius шаблонах невозможно вызывать методы из Ruby напрямую, то вы
723
+ почти всегда будете передавать в шаблон локальные переменные.
724
+
725
+ ### Markaby шаблоны
726
+
727
+ <table>
728
+ <tr>
729
+ <td>Зависимости</td>
730
+ <td><a href="http://markaby.github.com/" title="Markaby">Markaby</a></td>
731
+ </tr>
732
+ <tr>
733
+ <td>Расширения файлов</td>
734
+ <td><tt>.mab</tt></td>
735
+ </tr>
736
+ <tr>
737
+ <td>Пример</td>
738
+ <td><tt>markaby { h1 "Welcome!" }</tt></td>
739
+ </tr>
740
+ </table>
741
+
742
+ Блок также используется и для встроенных шаблонов (см. пример).
743
+
744
+ ### RABL шаблоны
745
+
746
+ <table>
747
+ <tr>
748
+ <td>Зависимости</td>
749
+ <td><a href="https://github.com/nesquena/rabl" title="Rabl">Rabl</a></td>
750
+ </tr>
751
+ <tr>
752
+ <td>Расширения файлов</td>
753
+ <td><tt>.rabl</tt></td>
754
+ </tr>
755
+ <tr>
756
+ <td>Пример</td>
757
+ <td><tt>rabl :index</tt></td>
758
+ </tr>
759
+ </table>
760
+
761
+ ### Slim шаблоны
762
+
763
+ <table>
764
+ <tr>
765
+ <td>Зависимости</td>
766
+ <td><a href="http://slim-lang.com/" title="Slim Lang">Slim Lang</a></td>
767
+ </tr>
768
+ <tr>
769
+ <td>Расширения файлов</td>
770
+ <td><tt>.slim</tt></td>
771
+ </tr>
772
+ <tr>
773
+ <td>Пример</td>
774
+ <td><tt>slim :index</tt></td>
775
+ </tr>
776
+ </table>
777
+
778
+ ### Creole шаблоны
779
+
780
+ <table>
781
+ <tr>
782
+ <td>Зависимости</td>
783
+ <td><a href="https://github.com/minad/creole" title="Creole">Creole</a></td>
784
+ </tr>
785
+ <tr>
786
+ <td>Расширения файлов</td>
787
+ <td><tt>.creole</tt></td>
788
+ </tr>
789
+ <tr>
790
+ <td>Пример</td>
791
+ <td><tt>creole :wiki, :layout_engine => :erb</tt></td>
792
+ </tr>
793
+ </table>
794
+
795
+ В Creole невозможно вызывать методы или передавать локальные переменные.
796
+ Следовательно, вам, скорее всего, придется использовать этот шаблон совместно
797
+ с другим шаблонизатором:
798
+
799
+ ```ruby
800
+ erb :overview, :locals => { :text => creole(:introduction) }
801
+ ```
802
+
803
+ Заметьте, что вы можете вызывать метод `creole` из других шаблонов:
804
+
805
+ ```ruby
806
+ %h1 Hello From Haml!
807
+ %p= creole(:greetings)
808
+ ```
809
+
810
+ Вы не можете вызывать Ruby из Creole, соответственно, вы не можете
811
+ использовать лэйауты на Creole. Тем не менее, есть возможность использовать
812
+ один шаблонизатор для отображения шаблона, а другой для лэйаута с помощью
813
+ опции `:layout_engine`.
814
+
815
+ ### CoffeeScript шаблоны
816
+
817
+ <table>
818
+ <tr>
819
+ <td>Зависимости</td>
820
+ <td>
821
+ <a href="https://github.com/josh/ruby-coffee-script" title="Ruby CoffeeScript">
822
+ CoffeeScript
823
+ </a> и способ
824
+ <a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
825
+ запускать JavaScript
826
+ </a>
827
+ </td>
828
+ </tr>
829
+ <tr>
830
+ <td>Расширения файлов</td>
831
+ <td><tt>.coffee</tt></td>
832
+ </tr>
833
+ <tr>
834
+ <td>Пример</td>
835
+ <td><tt>coffee :index</tt></td>
836
+ </tr>
837
+ </table>
838
+
839
+ ### Yajl шаблоны
840
+
841
+ <table>
842
+ <tr>
843
+ <td>Зависимости</td>
844
+ <td><a href="https://github.com/brianmario/yajl-ruby" title="yajl-ruby">yajl-ruby</a></td>
845
+ </tr>
846
+ <tr>
847
+ <td>Расширения файлов</td>
848
+ <td><tt>.yajl</tt></td>
849
+ </tr>
850
+ <tr>
851
+ <td>Пример</td>
852
+ <td>
853
+ <tt>
854
+ yajl :index,
855
+ :locals => { :key => 'qux' },
856
+ :callback => 'present',
857
+ :variable => 'resource'
858
+ </tt>
859
+ </td>
860
+ </tr>
861
+ </table>
862
+
863
+ Содержимое шаблона интерпретируется как код на Ruby, а результирующая
864
+ переменная json затем конвертируется с помощью `#to_json`.
865
+
866
+ ```ruby
867
+ json = { :foo => 'bar' }
868
+ json[:baz] = key
869
+ ```
870
+
871
+ Опции `:callback` и `:variable` используются для "декорирования" итогового
872
+ объекта.
873
+
874
+ ```ruby
875
+ var resource = {"foo":"bar","baz":"qux"}; present(resource);
876
+ ```
877
+
878
+ ### WLang шаблоны
879
+
880
+ <table>
881
+ <tr>
882
+ <td>Зависимости</td>
883
+ <td><a href="https://github.com/blambeau/wlang/" title="wlang">wlang</a></td>
884
+ </tr>
885
+ <tr>
886
+ <td>Расширения файлов</td>
887
+ <td><tt>.wlang</tt></td>
888
+ </tr>
889
+ <tr>
890
+ <td>Пример</td>
891
+ <td><tt>wlang :index, :locals => { :key => 'value' }</tt></td>
892
+ </tr>
893
+ </table>
894
+
895
+ Так как в WLang шаблонах невозможно вызывать методы из Ruby напрямую (за
896
+ исключением `yield`), то вы почти всегда будете передавать в шаблон локальные
897
+ переменные.
898
+
899
+ ### Доступ к переменным в шаблонах
900
+
901
+ Шаблоны интерпретируются в том же контексте, что и обработчики маршрутов.
902
+ Переменные экземпляра, установленные в процессе обработки маршрутов, будут
903
+ доступны напрямую в шаблонах:
904
+
905
+ ```ruby
906
+ get '/:id' do
907
+ @foo = Foo.find(params[:id])
908
+ haml '%h1= @foo.name'
909
+ end
910
+ ```
911
+
912
+ Либо установите их через хеш локальных переменных:
913
+
914
+ ```ruby
915
+ get '/:id' do
916
+ foo = Foo.find(params[:id])
917
+ haml '%h1= bar.name', :locals => { :bar => foo }
918
+ end
919
+ ```
920
+
921
+ Это обычный подход, когда шаблоны рендерятся как части других шаблонов.
922
+
923
+ ### Шаблоны с `yield` и вложенные раскладки (layout)
924
+
925
+ Раскладка (layout) обычно представляет собой шаблон, который исполняет
926
+ `yield`.
927
+ Такой шаблон может быть либо использован с помощью опции `:template`,
928
+ как описано выше, либо он может быть дополнен блоком:
929
+
930
+ ```ruby
931
+ erb :post, :layout => false do
932
+ erb :index
933
+ end
934
+ ```
935
+
936
+ Эти инструкции в основном эквивалентны `erb :index, :layout => :post`.
937
+
938
+ Передача блоков интерпретирующим шаблоны методам наиболее полезна для
939
+ создания вложенных раскладок:
940
+
941
+ ```ruby
942
+ erb :main_layout, :layout => false do
943
+ erb :admin_layout do
944
+ erb :user
945
+ end
946
+ end
947
+ ```
948
+
949
+ Это же самое может быть сделано короче:
950
+
951
+ ```ruby
952
+ erb :admin_layout, :layout => :main_layout do
953
+ erb :user
954
+ end
955
+ ```
956
+
957
+ В настоящее время, следующие интерпретирубщие шаблоны методы
958
+ принимают блок:
959
+ `erb`, `haml`, `liquid`, `slim `, `wlang`.
960
+ Общий метод заполнения шаблонов `render` также принимает блок.
961
+
962
+ ### Включённые шаблоны
963
+
964
+ Шаблоны также могут быть определены в конце исходного файла:
965
+
966
+ ```ruby
967
+ require 'sinatra'
968
+
969
+ get '/' do
970
+ haml :index
971
+ end
972
+
973
+ __END__
974
+
975
+ @@ layout
976
+ %html
977
+ = yield
978
+
979
+ @@ index
980
+ %div.title Hello world.
981
+ ```
982
+
983
+ Заметьте: включённые шаблоны, определенные в исходном файле, который подключил
984
+ Sinatra, будут загружены автоматически. Вызовите `enable :inline_templates`
985
+ напрямую, если используете включённые шаблоны в других файлах.
986
+
987
+ ### Именованные шаблоны
988
+
989
+ Шаблоны также могут быть определены при помощи `template` метода:
990
+
991
+ ```ruby
992
+ template :layout do
993
+ "%html\n =yield\n"
994
+ end
995
+
996
+ template :index do
997
+ '%div.title Hello World!'
998
+ end
999
+
1000
+ get '/' do
1001
+ haml :index
1002
+ end
1003
+ ```
1004
+
1005
+ Если шаблон с именем "layout" существует, то он будет использоваться каждый
1006
+ раз при рендеринге. Вы можете отключать лэйаут в каждом конкретном случае с
1007
+ помощью `:layout => false` или отключить его для всего приложения: `set :haml,
1008
+ :layout => false`:
1009
+
1010
+ ```ruby
1011
+ get '/' do
1012
+ haml :index, :layout => !request.xhr?
1013
+ end
1014
+ ```
1015
+
1016
+ ### Привязка файловых расширений
1017
+
1018
+ Чтобы связать расширение файла с движком рендеринга, используйте
1019
+ `Tilt.register`. Например, если вы хотите использовать расширение `tt` для
1020
+ шаблонов Textile:
1021
+
1022
+ ```ruby
1023
+ Tilt.register :tt, Tilt[:textile]
1024
+ ```
1025
+
1026
+ ### Добавление собственного движка рендеринга
1027
+
1028
+ Сначала зарегистрируйте свой движок в Tilt, а затем создайте метод, отвечающий
1029
+ за рендеринг:
1030
+
1031
+ ```ruby
1032
+ Tilt.register :myat, MyAwesomeTemplateEngine
1033
+
1034
+ helpers do
1035
+ def myat(*args) render(:myat, *args) end
1036
+ end
1037
+
1038
+ get '/' do
1039
+ myat :index
1040
+ end
1041
+ ```
1042
+
1043
+ Отобразит `./views/index.myat`. Чтобы узнать больше о Tilt, смотрите
1044
+ https://github.com/rtomayko/tilt
1045
+
1046
+ ## Фильтры
1047
+
1048
+ `before`-фильтры выполняются перед каждым запросом в том же контексте, что и
1049
+ маршруты, и могут изменять как запрос, так и ответ на него. Переменные
1050
+ экземпляра, установленные в фильтрах, доступны в маршрутах и шаблонах:
1051
+
1052
+ ```ruby
1053
+ before do
1054
+ @note = 'Hi!'
1055
+ request.path_info = '/foo/bar/baz'
1056
+ end
1057
+
1058
+ get '/foo/*' do
1059
+ @note #=> 'Hi!'
1060
+ params[:splat] #=> 'bar/baz'
1061
+ end
1062
+ ```
1063
+
1064
+ `after`-фильтры выполняются после каждого запроса в том же контексте
1065
+ и могут изменять как запрос, так и ответ на него. Переменные
1066
+ экземпляра, установленные в `before`-фильтрах и маршрутах, будут доступны в
1067
+ `after`-фильтрах:
1068
+
1069
+ ```ruby
1070
+ after do
1071
+ puts response.status
1072
+ end
1073
+ ```
1074
+
1075
+ Заметьте: если вы используете метод `body`, а не просто возвращаете строку из
1076
+ маршрута, то тело ответа не будет доступно в `after`-фильтрах, так как оно
1077
+ будет сгенерировано позднее.
1078
+
1079
+ Фильтры могут использовать шаблоны URL и будут интерпретированы, только если
1080
+ путь запроса совпадет с этим шаблоном:
1081
+
1082
+ ```ruby
1083
+ before '/protected/*' do
1084
+ authenticate!
1085
+ end
1086
+
1087
+ after '/create/:slug' do |slug|
1088
+ session[:last_slug] = slug
1089
+ end
1090
+ ```
1091
+
1092
+ Как и маршруты, фильтры могут использовать условия:
1093
+
1094
+ ```ruby
1095
+ before :agent => /Songbird/ do
1096
+ # ...
1097
+ end
1098
+
1099
+ after '/blog/*', :host_name => 'example.com' do
1100
+ # ...
1101
+ end
1102
+ ```
1103
+
1104
+ ## Методы-помощники
1105
+
1106
+ Используйте метод `helpers`, чтобы определить методы-помощники, которые в
1107
+ дальнейшем можно будет использовать в обработчиках маршрутов и шаблонах:
1108
+
1109
+ ```ruby
1110
+ helpers do
1111
+ def bar(name)
1112
+ "#{name}bar"
1113
+ end
1114
+ end
1115
+
1116
+ get '/:name' do
1117
+ bar(params[:name])
1118
+ end
1119
+ ```
1120
+
1121
+ Также методы-помощники могут быть заданы в отдельных модулях:
1122
+
1123
+ ```ruby
1124
+ module FooUtils
1125
+ def foo(name) "#{name}foo" end
1126
+ end
1127
+
1128
+ module BarUtils
1129
+ def bar(name) "#{name}bar" end
1130
+ end
1131
+
1132
+ helpers FooUtils, BarUtils
1133
+ ```
1134
+
1135
+ Эффект равносилен включению модулей в класс приложения.
1136
+
1137
+ ### Использование сессий
1138
+
1139
+ Сессия используется, чтобы сохранять состояние между запросами. Если эта опция
1140
+ включена, то у вас будет один хеш сессии на одну пользовательскую сессию:
1141
+
1142
+ ```ruby
1143
+ enable :sessions
1144
+
1145
+ get '/' do
1146
+ "value = " << session[:value].inspect
1147
+ end
1148
+
1149
+ get '/:value' do
1150
+ session[:value] = params[:value]
1151
+ end
1152
+ ```
1153
+
1154
+ Заметьте, что при использовании `enable :sessions` все данные сохраняются в
1155
+ куках (cookies). Это может быть не совсем то, что вы хотите (например,
1156
+ сохранение больших объемов данных увеличит ваш трафик). В таком случае вы
1157
+ можете использовать альтернативную Rack "прослойку" (middleware), реализующую
1158
+ механизм сессий. Для этого *не надо* вызывать `enable :sessions`, вместо этого
1159
+ следует подключить ее так же, как и любую другую "прослойку":
1160
+
1161
+ ```ruby
1162
+ use Rack::Session::Pool, :expire_after => 2592000
1163
+
1164
+ get '/' do
1165
+ "value = " << session[:value].inspect
1166
+ end
1167
+
1168
+ get '/:value' do
1169
+ session[:value] = params[:value]
1170
+ end
1171
+ ```
1172
+
1173
+ Для повышения безопасности данные сессии в куках подписываются секретным
1174
+ ключом. Секретный ключ генерируется Sinatra. Тем не менее, так как этот ключ
1175
+ будет меняться с каждым запуском приложения, вы, возможно, захотите установить
1176
+ ключ вручную, чтобы у всех экземпляров вашего приложения был один и тот же
1177
+ ключ:
1178
+
1179
+ ```ruby
1180
+ set :session_secret, 'super secret'
1181
+ ```
1182
+
1183
+ Если вы хотите больше настроек для сессий, вы можете задать их, передав хеш
1184
+ опций в параметр `sessions`:
1185
+
1186
+ ```ruby
1187
+ set :sessions, :domain => 'foo.com'
1188
+ ```
1189
+
1190
+ ### Прерывание
1191
+
1192
+ Чтобы незамедлительно прервать обработку запроса внутри фильтра или маршрута,
1193
+ используйте:
1194
+
1195
+ ```ruby
1196
+ halt
1197
+ ```
1198
+
1199
+ Можно также указать статус при прерывании:
1200
+
1201
+ ```ruby
1202
+ halt 410
1203
+ ```
1204
+
1205
+ Тело:
1206
+
1207
+ ```ruby
1208
+ halt 'this will be the body'
1209
+ ```
1210
+
1211
+ И то, и другое:
1212
+
1213
+ ```ruby
1214
+ halt 401, 'go away!'
1215
+ ```
1216
+
1217
+ Можно указать заголовки:
1218
+
1219
+ ```ruby
1220
+ halt 402, {'Content-Type' => 'text/plain'}, 'revenge'
1221
+ ```
1222
+
1223
+ И, конечно, можно использовать шаблоны с `halt`:
1224
+
1225
+ ```ruby
1226
+ halt erb(:error)
1227
+ ```
1228
+
1229
+ ### Передача
1230
+
1231
+ Маршрут может передать обработку запроса следующему совпадающему маршруту,
1232
+ используя `pass`:
1233
+
1234
+ ```ruby
1235
+ get '/guess/:who' do
1236
+ pass unless params[:who] == 'Frank'
1237
+ 'You got me!'
1238
+ end
1239
+
1240
+ get '/guess/*' do
1241
+ 'You missed!'
1242
+ end
1243
+ ```
1244
+
1245
+ Блок маршрута сразу же прерывается, и контроль переходит к следующему
1246
+ совпадающему маршруту. Если соответствующий маршрут не найден, то ответом на
1247
+ запрос будет 404.
1248
+
1249
+ ### Вызов другого маршрута
1250
+
1251
+ Иногда `pass` не подходит, например, если вы хотите получить результат вызова
1252
+ другого обработчика маршрута. В таком случае просто используйте `call`:
1253
+
1254
+ ```ruby
1255
+ get '/foo' do
1256
+ status, headers, body = call env.merge("PATH_INFO" => '/bar')
1257
+ [status, headers, body.map(&:upcase)]
1258
+ end
1259
+
1260
+ get '/bar' do
1261
+ "bar"
1262
+ end
1263
+ ```
1264
+
1265
+ Заметьте, что в предыдущем примере можно облегчить тестирование и повысить
1266
+ производительность, перенеся `"bar"` в метод-помощник, используемый и в
1267
+ `/foo`, и в `/bar`.
1268
+
1269
+ Если вы хотите, чтобы запрос был отправлен в тот же экземпляр приложения, а не
1270
+ в его копию, используйте `call!` вместо `call`.
1271
+
1272
+ Если хотите узнать больше о `call`, смотрите спецификацию Rack.
1273
+
1274
+ ### Задание тела, кода и заголовков ответа
1275
+
1276
+ Хорошим тоном является установка кода состояния HTTP и тела ответа в
1277
+ возвращаемом значении обработчика маршрута. Тем не менее, в некоторых
1278
+ ситуациях вам, возможно, понадобится задать тело ответа в произвольной точке
1279
+ потока исполнения. Вы можете сделать это с помощью метода-помощника `body`.
1280
+ Если вы задействуете метод `body`, то вы можете использовать его и в
1281
+ дальнейшем, чтобы получить доступ к телу ответа.
1282
+
1283
+ ```ruby
1284
+ get '/foo' do
1285
+ body "bar"
1286
+ end
1287
+
1288
+ after do
1289
+ puts body
1290
+ end
1291
+ ```
1292
+
1293
+ Также можно передать блок в метод `body`, который затем будет вызван
1294
+ обработчиком Rack (такой подход может быть использован для реализации
1295
+ поточного ответа, см. "Возвращаемые значения").
1296
+
1297
+ Аналогично вы можете установить код ответа и его заголовки:
1298
+
1299
+ ```ruby
1300
+ get '/foo' do
1301
+ status 418
1302
+ headers \
1303
+ "Allow" => "BREW, POST, GET, PROPFIND, WHEN",
1304
+ "Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
1305
+ body "I'm a tea pot!"
1306
+ end
1307
+ ```
1308
+
1309
+ Как и `body`, методы `headers` и `status`, вызванные без аргументов,
1310
+ возвращают свои текущие значения.
1311
+
1312
+ ### Стриминг ответов
1313
+
1314
+ Иногда требуется начать отправлять данные клиенту прямо в процессе
1315
+ генерирования частей этих данных. В особых случаях требуется постоянно
1316
+ отправлять данные до тех пор, пока клиент не закроет соединение. Вы можете
1317
+ использовать метод `stream` вместо написания собственных "оберток".
1318
+
1319
+ ```ruby
1320
+ get '/' do
1321
+ stream do |out|
1322
+ out << "It's gonna be legen -\n"
1323
+ sleep 0.5
1324
+ out << " (wait for it) \n"
1325
+ sleep 1
1326
+ out << "- dary!\n"
1327
+ end
1328
+ end
1329
+ ```
1330
+
1331
+ Что позволяет вам реализовать стриминговые API,
1332
+ [Server Sent Events](http://dev.w3.org/html5/eventsource/),
1333
+ и может служить основой для [WebSockets](http://en.wikipedia.org/wiki/WebSocket).
1334
+ Также такой подход можно использовать для увеличения производительности в случае,
1335
+ когда какая-то часть контента зависит от медленного ресурса.
1336
+
1337
+ Заметьте, что возможности стриминга, особенно количество одновременно
1338
+ обслуживаемых запросов, очень сильно зависят от используемого веб-сервера.
1339
+ Некоторые серверы, например, WEBRick, могут и вовсе не поддерживать стриминг.
1340
+ Если сервер не поддерживает стриминг, то все данные будут отправлены за один
1341
+ раз сразу после того, как блок, переданный в `stream`, завершится. Стриминг
1342
+ вообще не работает при использовании Shotgun.
1343
+
1344
+ Если метод используется с параметром `keep_open`, то он не будет вызывать
1345
+ `close` у объекта потока, что позволит вам закрыть его позже в любом другом
1346
+ месте. Это работает только с событийными серверами, например, с Thin и
1347
+ Rainbows. Другие же серверы все равно будут закрывать поток:
1348
+
1349
+ ```ruby
1350
+ # long polling
1351
+
1352
+ set :server, :thin
1353
+ connections = []
1354
+
1355
+ get '/subscribe' do
1356
+ # регистрация клиента
1357
+ stream(:keep_open) { |out| connections << out }
1358
+
1359
+ # удаление "мертвых клиентов"
1360
+ connections.reject!(&:closed?)
1361
+
1362
+ # допуск
1363
+ "subscribed"
1364
+ end
1365
+
1366
+ post '/message' do
1367
+ connections.each do |out|
1368
+ # уведомить клиента о новом сообщении
1369
+ out << params[:message] << "\n"
1370
+
1371
+ # указать клиенту на необходимость снова соединиться
1372
+ out.close
1373
+ end
1374
+
1375
+ # допуск
1376
+ "message received"
1377
+ end
1378
+ ```
1379
+
1380
+ ### Логирование
1381
+
1382
+ В области видимости запроса метод `logger` предоставляет доступ к экземпляру
1383
+ `Logger`:
1384
+
1385
+ ```ruby
1386
+ get '/' do
1387
+ logger.info "loading data"
1388
+ # ...
1389
+ end
1390
+ ```
1391
+
1392
+ Этот логер автоматически учитывает ваши настройки логирования в Rack. Если
1393
+ логирование выключено, то этот метод вернет пустой (dummy) объект, поэтому вы
1394
+ можете смело использовать его в маршрутах и фильтрах.
1395
+
1396
+ Заметьте, что логирование включено по умолчанию только для
1397
+ `Sinatra::Application`, а если ваше приложение — подкласс `Sinatra::Base`, то
1398
+ вы, наверное, захотите включить его вручную:
1399
+
1400
+ ```ruby
1401
+ class MyApp < Sinatra::Base
1402
+ configure :production, :development do
1403
+ enable :logging
1404
+ end
1405
+ end
1406
+ ```
1407
+
1408
+ Чтобы избежать использования любой логирующей "прослойки", задайте опции
1409
+ `logging` значение `nil`. Тем не менее, не забывайте, что в такой ситуации
1410
+ `logger` вернет `nil`. Чаще всего так делают, когда задают свой собственный
1411
+ логер. Sinatra будет использовать то, что находится в `env['rack.logger']`.
1412
+
1413
+ ### Mime-типы
1414
+
1415
+ Когда вы используете `send_file` или статические файлы, у вас могут быть
1416
+ mime-типы, которые Sinatra не понимает по умолчанию. Используйте `mime_type`
1417
+ для их регистрации по расширению файла:
1418
+
1419
+ ```ruby
1420
+ configure do
1421
+ mime_type :foo, 'text/foo'
1422
+ end
1423
+ ```
1424
+
1425
+ Вы также можете использовать это в `content_type` методе-помощнике:
1426
+
1427
+ ```ruby
1428
+ get '/' do
1429
+ content_type :foo
1430
+ "foo foo foo"
1431
+ end
1432
+ ```
1433
+
1434
+ ### Генерирование URL
1435
+
1436
+ Чтобы сформировать URL, вам следует использовать метод `url`, например, в Haml:
1437
+
1438
+ ```ruby
1439
+ %a{:href => url('/foo')} foo
1440
+ ```
1441
+
1442
+ Этот метод учитывает обратные прокси и маршрутизаторы Rack, если они
1443
+ присутствуют.
1444
+
1445
+ Наряду с `url` вы можете использовать `to` (смотрите пример ниже).
1446
+
1447
+ ### Перенаправление (редирект)
1448
+
1449
+ Вы можете перенаправить браузер пользователя с помощью метода `redirect`:
1450
+
1451
+ ```ruby
1452
+ get '/foo' do
1453
+ redirect to('/bar')
1454
+ end
1455
+ ```
1456
+
1457
+ Любые дополнительные параметры используются по аналогии с аргументами метода
1458
+ `halt`:
1459
+
1460
+ ```ruby
1461
+ redirect to('/bar'), 303
1462
+ redirect 'http://google.com', 'wrong place, buddy'
1463
+ ```
1464
+
1465
+ Вы также можете перенаправить пользователя обратно, на страницу, с которой он
1466
+ пришел, с помощью `redirect back`:
1467
+
1468
+ ```ruby
1469
+ get '/foo' do
1470
+ "<a href='/bar'>do something</a>"
1471
+ end
1472
+
1473
+ get '/bar' do
1474
+ do_something
1475
+ redirect back
1476
+ end
1477
+ ```
1478
+
1479
+ Чтобы передать какие-либо параметры вместе с перенаправлением, либо добавьте
1480
+ их в строку запроса:
1481
+
1482
+ ```ruby
1483
+ redirect to('/bar?sum=42')
1484
+ ```
1485
+
1486
+ либо используйте сессию:
1487
+
1488
+ ```ruby
1489
+ enable :sessions
1490
+
1491
+ get '/foo' do
1492
+ session[:secret] = 'foo'
1493
+ redirect to('/bar')
1494
+ end
1495
+
1496
+ get '/bar' do
1497
+ session[:secret]
1498
+ end
1499
+ ```
1500
+
1501
+ ### Управление кэшированием
1502
+
1503
+ Установка корректных заголовков — основа правильного HTTP кэширования.
1504
+
1505
+ Вы можете легко выставить заголовок Cache-Control таким образом:
1506
+
1507
+ ```ruby
1508
+ get '/' do
1509
+ cache_control :public
1510
+ "cache it!"
1511
+ end
1512
+ ```
1513
+
1514
+ Совет: задавайте кэширование в `before`-фильтре:
1515
+
1516
+ ```ruby
1517
+ before do
1518
+ cache_control :public, :must_revalidate, :max_age => 60
1519
+ end
1520
+ ```
1521
+
1522
+ Если вы используете метод `expires` для задания соответствующего заголовка, то
1523
+ `Cache-Control` будет выставлен автоматически:
1524
+
1525
+ ```ruby
1526
+ before do
1527
+ expires 500, :public, :must_revalidate
1528
+ end
1529
+ ```
1530
+
1531
+ Чтобы как следует использовать кэширование, вам следует подумать об
1532
+ использовании `etag` или `last_modified`. Рекомендуется использовать эти
1533
+ методы-помощники *до* выполнения ресурсоемких вычислений, так как они
1534
+ немедленно отправят ответ клиенту, если текущая версия уже есть в их кэше:
1535
+
1536
+ ```ruby
1537
+ get '/article/:id' do
1538
+ @article = Article.find params[:id]
1539
+ last_modified @article.updated_at
1540
+ etag @article.sha1
1541
+ erb :article
1542
+ end
1543
+ ```
1544
+
1545
+ Также вы можете использовать
1546
+ [weak ETag](http://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation):
1547
+
1548
+ ```ruby
1549
+ etag @article.sha1, :weak
1550
+ ```
1551
+
1552
+ Эти методы-помощники не станут ничего кэшировать для вас, но они дадут
1553
+ необходимую информацию для вашего кэша. Если вы ищете легкое решение для
1554
+ кэширования, попробуйте [rack-cache](https://github.com/rtomayko/rack-cache):
1555
+
1556
+ ```ruby
1557
+ require 'rack/cache'
1558
+ require 'sinatra'
1559
+
1560
+ use Rack::Cache
1561
+
1562
+ get '/' do
1563
+ cache_control :public, :max_age => 36000
1564
+ sleep 5
1565
+ "hello"
1566
+ end
1567
+ ```
1568
+
1569
+ Используйте опцию `:static_cache_control` (см. ниже), чтобы добавить заголовок
1570
+ `Cache-Control` к статическим файлам.
1571
+
1572
+ В соответствии с RFC 2616 ваше приложение должно вести себя по-разному, когда
1573
+ заголовки If-Match или If-None-Match имеют значение `*`, в зависимости от
1574
+ того, существует или нет запрашиваемый ресурс. Sinatra предполагает, что
1575
+ ресурсы, к которым обращаются с помощью безопасных (GET) и идемпотентных (PUT)
1576
+ методов, уже существуют, а остальные ресурсы (к которым обращаются, например,
1577
+ с помощью POST) считает новыми. Вы можете изменить данное поведение с помощью
1578
+ опции `:new_resource`:
1579
+
1580
+ ```ruby
1581
+ get '/create' do
1582
+ etag '', :new_resource => true
1583
+ Article.create
1584
+ erb :new_article
1585
+ end
1586
+ ```
1587
+
1588
+ Если вы хотите использовать weak ETag, задайте опцию `:kind`:
1589
+
1590
+ ```ruby
1591
+ etag '', :new_resource => true, :kind => :weak
1592
+ ```
1593
+
1594
+ ### Отправка файлов
1595
+
1596
+ Для отправки файлов пользователю вы можете использовать метод `send_file`:
1597
+
1598
+ ```ruby
1599
+ get '/' do
1600
+ send_file 'foo.png'
1601
+ end
1602
+ ```
1603
+
1604
+ Этот метод имеет несколько опций:
1605
+
1606
+ ```ruby
1607
+ send_file 'foo.png', :type => :jpg
1608
+ ```
1609
+
1610
+ Возможные опции:
1611
+
1612
+ <dl>
1613
+ <dt>filename</dt>
1614
+ <dd>имя файла, по умолчанию: реальное имя файла.</dd>
1615
+
1616
+ <dt>last_modified</dt>
1617
+ <dd>значение для заголовка Last-Modified, по умолчанию: mtime (время
1618
+ изменения) файла.</dd>
1619
+
1620
+ <dt>type</dt>
1621
+ <dd>тип файла, по умолчанию: определяется по расширению файла.</dd>
1622
+
1623
+ <dt>disposition</dt>
1624
+ <dd>используется для заголовка Content-Disposition, возможные значения: <tt>nil</tt>
1625
+ (по умолчанию), <tt>:attachment</tt> и <tt>:inline</tt>.</dd>
1626
+
1627
+ <dt>length</dt>
1628
+ <dd>значения для заголовка Content-Length, по умолчанию: размер файла.</dd>
1629
+
1630
+ <dt>status</dt>
1631
+ <dd>Код ответа. Полезно, когда отдается статический файл в качестве страницы с
1632
+ сообщением об ошибке.</dd>
1633
+ </dl>
1634
+
1635
+ Этот метод будет использовать возможности Rack сервера для отправки файлов,
1636
+ если они доступны, в противном случае будет напрямую отдавать файл из Ruby
1637
+ процесса. Метод `send_file` также обеспечивает автоматическую обработку
1638
+ частичных (range) запросов с помощью Sinatra.
1639
+
1640
+ ### Доступ к объекту запроса
1641
+
1642
+ Объект входящего запроса доступен на уровне обработки запроса (в фильтрах,
1643
+ маршрутах, обработчиках ошибок) с помощью `request` метода:
1644
+
1645
+ ```ruby
1646
+ # приложение запущено на http://example.com/example
1647
+ get '/foo' do
1648
+ t = %w[text/css text/html application/javascript]
1649
+ request.accept # ['text/html', '*/*']
1650
+ request.accept? 'text/xml' # true
1651
+ request.preferred_type(t) # 'text/html'
1652
+ request.body # тело запроса, посланное клиентом (см. ниже)
1653
+ request.scheme # "http"
1654
+ request.script_name # "/example"
1655
+ request.path_info # "/foo"
1656
+ request.port # 80
1657
+ request.request_method # "GET"
1658
+ request.query_string # ""
1659
+ request.content_length # длина тела запроса
1660
+ request.media_type # медиатип тела запроса
1661
+ request.host # "example.com"
1662
+ request.get? # true (есть аналоги для других методов HTTP)
1663
+ request.form_data? # false
1664
+ request["some_param"] # значение параметра some_param. Шорткат для хеша params
1665
+ request.referrer # источник запроса клиента либо '/'
1666
+ request.user_agent # user agent (используется для :agent условия)
1667
+ request.cookies # хеш, содержащий cookies браузера
1668
+ request.xhr? # является ли запрос ajax запросом?
1669
+ request.url # "http://example.com/example/foo"
1670
+ request.path # "/example/foo"
1671
+ request.ip # IP-адрес клиента
1672
+ request.secure? # false (true, если запрос сделан через SSL)
1673
+ request.forwarded? # true (если сервер работает за обратным прокси)
1674
+ request.env # "сырой" env хеш, полученный Rack
1675
+ end
1676
+ ```
1677
+
1678
+ Некоторые опции, такие как `script_name` или `path_info`, доступны для
1679
+ изменения:
1680
+
1681
+ ```ruby
1682
+ before { request.path_info = "/" }
1683
+
1684
+ get "/" do
1685
+ "all requests end up here"
1686
+ end
1687
+ ```
1688
+
1689
+ `request.body` является IO или StringIO объектом:
1690
+
1691
+ ```ruby
1692
+ post "/api" do
1693
+ request.body.rewind # в случае, если кто-то уже прочитал тело запроса
1694
+ data = JSON.parse request.body.read
1695
+ "Hello #{data['name']}!"
1696
+ end
1697
+ ```
1698
+
1699
+ ### Вложения
1700
+
1701
+ Вы можете использовать метод `attachment`, чтобы сказать браузеру, что ответ
1702
+ сервера должен быть сохранен на диск, а не отображен:
1703
+
1704
+ ```ruby
1705
+ get '/' do
1706
+ attachment
1707
+ "store it!"
1708
+ end
1709
+ ```
1710
+
1711
+ Вы также можете указать имя файла:
1712
+
1713
+ ```ruby
1714
+ get '/' do
1715
+ attachment "info.txt"
1716
+ "store it!"
1717
+ end
1718
+ ```
1719
+
1720
+ ### Работа со временем и датами
1721
+
1722
+ Sinatra предлагает метод-помощник `time_for`, который из заданного значения
1723
+ создает объект Time. Он также может конвертировать `DateTime`, `Date` и
1724
+ подобные классы:
1725
+
1726
+ ```ruby
1727
+ get '/' do
1728
+ pass if Time.now > time_for('Dec 23, 2012')
1729
+ "still time"
1730
+ end
1731
+ ```
1732
+
1733
+ Этот метод используется внутри Sinatra методами `expires`, `last_modified` и
1734
+ им подобными. Поэтому вы легко можете расширить функционал этих методов,
1735
+ переопределив `time_for` в своем приложении:
1736
+
1737
+ ```ruby
1738
+ helpers do
1739
+ def time_for(value)
1740
+ case value
1741
+ when :yesterday then Time.now - 24*60*60
1742
+ when :tomorrow then Time.now + 24*60*60
1743
+ else super
1744
+ end
1745
+ end
1746
+ end
1747
+
1748
+ get '/' do
1749
+ last_modified :yesterday
1750
+ expires :tomorrow
1751
+ "hello"
1752
+ end
1753
+ ```
1754
+
1755
+ ### Поиск шаблонов
1756
+
1757
+ Для поиска шаблонов и их последующего рендеринга используется метод
1758
+ `find_template`:
1759
+
1760
+ ```ruby
1761
+ find_template settings.views, 'foo', Tilt[:haml] do |file|
1762
+ puts "could be #{file}"
1763
+ end
1764
+ ```
1765
+
1766
+ Это не слишком полезный пример. Зато полезен тот факт, что вы можете
1767
+ переопределить этот метод, чтобы использовать свой собственный механизм
1768
+ поиска. Например, если вы хотите, чтобы можно было использовать несколько
1769
+ директорий с шаблонами:
1770
+
1771
+ ```ruby
1772
+ set :views, ['views', 'templates']
1773
+
1774
+ helpers do
1775
+ def find_template(views, name, engine, &block)
1776
+ Array(views).each { |v| super(v, name, engine, &block) }
1777
+ end
1778
+ end
1779
+ ```
1780
+
1781
+ Другой пример, в котором используются разные директории для движков
1782
+ рендеринга:
1783
+
1784
+ ```ruby
1785
+ set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
1786
+
1787
+ helpers do
1788
+ def find_template(views, name, engine, &block)
1789
+ _, folder = views.detect { |k,v| engine == Tilt[k] }
1790
+ folder ||= views[:default]
1791
+ super(folder, name, engine, &block)
1792
+ end
1793
+ end
1794
+ ```
1795
+
1796
+ Вы можете легко вынести этот код в расширение и поделиться им с остальными!
1797
+
1798
+ Заметьте, что `find_template` не проверяет, существует ли файл на самом деле,
1799
+ а вызывает заданный блок для всех возможных путей. Дело тут не в
1800
+ производительности, дело в том, что `render` вызовет `break`, как только файл
1801
+ не будет найден. Содержимое и местонахождение шаблонов будет закэшировано,
1802
+ если приложение запущено не в режиме разработки (`set :environment,
1803
+ :development`). Вы должны помнить об этих нюансах, если пишите по-настоящему
1804
+ "сумасшедший" метод.
1805
+
1806
+ ## Конфигурация
1807
+
1808
+ Этот блок исполняется один раз при старте в любом окружении, режиме
1809
+ (environment):
1810
+
1811
+ ```ruby
1812
+ configure do
1813
+ # задание одной опции
1814
+ set :option, 'value'
1815
+
1816
+ # устанавливаем несколько опций
1817
+ set :a => 1, :b => 2
1818
+
1819
+ # то же самое, что и `set :option, true`
1820
+ enable :option
1821
+
1822
+ # то же самое, что и `set :option, false`
1823
+ disable :option
1824
+
1825
+ # у вас могут быть "динамические" опции с блоками
1826
+ set(:css_dir) { File.join(views, 'css') }
1827
+ end
1828
+ ```
1829
+
1830
+ Будет запущено, когда окружение (RACK_ENV переменная) `:production`:
1831
+
1832
+ ```ruby
1833
+ configure :production do
1834
+ ...
1835
+ end
1836
+ ```
1837
+
1838
+ Будет запущено, когда окружение `:production` или `:test`:
1839
+
1840
+ ```ruby
1841
+ configure :production, :test do
1842
+ ...
1843
+ end
1844
+ ```
1845
+
1846
+ Вы можете получить доступ к этим опциям с помощью `settings`:
1847
+
1848
+ ```ruby
1849
+ configure do
1850
+ set :foo, 'bar'
1851
+ end
1852
+
1853
+ get '/' do
1854
+ settings.foo? # => true
1855
+ settings.foo # => 'bar'
1856
+ ...
1857
+ end
1858
+ ```
1859
+
1860
+ ### Настройка защиты от атак
1861
+
1862
+ Sinatra использует
1863
+ [Rack::Protection](https://github.com/rkh/rack-protection#readme) для защиты
1864
+ приложения от простых атак. Вы можете легко выключить эту защиту (что сделает
1865
+ ваше приложение чрезвычайно уязвимым):
1866
+
1867
+ ```ruby
1868
+ disable :protection
1869
+ ```
1870
+
1871
+ Чтобы пропустить какой-либо уровень защиты, передайте хеш опций в параметр
1872
+ `protection`:
1873
+
1874
+ ```ruby
1875
+ set :protection, :except => :path_traversal
1876
+ ```
1877
+
1878
+ Вы также можете отключить сразу несколько уровней защиты:
1879
+
1880
+ ```ruby
1881
+ set :protection, :except => [:path_traversal, :session_hijacking]
1882
+ ```
1883
+
1884
+ ### Доступные настройки
1885
+
1886
+ <dl>
1887
+ <dt>absolute_redirects</dt>
1888
+ <dd>
1889
+ если отключено, то Sinatra будет позволять использование относительных
1890
+ перенаправлений, но при этом перестанет соответствовать RFC 2616 (HTTP
1891
+ 1.1), который разрешает только абсолютные перенаправления.
1892
+ </dd>
1893
+ <dd>
1894
+ Включайте эту опцию, если ваше приложение работает за обратным прокси,
1895
+ который настроен не совсем корректно. Обратите внимание, метод <tt>url</tt> все
1896
+ равно будет генерировать абсолютные URL, если вы не передадите <tt>false</tt>
1897
+ вторым аргументом.
1898
+ </dd>
1899
+ <dd>Отключено по умолчанию.</dd>
1900
+
1901
+ <dt>add_charsets</dt>
1902
+ <dd>
1903
+ mime-типы, к которым метод <tt>content_type</tt> будет автоматически добавлять
1904
+ информацию о кодировке. Вам следует добавлять значения к этой опции
1905
+ вместо ее переопределения: <tt>settings.add_charsets &lt;&lt; "application/foobar"</tt>
1906
+ </dd>
1907
+
1908
+ <dt>app_file</dt>
1909
+ <dd>
1910
+ путь к главному файлу приложения, используется для нахождения корневой
1911
+ директории проекта, директорий с шаблонами и статическими файлами,
1912
+ вложенных шаблонов.
1913
+ </dd>
1914
+
1915
+ <dt>bind</dt>
1916
+ <dd>
1917
+ используемый IP-адрес (по умолчанию: 0.0.0.0). Используется только
1918
+ встроенным сервером.
1919
+ </dd>
1920
+
1921
+ <dt>default_encoding</dt>
1922
+ <dd>кодировка, если неизвестна (по умолчанию: <tt>"utf-8"</tt>).</dd>
1923
+
1924
+ <dt>dump_errors</dt>
1925
+ <dd>отображать ошибки в логе.</dd>
1926
+
1927
+ <dt>environment</dt>
1928
+ <dd>
1929
+ текущее окружение, по умолчанию, значение <tt>ENV['RACK_ENV']</tt> или
1930
+ <tt>"development"</tt>, если <tt>ENV['RACK_ENV']</tt> недоступна.
1931
+ </dd>
1932
+
1933
+ <dt>logging</dt>
1934
+ <dd>использовать логер.</dd>
1935
+
1936
+ <dt>lock</dt>
1937
+ <dd>
1938
+ создает блокировку для каждого запроса, которая гарантирует обработку
1939
+ только одного запроса в текущий момент времени в Ruby процессе.
1940
+ </dd>
1941
+ <dd>
1942
+ Включайте, если ваше приложение не потоко-безопасно (thread-safe).
1943
+ Отключено по умолчанию.</dd>
1944
+
1945
+ <dt>method_override</dt>
1946
+ <dd>
1947
+ использовать "магический" параметр <tt>_method</tt>, для поддержки
1948
+ PUT/DELETE форм в браузерах, которые не поддерживают эти методы.
1949
+ </dd>
1950
+
1951
+ <dt>port</dt>
1952
+ <dd>
1953
+ порт, на котором будет работать сервер.
1954
+ Используется только встроенным сервером.
1955
+ </dd>
1956
+
1957
+ <dt>prefixed_redirects</dt>
1958
+ <dd>
1959
+ добавлять или нет параметр <tt>request.script_name</tt> к редиректам, если не
1960
+ задан абсолютный путь. Таким образом, <tt>redirect '/foo'</tt> будет вести себя
1961
+ как <tt>redirect to('/foo')</tt>. Отключено по умолчанию.
1962
+ </dd>
1963
+
1964
+ <dt>protection</dt>
1965
+ <dd>включена или нет защита от атак. Смотрите секцию выше.</dd>
1966
+
1967
+ <dt>public_dir</dt>
1968
+ <dd>Алиас для <tt>public_folder</tt>.</dd>
1969
+
1970
+ <dt>public_folder</dt>
1971
+ <dd>
1972
+ путь к директории, откуда будут раздаваться статические файлы.
1973
+ Используется, только если включена раздача статических файлов
1974
+ (см. опцию <tt>static</tt> ниже).
1975
+ </dd>
1976
+
1977
+ <dt>reload_templates</dt>
1978
+ <dd>
1979
+ перезагружать или нет шаблоны на каждый запрос. Включено в режиме
1980
+ разработки.
1981
+ </dd>
1982
+
1983
+ <dt>root</dt>
1984
+ <dd>путь к корневой директории проекта.</dd>
1985
+
1986
+ <dt>raise_errors</dt>
1987
+ <dd>
1988
+ выбрасывать исключения (будет останавливать приложение).
1989
+ По умолчанию включено только в окружении <tt>test</tt>.
1990
+ </dd>
1991
+
1992
+ <dt>run</dt>
1993
+ <dd>
1994
+ если включено, Sinatra будет самостоятельно запускать веб-сервер. Не
1995
+ включайте, если используете rackup или аналогичные средства.
1996
+ </dd>
1997
+
1998
+ <dt>running</dt>
1999
+ <dd>работает ли сейчас встроенный сервер? Не меняйте эту опцию!</dd>
2000
+
2001
+ <dt>server</dt>
2002
+ <dd>
2003
+ сервер или список серверов, которые следует использовать в качестве
2004
+ встроенного сервера. По умолчанию: <tt>['thin', 'mongrel', 'webrick']</tt>, порядок
2005
+ задает приоритет.</dd>
2006
+
2007
+ <dt>sessions</dt>
2008
+ <dd>
2009
+ включить сессии на основе кук (cookie) на базе <tt>Rack::Session::Cookie</tt>.
2010
+ Смотрите секцию "Использование сессий" выше.
2011
+ </dd>
2012
+
2013
+ <dt>show_exceptions</dt>
2014
+ <dd>
2015
+ показывать исключения/стек вызовов (stack trace) в браузере. По умолчанию
2016
+ включено только в окружении <tt>development</tt>.
2017
+ </dd>
2018
+ <dd>
2019
+ Может быть установлено в
2020
+ <tt>:after_handler</tt> для запуска специфичной для приложения обработки ошибок,
2021
+ перед показом трассировки стека в браузере.
2022
+ </dd>
2023
+
2024
+ <dt>static</dt>
2025
+ <dd>должна ли Sinatra осуществлять раздачу статических файлов.</dd>
2026
+ <dd>Отключите, когда используете какой-либо веб-сервер для этой цели.</dd>
2027
+ <dd>Отключение значительно улучшит производительность приложения.</dd>
2028
+ <dd>По умолчанию включено в классических и отключено в модульных приложениях.</dd>
2029
+
2030
+ <dt>static_cache_control</dt>
2031
+ <dd>
2032
+ когда Sinatra отдает статические файлы, используйте эту опцию, чтобы
2033
+ добавить им заголовок <tt>Cache-Control</tt>. Для этого используется
2034
+ метод-помощник <tt>cache_control</tt>. По умолчанию отключено.
2035
+ </dd>
2036
+ <dd>
2037
+ Используйте массив, когда надо задать несколько значений:
2038
+ <tt>set :static_cache_control, [:public, :max_age => 300]</tt>
2039
+ </dd>
2040
+
2041
+ <dt>threaded</dt>
2042
+ <dd>
2043
+ если включено, то Thin будет использовать <tt>EventMachine.defer</tt> для
2044
+ обработки запросов.
2045
+ </dd>
2046
+
2047
+ <dt>views</dt>
2048
+ <dd>путь к директории с шаблонами.</dd>
2049
+ </dl>
2050
+
2051
+ ## Режим, окружение
2052
+
2053
+ Есть 3 предопределенных режима, окружения: `"development"`, `"production"` и
2054
+ `"test"`. Режим может быть задан через переменную окружения `RACK_ENV`.
2055
+ Значение по умолчанию — `"development"`. В этом режиме работы все шаблоны
2056
+ перезагружаются между запросами. А также задаются специальные обработчики
2057
+ `not_found` и `error`, чтобы вы могли увидеть стек вызовов. В окружениях
2058
+ `"production"` и `"test"` шаблоны по умолчанию кэшируются.
2059
+
2060
+ Для запуска приложения в определенном окружении используйте ключ `-e`
2061
+
2062
+ ```
2063
+ ruby my_app.rb -e [ENVIRONMENT]
2064
+ ```
2065
+
2066
+ Вы можете использовать предопределенные методы `development?`, `test?` и
2067
+ +production?, чтобы определить текущее окружение.
2068
+
2069
+ ## Обработка ошибок
2070
+
2071
+ Обработчики ошибок исполняются в том же контексте, что и маршруты, и
2072
+ `before`-фильтры, а это означает, что всякие прелести вроде `haml`, `erb`,
2073
+ `halt` и т.д. доступны и им.
2074
+
2075
+ ### Not Found
2076
+
2077
+ Когда выброшено исключение `Sinatra::NotFound`, или кодом ответа является 404,
2078
+ то будет вызван `not_found` обработчик:
2079
+
2080
+ ```ruby
2081
+ not_found do
2082
+ 'This is nowhere to be found.'
2083
+ end
2084
+ ```
2085
+
2086
+ ### Ошибки
2087
+
2088
+ Обработчик ошибок `error` будет вызван, когда исключение выброшено из блока
2089
+ маршрута, либо из фильтра. Объект-исключение доступен как переменная
2090
+ `sinatra.error` в Rack:
2091
+
2092
+ ```ruby
2093
+ error do
2094
+ 'Sorry there was a nasty error - ' + env['sinatra.error'].name
2095
+ end
2096
+ ```
2097
+
2098
+ Конкретные ошибки:
2099
+
2100
+ ```ruby
2101
+ error MyCustomError do
2102
+ 'So what happened was...' + env['sinatra.error'].message
2103
+ end
2104
+ ```
2105
+
2106
+ Тогда, если это произошло:
2107
+
2108
+ ```ruby
2109
+ get '/' do
2110
+ raise MyCustomError, 'something bad'
2111
+ end
2112
+ ```
2113
+
2114
+ То вы получите:
2115
+
2116
+ ```
2117
+ So what happened was... something bad
2118
+ ```
2119
+
2120
+ Также вы можете установить обработчик ошибок для кода состояния HTTP:
2121
+
2122
+ ```ruby
2123
+ error 403 do
2124
+ 'Access forbidden'
2125
+ end
2126
+
2127
+ get '/secret' do
2128
+ 403
2129
+ end
2130
+ ```
2131
+
2132
+ Либо набора кодов:
2133
+
2134
+ ```ruby
2135
+ error 400..510 do
2136
+ 'Boom'
2137
+ end
2138
+ ```
2139
+
2140
+ Sinatra устанавливает специальные `not_found` и `error` обработчики, когда
2141
+ приложение запущено в режиме разработки (окружение `:development`).
2142
+
2143
+ ## Rack "прослойки"
2144
+
2145
+ Sinatra использует [Rack](http://rack.rubyforge.org/), минимальный стандартный
2146
+ интерфейс для веб-фреймворков на Ruby. Одной из самых интересных для
2147
+ разработчиков возможностей Rack является поддержка "прослоек" ("middleware") —
2148
+ компонентов, находящихся "между" сервером и вашим приложением, которые
2149
+ отслеживают и/или манипулируют HTTP запросами/ответами для предоставления
2150
+ различной функциональности.
2151
+
2152
+ В Sinatra очень просто использовать такие "прослойки" с помощью метода `use`:
2153
+
2154
+ ```ruby
2155
+ require 'sinatra'
2156
+ require 'my_custom_middleware'
2157
+
2158
+ use Rack::Lint
2159
+ use MyCustomMiddleware
2160
+
2161
+ get '/hello' do
2162
+ 'Hello World'
2163
+ end
2164
+ ```
2165
+
2166
+ Семантика `use` идентична той, что определена для
2167
+ [Rack::Builder](http://rack.rubyforge.org/doc/classes/Rack/Builder.html) DSL
2168
+ (чаще всего используется в rackup файлах). Например, метод `use` принимает как
2169
+ множественные переменные, так и блоки:
2170
+
2171
+ ```ruby
2172
+ use Rack::Auth::Basic do |username, password|
2173
+ username == 'admin' && password == 'secret'
2174
+ end
2175
+ ```
2176
+
2177
+ Rack распространяется с различными стандартными "прослойками" для логирования,
2178
+ отладки, маршрутизации URL, аутентификации, обработки сессий. Sinatra
2179
+ использует многие из этих компонентов автоматически, основываясь на
2180
+ конфигурации, чтобы вам не приходилось подключать (`use`) их вручную.
2181
+
2182
+ Вы можете найти полезные прослойки в
2183
+ [rack](https://github.com/rack/rack/tree/master/lib/rack),
2184
+ [rack-contrib](https://github.com/rack/rack-contrib#readme),
2185
+ [CodeRack](http://coderack.org/) или в
2186
+ [Rack wiki](https://github.com/rack/rack/wiki/List-of-Middleware).
2187
+
2188
+ ## Тестирование
2189
+
2190
+ Тесты для Sinatra приложений могут быть написаны с помощью библиотек,
2191
+ фреймворков, поддерживающих тестирование Rack.
2192
+ [Rack::Test](http://rdoc.info/github/brynary/rack-test/master/frames)
2193
+ рекомендован:
2194
+
2195
+ ```ruby
2196
+ require 'my_sinatra_app'
2197
+ require 'test/unit'
2198
+ require 'rack/test'
2199
+
2200
+ class MyAppTest < Test::Unit::TestCase
2201
+ include Rack::Test::Methods
2202
+
2203
+ def app
2204
+ Sinatra::Application
2205
+ end
2206
+
2207
+ def test_my_default
2208
+ get '/'
2209
+ assert_equal 'Hello World!', last_response.body
2210
+ end
2211
+
2212
+ def test_with_params
2213
+ get '/meet', :name => 'Frank'
2214
+ assert_equal 'Hello Frank!', last_response.body
2215
+ end
2216
+
2217
+ def test_with_rack_env
2218
+ get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
2219
+ assert_equal "You're using Songbird!", last_response.body
2220
+ end
2221
+ end
2222
+ ```
2223
+
2224
+ ## Sinatra::Base — "прослойки", библиотеки и модульные приложения
2225
+
2226
+ Описание своего приложения самым простейшим способом (с помощью DSL верхнего
2227
+ уровня, классический стиль) отлично работает для крохотных приложений. В таких
2228
+ случаях используется конфигурация, рассчитанная на микро-приложения
2229
+ (единственный файл приложения, `./public` и `./views` директории, логирование,
2230
+ страница информации об исключении и т.д.). Тем не менее, такой метод имеет
2231
+ множество недостатков при создании компонентов, таких как Rack middleware
2232
+ ("прослоек"), Rails metal, простых библиотек с серверными компонентами,
2233
+ расширений Sinatra. И тут на помощь приходит `Sinatra::Base`:
2234
+
2235
+ ```ruby
2236
+ require 'sinatra/base'
2237
+
2238
+ class MyApp < Sinatra::Base
2239
+ set :sessions, true
2240
+ set :foo, 'bar'
2241
+
2242
+ get '/' do
2243
+ 'Hello world!'
2244
+ end
2245
+ end
2246
+ ```
2247
+
2248
+ Методы, доступные `Sinatra::Base` подклассам идентичны тем, что доступны
2249
+ приложениям в DSL верхнего уровня. Большинство таких приложений могут быть
2250
+ конвертированы в `Sinatra::Base` компоненты с помощью двух модификаций:
2251
+
2252
+ * Вы должны подключать `sinatra/base` вместо `sinatra`, иначе все методы,
2253
+ предоставляемые Sinatra, будут импортированы в глобальное пространство
2254
+ имен.
2255
+ * Поместите все маршруты, обработчики ошибок, фильтры и опции в подкласс
2256
+ `Sinatra::Base`.
2257
+
2258
+ `Sinatra::Base` — это чистый лист. Большинство опций, включая встроенный
2259
+ сервер, по умолчанию отключены. Смотрите
2260
+ [Опции и конфигурация](http://www.sinatrarb.com/configuration.html)
2261
+ для детальной информации об опциях и их поведении.
2262
+
2263
+ ### Модульные приложения против классических
2264
+
2265
+ Вопреки всеобщему убеждению, в классическом стиле (самом простом) нет ничего
2266
+ плохого. Если этот стиль подходит вашему приложению, вы не обязаны
2267
+ переписывать его в модульное приложение.
2268
+
2269
+ Основным недостатком классического стиля является тот факт, что у вас может
2270
+ быть только одно приложение Sinatra на один процесс Ruby. Если вы планируете
2271
+ использовать больше, переключайтесь на модульный стиль. Вы можете смело
2272
+ смешивать модульный и классический стили.
2273
+
2274
+ Переходя с одного стиля на другой, примите во внимание следующие изменения в
2275
+ настройках:
2276
+
2277
+ Опция Классический Модульный
2278
+
2279
+ app_file файл с приложением файл с подклассом Sinatra::Base
2280
+ run $0 == app_file false
2281
+ logging true false
2282
+ method_override true false
2283
+ inline_templates true false
2284
+ static true false
2285
+
2286
+ ### Запуск модульных приложений
2287
+
2288
+ Есть два общепринятых способа запускать модульные приложения: запуск напрямую
2289
+ с помощью `run!`:
2290
+
2291
+ ```ruby
2292
+ # my_app.rb
2293
+ require 'sinatra/base'
2294
+
2295
+ class MyApp < Sinatra::Base
2296
+ # ... здесь код приложения ...
2297
+
2298
+ # запускаем сервер, если исполняется текущий файл
2299
+ run! if app_file == $0
2300
+ end
2301
+ ```
2302
+
2303
+ Затем:
2304
+
2305
+ ```
2306
+ ruby my_app.rb
2307
+ ```
2308
+
2309
+ Или с помощью конфигурационного файла `config.ru`, который позволяет
2310
+ использовать любой Rack-совместимый сервер приложений.
2311
+
2312
+ ```ruby
2313
+ # config.ru
2314
+ require './my_app'
2315
+ run MyApp
2316
+ ```
2317
+
2318
+ Запускаем:
2319
+
2320
+ ```
2321
+ rackup -p 4567
2322
+ ```
2323
+
2324
+ ### Запуск классических приложений с config.ru
2325
+
2326
+ Файл приложения:
2327
+
2328
+ ```ruby
2329
+ # app.rb
2330
+ require 'sinatra'
2331
+
2332
+ get '/' do
2333
+ 'Hello world!'
2334
+ end
2335
+ ```
2336
+
2337
+ И соответствующий `config.ru`:
2338
+
2339
+ ```ruby
2340
+ require './app'
2341
+ run Sinatra::Application
2342
+ ```
2343
+
2344
+ ### Когда использовать config.ru?
2345
+
2346
+ Вот несколько причин, по которым вы, возможно, захотите использовать
2347
+ `config.ru`:
2348
+
2349
+ * вы хотите разворачивать свое приложение на различных Rack-совместимых
2350
+ серверах (Passenger, Unicorn, Heroku, ...);
2351
+ * вы хотите использовать более одного подкласса `Sinatra::Base`;
2352
+ * вы хотите использовать Sinatra только в качестве "прослойки" Rack.
2353
+
2354
+ **Совсем необязательно переходить на использование `config.ru` лишь потому,
2355
+ что вы стали использовать модульный стиль приложения. И необязательно
2356
+ использовать модульный стиль, чтобы запускать приложение с помощью
2357
+ `config.ru`.**
2358
+
2359
+ ### Использование Sinatra в качестве "прослойки"
2360
+
2361
+ Не только сама Sinatra может использовать "прослойки" Rack, но и любое Sinatra
2362
+ приложение само может быть добавлено к любому Rack endpoint в качестве
2363
+ "прослойки". Этим endpoint (конечной точкой) может быть другое Sinatra
2364
+ приложение, или приложение, основанное на Rack (Rails/Ramaze/Camping/...):
2365
+
2366
+ ```ruby
2367
+ require 'sinatra/base'
2368
+
2369
+ class LoginScreen < Sinatra::Base
2370
+ enable :sessions
2371
+
2372
+ get('/login') { haml :login }
2373
+
2374
+ post('/login') do
2375
+ if params[:name] == 'admin' && params[:password] == 'admin'
2376
+ session['user_name'] = params[:name]
2377
+ else
2378
+ redirect '/login'
2379
+ end
2380
+ end
2381
+ end
2382
+
2383
+ class MyApp < Sinatra::Base
2384
+ # "прослойка" будет запущена перед фильтрами
2385
+ use LoginScreen
2386
+
2387
+ before do
2388
+ unless session['user_name']
2389
+ halt "Access denied, please <a href='/login'>login</a>."
2390
+ end
2391
+ end
2392
+
2393
+ get('/') { "Hello #{session['user_name']}." }
2394
+ end
2395
+ ```
2396
+
2397
+ ### Создание приложений "на лету"
2398
+
2399
+ Иногда требуется создавать Sinatra приложения "на лету" (например, из другого
2400
+ приложения). Это возможно с помощью `Sinatra.new`:
2401
+
2402
+ ```ruby
2403
+ require 'sinatra/base'
2404
+ my_app = Sinatra.new { get('/') { "hi" } }
2405
+ my_app.run!
2406
+ ```
2407
+
2408
+ Этот метод может принимать аргументом приложение, от которого следует
2409
+ наследоваться:
2410
+
2411
+ ```ruby
2412
+ # config.ru
2413
+ require 'sinatra/base'
2414
+
2415
+ controller = Sinatra.new do
2416
+ enable :logging
2417
+ helpers MyHelpers
2418
+ end
2419
+
2420
+ map('/a') do
2421
+ run Sinatra.new(controller) { get('/') { 'a' } }
2422
+ end
2423
+
2424
+ map('/b') do
2425
+ run Sinatra.new(controller) { get('/') { 'b' } }
2426
+ end
2427
+ ```
2428
+
2429
+ Это особенно полезно для тестирования расширений Sinatra и при использовании
2430
+ Sinatra внутри вашей библиотеки.
2431
+
2432
+ Благодаря этому, использовать Sinatra как "прослойку" очень просто:
2433
+
2434
+ ```ruby
2435
+ require 'sinatra/base'
2436
+
2437
+ use Sinatra do
2438
+ get('/') { ... }
2439
+ end
2440
+
2441
+ run RailsProject::Application
2442
+ ```
2443
+
2444
+ ## Области видимости и привязка
2445
+
2446
+ Текущая область видимости определяет методы и переменные, доступные в данный
2447
+ момент.
2448
+
2449
+ ### Область видимости приложения / класса
2450
+
2451
+ Любое Sinatra приложение соответствует подклассу `Sinatra::Base`. Если вы
2452
+ используете DSL верхнего уровня (`require 'sinatra'`), то этим классом будет
2453
+ `Sinatra::Application`, иначе это будет подкласс, который вы создали вручную.
2454
+ На уровне класса вам будут доступны такие методы, как `get` или `before`, но
2455
+ вы не сможете получить доступ к объектам `request` или `session`, так как
2456
+ существует только один класс приложения для всех запросов.
2457
+
2458
+ Опции, созданные с помощью `set`, являются методами уровня класса:
2459
+
2460
+ ```ruby
2461
+ class MyApp < Sinatra::Base
2462
+ # Я в области видимости приложения!
2463
+ set :foo, 42
2464
+ foo # => 42
2465
+
2466
+ get '/foo' do
2467
+ # Я больше не в области видимости приложения!
2468
+ end
2469
+ end
2470
+ ```
2471
+
2472
+ У вас будет область видимости приложения внутри:
2473
+
2474
+ * тела вашего класса приложения;
2475
+ * методов, определенных расширениями;
2476
+ * блока, переданного в `helpers`;
2477
+ * блоков, использованных как значения для `set`;
2478
+ * блока, переданного в `Sinatra.new`.
2479
+
2480
+ Вы можете получить доступ к объекту области видимости (классу приложения)
2481
+ следующими способами:
2482
+
2483
+ * через объект, переданный блокам конфигурации (`configure { |c| ... }`);
2484
+ * `settings` внутри области видимости запроса.
2485
+
2486
+ ### Область видимости запроса/экземпляра
2487
+
2488
+ Для каждого входящего запроса будет создан новый экземпляр вашего приложения,
2489
+ и все блоки обработчика будут запущены в этом контексте. В этой области
2490
+ видимости вам доступны `request` и `session` объекты, вызовы методов
2491
+ рендеринга, такие как `erb` или `haml`. Вы можете получить доступ к области
2492
+ видимости приложения из контекста запроса, используя метод-помощник
2493
+ `settings`:
2494
+
2495
+ ```ruby
2496
+ class MyApp < Sinatra::Base
2497
+ # Я в области видимости приложения!
2498
+ get '/define_route/:name' do
2499
+ # Область видимости запроса '/define_route/:name'
2500
+ @value = 42
2501
+
2502
+ settings.get("/#{params[:name]}") do
2503
+ # Область видимости запроса "/#{params[:name]}"
2504
+ @value # => nil (другой запрос)
2505
+ end
2506
+
2507
+ "Route defined!"
2508
+ end
2509
+ end
2510
+ ```
2511
+
2512
+ У вас будет область видимости запроса в:
2513
+
2514
+ * get/head/post/put/delete/options блоках;
2515
+ * before/after фильтрах;
2516
+ * методах-помощниках;
2517
+ * шаблонах/отображениях.
2518
+
2519
+ ### Область видимости делегирования
2520
+
2521
+ Область видимости делегирования просто перенаправляет методы в область
2522
+ видимости класса. Однако, она не полностью ведет себя как область видимости
2523
+ класса, так как у вас нет привязки к классу. Только методы, явно помеченные
2524
+ для делегирования, будут доступны, а переменных/состояний области видимости
2525
+ класса не будет (иначе говоря, у вас будет другой `self` объект). Вы можете
2526
+ непосредственно добавить методы делегирования, используя
2527
+ `Sinatra::Delegator.delegate :method_name`.
2528
+
2529
+ У вас будет контекст делегирования внутри:
2530
+
2531
+ * привязки верхнего уровня, если вы сделали `require 'sinatra'`;
2532
+ * объекта, расширенного с помощью `Sinatra::Delegator`.
2533
+
2534
+ Посмотрите сами в код: вот
2535
+ [примесь Sinatra::Delegator](https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/base.rb#L1609-1633)
2536
+ [расширяет главный объект](https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/main.rb#L28-30).
2537
+
2538
+ ## Командная строка
2539
+
2540
+ Sinatra приложения могут быть запущены напрямую:
2541
+
2542
+ ```
2543
+ ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-o HOST] [-s HANDLER]
2544
+ ```
2545
+
2546
+ Опции включают:
2547
+
2548
+ ```
2549
+ -h # раздел помощи
2550
+ -p # указание порта (по умолчанию 4567)
2551
+ -o # указание хоста (по умолчанию 0.0.0.0)
2552
+ -e # указание окружения, режима (по умолчанию development)
2553
+ -s # указание rack сервера/обработчика (по умолчанию thin)
2554
+ -x # включить мьютекс-блокировку (по умолчанию выключена)
2555
+ ```
2556
+
2557
+ ## Системные требования
2558
+
2559
+ Следующие версии Ruby официально поддерживаются:
2560
+
2561
+ <dl>
2562
+ <dt>Ruby 1.8.7</dt>
2563
+ <dd>1.8.7 полностью поддерживается, тем не менее, если вас ничто не держит на
2564
+ этой версии, рекомендуем обновиться до 1.9.2 или перейти на JRuby или
2565
+ Rubinius. Поддержка 1.8.7 не будет прекращена до выхода Sinatra 2.0 и Ruby
2566
+ 2.0, разве что в случае релиза 1.8.8 (что маловероятно). Но даже тогда,
2567
+ возможно, поддержка не будет прекращена. <b>Ruby 1.8.6 больше не
2568
+ поддерживается.</b> Если вы хотите использовать 1.8.6, откатитесь до Sinatra
2569
+ 1.2, которая будет получать все исправления ошибок до тех пор, пока не
2570
+ будет выпущена Sinatra 1.4.0.</dd>
2571
+
2572
+ <dt>Ruby 1.9.2</dt>
2573
+ <dd>1.9.2 полностью поддерживается и рекомендована к использованию.
2574
+ Не используйте 1.9.2p0,
2575
+ известно, что эта версия очень нестабильна при использовании Sinatra. Эта
2576
+ версия будет поддерживаться по крайней мере до выхода Ruby 1.9.4/2.0, а
2577
+ поддержка последней версии 1.9 будет осуществляться до тех пор, пока она
2578
+ поддерживается командой разработчиков Ruby.</dd>
2579
+
2580
+ <dt>Ruby 1.9.3</dt>
2581
+ <dd>1.9.3 полностью поддерживается. Заметьте, что переход на 1.9.3 с
2582
+ ранних версий сделает недействительными все сессии.</dd>
2583
+
2584
+ <dt>Rubinius</dt>
2585
+ <dd>Rubinius официально поддерживается (Rubinius &gt;= 1.2.4), всё, включая все
2586
+ языки шаблонов, работает. Предстоящий релиз 2.0 также поддерживается.</dd>
2587
+
2588
+ <dt>JRuby</dt>
2589
+ <dd>JRuby официально поддерживается (JRuby &gt;= 1.6.5). Нет никаких проблем с
2590
+ использованием альтернативных шаблонов. Тем не менее, если вы выбираете
2591
+ JRuby, то, пожалуйста, посмотрите на JRuby Rack-серверы, так как Thin не
2592
+ поддерживается полностью на JRuby. Поддержка расширений на C в JRuby все
2593
+ еще экспериментальная, что на данный момент затрагивает только RDiscount,
2594
+ Redcarpet и RedCloth.</dd>
2595
+ </dl>
2596
+
2597
+ Мы также следим за предстоящими к выходу версиями Ruby.
2598
+
2599
+ Следующие реализации Ruby не поддерживаются официально, но известно, что на
2600
+ них запускается Sinatra:
2601
+
2602
+ * старые версии JRuby и Rubinius;
2603
+ * Ruby Enterprise Edition;
2604
+ * MacRuby, Maglev, IronRuby;
2605
+ * Ruby 1.9.0 и 1.9.1 (настоятельно не рекомендуются к использованию).
2606
+
2607
+ То, что версия официально не поддерживается, означает, что, если что-то не
2608
+ работает на этой версии, а на поддерживаемой работает — это не наша проблема,
2609
+ а их.
2610
+
2611
+ Мы также запускаем наши CI-тесты на версии Ruby, находящейся в разработке
2612
+ (предстоящей 2.0.0), и на 1.9.4, но мы не можем ничего гарантировать, так как
2613
+ они находятся в разработке. Предполагается, что 1.9.4p0 и 2.0.0p0 будут
2614
+ поддерживаться.
2615
+
2616
+ Sinatra должна работать на любой операционной системе, в которой есть одна из
2617
+ указанных выше версий Ruby.
2618
+
2619
+ Пока невозможно запустить Sinatra на Cardinal, SmallRuby, BlueRuby и на любой
2620
+ версии Ruby до 1.8.7.
2621
+
2622
+ ## На острие
2623
+
2624
+ Если вы хотите использовать самый последний код Sinatra, не бойтесь запускать
2625
+ свое приложение вместе с кодом из master ветки Sinatra, она весьма стабильна.
2626
+
2627
+ Мы также время от времени выпускаем предварительные версии, так что вы можете
2628
+ делать так:
2629
+
2630
+ ```
2631
+ gem install sinatra --pre
2632
+ ```
2633
+
2634
+ Чтобы воспользоваться некоторыми самыми последними возможностями.
2635
+
2636
+ ### С помощью Bundler
2637
+
2638
+ Если вы хотите запускать свое приложение с последней версией Sinatra, то
2639
+ рекомендуем использовать [Bundler](http://gembundler.com/).
2640
+
2641
+ Сначала установите Bundler, если у вас его еще нет:
2642
+
2643
+ ```
2644
+ gem install bundler
2645
+ ```
2646
+
2647
+ Затем создайте файл `Gemfile` в директории вашего проекта:
2648
+
2649
+ ```ruby
2650
+ source :rubygems
2651
+ gem 'sinatra', :git => "git://github.com/sinatra/sinatra.git"
2652
+
2653
+ # другие зависимости
2654
+ gem 'haml' # например, если используете haml
2655
+ gem 'activerecord', '~> 3.0' # может быть, вам нужен и ActiveRecord 3.x
2656
+ ```
2657
+
2658
+ Обратите внимание, вам нужно будет указывать все зависимости вашего приложения
2659
+ в этом файле. Однако, непосредственные зависимости Sinatra (Rack и Tilt)
2660
+ Bundler автоматически скачает и добавит.
2661
+
2662
+ Теперь вы можете запускать свое приложение так:
2663
+
2664
+ ```
2665
+ bundle exec ruby myapp.rb
2666
+ ```
2667
+
2668
+ ### Вручную
2669
+
2670
+ Создайте локальный клон репозитория и запускайте свое приложение с
2671
+ `sinatra/lib` директорией в `$LOAD_PATH`:
2672
+
2673
+ ```
2674
+ cd myapp
2675
+ git clone git://github.com/sinatra/sinatra.git
2676
+ ruby -Isinatra/lib myapp.rb
2677
+ ```
2678
+
2679
+ Чтобы обновить исходники Sinatra:
2680
+
2681
+ ```
2682
+ cd myapp/sinatra
2683
+ git pull
2684
+ ```
2685
+
2686
+ ### Установка глобально
2687
+
2688
+ Вы можете самостоятельно собрать gem:
2689
+
2690
+ ```
2691
+ git clone git://github.com/sinatra/sinatra.git
2692
+ cd sinatra
2693
+ rake sinatra.gemspec
2694
+ rake install
2695
+ ```
2696
+
2697
+ Если вы устанавливаете пакеты (gem) от пользователя root, то вашим последним
2698
+ шагом должна быть команда
2699
+
2700
+ ```
2701
+ sudo rake install
2702
+ ```
2703
+
2704
+ ## Версии
2705
+
2706
+ Sinatra использует [Semantic Versioning](http://semver.org/), SemVer и
2707
+ SemVerTag.
2708
+
2709
+ ## Дальнейшее чтение
2710
+
2711
+ * [Веб-сайт проекта](http://www.sinatrarb.com/) — Дополнительная
2712
+ документация, новости и ссылки на другие ресурсы.
2713
+ * [Участие в проекте](http://www.sinatrarb.com/contributing) — Обнаружили
2714
+ баг? Нужна помощь? Написали патч?
2715
+ * [Слежение за проблемами/ошибками](http://github.com/sinatra/sinatra/issues)
2716
+ * [Twitter](http://twitter.com/sinatra)
2717
+ * [Группы рассылки](http://groups.google.com/group/sinatrarb/topics)
2718
+ * [#sinatra](irc://chat.freenode.net/#sinatra) на http://freenode.net
2719
+ * [Sinatra Book](http://sinatra-book.gittr.com) учебник и сборник рецептов
2720
+ * [Sinatra Recipes](http://recipes.sinatrarb.com/) сборник рецептов
2721
+ * API документация к [последнему релизу](http://rubydoc.info/gems/sinatra)
2722
+ или [текущему HEAD](http://rubydoc.info/github/sinatra/sinatra) на
2723
+ http://rubydoc.info
2724
+ * [Сервер непрерывной интеграции](http://travis-ci.org/sinatra/sinatra)