sinatra 2.2.4 → 3.0.6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sinatra might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +99 -17
- data/CONTRIBUTING.md +11 -11
- data/Gemfile +44 -64
- data/MAINTENANCE.md +2 -2
- data/README.md +116 -414
- data/Rakefile +66 -75
- data/VERSION +1 -1
- data/examples/chat.rb +25 -12
- data/examples/rainbows.rb +3 -1
- data/examples/simple.rb +2 -0
- data/examples/stream.ru +2 -0
- data/lib/sinatra/base.rb +350 -336
- data/lib/sinatra/indifferent_hash.rb +25 -33
- data/lib/sinatra/main.rb +18 -16
- data/lib/sinatra/show_exceptions.rb +17 -15
- data/lib/sinatra/version.rb +3 -1
- data/lib/sinatra.rb +2 -0
- data/sinatra.gemspec +38 -33
- metadata +34 -26
- data/README.de.md +0 -3239
- data/README.es.md +0 -3231
- data/README.fr.md +0 -3111
- data/README.hu.md +0 -728
- data/README.ja.md +0 -2844
- data/README.ko.md +0 -2967
- data/README.malayalam.md +0 -3141
- data/README.pt-br.md +0 -3787
- data/README.pt-pt.md +0 -791
- data/README.ru.md +0 -3207
- data/README.zh.md +0 -2934
data/README.ru.md
DELETED
@@ -1,3207 +0,0 @@
|
|
1
|
-
# Sinatra
|
2
|
-
|
3
|
-
[![Build Status](https://secure.travis-ci.org/sinatra/sinatra.svg)](https://travis-ci.org/sinatra/sinatra)
|
4
|
-
|
5
|
-
*Внимание: Этот документ является переводом английской версии и может быть
|
6
|
-
устаревшим*
|
7
|
-
|
8
|
-
Sinatra — это предметно-ориентированный каркас
|
9
|
-
([DSL](https://ru.wikipedia.org/wiki/Предметно-ориентированный_язык))
|
10
|
-
для быстрого создания функциональных веб-приложений на Ruby с минимумом усилий:
|
11
|
-
|
12
|
-
```ruby
|
13
|
-
# myapp.rb
|
14
|
-
require 'sinatra'
|
15
|
-
|
16
|
-
get '/' do
|
17
|
-
'Hello world!'
|
18
|
-
end
|
19
|
-
```
|
20
|
-
|
21
|
-
Установите gem:
|
22
|
-
|
23
|
-
```shell
|
24
|
-
gem install sinatra
|
25
|
-
```
|
26
|
-
|
27
|
-
и запустите приложение при помощи:
|
28
|
-
|
29
|
-
```shell
|
30
|
-
ruby myapp.rb
|
31
|
-
```
|
32
|
-
|
33
|
-
Оцените результат: [http://localhost:4567](http://localhost:4567)
|
34
|
-
|
35
|
-
Имейте ввиду, что изменения в коде не будут видны до тех пор, пока вы не перезапустите
|
36
|
-
сервер. Пожалуйста, перезагружайте сервер каждый раз как вносите изменения или добавьте
|
37
|
-
в проект [sinatra/reloader](http://www.sinatrarb.com/contrib/reloader).
|
38
|
-
|
39
|
-
Рекомендуется также установить Thin сервер (`gem install thin`), который автоматически
|
40
|
-
работает с Sinatra приложениями.
|
41
|
-
|
42
|
-
## Содержание
|
43
|
-
|
44
|
-
* [Sinatra](#sinatra)
|
45
|
-
* [Содержание](#Содержание)
|
46
|
-
* [Маршруты](#Маршруты)
|
47
|
-
* [Условия](#Условия)
|
48
|
-
* [Возвращаемые значения](#Возвращаемые-значения)
|
49
|
-
* [Собственные детекторы совпадений для маршрутов](#Собственные-детекторы-совпадений-для-маршрутов)
|
50
|
-
* [Статические файлы](#Статические-файлы)
|
51
|
-
* [Представления / Шаблоны](#Представления--Шаблоны)
|
52
|
-
* [Буквальные шаблоны](#Буквальные-шаблоны)
|
53
|
-
* [Доступные шаблонизаторы](#Доступные-шаблонизаторы)
|
54
|
-
* [Haml шаблоны](#haml-шаблоны)
|
55
|
-
* [Erb шаблоны](#erb-шаблоны)
|
56
|
-
* [Builder шаблоны](#builder-шаблоны)
|
57
|
-
* [Nokogiri шаблоны](#nokogiri-шаблоны)
|
58
|
-
* [Sass шаблоны](#sass-шаблоны)
|
59
|
-
* [SCSS шаблоны](#scss-шаблоны)
|
60
|
-
* [Less шаблоны](#less-шаблоны)
|
61
|
-
* [Liquid шаблоны](#liquid-шаблоны)
|
62
|
-
* [Markdown шаблоны](#markdown-шаблоны)
|
63
|
-
* [Textile шаблоны](#textile-шаблоны)
|
64
|
-
* [RDoc шаблоны](#rdoc-шаблоны)
|
65
|
-
* [AsciiDoc шаблоны](#asciidoc-шаблоны)
|
66
|
-
* [Radius шаблоны](#radius-шаблоны)
|
67
|
-
* [Markaby шаблоны](#markaby-шаблоны)
|
68
|
-
* [RABL шаблоны](#rabl-шаблоны)
|
69
|
-
* [Slim шаблоны](#slim-шаблоны)
|
70
|
-
* [Creole шаблоны](#creole-шаблоны)
|
71
|
-
* [MediaWiki шаблоны](#mediawiki-шаблоны)
|
72
|
-
* [CoffeeScript шаблоны](#coffeescript-шаблоны)
|
73
|
-
* [Stylus шаблоны](#stylus-шаблоны)
|
74
|
-
* [Yajl шаблоны](#yajl-шаблоны)
|
75
|
-
* [WLang шаблоны](#wlang-шаблоны)
|
76
|
-
* [Доступ к переменным в шаблонах](#Доступ-к-переменным-в-шаблонах)
|
77
|
-
* [Шаблоны с `yield` и вложенные лэйауты](#Шаблоны-с-yield-и-вложенные-лэйауты)
|
78
|
-
* [Включённые шаблоны](#Включённые-шаблоны)
|
79
|
-
* [Именованные шаблоны](#Именованные-шаблоны)
|
80
|
-
* [Привязка файловых расширений](#Привязка-файловых-расширений)
|
81
|
-
* [Добавление собственного движка рендеринга](#Добавление-собственного-движка-рендеринга)
|
82
|
-
* [Использование пользовательской логики для поиска шаблона](#Использование-пользовательской-логики-для-поиска-шаблона)
|
83
|
-
* [Фильтры](#Фильтры)
|
84
|
-
* [Методы-помощники](#Методы-помощники)
|
85
|
-
* [Использование сессий](#Использование-сессий)
|
86
|
-
* [Безопасность сессии](#Безопасность-сессии)
|
87
|
-
* [Конфигурация сессии](#Конфигурация-сессии)
|
88
|
-
* [Выбор вашей собственной "прослойки" сессии](#Выбор-вашей-собственной-прослойки-сессии)
|
89
|
-
* [Прерывание](#Прерывание)
|
90
|
-
* [Передача](#Передача)
|
91
|
-
* [Вызов другого маршрута](#Вызов-другого-маршрута)
|
92
|
-
* [Установка тела, статус кода и заголовков ответа](#Установка-тела-статус-кода-и-заголовков-ответа)
|
93
|
-
* [Потоковые ответы](#Потоковые-ответы)
|
94
|
-
* [Логирование](#Логирование)
|
95
|
-
* [Mime-типы](#mime-типы)
|
96
|
-
* [Генерирование URL](#Генерирование-url)
|
97
|
-
* [Перенаправление (редирект)](#Перенаправление-редирект)
|
98
|
-
* [Управление кэшированием](#Управление-кэшированием)
|
99
|
-
* [Отправка файлов](#Отправка-файлов)
|
100
|
-
* [Доступ к объекту запроса](#Доступ-к-объекту-запроса)
|
101
|
-
* [Вложения](#Вложения)
|
102
|
-
* [Работа со временем и датами](#Работа-со-временем-и-датами)
|
103
|
-
* [Поиск файлов шаблонов](#Поиск-файлов-шаблонов)
|
104
|
-
* [Конфигурация](#Конфигурация)
|
105
|
-
* [Настройка защиты от атак](#Настройка-защиты-от-атак)
|
106
|
-
* [Доступные настройки](#Доступные-настройки)
|
107
|
-
* [Режим, окружение](#Режим-окружение)
|
108
|
-
* [Обработка ошибок](#Обработка-ошибок)
|
109
|
-
* [Not Found](#not-found)
|
110
|
-
* [Error](#error)
|
111
|
-
* [Rack "прослойки"](#rack-прослойки)
|
112
|
-
* [Тестирование](#Тестирование)
|
113
|
-
* [Sinatra::Base — "прослойки", библиотеки и модульные приложения](#sinatrabase--прослойки-библиотеки-и-модульные-приложения)
|
114
|
-
* [Модульные приложения против классических](#Модульные-приложения-против-классических)
|
115
|
-
* [Запуск модульных приложений](#Запуск-модульных-приложений)
|
116
|
-
* [Запуск классических приложений с config.ru](#Запуск-классических-приложений-с-configru)
|
117
|
-
* [Когда использовать config.ru?](#Когда-использовать-configru)
|
118
|
-
* [Использование Sinatra в качестве "прослойки"](#Использование-sinatra-в-качестве-прослойки)
|
119
|
-
* [Создание приложений "на лету"](#Создание-приложений-на-лету)
|
120
|
-
* [Области видимости и привязка](#Области-видимости-и-привязка)
|
121
|
-
* [Область видимости приложения / класса](#Область-видимости-приложения--класса)
|
122
|
-
* [Область видимости запроса / экземпляра](#Область-видимости-запроса--экземпляра)
|
123
|
-
* [Область видимости делегирования](#Область-видимости-делегирования)
|
124
|
-
* [Командная строка](#Командная-строка)
|
125
|
-
* [Многопоточность](#Многопоточность)
|
126
|
-
* [Системные требования](#Системные-требования)
|
127
|
-
* [Самая свежая версия](#Самая-свежая-версия)
|
128
|
-
* [При помощи Bundler](#При-помощи-bundler)
|
129
|
-
* [Версии](#Версии)
|
130
|
-
* [Дальнейшее чтение](#Дальнейшее-чтение)
|
131
|
-
|
132
|
-
## Маршруты
|
133
|
-
|
134
|
-
В Sinatra маршрут — это пара: <HTTP метод> и <шаблон URL>. Каждый маршрут
|
135
|
-
связан с блоком кода:
|
136
|
-
|
137
|
-
```ruby
|
138
|
-
get '/' do
|
139
|
-
# .. что-то показать ..
|
140
|
-
end
|
141
|
-
|
142
|
-
post '/' do
|
143
|
-
# .. что-то создать ..
|
144
|
-
end
|
145
|
-
|
146
|
-
put '/' do
|
147
|
-
# .. что-то заменить ..
|
148
|
-
end
|
149
|
-
|
150
|
-
patch '/' do
|
151
|
-
# .. что-то изменить ..
|
152
|
-
end
|
153
|
-
|
154
|
-
delete '/' do
|
155
|
-
# .. что-то удалить ..
|
156
|
-
end
|
157
|
-
|
158
|
-
options '/' do
|
159
|
-
# .. что-то ответить ..
|
160
|
-
end
|
161
|
-
|
162
|
-
link '/' do
|
163
|
-
# .. что-то подключить ..
|
164
|
-
end
|
165
|
-
|
166
|
-
unlink '/' do
|
167
|
-
# .. что-то отключить ..
|
168
|
-
end
|
169
|
-
```
|
170
|
-
|
171
|
-
Маршруты сверяются с запросом в порядке очерёдности их записи в файле
|
172
|
-
приложения. Первый же совпавший с запросом маршрут и будет вызван.
|
173
|
-
|
174
|
-
Маршруты с конечным слэшем отличаются от маршрутов без него:
|
175
|
-
|
176
|
-
```ruby
|
177
|
-
get '/foo' do
|
178
|
-
# не соответствует "GET /foo/"
|
179
|
-
end
|
180
|
-
```
|
181
|
-
|
182
|
-
Шаблоны маршрутов могут включать в себя именованные параметры, доступные в xэше
|
183
|
-
`params`:
|
184
|
-
|
185
|
-
```ruby
|
186
|
-
get '/hello/:name' do
|
187
|
-
# соответствует "GET /hello/foo" и "GET /hello/bar",
|
188
|
-
# где params['name'] - это 'foo' или 'bar'
|
189
|
-
"Hello #{params['name']}!"
|
190
|
-
end
|
191
|
-
```
|
192
|
-
|
193
|
-
Также можно получить доступ к именованным параметрам через параметры блока:
|
194
|
-
|
195
|
-
```ruby
|
196
|
-
get '/hello/:name' do |n|
|
197
|
-
# соответствует "GET /hello/foo" и "GET /hello/bar",
|
198
|
-
# где params['name'] - это 'foo' или 'bar'
|
199
|
-
# n хранит params['name']
|
200
|
-
"Hello #{n}!"
|
201
|
-
end
|
202
|
-
```
|
203
|
-
|
204
|
-
Шаблоны маршрутов также могут включать в себя splat параметры (или '*' маску,
|
205
|
-
обозначающую любой символ), доступные в массиве `params['splat']`:
|
206
|
-
|
207
|
-
```ruby
|
208
|
-
get '/say/*/to/*' do
|
209
|
-
# соответствует /say/hello/to/world
|
210
|
-
params['splat'] # => ["hello", "world"]
|
211
|
-
end
|
212
|
-
|
213
|
-
get '/download/*.*' do
|
214
|
-
# соответствует /download/path/to/file.xml
|
215
|
-
params['splat'] # => ["path/to/file", "xml"]
|
216
|
-
end
|
217
|
-
```
|
218
|
-
|
219
|
-
Или с параметрами блока:
|
220
|
-
|
221
|
-
```ruby
|
222
|
-
get '/download/*.*' do |path, ext|
|
223
|
-
[path, ext] # => ["path/to/file", "xml"]
|
224
|
-
end
|
225
|
-
```
|
226
|
-
|
227
|
-
Можно также использовать регулярные выражения в качестве шаблонов маршрутов:
|
228
|
-
|
229
|
-
```ruby
|
230
|
-
get /\/hello\/([\w]+)/ do
|
231
|
-
"Hello, #{params['captures'].first}!"
|
232
|
-
end
|
233
|
-
```
|
234
|
-
|
235
|
-
Или с параметром блока:
|
236
|
-
|
237
|
-
```ruby
|
238
|
-
# Соответствует "GET /meta/hello/world", "GET /hello/world/1234" и т.д.
|
239
|
-
get %r{/hello/([\w]+)} do |c|
|
240
|
-
"Hello, #{c}!"
|
241
|
-
end
|
242
|
-
```
|
243
|
-
|
244
|
-
Шаблоны маршрутов могут иметь необязательные параметры:
|
245
|
-
|
246
|
-
```ruby
|
247
|
-
get '/posts/:format?' do
|
248
|
-
# соответствует "GET /posts/", "GET /posts/json", "GET /posts/xml" и т.д.
|
249
|
-
end
|
250
|
-
```
|
251
|
-
|
252
|
-
Маршруты также могут использовать параметры запроса:
|
253
|
-
|
254
|
-
```ruby
|
255
|
-
get '/posts' do
|
256
|
-
# соответствует "GET /posts?title=foo&author=bar"
|
257
|
-
title = params['title']
|
258
|
-
author = params['author']
|
259
|
-
# используются переменные title и author; запрос не обязателен для маршрута /posts
|
260
|
-
end
|
261
|
-
```
|
262
|
-
|
263
|
-
**Имеейте ввиду**: если вы не отключите защиту от обратного пути в директориях
|
264
|
-
(_path traversal_, см. ниже), путь запроса может быть изменён до начала
|
265
|
-
поиска подходящего маршрута.
|
266
|
-
|
267
|
-
Вы можете настроить Mustermann опции, используемые для данного маршрута, путём передачи в `:mustermann_opts` хэш:
|
268
|
-
|
269
|
-
```ruby
|
270
|
-
get '\A/posts\z', :mustermann_opts => { :type => :regexp, :check_anchors => false } do
|
271
|
-
# в точности соответствует /posts, с явной привязкой
|
272
|
-
"If you match an anchored pattern clap your hands!"
|
273
|
-
end
|
274
|
-
```
|
275
|
-
|
276
|
-
Это похоже на [условие](#Условия), но это не так! Эти опции будут объеденины в глобальный `:mustermann_opts` хэш, описанный
|
277
|
-
[ниже](#Доступные-настройки).
|
278
|
-
|
279
|
-
### Условия
|
280
|
-
|
281
|
-
Маршруты могут включать в себя различные условия совпадений, такие как, например,
|
282
|
-
строка агента пользователя (user agent):
|
283
|
-
|
284
|
-
```ruby
|
285
|
-
get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
|
286
|
-
"You're using Songbird version #{params['agent'][0]}"
|
287
|
-
end
|
288
|
-
|
289
|
-
get '/foo' do
|
290
|
-
# соответствует не-songbird браузерам
|
291
|
-
end
|
292
|
-
```
|
293
|
-
|
294
|
-
Другими доступными условиями являются `host_name` и `provides`:
|
295
|
-
|
296
|
-
```ruby
|
297
|
-
get '/', :host_name => /^admin\./ do
|
298
|
-
"Admin Area, Access denied!"
|
299
|
-
end
|
300
|
-
|
301
|
-
get '/', :provides => 'html' do
|
302
|
-
haml :index
|
303
|
-
end
|
304
|
-
|
305
|
-
get '/', :provides => ['rss', 'atom', 'xml'] do
|
306
|
-
builder :feed
|
307
|
-
end
|
308
|
-
```
|
309
|
-
|
310
|
-
`provides` ищет заголовок запроса `Accept`.
|
311
|
-
|
312
|
-
Вы можете с лёгкостью задавать собственные условия:
|
313
|
-
|
314
|
-
```ruby
|
315
|
-
set(:probability) { |value| condition { rand <= value } }
|
316
|
-
|
317
|
-
get '/win_a_car', :probability => 0.1 do
|
318
|
-
"You won!"
|
319
|
-
end
|
320
|
-
|
321
|
-
get '/win_a_car' do
|
322
|
-
"Sorry, you lost."
|
323
|
-
end
|
324
|
-
```
|
325
|
-
|
326
|
-
Ипользуйте splat-оператор (`*`) для условий, которые принимают несколько аргументов:
|
327
|
-
|
328
|
-
```ruby
|
329
|
-
set(:auth) do |*roles| # <- обратите внимание на звёздочку
|
330
|
-
condition do
|
331
|
-
unless logged_in? && roles.any? {|role| current_user.in_role? role }
|
332
|
-
redirect "/login/", 303
|
333
|
-
end
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
|
-
get "/my/account/", :auth => [:user, :admin] do
|
338
|
-
"Your Account Details"
|
339
|
-
end
|
340
|
-
|
341
|
-
get "/only/admin/", :auth => :admin do
|
342
|
-
"Only admins are allowed here!"
|
343
|
-
end
|
344
|
-
```
|
345
|
-
|
346
|
-
### Возвращаемые значения
|
347
|
-
|
348
|
-
Возвращаемое значение блока маршрута ограничивается телом ответа, которое
|
349
|
-
будет передано HTTP клиенту, или, по крайней мере, следующей "прослойке" (middleware)
|
350
|
-
в Rack стеке. Чаще всего это строка как в примерах выше. Но также приемлемы и
|
351
|
-
другие значения.
|
352
|
-
|
353
|
-
Вы можете вернуть любой объект, который будет либо корректным Rack ответом,
|
354
|
-
либо объектом Rack body, либо кодом состояния HTTP:
|
355
|
-
|
356
|
-
* массив с тремя переменными: `[код (Integer), заголовки (Hash), тело ответа
|
357
|
-
(должно отвечать на #each)]`;
|
358
|
-
* массив с двумя переменными: `[код (Integer), тело ответа (должно отвечать
|
359
|
-
на #each)]`;
|
360
|
-
* объект, отвечающий на `#each`, который передает только строковые типы
|
361
|
-
данных в этот блок;
|
362
|
-
* Integer, представляющий код состояния HTTP.
|
363
|
-
|
364
|
-
Таким образом легко можно реализовать, например, потоковую передачу:
|
365
|
-
|
366
|
-
```ruby
|
367
|
-
class Stream
|
368
|
-
def each
|
369
|
-
100.times { |i| yield "#{i}\n" }
|
370
|
-
end
|
371
|
-
end
|
372
|
-
|
373
|
-
get('/') { Stream.new }
|
374
|
-
```
|
375
|
-
|
376
|
-
Вы также можете использовать вспомогательный метод `stream` (описанный ниже)
|
377
|
-
для того, чтобы уменьшить количество шаблонного кода и встроить потоковую
|
378
|
-
логику прямо в маршрут.
|
379
|
-
|
380
|
-
### Собственные детекторы совпадений для маршрутов
|
381
|
-
|
382
|
-
Как показано выше, Sinatra поставляется со встроенной поддержкой строк и
|
383
|
-
регулярных выражений в качестве шаблонов URL. Но и это ещё не всё. Вы можете
|
384
|
-
легко определить свои собственные детекторы совпадений (matchers) для
|
385
|
-
маршрутов:
|
386
|
-
|
387
|
-
```ruby
|
388
|
-
class AllButPattern
|
389
|
-
Match = Struct.new(:captures)
|
390
|
-
|
391
|
-
def initialize(except)
|
392
|
-
@except = except
|
393
|
-
@captures = Match.new([])
|
394
|
-
end
|
395
|
-
|
396
|
-
def match(str)
|
397
|
-
@captures unless @except === str
|
398
|
-
end
|
399
|
-
end
|
400
|
-
|
401
|
-
def all_but(pattern)
|
402
|
-
AllButPattern.new(pattern)
|
403
|
-
end
|
404
|
-
|
405
|
-
get all_but("/index") do
|
406
|
-
# ...
|
407
|
-
end
|
408
|
-
```
|
409
|
-
|
410
|
-
Обратите внимание на то, что предыдущий пример, возможно, чересчур усложнён, потому что он
|
411
|
-
может быть реализован следующим образом:
|
412
|
-
|
413
|
-
```ruby
|
414
|
-
get // do
|
415
|
-
pass if request.path_info == "/index"
|
416
|
-
# ...
|
417
|
-
end
|
418
|
-
```
|
419
|
-
|
420
|
-
Или с использованием негативной опережающей проверки (отрицательное look-ahead условие):
|
421
|
-
|
422
|
-
```ruby
|
423
|
-
get %r{(?!/index)} do
|
424
|
-
# ...
|
425
|
-
end
|
426
|
-
```
|
427
|
-
|
428
|
-
## Статические файлы
|
429
|
-
|
430
|
-
Статические файлы раздаются из `./public` директории. Вы можете указать другое
|
431
|
-
месторасположение при помощи опции `:public_folder`:
|
432
|
-
|
433
|
-
```ruby
|
434
|
-
set :public_folder, __dir__ + '/static'
|
435
|
-
```
|
436
|
-
|
437
|
-
Учтите, что имя директории со статическими файлами не включено в URL.
|
438
|
-
Например, файл `./public/css/style.css` будет доступен как
|
439
|
-
`http://example.com/css/style.css`.
|
440
|
-
|
441
|
-
Используйте опцию `:static_cache_control` (см. ниже) для того, чтобы добавить
|
442
|
-
заголовок `Cache-Control`.
|
443
|
-
|
444
|
-
## Представления / Шаблоны
|
445
|
-
|
446
|
-
Каждый шаблонизатор представлен своим собственным методом. Эти методы попросту
|
447
|
-
возвращают строку:
|
448
|
-
|
449
|
-
```ruby
|
450
|
-
get '/' do
|
451
|
-
erb :index
|
452
|
-
end
|
453
|
-
```
|
454
|
-
|
455
|
-
Данный код отрендерит файл `views/index.erb`.
|
456
|
-
|
457
|
-
Вместо имени шаблона вы так же можете передавать непосредственно само
|
458
|
-
содержимое шаблона:
|
459
|
-
|
460
|
-
```ruby
|
461
|
-
get '/' do
|
462
|
-
code = "<%= Time.now %>"
|
463
|
-
erb code
|
464
|
-
end
|
465
|
-
```
|
466
|
-
|
467
|
-
Метод рендеринга шаблона принимает в качестве второго аргумента хэш с опциями:
|
468
|
-
|
469
|
-
```ruby
|
470
|
-
get '/' do
|
471
|
-
erb :index, :layout => :post
|
472
|
-
end
|
473
|
-
```
|
474
|
-
|
475
|
-
Данный метод отрендерит шаблон `views/index.erb`, который будет вложен в `views/post.erb`
|
476
|
-
(по умолчанию: `views/layout.erb`, если файл существует).
|
477
|
-
|
478
|
-
Любые опции, которые Sinatra не распознает, будут переданы в шаблонизатор:
|
479
|
-
|
480
|
-
```ruby
|
481
|
-
get '/' do
|
482
|
-
haml :index, :format => :html5
|
483
|
-
end
|
484
|
-
```
|
485
|
-
|
486
|
-
Вы также можете глобально задавать опции для шаблонизаторов:
|
487
|
-
|
488
|
-
```ruby
|
489
|
-
set :haml, :format => :html5
|
490
|
-
|
491
|
-
get '/' do
|
492
|
-
haml :index
|
493
|
-
end
|
494
|
-
```
|
495
|
-
|
496
|
-
Опции, переданные в метод, переопределяют опции, заданные при помощи `set`.
|
497
|
-
|
498
|
-
Доступные опции:
|
499
|
-
|
500
|
-
<dl>
|
501
|
-
<dt>locals</dt>
|
502
|
-
<dd>
|
503
|
-
Список локальных переменных, передаваемых в документ.
|
504
|
-
Пример: <tt>erb "<%= foo %>", :locals => {:foo => "bar"}</tt>
|
505
|
-
</dd>
|
506
|
-
|
507
|
-
<dt>default_encoding</dt>
|
508
|
-
<dd>
|
509
|
-
Кодировка, которую следует использовать в том случае, если не удалось
|
510
|
-
определить оригинальную. По умолчанию: <tt>settings.default_encoding</tt>.
|
511
|
-
</dd>
|
512
|
-
|
513
|
-
<dt>views</dt>
|
514
|
-
<dd>
|
515
|
-
Директория с шаблонами. По умолчанию: <tt>settings.views</tt>.
|
516
|
-
</dd>
|
517
|
-
|
518
|
-
<dt>layout</dt>
|
519
|
-
<dd>
|
520
|
-
Определяет необходимость использования лэйаута (<tt>true</tt> или <tt>false</tt>).
|
521
|
-
Если же в качестве значения передан символ, то его значение будет интерпретировано
|
522
|
-
как наименования файла шаблона лэйаута.
|
523
|
-
Пример: <tt>erb :index, :layout => !request.xhr?</tt>
|
524
|
-
</dd>
|
525
|
-
|
526
|
-
<dt>content_type</dt>
|
527
|
-
<dd>
|
528
|
-
Content-Type отображенного шаблона. По умолчанию: задаётся шаблонизатором.
|
529
|
-
</dd>
|
530
|
-
|
531
|
-
<dt>scope</dt>
|
532
|
-
<dd>
|
533
|
-
Область видимости, в которой рендерятся шаблоны. По умолчанию: экземпляр
|
534
|
-
приложения. Если вы измените эту опцию, то переменные экземпляра и
|
535
|
-
методы-помощники станут недоступными в ваших шаблонах.
|
536
|
-
</dd>
|
537
|
-
|
538
|
-
<dt>layout_engine</dt>
|
539
|
-
<dd>
|
540
|
-
Шаблонизатор, который следует использовать для отображения лэйаута.
|
541
|
-
Полезная опция для шаблонизаторов, в которых отсутствует поддержка
|
542
|
-
лэйаутов. По умолчанию: тот же шаблонизатор, что используется и для самого
|
543
|
-
шаблона. Пример: <tt>set :rdoc, :layout_engine => :erb</tt>
|
544
|
-
</dd>
|
545
|
-
|
546
|
-
<dt>layout_options</dt>
|
547
|
-
<dd>
|
548
|
-
Специальные опции, используемые только для рендеринга лэйаута. Пример:
|
549
|
-
<tt>set :rdoc, :layout_options => { :views => 'views/layouts' }</tt>
|
550
|
-
</dd>
|
551
|
-
</dl>
|
552
|
-
|
553
|
-
По умолчанию в качестве пути для хранения шаблонов принята директория `./views`.
|
554
|
-
Чтобы назначить другую директорию с шаблонами необходимо изменить настройки:
|
555
|
-
|
556
|
-
```ruby
|
557
|
-
set :views, settings.root + '/templates'
|
558
|
-
```
|
559
|
-
|
560
|
-
Важное замечание: вы всегда должны ссылаться на шаблоны при помощи символов
|
561
|
-
(Symbol), даже тогда, когда они расположены в поддиректории (в этом случае
|
562
|
-
используйте конструкции вида `:'subdir/template'`). Вы должны использовать
|
563
|
-
символы в связи с тем, что в ином случае шаблонизаторы попросту отображают
|
564
|
-
любые строки, переданные им.
|
565
|
-
|
566
|
-
### Буквальные шаблоны
|
567
|
-
|
568
|
-
```ruby
|
569
|
-
get '/' do
|
570
|
-
haml '%div.title Hello World'
|
571
|
-
end
|
572
|
-
```
|
573
|
-
|
574
|
-
Отобразит шаблон, содержимое которого передано строкой. Опционально можно
|
575
|
-
указать дополнительные опции `:path` и `:line` для того, чтобы улучшить бэктрейс.
|
576
|
-
Делайте это в том случае, если строка определена в некотором файле, к которому
|
577
|
-
можно указать путь и номер строки, где расположена исходная строка:
|
578
|
-
|
579
|
-
```ruby
|
580
|
-
get '/' do
|
581
|
-
haml '%div.title Hello World', :path => 'examples/file.haml', :line => 3
|
582
|
-
end
|
583
|
-
```
|
584
|
-
|
585
|
-
### Доступные шаблонизаторы
|
586
|
-
|
587
|
-
Некоторые языки шаблонов имеют несколько реализаций. Для того, чтобы указать
|
588
|
-
конкретную реализацию, которую вы хотите использовать, вам следует просто
|
589
|
-
подключить нужную библиотеку:
|
590
|
-
|
591
|
-
```ruby
|
592
|
-
require 'rdiscount' # или require 'bluecloth'
|
593
|
-
get('/') { markdown :index }
|
594
|
-
```
|
595
|
-
|
596
|
-
#### Haml шаблоны
|
597
|
-
|
598
|
-
<table>
|
599
|
-
<tr>
|
600
|
-
<td>Зависимости</td>
|
601
|
-
<td><a href="http://haml.info/" title="haml">haml</a></td>
|
602
|
-
</tr>
|
603
|
-
<tr>
|
604
|
-
<td>Расширения файлов</td>
|
605
|
-
<td><tt>.haml</tt></td>
|
606
|
-
</tr>
|
607
|
-
<tr>
|
608
|
-
<td>Пример</td>
|
609
|
-
<td><tt>haml :index, :format => :html5</tt></td>
|
610
|
-
</tr>
|
611
|
-
</table>
|
612
|
-
|
613
|
-
#### Erb шаблоны
|
614
|
-
|
615
|
-
<table>
|
616
|
-
<tr>
|
617
|
-
<td>Зависимости</td>
|
618
|
-
<td>
|
619
|
-
<a href="http://www.kuwata-lab.com/erubis/" title="erubis">erubis</a>
|
620
|
-
или erb (включён в Ruby)
|
621
|
-
</td>
|
622
|
-
</tr>
|
623
|
-
<tr>
|
624
|
-
<td>Расширения файлов</td>
|
625
|
-
<td><tt>.erb</tt>, <tt>.rhtml</tt> or <tt>.erubis</tt> (только Erubis)</td>
|
626
|
-
</tr>
|
627
|
-
<tr>
|
628
|
-
<td>Пример</td>
|
629
|
-
<td><tt>erb :index</tt></td>
|
630
|
-
</tr>
|
631
|
-
</table>
|
632
|
-
|
633
|
-
#### Builder шаблоны
|
634
|
-
|
635
|
-
<table>
|
636
|
-
<tr>
|
637
|
-
<td>Зависимости</td>
|
638
|
-
<td>
|
639
|
-
<a href="https://github.com/jimweirich/builder" title="builder">builder</a>
|
640
|
-
</td>
|
641
|
-
</tr>
|
642
|
-
<tr>
|
643
|
-
<td>Расширения файлов</td>
|
644
|
-
<td><tt>.builder</tt></td>
|
645
|
-
</tr>
|
646
|
-
<tr>
|
647
|
-
<td>Пример</td>
|
648
|
-
<td><tt>builder { |xml| xml.em "hi" }</tt></td>
|
649
|
-
</tr>
|
650
|
-
</table>
|
651
|
-
|
652
|
-
Шаблонизатор также принимает блоки для включённых шаблонов ([см. пример](#Включённые-шаблоны)).
|
653
|
-
|
654
|
-
#### Nokogiri шаблоны
|
655
|
-
|
656
|
-
<table>
|
657
|
-
<tr>
|
658
|
-
<td>Зависимости</td>
|
659
|
-
<td><a href="http://www.nokogiri.org/" title="nokogiri">nokogiri</a></td>
|
660
|
-
</tr>
|
661
|
-
<tr>
|
662
|
-
<td>Расширения файлов</td>
|
663
|
-
<td><tt>.nokogiri</tt></td>
|
664
|
-
</tr>
|
665
|
-
<tr>
|
666
|
-
<td>Пример</td>
|
667
|
-
<td><tt>nokogiri { |xml| xml.em "hi" }</tt></td>
|
668
|
-
</tr>
|
669
|
-
</table>
|
670
|
-
|
671
|
-
Шаблонизатор также принимает блоки для включённых шаблонов ([см. пример](#Включённые-шаблоны)).
|
672
|
-
|
673
|
-
#### Sass шаблоны
|
674
|
-
|
675
|
-
<table>
|
676
|
-
<tr>
|
677
|
-
<td>Зависимости</td>
|
678
|
-
<td><a href="https://sass-lang.com/" title="sass">sass</a></td>
|
679
|
-
</tr>
|
680
|
-
<tr>
|
681
|
-
<td>Расширения файлов</td>
|
682
|
-
<td><tt>.sass</tt></td>
|
683
|
-
</tr>
|
684
|
-
<tr>
|
685
|
-
<td>Пример</td>
|
686
|
-
<td><tt>sass :stylesheet, :style => :expanded</tt></td>
|
687
|
-
</tr>
|
688
|
-
</table>
|
689
|
-
|
690
|
-
#### SCSS шаблоны
|
691
|
-
|
692
|
-
<table>
|
693
|
-
<tr>
|
694
|
-
<td>Зависимости</td>
|
695
|
-
<td><a href="https://sass-lang.com/" title="sass">sass</a></td>
|
696
|
-
</tr>
|
697
|
-
<tr>
|
698
|
-
<td>Расширения файлов</td>
|
699
|
-
<td><tt>.scss</tt></td>
|
700
|
-
</tr>
|
701
|
-
<tr>
|
702
|
-
<td>Пример</td>
|
703
|
-
<td><tt>scss :stylesheet, :style => :expanded</tt></td>
|
704
|
-
</tr>
|
705
|
-
</table>
|
706
|
-
|
707
|
-
#### Less шаблоны
|
708
|
-
|
709
|
-
<table>
|
710
|
-
<tr>
|
711
|
-
<td>Зависимости</td>
|
712
|
-
<td><a href="http://lesscss.org/" title="less">less</a></td>
|
713
|
-
</tr>
|
714
|
-
<tr>
|
715
|
-
<td>Расширения файлов</td>
|
716
|
-
<td><tt>.less</tt></td>
|
717
|
-
</tr>
|
718
|
-
<tr>
|
719
|
-
<td>Пример</td>
|
720
|
-
<td><tt>less :stylesheet</tt></td>
|
721
|
-
</tr>
|
722
|
-
</table>
|
723
|
-
|
724
|
-
#### Liquid шаблоны
|
725
|
-
|
726
|
-
<table>
|
727
|
-
<tr>
|
728
|
-
<td>Зависимости</td>
|
729
|
-
<td><a href="https://shopify.github.io/liquid/" title="liquid">liquid</a></td>
|
730
|
-
</tr>
|
731
|
-
<tr>
|
732
|
-
<td>Расширения файлов</td>
|
733
|
-
<td><tt>.liquid</tt></td>
|
734
|
-
</tr>
|
735
|
-
<tr>
|
736
|
-
<td>Пример</td>
|
737
|
-
<td><tt>liquid :index, :locals => { :key => 'value' }</tt></td>
|
738
|
-
</tr>
|
739
|
-
</table>
|
740
|
-
|
741
|
-
В связи с тем, что в Liquid шаблонах невозможно вызывать методы из Ruby
|
742
|
-
(за исключением `yield`), вам почти всегда понадобиться передавать в шаблон
|
743
|
-
локальные переменные.
|
744
|
-
|
745
|
-
#### Markdown шаблоны
|
746
|
-
|
747
|
-
<table>
|
748
|
-
<tr>
|
749
|
-
<td>Зависимости</td>
|
750
|
-
<td>
|
751
|
-
Любая из библиотек:
|
752
|
-
<a href="https://github.com/davidfstr/rdiscount" title="RDiscount">RDiscount</a>,
|
753
|
-
<a href="https://github.com/vmg/redcarpet" title="RedCarpet">RedCarpet</a>,
|
754
|
-
<a href="https://github.com/ged/bluecloth" title="bluecloth">BlueCloth</a>,
|
755
|
-
<a href="https://kramdown.gettalong.org/" title="kramdown">kramdown</a>,
|
756
|
-
<a href="https://github.com/bhollis/maruku" title="maruku">maruku</a>
|
757
|
-
</td>
|
758
|
-
</tr>
|
759
|
-
<tr>
|
760
|
-
<td>Расширения файлов</td>
|
761
|
-
<td><tt>.markdown</tt>, <tt>.mkd</tt> and <tt>.md</tt></td>
|
762
|
-
</tr>
|
763
|
-
<tr>
|
764
|
-
<td>Пример</td>
|
765
|
-
<td><tt>markdown :index, :layout_engine => :erb</tt></td>
|
766
|
-
</tr>
|
767
|
-
</table>
|
768
|
-
|
769
|
-
В Markdown невозможно вызывать методы или передавать локальные переменные.
|
770
|
-
По этой причине вам, скорее всего, придётся использовать этот шаблон совместно
|
771
|
-
с другим шаблонизатором:
|
772
|
-
|
773
|
-
```ruby
|
774
|
-
erb :overview, :locals => { :text => markdown(:introduction) }
|
775
|
-
```
|
776
|
-
|
777
|
-
Обратите внимание на то, что вы можете вызывать метод `markdown` из других шаблонов:
|
778
|
-
|
779
|
-
```ruby
|
780
|
-
%h1 Hello From Haml!
|
781
|
-
%p= markdown(:greetings)
|
782
|
-
```
|
783
|
-
|
784
|
-
Вы не можете вызывать Ruby код код из Markdown, соответственно вы не можете
|
785
|
-
использовать лэйауты на Markdown. Тем не менее, существует возможность использовать
|
786
|
-
один шаблонизатор для отображения шаблона, а другой для лэйаута при помощи
|
787
|
-
опции `:layout_engine`.
|
788
|
-
|
789
|
-
#### Textile шаблоны
|
790
|
-
|
791
|
-
<table>
|
792
|
-
<tr>
|
793
|
-
<td>Зависимости</td>
|
794
|
-
<td><a href="http://redcloth.org/" title="RedCloth">RedCloth</a></td>
|
795
|
-
</tr>
|
796
|
-
<tr>
|
797
|
-
<td>Расширения файлов</td>
|
798
|
-
<td><tt>.textile</tt></td>
|
799
|
-
</tr>
|
800
|
-
<tr>
|
801
|
-
<td>Пример</td>
|
802
|
-
<td><tt>textile :index, :layout_engine => :erb</tt></td>
|
803
|
-
</tr>
|
804
|
-
</table>
|
805
|
-
|
806
|
-
В Textile невозможно вызывать методы или передавать локальные переменные.
|
807
|
-
Следовательно, вам, скорее всего, придётся использовать данный шаблон
|
808
|
-
совместно с другим шаблонизатором:
|
809
|
-
|
810
|
-
```ruby
|
811
|
-
erb :overview, :locals => { :text => textile(:introduction) }
|
812
|
-
```
|
813
|
-
|
814
|
-
Обратите внимание на то, что вы можете вызывать метод `textile` из других шаблонов:
|
815
|
-
|
816
|
-
```ruby
|
817
|
-
%h1 Hello From Haml!
|
818
|
-
%p= textile(:greetings)
|
819
|
-
```
|
820
|
-
|
821
|
-
Вы не можете вызывать Ruby код код из Textile, соответственно вы не можете
|
822
|
-
использовать лэйауты на Textile. Тем не менее, существует возможность использовать
|
823
|
-
один шаблонизатор для отображения шаблона, а другой для лэйаута при помощи
|
824
|
-
опции `:layout_engine`.
|
825
|
-
|
826
|
-
#### RDoc шаблоны
|
827
|
-
|
828
|
-
<table>
|
829
|
-
<tr>
|
830
|
-
<td>Зависимости</td>
|
831
|
-
<td><a href="http://rdoc.sourceforge.net/" title="RDoc">RDoc</a></td>
|
832
|
-
</tr>
|
833
|
-
<tr>
|
834
|
-
<td>Расширения файлов</td>
|
835
|
-
<td><tt>.rdoc</tt></td>
|
836
|
-
</tr>
|
837
|
-
<tr>
|
838
|
-
<td>Пример</td>
|
839
|
-
<td><tt>rdoc :README, :layout_engine => :erb</tt></td>
|
840
|
-
</tr>
|
841
|
-
</table>
|
842
|
-
|
843
|
-
В RDoc невозможно вызывать методы или передавать локальные переменные.
|
844
|
-
Следовательно, вам, скорее всего, придётся использовать этот шаблон совместно
|
845
|
-
с другим шаблонизатором:
|
846
|
-
|
847
|
-
```ruby
|
848
|
-
erb :overview, :locals => { :text => rdoc(:introduction) }
|
849
|
-
```
|
850
|
-
|
851
|
-
Обратите внимание на то, что вы можете вызывать метод `rdoc` из других шаблонов:
|
852
|
-
|
853
|
-
```ruby
|
854
|
-
%h1 Hello From Haml!
|
855
|
-
%p= rdoc(:greetings)
|
856
|
-
```
|
857
|
-
|
858
|
-
Вы не можете вызывать Ruby код код из RDoc, соответственно вы не можете использовать
|
859
|
-
лэйауты на RDoc. Тем не менее, существует возможность использовать один шаблонизатор
|
860
|
-
для отображения шаблона, а другой для лэйаута при помощи опции
|
861
|
-
`:layout_engine`.
|
862
|
-
|
863
|
-
#### AsciiDoc шаблоны
|
864
|
-
|
865
|
-
<table>
|
866
|
-
<tr>
|
867
|
-
<td>Зависимости</td>
|
868
|
-
<td><a href="http://asciidoctor.org/" title="Asciidoctor">Asciidoctor</a></td>
|
869
|
-
</tr>
|
870
|
-
<tr>
|
871
|
-
<td>Расширения файлов</td>
|
872
|
-
<td><tt>.asciidoc</tt>, <tt>.adoc</tt> и <tt>.ad</tt></td>
|
873
|
-
</tr>
|
874
|
-
<tr>
|
875
|
-
<td>Пример</td>
|
876
|
-
<td><tt>asciidoc :README, :layout_engine => :erb</tt></td>
|
877
|
-
</tr>
|
878
|
-
</table>
|
879
|
-
|
880
|
-
Так как в AsciiDoc шаблонах невозможно вызывать методы из Ruby напрямую, то вы
|
881
|
-
почти всегда будете передавать в шаблон локальные переменные.
|
882
|
-
|
883
|
-
#### Radius шаблоны
|
884
|
-
|
885
|
-
<table>
|
886
|
-
<tr>
|
887
|
-
<td>Зависимости</td>
|
888
|
-
<td><a href="https://github.com/jlong/radius" title="Radius">Radius</a></td>
|
889
|
-
</tr>
|
890
|
-
<tr>
|
891
|
-
<td>Расширения файлов</td>
|
892
|
-
<td><tt>.radius</tt></td>
|
893
|
-
</tr>
|
894
|
-
<tr>
|
895
|
-
<td>Пример</td>
|
896
|
-
<td><tt>radius :index, :locals => { :key => 'value' }</tt></td>
|
897
|
-
</tr>
|
898
|
-
</table>
|
899
|
-
|
900
|
-
Так как в Radius шаблонах невозможно вызывать методы из Ruby напрямую, то вы
|
901
|
-
почти всегда будете передавать в шаблон локальные переменные.
|
902
|
-
|
903
|
-
#### Markaby шаблоны
|
904
|
-
|
905
|
-
<table>
|
906
|
-
<tr>
|
907
|
-
<td>Зависимости</td>
|
908
|
-
<td><a href="https://markaby.github.io/" title="Markaby">Markaby</a></td>
|
909
|
-
</tr>
|
910
|
-
<tr>
|
911
|
-
<td>Расширения файлов</td>
|
912
|
-
<td><tt>.mab</tt></td>
|
913
|
-
</tr>
|
914
|
-
<tr>
|
915
|
-
<td>Пример</td>
|
916
|
-
<td><tt>markaby { h1 "Welcome!" }</tt></td>
|
917
|
-
</tr>
|
918
|
-
</table>
|
919
|
-
|
920
|
-
Шаблонизатор также принимает блоки для включённых шаблонов ([см. пример](#Включённые-шаблоны)).
|
921
|
-
|
922
|
-
#### RABL шаблоны
|
923
|
-
|
924
|
-
<table>
|
925
|
-
<tr>
|
926
|
-
<td>Зависимости</td>
|
927
|
-
<td><a href="https://github.com/nesquena/rabl" title="Rabl">Rabl</a></td>
|
928
|
-
</tr>
|
929
|
-
<tr>
|
930
|
-
<td>Расширения файлов</td>
|
931
|
-
<td><tt>.rabl</tt></td>
|
932
|
-
</tr>
|
933
|
-
<tr>
|
934
|
-
<td>Пример</td>
|
935
|
-
<td><tt>rabl :index</tt></td>
|
936
|
-
</tr>
|
937
|
-
</table>
|
938
|
-
|
939
|
-
#### Slim шаблоны
|
940
|
-
|
941
|
-
<table>
|
942
|
-
<tr>
|
943
|
-
<td>Зависимости</td>
|
944
|
-
<td><a href="http://slim-lang.com/" title="Slim Lang">Slim Lang</a></td>
|
945
|
-
</tr>
|
946
|
-
<tr>
|
947
|
-
<td>Расширения файлов</td>
|
948
|
-
<td><tt>.slim</tt></td>
|
949
|
-
</tr>
|
950
|
-
<tr>
|
951
|
-
<td>Пример</td>
|
952
|
-
<td><tt>slim :index</tt></td>
|
953
|
-
</tr>
|
954
|
-
</table>
|
955
|
-
|
956
|
-
#### Creole шаблоны
|
957
|
-
|
958
|
-
<table>
|
959
|
-
<tr>
|
960
|
-
<td>Зависимости</td>
|
961
|
-
<td><a href="https://github.com/minad/creole" title="Creole">Creole</a></td>
|
962
|
-
</tr>
|
963
|
-
<tr>
|
964
|
-
<td>Расширения файлов</td>
|
965
|
-
<td><tt>.creole</tt></td>
|
966
|
-
</tr>
|
967
|
-
<tr>
|
968
|
-
<td>Пример</td>
|
969
|
-
<td><tt>creole :wiki, :layout_engine => :erb</tt></td>
|
970
|
-
</tr>
|
971
|
-
</table>
|
972
|
-
|
973
|
-
В Creole невозможно вызывать методы или передавать локальные переменные.
|
974
|
-
Следовательно, вам, скорее всего, придётся использовать данный шаблон совместно
|
975
|
-
с другим шаблонизатором:
|
976
|
-
|
977
|
-
```ruby
|
978
|
-
erb :overview, :locals => { :text => creole(:introduction) }
|
979
|
-
```
|
980
|
-
|
981
|
-
обратите внимание на то, что вы можете вызывать метод `creole` из других шаблонов:
|
982
|
-
|
983
|
-
```ruby
|
984
|
-
%h1 Hello From Haml!
|
985
|
-
%p= creole(:greetings)
|
986
|
-
```
|
987
|
-
|
988
|
-
Вы не можете вызывать Ruby код из Creole, соответственно вы не можете
|
989
|
-
использовать лэйауты на Creole. Тем не менее, существует возможность использовать
|
990
|
-
один шаблонизатор для отображения шаблона, а другой для лэйаута при помощи
|
991
|
-
опции `:layout_engine`.
|
992
|
-
|
993
|
-
#### MediaWiki шаблоны
|
994
|
-
|
995
|
-
<table>
|
996
|
-
<tr>
|
997
|
-
<td>Зависимости</td>
|
998
|
-
<td><a href="https://github.com/nricciar/wikicloth" title="WikiCloth">WikiCloth</a></td>
|
999
|
-
</tr>
|
1000
|
-
<tr>
|
1001
|
-
<td>Расширения файлов</td>
|
1002
|
-
<td><tt>.mediawiki</tt> и <tt>.mw</tt></td>
|
1003
|
-
</tr>
|
1004
|
-
<tr>
|
1005
|
-
<td>Пример</td>
|
1006
|
-
<td><tt>mediawiki :wiki, :layout_engine => :erb</tt></td>
|
1007
|
-
</tr>
|
1008
|
-
</table>
|
1009
|
-
|
1010
|
-
В разметке MediaWiki невозможно вызывать методы или передавать локальные переменные.
|
1011
|
-
Следовательно, вам, скорее всего, придётся использовать этот шаблон совместно
|
1012
|
-
с другим шаблонизатором:
|
1013
|
-
|
1014
|
-
```ruby
|
1015
|
-
erb :overview, :locals => { :text => mediawiki(:introduction) }
|
1016
|
-
```
|
1017
|
-
|
1018
|
-
Обратите внимание на то, что вы можете вызывать метод `mediawiki` из других шаблонов:
|
1019
|
-
|
1020
|
-
```ruby
|
1021
|
-
%h1 Hello From Haml!
|
1022
|
-
%p= mediawiki(:greetings)
|
1023
|
-
```
|
1024
|
-
|
1025
|
-
Вы не можете вызывать Ruby код из MediaWiki, соответственно вы не можете
|
1026
|
-
использовать лэйауты на MediaWiki. Тем не менее, существует возможность использовать
|
1027
|
-
один шаблонизатор для отображения шаблона, а другой для лэйаута при помощи
|
1028
|
-
опции `:layout_engine`.
|
1029
|
-
|
1030
|
-
#### CoffeeScript шаблоны
|
1031
|
-
|
1032
|
-
<table>
|
1033
|
-
<tr>
|
1034
|
-
<td>Зависимости</td>
|
1035
|
-
<td>
|
1036
|
-
<a href="https://github.com/josh/ruby-coffee-script" title="Ruby CoffeeScript">
|
1037
|
-
CoffeeScript
|
1038
|
-
</a> и
|
1039
|
-
<a href="https://github.com/sstephenson/execjs" title="ExecJS">
|
1040
|
-
способ запускать JavaScript
|
1041
|
-
</a>
|
1042
|
-
</td>
|
1043
|
-
</tr>
|
1044
|
-
<tr>
|
1045
|
-
<td>Расширения файлов</td>
|
1046
|
-
<td><tt>.coffee</tt></td>
|
1047
|
-
</tr>
|
1048
|
-
<tr>
|
1049
|
-
<td>Пример</td>
|
1050
|
-
<td><tt>coffee :index</tt></td>
|
1051
|
-
</tr>
|
1052
|
-
</table>
|
1053
|
-
|
1054
|
-
#### Stylus шаблоны
|
1055
|
-
|
1056
|
-
<table>
|
1057
|
-
<tr>
|
1058
|
-
<td>Зависимости</td>
|
1059
|
-
<td>
|
1060
|
-
<a href="https://github.com/forgecrafted/ruby-stylus" title="Ruby Stylus">
|
1061
|
-
Stylus
|
1062
|
-
</a> и
|
1063
|
-
<a href="https://github.com/sstephenson/execjs" title="ExecJS">
|
1064
|
-
способ запускать JavaScript
|
1065
|
-
</a>
|
1066
|
-
</td>
|
1067
|
-
</tr>
|
1068
|
-
<tr>
|
1069
|
-
<td>Расширение файла</td>
|
1070
|
-
<td><tt>.styl</tt></td>
|
1071
|
-
</tr>
|
1072
|
-
<tr>
|
1073
|
-
<td>Пример</td>
|
1074
|
-
<td><tt>stylus :index</tt></td>
|
1075
|
-
</tr>
|
1076
|
-
</table>
|
1077
|
-
|
1078
|
-
Перед тем, как использовать шаблоны Stylus, необходимо сперва подключить
|
1079
|
-
`stylus` и `stylus/tilt`:
|
1080
|
-
|
1081
|
-
```ruby
|
1082
|
-
require 'sinatra'
|
1083
|
-
require 'stylus'
|
1084
|
-
require 'stylus/tilt'
|
1085
|
-
|
1086
|
-
get '/' do
|
1087
|
-
stylus :example
|
1088
|
-
end
|
1089
|
-
```
|
1090
|
-
|
1091
|
-
#### Yajl шаблоны
|
1092
|
-
|
1093
|
-
<table>
|
1094
|
-
<tr>
|
1095
|
-
<td>Зависимости</td>
|
1096
|
-
<td><a href="https://github.com/brianmario/yajl-ruby" title="yajl-ruby">yajl-ruby</a></td>
|
1097
|
-
</tr>
|
1098
|
-
<tr>
|
1099
|
-
<td>Расширения файлов</td>
|
1100
|
-
<td><tt>.yajl</tt></td>
|
1101
|
-
</tr>
|
1102
|
-
<tr>
|
1103
|
-
<td>Пример</td>
|
1104
|
-
<td>
|
1105
|
-
<tt>
|
1106
|
-
yajl :index,
|
1107
|
-
:locals => { :key => 'qux' },
|
1108
|
-
:callback => 'present',
|
1109
|
-
:variable => 'resource'
|
1110
|
-
</tt>
|
1111
|
-
</td>
|
1112
|
-
</tr>
|
1113
|
-
</table>
|
1114
|
-
|
1115
|
-
Содержимое шаблона интерпретируется как код на Ruby, а результирующая
|
1116
|
-
переменная json затем конвертируется при помощи `#to_json`.
|
1117
|
-
|
1118
|
-
```ruby
|
1119
|
-
json = { :foo => 'bar' }
|
1120
|
-
json[:baz] = key
|
1121
|
-
```
|
1122
|
-
|
1123
|
-
Опции `:callback` и `:variable` используются для "декорирования" итогового
|
1124
|
-
объекта:
|
1125
|
-
|
1126
|
-
```ruby
|
1127
|
-
var resource = {"foo":"bar","baz":"qux"};
|
1128
|
-
present(resource);
|
1129
|
-
```
|
1130
|
-
|
1131
|
-
#### WLang шаблоны
|
1132
|
-
|
1133
|
-
<table>
|
1134
|
-
<tr>
|
1135
|
-
<td>Зависимости</td>
|
1136
|
-
<td><a href="https://github.com/blambeau/wlang" title="WLang">WLang</a></td>
|
1137
|
-
</tr>
|
1138
|
-
<tr>
|
1139
|
-
<td>Расширения файлов</td>
|
1140
|
-
<td><tt>.wlang</tt></td>
|
1141
|
-
</tr>
|
1142
|
-
<tr>
|
1143
|
-
<td>Пример</td>
|
1144
|
-
<td><tt>wlang :index, :locals => { :key => 'value' }</tt></td>
|
1145
|
-
</tr>
|
1146
|
-
</table>
|
1147
|
-
|
1148
|
-
Так как в WLang шаблонах невозможно вызывать методы из Ruby напрямую (за
|
1149
|
-
исключением `yield`), то вы почти всегда будете передавать в шаблон локальные
|
1150
|
-
переменные. Лэйауты также могут быть описаны при помощи WLang.
|
1151
|
-
|
1152
|
-
### Доступ к переменным в шаблонах
|
1153
|
-
|
1154
|
-
Шаблоны интерпретируются в том же контексте, что и обработчики маршрутов.
|
1155
|
-
Переменные экземпляра, установленные в процессе обработки маршрутов, будут
|
1156
|
-
доступны напрямую в шаблонах:
|
1157
|
-
|
1158
|
-
```ruby
|
1159
|
-
get '/:id' do
|
1160
|
-
@foo = Foo.find(params['id'])
|
1161
|
-
haml '%h1= @foo.name'
|
1162
|
-
end
|
1163
|
-
```
|
1164
|
-
|
1165
|
-
Вы также можете установить их при помощи хэша локальных переменных:
|
1166
|
-
|
1167
|
-
```ruby
|
1168
|
-
get '/:id' do
|
1169
|
-
foo = Foo.find(params['id'])
|
1170
|
-
haml '%h1= bar.name', :locals => { :bar => foo }
|
1171
|
-
end
|
1172
|
-
```
|
1173
|
-
|
1174
|
-
Это обычный подход, применяемый тогда, когда шаблоны рендерятся как части других шаблонов.
|
1175
|
-
|
1176
|
-
### Шаблоны с `yield` и вложенные лэйауты
|
1177
|
-
|
1178
|
-
Лэйаут (layout) обычно представляет собой шаблон, который исполняет
|
1179
|
-
`yield`. Такой шаблон может быть использован либо при помощи опции `:template`,
|
1180
|
-
как описано выше, либо при помощи блока:
|
1181
|
-
|
1182
|
-
```ruby
|
1183
|
-
erb :post, :layout => false do
|
1184
|
-
erb :index
|
1185
|
-
end
|
1186
|
-
```
|
1187
|
-
|
1188
|
-
Эти инструкции по сути эквивалентны `erb :index, :layout => :post`.
|
1189
|
-
|
1190
|
-
Передача блоков интерпретирующим шаблоны методам наиболее полезна для
|
1191
|
-
создания вложенных лэйаутов:
|
1192
|
-
|
1193
|
-
```ruby
|
1194
|
-
erb :main_layout, :layout => false do
|
1195
|
-
erb :admin_layout do
|
1196
|
-
erb :user
|
1197
|
-
end
|
1198
|
-
end
|
1199
|
-
```
|
1200
|
-
|
1201
|
-
То же самое может быть сделано в более короткой форме:
|
1202
|
-
|
1203
|
-
```ruby
|
1204
|
-
erb :admin_layout, :layout => :main_layout do
|
1205
|
-
erb :user
|
1206
|
-
end
|
1207
|
-
```
|
1208
|
-
|
1209
|
-
В настоящее время следующие методы шаблонизаторов
|
1210
|
-
принимают блок: `erb`, `haml`, `liquid`, `slim `, `wlang`. Кроме того,
|
1211
|
-
общий метод построения шаблонов `render` также принимает блок.
|
1212
|
-
|
1213
|
-
### Включённые шаблоны
|
1214
|
-
|
1215
|
-
Шаблоны также могут быть определены в конце исходного файла:
|
1216
|
-
|
1217
|
-
```ruby
|
1218
|
-
require 'sinatra'
|
1219
|
-
|
1220
|
-
get '/' do
|
1221
|
-
haml :index
|
1222
|
-
end
|
1223
|
-
|
1224
|
-
__END__
|
1225
|
-
|
1226
|
-
@@ layout
|
1227
|
-
%html
|
1228
|
-
= yield
|
1229
|
-
|
1230
|
-
@@ index
|
1231
|
-
%div.title Hello world.
|
1232
|
-
```
|
1233
|
-
|
1234
|
-
Обратите внимание: включённые шаблоны, определённые в исходном файле, который подключил
|
1235
|
-
Sinatra, будут загружены автоматически. Вызовите `enable :inline_templates`
|
1236
|
-
напрямую в том случае, если используете включённые шаблоны в других файлах.
|
1237
|
-
|
1238
|
-
### Именованные шаблоны
|
1239
|
-
|
1240
|
-
Шаблоны также могут быть определены при помощи метода `template`:
|
1241
|
-
|
1242
|
-
```ruby
|
1243
|
-
template :layout do
|
1244
|
-
"%html\n =yield\n"
|
1245
|
-
end
|
1246
|
-
|
1247
|
-
template :index do
|
1248
|
-
'%div.title Hello World!'
|
1249
|
-
end
|
1250
|
-
|
1251
|
-
get '/' do
|
1252
|
-
haml :index
|
1253
|
-
end
|
1254
|
-
```
|
1255
|
-
|
1256
|
-
Если шаблон с именем "layout" существует, то он будет использоваться каждый
|
1257
|
-
раз при рендеринге. Вы можете отключать лэйаут в каждом конкретном случае при
|
1258
|
-
помощи опции `:layout => false` или отключить его для всего приложения: `set :haml,
|
1259
|
-
:layout => false`:
|
1260
|
-
|
1261
|
-
```ruby
|
1262
|
-
get '/' do
|
1263
|
-
haml :index, :layout => !request.xhr?
|
1264
|
-
end
|
1265
|
-
```
|
1266
|
-
|
1267
|
-
### Привязка файловых расширений
|
1268
|
-
|
1269
|
-
Для того, чтобы связать расширение файла с движком рендеринга, используйте
|
1270
|
-
`Tilt.register`. Так, например, вызовите следующий код в том случае, если вы
|
1271
|
-
хотите использовать расширение `tt` для шаблонов Textile:
|
1272
|
-
|
1273
|
-
```ruby
|
1274
|
-
Tilt.register :tt, Tilt[:textile]
|
1275
|
-
```
|
1276
|
-
|
1277
|
-
### Добавление собственного движка рендеринга
|
1278
|
-
|
1279
|
-
Сначала зарегистрируйте собственный движок в Tilt, а затем создайте метод, отвечающий
|
1280
|
-
за рендеринг:
|
1281
|
-
|
1282
|
-
```ruby
|
1283
|
-
Tilt.register :myat, MyAwesomeTemplateEngine
|
1284
|
-
|
1285
|
-
helpers do
|
1286
|
-
def myat(*args) render(:myat, *args) end
|
1287
|
-
end
|
1288
|
-
|
1289
|
-
get '/' do
|
1290
|
-
myat :index
|
1291
|
-
end
|
1292
|
-
```
|
1293
|
-
|
1294
|
-
Данный код отрендерит `./views/index.myat`.
|
1295
|
-
Подробнее о [Tilt](https://github.com/rtomayko/tilt#readme).
|
1296
|
-
|
1297
|
-
### Использование пользовательской логики для поиска шаблона
|
1298
|
-
|
1299
|
-
Для того, чтобы реализовать собственный механизм поиска шаблона,
|
1300
|
-
необходимо написать метод `#find_template`:
|
1301
|
-
|
1302
|
-
```ruby
|
1303
|
-
configure do
|
1304
|
-
set :views [ './views/a', './views/b' ]
|
1305
|
-
end
|
1306
|
-
|
1307
|
-
def find_template(views, name, engine, &block)
|
1308
|
-
Array(views).each do |v|
|
1309
|
-
super(v, name, engine, &block)
|
1310
|
-
end
|
1311
|
-
end
|
1312
|
-
```
|
1313
|
-
|
1314
|
-
## Фильтры
|
1315
|
-
|
1316
|
-
`before`-фильтры выполняются перед каждым запросом в том же контексте, что и
|
1317
|
-
маршруты, и могут изменять как запрос, так и ответ на него. Переменные
|
1318
|
-
экземпляра, установленные в фильтрах, доступны в маршрутах и шаблонах:
|
1319
|
-
|
1320
|
-
```ruby
|
1321
|
-
before do
|
1322
|
-
@note = 'Hi!'
|
1323
|
-
request.path_info = '/foo/bar/baz'
|
1324
|
-
end
|
1325
|
-
|
1326
|
-
get '/foo/*' do
|
1327
|
-
@note #=> 'Hi!'
|
1328
|
-
params['splat'] #=> 'bar/baz'
|
1329
|
-
end
|
1330
|
-
```
|
1331
|
-
|
1332
|
-
`after`-фильтры выполняются после каждого запроса в том же контексте
|
1333
|
-
и могут изменять как запрос, так и ответ на него. Переменные
|
1334
|
-
экземпляра, установленные в `before`-фильтрах и маршрутах, будут доступны в
|
1335
|
-
`after`-фильтрах:
|
1336
|
-
|
1337
|
-
```ruby
|
1338
|
-
after do
|
1339
|
-
puts response.status
|
1340
|
-
end
|
1341
|
-
```
|
1342
|
-
|
1343
|
-
Обратите внимание: если вы используете метод `body`, а не просто возвращаете строку из
|
1344
|
-
маршрута, то тело ответа не будет доступно в `after`-фильтрах, так как оно
|
1345
|
-
будет сгенерировано позднее.
|
1346
|
-
|
1347
|
-
Фильтры также могут использовать шаблоны URL и будут выполнены только в том случае,
|
1348
|
-
если путь запроса совпадет с указанным шаблоном:
|
1349
|
-
|
1350
|
-
```ruby
|
1351
|
-
before '/protected/*' do
|
1352
|
-
authenticate!
|
1353
|
-
end
|
1354
|
-
|
1355
|
-
after '/create/:slug' do |slug|
|
1356
|
-
session[:last_slug] = slug
|
1357
|
-
end
|
1358
|
-
```
|
1359
|
-
|
1360
|
-
Как и маршруты, фильтры могут использовать условия:
|
1361
|
-
|
1362
|
-
```ruby
|
1363
|
-
before :agent => /Songbird/ do
|
1364
|
-
# ...
|
1365
|
-
end
|
1366
|
-
|
1367
|
-
after '/blog/*', :host_name => 'example.com' do
|
1368
|
-
# ...
|
1369
|
-
end
|
1370
|
-
```
|
1371
|
-
|
1372
|
-
## Методы-помощники
|
1373
|
-
|
1374
|
-
Используйте высокоуровневый метод `helpers` для того, чтобы определить
|
1375
|
-
методы-помощники, которые могут быть использованы в обработчиках маршрутов
|
1376
|
-
и шаблонах:
|
1377
|
-
|
1378
|
-
```ruby
|
1379
|
-
helpers do
|
1380
|
-
def bar(name)
|
1381
|
-
"#{name}bar"
|
1382
|
-
end
|
1383
|
-
end
|
1384
|
-
|
1385
|
-
get '/:name' do
|
1386
|
-
bar(params['name'])
|
1387
|
-
end
|
1388
|
-
```
|
1389
|
-
|
1390
|
-
Также методы-помощники могут быть заданы в отдельных модулях:
|
1391
|
-
|
1392
|
-
```ruby
|
1393
|
-
module FooUtils
|
1394
|
-
def foo(name) "#{name}foo" end
|
1395
|
-
end
|
1396
|
-
|
1397
|
-
module BarUtils
|
1398
|
-
def bar(name) "#{name}bar" end
|
1399
|
-
end
|
1400
|
-
|
1401
|
-
helpers FooUtils, BarUtils
|
1402
|
-
```
|
1403
|
-
|
1404
|
-
Эффект равносилен включению модулей в класс приложения.
|
1405
|
-
|
1406
|
-
### Использование сессий
|
1407
|
-
|
1408
|
-
Сессия используется для того, чтобы сохранять состояние между запросами. Если
|
1409
|
-
эта опция включена, то у вас будет один хэш сессии на один пользовательский сеанс:
|
1410
|
-
|
1411
|
-
```ruby
|
1412
|
-
enable :sessions
|
1413
|
-
|
1414
|
-
get '/' do
|
1415
|
-
"value = " << session[:value].inspect
|
1416
|
-
end
|
1417
|
-
|
1418
|
-
get '/:value' do
|
1419
|
-
session['value'] = params['value']
|
1420
|
-
end
|
1421
|
-
```
|
1422
|
-
|
1423
|
-
### Безопасность сессии
|
1424
|
-
|
1425
|
-
Для того, чтобы повысить безопасность, данные сессии в файле 'cookie'
|
1426
|
-
подписываются ключом сессии с использованием `HMAC-SHA1`. Этот ключ сессии
|
1427
|
-
должен быть оптимальным криптографическим 'secure random' значением соответствующей
|
1428
|
-
длины, которая для `HMAC-SHA1` больше или равна 64 байтам (512 бит, 128
|
1429
|
-
шестнадцатеричных символов). Не рекомендуется использовать ключ, длина
|
1430
|
-
которого менее 32 байт (256 бит, 64 шестнадцатеричных символа). Поэтому
|
1431
|
-
**очень важно**, чтобы вы не просто составили значение ключа, а использовали
|
1432
|
-
безопасный генератор случайных чисел для его создания. Люди очень плохо
|
1433
|
-
придумывают случайные значения.
|
1434
|
-
|
1435
|
-
По умолчанию, Sinatra создаёт для вас безопасный случайный ключ сессии из
|
1436
|
-
32 байт, однако он будет меняться при каждом перезапуске приложения. Если у
|
1437
|
-
вас есть несколько экземпляров вашего приложения, и вы доверили Sinatra
|
1438
|
-
генерацию ключа, то каждый экземпляр будет иметь отличный ключ сессии,
|
1439
|
-
что, вероятно, не совсем то, что вам необходимо.
|
1440
|
-
|
1441
|
-
Для лучшей безопасности и удобства использования
|
1442
|
-
[рекомендуется](https://12factor.net/config) генерировать случайный безопасный
|
1443
|
-
ключ и хранить его в переменной среды на каждом хосте, на котором запущено
|
1444
|
-
приложение, чтобы все экземпляры вашего приложения использовали один и тот
|
1445
|
-
же ключ. Вы должны периодически менять значение ключа сессии на новое.
|
1446
|
-
Вот несколько примеров того, как вы можете создать 64-байтный ключ
|
1447
|
-
и установить его:
|
1448
|
-
|
1449
|
-
**Генерация ключа сессии**
|
1450
|
-
|
1451
|
-
```text
|
1452
|
-
$ ruby -e "require 'securerandom'; puts SecureRandom.hex(64)"
|
1453
|
-
99ae8af...snip...ec0f262ac
|
1454
|
-
```
|
1455
|
-
|
1456
|
-
**Генерация ключа сессии (бонусные пункты)**
|
1457
|
-
|
1458
|
-
Используйте [гем 'sysrandom'](https://github.com/cryptosphere/sysrandom#readme).
|
1459
|
-
Предпочтительнее использовать системные средства RNG для генерации случайных
|
1460
|
-
значений вместо пространства пользователя `OpenSSL`, который в настоящее время
|
1461
|
-
по умолчанию используется в MRI Ruby:
|
1462
|
-
|
1463
|
-
```text
|
1464
|
-
$ gem install sysrandom
|
1465
|
-
Создание собственных расширений. Это может занять некоторое время...
|
1466
|
-
Успешно установлен sysrandom-1.x
|
1467
|
-
1 gem установлен
|
1468
|
-
|
1469
|
-
$ ruby -e "require 'sysrandom/securerandom'; puts SecureRandom.hex(64)"
|
1470
|
-
99ae8af...snip...ec0f262ac
|
1471
|
-
```
|
1472
|
-
|
1473
|
-
**Переменная среды для ключа сессии**
|
1474
|
-
|
1475
|
-
Задайте переменной среды `SESSION_SECRET` значение, которое вы
|
1476
|
-
сгенерировали. Данная переменная автоматически будет использована Sinatra.
|
1477
|
-
Сделайте это значение постоянным при перезагрузке вашего
|
1478
|
-
сервера. Поскольку метод для генерации будет различным в разных системах,
|
1479
|
-
то код ниже приведён только в качестве примера:
|
1480
|
-
|
1481
|
-
```bash
|
1482
|
-
# echo "export SESSION_SECRET=99ae8af...snip...ec0f262ac" >> ~/.bashrc
|
1483
|
-
```
|
1484
|
-
|
1485
|
-
**Конфигурация приложения**
|
1486
|
-
|
1487
|
-
В целях безопасности настройте конфигурацию вашего приложения таким образом,
|
1488
|
-
чтобы оно генерировало случайный безопасный ключ тогда, когда переменная
|
1489
|
-
среды `SESSION_SECRET` не доступна.
|
1490
|
-
|
1491
|
-
В качестве бонусных пунктов здесь тоже используйте
|
1492
|
-
[гем 'sysrandom'gem](https://github.com/cryptosphere/sysrandom):
|
1493
|
-
|
1494
|
-
```ruby
|
1495
|
-
require 'securerandom'
|
1496
|
-
# -или- require 'sysrandom/securerandom'
|
1497
|
-
set :session_secret, ENV.fetch('SESSION_SECRET') { SecureRandom.hex(64) }
|
1498
|
-
```
|
1499
|
-
|
1500
|
-
#### Конфигурация сессии
|
1501
|
-
|
1502
|
-
Если вы хотите больше настроек для сессий, вы можете задать их, передав хэш
|
1503
|
-
опций в параметр `sessions`:
|
1504
|
-
|
1505
|
-
```ruby
|
1506
|
-
set :sessions, :domain => 'foo.com'
|
1507
|
-
```
|
1508
|
-
|
1509
|
-
Чтобы сделать сессию доступной другим приложениям, размещенным на поддоменах
|
1510
|
-
foo.com, добавьте *.* перед доменом:
|
1511
|
-
|
1512
|
-
```ruby
|
1513
|
-
set :sessions, :domain => '.foo.com'
|
1514
|
-
```
|
1515
|
-
|
1516
|
-
#### Выбор вашей собственной "прослойки" сессии
|
1517
|
-
|
1518
|
-
Обратите внимание на то, что при использовании `enable :sessions` все данные
|
1519
|
-
сохраняются в куках (cookies). Это может быть не совсем то, что вы хотите (например,
|
1520
|
-
сохранение больших объёмов данных увеличит ваш трафик). В таком случае вы
|
1521
|
-
можете использовать альтернативную Rack "прослойку" (middleware), реализующую
|
1522
|
-
механизм сессий. Для этого используете один из способов ниже:
|
1523
|
-
|
1524
|
-
```ruby
|
1525
|
-
enable :sessions
|
1526
|
-
set :session_store, Rack::Session::Pool
|
1527
|
-
```
|
1528
|
-
|
1529
|
-
Или установите параметры сессии при помощи хэша опций:
|
1530
|
-
|
1531
|
-
```ruby
|
1532
|
-
set :sessions, :expire_after => 2592000
|
1533
|
-
set :session_store, Rack::Session::Pool
|
1534
|
-
```
|
1535
|
-
|
1536
|
-
Вы также можете **не вызывать** `enable :sessions`, а вместо этого использовать
|
1537
|
-
необходимую вам Rack прослойку так же, как вы это обычно делаете.
|
1538
|
-
|
1539
|
-
Очень важно обратить внимание на то, что когда вы используете этот метод,
|
1540
|
-
основной способ защиты сессии **не будет включён по умолчанию**.
|
1541
|
-
|
1542
|
-
Вам также потребуется добавить следующие Rack middleware для этого:
|
1543
|
-
|
1544
|
-
```ruby
|
1545
|
-
use Rack::Session::Pool, :expire_after => 2592000
|
1546
|
-
use Rack::Protection::RemoteToken
|
1547
|
-
use Rack::Protection::SessionHijacking
|
1548
|
-
```
|
1549
|
-
|
1550
|
-
Смотрите раздел ["Настройка защиты от атак"](#Настройка-защиты-от-атак) для более подробной информации.
|
1551
|
-
|
1552
|
-
### Прерывание
|
1553
|
-
|
1554
|
-
Чтобы незамедлительно прервать обработку запроса внутри фильтра или маршрута,
|
1555
|
-
используйте следующую команду:
|
1556
|
-
|
1557
|
-
```ruby
|
1558
|
-
halt
|
1559
|
-
```
|
1560
|
-
|
1561
|
-
Можно также указать статус при прерывании:
|
1562
|
-
|
1563
|
-
```ruby
|
1564
|
-
halt 410
|
1565
|
-
```
|
1566
|
-
|
1567
|
-
Тело:
|
1568
|
-
|
1569
|
-
```ruby
|
1570
|
-
halt 'this will be the body'
|
1571
|
-
```
|
1572
|
-
|
1573
|
-
И то, и другое:
|
1574
|
-
|
1575
|
-
```ruby
|
1576
|
-
halt 401, 'go away!'
|
1577
|
-
```
|
1578
|
-
|
1579
|
-
Можно указать заголовки:
|
1580
|
-
|
1581
|
-
```ruby
|
1582
|
-
halt 402, {'Content-Type' => 'text/plain'}, 'revenge'
|
1583
|
-
```
|
1584
|
-
|
1585
|
-
И, конечно, можно использовать шаблоны с `halt`:
|
1586
|
-
|
1587
|
-
```ruby
|
1588
|
-
halt erb(:error)
|
1589
|
-
```
|
1590
|
-
|
1591
|
-
### Передача
|
1592
|
-
|
1593
|
-
Маршрут может передать обработку запроса следующему совпадающему маршруту
|
1594
|
-
используя метод `pass`:
|
1595
|
-
|
1596
|
-
```ruby
|
1597
|
-
get '/guess/:who' do
|
1598
|
-
pass unless params['who'] == 'Frank'
|
1599
|
-
'You got me!'
|
1600
|
-
end
|
1601
|
-
|
1602
|
-
get '/guess/*' do
|
1603
|
-
'You missed!'
|
1604
|
-
end
|
1605
|
-
```
|
1606
|
-
|
1607
|
-
Блок маршрута сразу же прерывается, а контроль переходит к следующему
|
1608
|
-
совпадающему маршруту. Если соответствующий маршрут не найден, то ответом на
|
1609
|
-
запрос будет 404.
|
1610
|
-
|
1611
|
-
### Вызов другого маршрута
|
1612
|
-
|
1613
|
-
Иногда `pass` не подходит, например, если вы хотите получить результат вызова
|
1614
|
-
другого обработчика маршрута. В таком случае просто используйте `call`:
|
1615
|
-
|
1616
|
-
```ruby
|
1617
|
-
get '/foo' do
|
1618
|
-
status, headers, body = call env.merge("PATH_INFO" => '/bar')
|
1619
|
-
[status, headers, body.map(&:upcase)]
|
1620
|
-
end
|
1621
|
-
|
1622
|
-
get '/bar' do
|
1623
|
-
"bar"
|
1624
|
-
end
|
1625
|
-
```
|
1626
|
-
|
1627
|
-
Обратите внимание на то, что в предыдущем примере можно облегчить тестирование и
|
1628
|
-
повысить производительность, перенеся `"bar"` в метод-помощник, используемый и в
|
1629
|
-
`/foo`, и в `/bar`.
|
1630
|
-
|
1631
|
-
Если вы хотите, чтобы запрос был отправлен в тот же экземпляр приложения,
|
1632
|
-
а не в его копию, используйте `call!` вместо `call`.
|
1633
|
-
|
1634
|
-
Если хотите узнать больше о `call`, смотрите спецификацию Rack.
|
1635
|
-
|
1636
|
-
### Установка тела, статус кода и заголовков ответа
|
1637
|
-
|
1638
|
-
Хорошим тоном является установка кода состояния HTTP и тела ответа в
|
1639
|
-
возвращаемом значении обработчика маршрута. Тем не менее, в некоторых
|
1640
|
-
ситуациях вам, возможно, понадобится задать тело ответа в произвольной точке
|
1641
|
-
потока исполнения. Вы можете сделать это при помощи метода-помощника `body`.
|
1642
|
-
Если вы задействуете метод `body`, то вы можете использовать его и в
|
1643
|
-
дальнейшем, чтобы получить доступ к телу ответа:
|
1644
|
-
|
1645
|
-
```ruby
|
1646
|
-
get '/foo' do
|
1647
|
-
body "bar"
|
1648
|
-
end
|
1649
|
-
|
1650
|
-
after do
|
1651
|
-
puts body
|
1652
|
-
end
|
1653
|
-
```
|
1654
|
-
|
1655
|
-
Также можно передать блок в метод `body`, который затем будет вызван
|
1656
|
-
обработчиком Rack (такой подход может быть использован для реализации
|
1657
|
-
потокового ответа, см. ["Возвращаемые значения"](#Возвращаемые-значения)).
|
1658
|
-
|
1659
|
-
Аналогично вы можете установить код ответа и его заголовки:
|
1660
|
-
|
1661
|
-
```ruby
|
1662
|
-
get '/foo' do
|
1663
|
-
status 418
|
1664
|
-
headers \
|
1665
|
-
"Allow" => "BREW, POST, GET, PROPFIND, WHEN",
|
1666
|
-
"Refresh" => "Refresh: 20; https://ietf.org/rfc/rfc2324.txt"
|
1667
|
-
body "I'm a tea pot!"
|
1668
|
-
end
|
1669
|
-
```
|
1670
|
-
|
1671
|
-
Как и `body`, методы `headers` и `status`, вызванные без аргументов,
|
1672
|
-
возвращают свои текущие значения.
|
1673
|
-
|
1674
|
-
### Потоковые ответы
|
1675
|
-
|
1676
|
-
Иногда требуется начать отправлять данные клиенту прямо в процессе
|
1677
|
-
генерирования частей этих данных. В особых случаях требуется постоянно
|
1678
|
-
отправлять данные до тех пор, пока клиент не закроет соединение. Вы можете
|
1679
|
-
использовать метод `stream` вместо разработки собственных "обёрток".
|
1680
|
-
|
1681
|
-
```ruby
|
1682
|
-
get '/' do
|
1683
|
-
stream do |out|
|
1684
|
-
out << "It's gonna be legen -\n"
|
1685
|
-
sleep 0.5
|
1686
|
-
out << " (wait for it) \n"
|
1687
|
-
sleep 1
|
1688
|
-
out << "- dary!\n"
|
1689
|
-
end
|
1690
|
-
end
|
1691
|
-
```
|
1692
|
-
|
1693
|
-
Это позволяет вам реализовать стриминговые API,
|
1694
|
-
[Server Sent Events](https://w3c.github.io/eventsource/),
|
1695
|
-
и может служить основой для [WebSockets](https://en.wikipedia.org/wiki/WebSocket).
|
1696
|
-
Также такой подход можно использовать для увеличения производительности в том случае,
|
1697
|
-
когда какая-то часть контента (а не весь) зависит от медленного ресурса.
|
1698
|
-
|
1699
|
-
Обратите внимание на то, что возможности стриминга, особенно количество одновременно
|
1700
|
-
обслуживаемых запросов, очень сильно зависят от используемого веб-сервера.
|
1701
|
-
Некоторые серверы могут и вовсе не поддерживать стриминг. Если сервер не
|
1702
|
-
поддерживает стриминг, то все данные будут отправлены за один раз сразу после
|
1703
|
-
того, как блок, переданный в `stream`, завершится. Стриминг вообще не работает
|
1704
|
-
при использовании Shotgun.
|
1705
|
-
|
1706
|
-
Если метод используется с параметром `keep_open`, то он не будет вызывать
|
1707
|
-
`close` у объекта потока, что позволит вам закрыть его позже в любом другом
|
1708
|
-
месте. Это работает только с событийными серверами, например, с Thin и
|
1709
|
-
Rainbows. Другие же серверы всё равно будут закрывать поток:
|
1710
|
-
|
1711
|
-
```ruby
|
1712
|
-
# long polling
|
1713
|
-
|
1714
|
-
set :server, :thin
|
1715
|
-
connections = []
|
1716
|
-
|
1717
|
-
get '/subscribe' do
|
1718
|
-
# регистрация клиента в событиях сервера
|
1719
|
-
stream(:keep_open) do |out|
|
1720
|
-
connections << out
|
1721
|
-
# удаление "мёртвых клиентов"
|
1722
|
-
connections.reject!(&:closed?)
|
1723
|
-
end
|
1724
|
-
end
|
1725
|
-
|
1726
|
-
post '/:message' do
|
1727
|
-
connections.each do |out|
|
1728
|
-
# уведомить клиента о новом сообщении
|
1729
|
-
out << params['message'] << "\n"
|
1730
|
-
|
1731
|
-
# указать клиенту на необходимость снова соединиться
|
1732
|
-
out.close
|
1733
|
-
end
|
1734
|
-
|
1735
|
-
# допуск
|
1736
|
-
"message received"
|
1737
|
-
end
|
1738
|
-
```
|
1739
|
-
|
1740
|
-
Также клиент может закрыть соединение при попытке записи в сокет. В связи с
|
1741
|
-
этим рекомендуется выполнить проверку `out.closed?` прежде, чем пытаться произвести запись.
|
1742
|
-
|
1743
|
-
### Логирование
|
1744
|
-
|
1745
|
-
В области видимости запроса метод `logger` предоставляет доступ к экземпляру
|
1746
|
-
`Logger`:
|
1747
|
-
|
1748
|
-
```ruby
|
1749
|
-
get '/' do
|
1750
|
-
logger.info "loading data"
|
1751
|
-
# ...
|
1752
|
-
end
|
1753
|
-
```
|
1754
|
-
|
1755
|
-
Этот логер автоматически учитывает ваши настройки логирования в Rack. Если
|
1756
|
-
логирование выключено, то этот метод вернет пустой (dummy) объект, поэтому вы
|
1757
|
-
можете смело использовать его в маршрутах и фильтрах.
|
1758
|
-
|
1759
|
-
Обратите внимание на то, что логирование включено по умолчанию только для
|
1760
|
-
`Sinatra::Application`. Если ваше приложение является подклассом `Sinatra::Base`, то
|
1761
|
-
вы, скорее всего, захотите включить его вручную:
|
1762
|
-
|
1763
|
-
```ruby
|
1764
|
-
class MyApp < Sinatra::Base
|
1765
|
-
configure :production, :development do
|
1766
|
-
enable :logging
|
1767
|
-
end
|
1768
|
-
end
|
1769
|
-
```
|
1770
|
-
|
1771
|
-
Чтобы избежать использования любой логирующей "прослойки", задайте опции
|
1772
|
-
`logging` значение `nil`. При этом не забывайте, что в такой ситуации
|
1773
|
-
`logger` будет возвращать `nil`. Чаще всего так делают, когда задают свой собственный
|
1774
|
-
логер. Sinatra будет использовать то, что находится в `env['rack.logger']`.
|
1775
|
-
|
1776
|
-
### Mime-типы
|
1777
|
-
|
1778
|
-
Когда вы используете `send_file` или статические файлы, у вас могут быть
|
1779
|
-
mime-типы, которые Sinatra не понимает по умолчанию. Используйте `mime_type`
|
1780
|
-
для их регистрации по расширению файла:
|
1781
|
-
|
1782
|
-
```ruby
|
1783
|
-
configure do
|
1784
|
-
mime_type :foo, 'text/foo'
|
1785
|
-
end
|
1786
|
-
```
|
1787
|
-
|
1788
|
-
Вы также можете использовать это в методе-помощнике `content_type`:
|
1789
|
-
|
1790
|
-
```ruby
|
1791
|
-
get '/' do
|
1792
|
-
content_type :foo
|
1793
|
-
"foo foo foo"
|
1794
|
-
end
|
1795
|
-
```
|
1796
|
-
|
1797
|
-
### Генерирование URL
|
1798
|
-
|
1799
|
-
Чтобы сформировать URL, вам следует использовать метод `url`, например, в Haml:
|
1800
|
-
|
1801
|
-
```ruby
|
1802
|
-
%a{:href => url('/foo')} foo
|
1803
|
-
```
|
1804
|
-
|
1805
|
-
Этот метод учитывает обратные прокси и маршрутизаторы Rack, если они
|
1806
|
-
присутствуют.
|
1807
|
-
|
1808
|
-
Наряду с `url` вы можете использовать `to` (смотрите пример ниже).
|
1809
|
-
|
1810
|
-
### Перенаправление (редирект)
|
1811
|
-
|
1812
|
-
Вы можете перенаправить браузер пользователя при помощи метода `redirect`:
|
1813
|
-
|
1814
|
-
```ruby
|
1815
|
-
get '/foo' do
|
1816
|
-
redirect to('/bar')
|
1817
|
-
end
|
1818
|
-
```
|
1819
|
-
|
1820
|
-
Любые дополнительные параметры используются по аналогии с аргументами метода
|
1821
|
-
`halt`:
|
1822
|
-
|
1823
|
-
```ruby
|
1824
|
-
redirect to('/bar'), 303
|
1825
|
-
redirect 'http://www.google.com/', 'wrong place, buddy'
|
1826
|
-
```
|
1827
|
-
|
1828
|
-
Вы также можете перенаправить пользователя обратно на страницу, с которой он
|
1829
|
-
пришёл, при помощи `redirect back`:
|
1830
|
-
|
1831
|
-
```ruby
|
1832
|
-
get '/foo' do
|
1833
|
-
"<a href='/bar'>do something</a>"
|
1834
|
-
end
|
1835
|
-
|
1836
|
-
get '/bar' do
|
1837
|
-
do_something
|
1838
|
-
redirect back
|
1839
|
-
end
|
1840
|
-
```
|
1841
|
-
|
1842
|
-
Для того, чтобы передать какие-либо параметры вместе с перенаправлением,
|
1843
|
-
добавьте их в строку запроса:
|
1844
|
-
|
1845
|
-
```ruby
|
1846
|
-
redirect to('/bar?sum=42')
|
1847
|
-
```
|
1848
|
-
|
1849
|
-
либо используйте сессию:
|
1850
|
-
|
1851
|
-
```ruby
|
1852
|
-
enable :sessions
|
1853
|
-
|
1854
|
-
get '/foo' do
|
1855
|
-
session[:secret] = 'foo'
|
1856
|
-
redirect to('/bar')
|
1857
|
-
end
|
1858
|
-
|
1859
|
-
get '/bar' do
|
1860
|
-
session[:secret]
|
1861
|
-
end
|
1862
|
-
```
|
1863
|
-
|
1864
|
-
### Управление кэшированием
|
1865
|
-
|
1866
|
-
Установка корректных заголовков — основа правильного HTTP кэширования.
|
1867
|
-
|
1868
|
-
Вы можете легко выставить заголовок Cache-Control следующим образом:
|
1869
|
-
|
1870
|
-
```ruby
|
1871
|
-
get '/' do
|
1872
|
-
cache_control :public
|
1873
|
-
"cache it!"
|
1874
|
-
end
|
1875
|
-
```
|
1876
|
-
|
1877
|
-
Совет: задавайте кэширование в `before`-фильтре:
|
1878
|
-
|
1879
|
-
```ruby
|
1880
|
-
before do
|
1881
|
-
cache_control :public, :must_revalidate, :max_age => 60
|
1882
|
-
end
|
1883
|
-
```
|
1884
|
-
|
1885
|
-
Если вы используете метод `expires` для задания соответствующего заголовка, то
|
1886
|
-
`Cache-Control` будет выставлен автоматически:
|
1887
|
-
|
1888
|
-
```ruby
|
1889
|
-
before do
|
1890
|
-
expires 500, :public, :must_revalidate
|
1891
|
-
end
|
1892
|
-
```
|
1893
|
-
|
1894
|
-
Чтобы использовать кэширование правильно, вам стоит подумать о
|
1895
|
-
применении `etag` или `last_modified`. Рекомендуется использовать эти
|
1896
|
-
методы-помощники *до* выполнения ресурсоёмких вычислений, так как они
|
1897
|
-
немедленно отправят ответ клиенту в том случае, если текущая версия
|
1898
|
-
уже присутствует в их кэше:
|
1899
|
-
|
1900
|
-
```ruby
|
1901
|
-
get "/article/:id" do
|
1902
|
-
@article = Article.find params['id']
|
1903
|
-
last_modified @article.updated_at
|
1904
|
-
etag @article.sha1
|
1905
|
-
erb :article
|
1906
|
-
end
|
1907
|
-
```
|
1908
|
-
|
1909
|
-
Также вы можете использовать
|
1910
|
-
[weak ETag](https://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation):
|
1911
|
-
|
1912
|
-
```ruby
|
1913
|
-
etag @article.sha1, :weak
|
1914
|
-
```
|
1915
|
-
|
1916
|
-
Эти методы-помощники не станут ничего кэшировать, однако они дадут
|
1917
|
-
необходимую информацию для вашего кэша. Если вы ищете лёгкое решение для
|
1918
|
-
кэширования, попробуйте [rack-cache](https://github.com/rtomayko/rack-cache#readme):
|
1919
|
-
|
1920
|
-
```ruby
|
1921
|
-
require "rack/cache"
|
1922
|
-
require "sinatra"
|
1923
|
-
|
1924
|
-
use Rack::Cache
|
1925
|
-
|
1926
|
-
get '/' do
|
1927
|
-
cache_control :public, :max_age => 36000
|
1928
|
-
sleep 5
|
1929
|
-
"hello"
|
1930
|
-
end
|
1931
|
-
```
|
1932
|
-
|
1933
|
-
Используйте опцию `:static_cache_control` (см. ниже), чтобы добавить заголовок
|
1934
|
-
`Cache-Control` к статическим файлам.
|
1935
|
-
|
1936
|
-
В соответствии с RFC 2616 ваше приложение должно вести себя по-разному, когда
|
1937
|
-
заголовки If-Match или If-None-Match имеют значение `*`, в зависимости от
|
1938
|
-
того, существует или нет запрашиваемый ресурс. Sinatra предполагает, что
|
1939
|
-
ресурсы, к которым обращаются при помощи безопасных (GET) и идемпотентных (PUT)
|
1940
|
-
методов, уже существуют, а остальные ресурсы (к которым обращаются, например,
|
1941
|
-
при помощи POST) считает новыми. Вы можете изменить данное поведение при помощи
|
1942
|
-
опции `:new_resource`:
|
1943
|
-
|
1944
|
-
```ruby
|
1945
|
-
get '/create' do
|
1946
|
-
etag '', :new_resource => true
|
1947
|
-
Article.create
|
1948
|
-
erb :new_article
|
1949
|
-
end
|
1950
|
-
```
|
1951
|
-
|
1952
|
-
Если вы хотите использовать weak ETag, задайте опцию `:kind`:
|
1953
|
-
|
1954
|
-
```ruby
|
1955
|
-
etag '', :new_resource => true, :kind => :weak
|
1956
|
-
```
|
1957
|
-
|
1958
|
-
### Отправка файлов
|
1959
|
-
|
1960
|
-
Для отправки файлов пользователю вы можете использовать метод `send_file`:
|
1961
|
-
|
1962
|
-
```ruby
|
1963
|
-
get '/' do
|
1964
|
-
send_file 'foo.png'
|
1965
|
-
end
|
1966
|
-
```
|
1967
|
-
|
1968
|
-
Этот метод имеет несколько опций:
|
1969
|
-
|
1970
|
-
```ruby
|
1971
|
-
send_file 'foo.png', :type => :jpg
|
1972
|
-
```
|
1973
|
-
|
1974
|
-
Возможные опции:
|
1975
|
-
|
1976
|
-
<dl>
|
1977
|
-
<dt>filename</dt>
|
1978
|
-
<dd>имя файла, по умолчанию: реальное имя файла.</dd>
|
1979
|
-
|
1980
|
-
<dt>last_modified</dt>
|
1981
|
-
<dd>значение для заголовка Last-Modified, по умолчанию: mtime (время
|
1982
|
-
изменения) файла.</dd>
|
1983
|
-
|
1984
|
-
<dt>type</dt>
|
1985
|
-
<dd>тип файла, по умолчанию: определяется по расширению файла.</dd>
|
1986
|
-
|
1987
|
-
<dt>disposition</dt>
|
1988
|
-
<dd>
|
1989
|
-
используется для заголовка Content-Disposition, возможные значения: <tt>nil</tt>
|
1990
|
-
(по умолчанию), <tt>:attachment</tt> и <tt>:inline</tt>
|
1991
|
-
</dd>
|
1992
|
-
|
1993
|
-
<dt>length</dt>
|
1994
|
-
<dd>значения для заголовка Content-Length, по умолчанию: размер файла.</dd>
|
1995
|
-
|
1996
|
-
<dt>status</dt>
|
1997
|
-
<dd>
|
1998
|
-
Код ответа. Полезно в том случае, когда отсылается статический файл в качестве
|
1999
|
-
страницы с сообщением об ошибке. Если поддерживается обработчик Rack, будут использоваться
|
2000
|
-
другие средства, кроме потоковой передачи из процесса Ruby. Если вы используете
|
2001
|
-
этот вспомогательный метод, Sinatra автоматически обрабатывает запросы диапазона.
|
2002
|
-
</dd>
|
2003
|
-
</dl>
|
2004
|
-
|
2005
|
-
### Доступ к объекту запроса
|
2006
|
-
|
2007
|
-
Объект входящего запроса доступен на уровне обработки запроса (в фильтрах,
|
2008
|
-
маршрутах, обработчиках ошибок) при помощи `request` метода:
|
2009
|
-
|
2010
|
-
```ruby
|
2011
|
-
# приложение запущено на http://example.com/example
|
2012
|
-
get '/foo' do
|
2013
|
-
t = %w[text/css text/html application/javascript]
|
2014
|
-
request.accept # ['text/html', '*/*']
|
2015
|
-
request.accept? 'text/xml' # true
|
2016
|
-
request.preferred_type(t) # 'text/html'
|
2017
|
-
request.body # тело запроса, посланное клиентом (см. ниже)
|
2018
|
-
request.scheme # "http"
|
2019
|
-
request.script_name # "/example"
|
2020
|
-
request.path_info # "/foo"
|
2021
|
-
request.port # 80
|
2022
|
-
request.request_method # "GET"
|
2023
|
-
request.query_string # ""
|
2024
|
-
request.content_length # длина тела запроса
|
2025
|
-
request.media_type # медиатип тела запроса
|
2026
|
-
request.host # "example.com"
|
2027
|
-
request.get? # true (есть аналоги для других методов HTTP)
|
2028
|
-
request.form_data? # false
|
2029
|
-
request["some_param"] # значение параметра some_param. Шорткат для хэша params
|
2030
|
-
request.referrer # источник запроса клиента либо '/'
|
2031
|
-
request.user_agent # user agent (используется для :agent условия)
|
2032
|
-
request.cookies # хэш, содержащий cookies браузера
|
2033
|
-
request.xhr? # является ли запрос ajax запросом?
|
2034
|
-
request.url # "http://example.com/example/foo"
|
2035
|
-
request.path # "/example/foo"
|
2036
|
-
request.ip # IP-адрес клиента
|
2037
|
-
request.secure? # false (true, если запрос сделан через SSL)
|
2038
|
-
request.forwarded? # true (если сервер работает за обратным прокси)
|
2039
|
-
request.env # "сырой" env хэш, полученный Rack
|
2040
|
-
end
|
2041
|
-
```
|
2042
|
-
|
2043
|
-
Некоторые опции, такие как `script_name` или `path_info`, доступны для
|
2044
|
-
модификации:
|
2045
|
-
|
2046
|
-
```ruby
|
2047
|
-
before { request.path_info = "/" }
|
2048
|
-
|
2049
|
-
get "/" do
|
2050
|
-
"all requests end up here"
|
2051
|
-
end
|
2052
|
-
```
|
2053
|
-
|
2054
|
-
`request.body` является IO или StringIO объектом:
|
2055
|
-
|
2056
|
-
```ruby
|
2057
|
-
post "/api" do
|
2058
|
-
request.body.rewind # в случае, если кто-то уже прочитал тело запроса
|
2059
|
-
data = JSON.parse request.body.read
|
2060
|
-
"Hello #{data['name']}!"
|
2061
|
-
end
|
2062
|
-
```
|
2063
|
-
|
2064
|
-
### Вложения
|
2065
|
-
|
2066
|
-
Вы можете использовать метод `attachment`, чтобы сообщить браузеру о том,
|
2067
|
-
что ответ сервера должен быть сохранён на диск, а не отображён:
|
2068
|
-
|
2069
|
-
```ruby
|
2070
|
-
get '/' do
|
2071
|
-
attachment
|
2072
|
-
"store it!"
|
2073
|
-
end
|
2074
|
-
```
|
2075
|
-
|
2076
|
-
Вы также можете указать имя файла:
|
2077
|
-
|
2078
|
-
```ruby
|
2079
|
-
get '/' do
|
2080
|
-
attachment "info.txt"
|
2081
|
-
"store it!"
|
2082
|
-
end
|
2083
|
-
```
|
2084
|
-
|
2085
|
-
### Работа со временем и датами
|
2086
|
-
|
2087
|
-
Sinatra предлагает метод-помощник `time_for`, который из заданного значения
|
2088
|
-
создает объект Time. Он также может конвертировать `DateTime`, `Date` и
|
2089
|
-
схожие классы:
|
2090
|
-
|
2091
|
-
```ruby
|
2092
|
-
get '/' do
|
2093
|
-
pass if Time.now > time_for('Dec 23, 2016')
|
2094
|
-
"still time"
|
2095
|
-
end
|
2096
|
-
```
|
2097
|
-
|
2098
|
-
Этот метод используется внутри Sinatra методами `expires`, `last_modified` и
|
2099
|
-
им подобными. Поэтому вы легко можете изменить и дополнить поведение этих методов,
|
2100
|
-
переопределив `time_for` в своём приложении:
|
2101
|
-
|
2102
|
-
```ruby
|
2103
|
-
helpers do
|
2104
|
-
def time_for(value)
|
2105
|
-
case value
|
2106
|
-
when :yesterday then Time.now - 24*60*60
|
2107
|
-
when :tomorrow then Time.now + 24*60*60
|
2108
|
-
else super
|
2109
|
-
end
|
2110
|
-
end
|
2111
|
-
end
|
2112
|
-
|
2113
|
-
get '/' do
|
2114
|
-
last_modified :yesterday
|
2115
|
-
expires :tomorrow
|
2116
|
-
"hello"
|
2117
|
-
end
|
2118
|
-
```
|
2119
|
-
|
2120
|
-
### Поиск файлов шаблонов
|
2121
|
-
|
2122
|
-
Для поиска шаблонов и их последующего рендеринга используется метод
|
2123
|
-
`find_template`:
|
2124
|
-
|
2125
|
-
```ruby
|
2126
|
-
find_template settings.views, 'foo', Tilt[:haml] do |file|
|
2127
|
-
puts "could be #{file}"
|
2128
|
-
end
|
2129
|
-
```
|
2130
|
-
|
2131
|
-
Это не слишком полезный пример. Зато полезен тот факт, что вы можете
|
2132
|
-
переопределить этот метод, чтобы использовать свой собственный механизм
|
2133
|
-
поиска. Например, если вы хотите, чтобы можно было использовать несколько
|
2134
|
-
директорий с шаблонами:
|
2135
|
-
|
2136
|
-
```ruby
|
2137
|
-
set :views, ['views', 'templates']
|
2138
|
-
|
2139
|
-
helpers do
|
2140
|
-
def find_template(views, name, engine, &block)
|
2141
|
-
Array(views).each { |v| super(v, name, engine, &block) }
|
2142
|
-
end
|
2143
|
-
end
|
2144
|
-
```
|
2145
|
-
|
2146
|
-
Другой пример, в котором используются разные директории для движков
|
2147
|
-
рендеринга:
|
2148
|
-
|
2149
|
-
```ruby
|
2150
|
-
set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
|
2151
|
-
|
2152
|
-
helpers do
|
2153
|
-
def find_template(views, name, engine, &block)
|
2154
|
-
_, folder = views.detect { |k,v| engine == Tilt[k] }
|
2155
|
-
folder ||= views[:default]
|
2156
|
-
super(folder, name, engine, &block)
|
2157
|
-
end
|
2158
|
-
end
|
2159
|
-
```
|
2160
|
-
|
2161
|
-
Вы можете легко вынести этот код в расширение и поделиться им с остальными!
|
2162
|
-
|
2163
|
-
Обратите внимание на тот факт, что `find_template` не проверяет, существует ли
|
2164
|
-
файл на самом деле, а вызывает заданный блок для всех возможных путей. Дело тут не в
|
2165
|
-
производительности, а в том, что `render` вызовет `break` как только файл
|
2166
|
-
будет найден. Содержимое и местонахождение шаблонов будет закэшировано в том случае,
|
2167
|
-
если приложение запущено не в режиме разработки (`set :environment, :development`).
|
2168
|
-
Вы должны помнить об этих нюансах, если пишите по-настоящему "сумасшедший"
|
2169
|
-
метод.
|
2170
|
-
|
2171
|
-
## Конфигурация
|
2172
|
-
|
2173
|
-
Этот блок исполняется один раз при старте в любом окружении (environment):
|
2174
|
-
|
2175
|
-
```ruby
|
2176
|
-
configure do
|
2177
|
-
# задание одной опции
|
2178
|
-
set :option, 'value'
|
2179
|
-
|
2180
|
-
# устанавливаем несколько опций
|
2181
|
-
set :a => 1, :b => 2
|
2182
|
-
|
2183
|
-
# то же самое, что и `set :option, true`
|
2184
|
-
enable :option
|
2185
|
-
|
2186
|
-
# то же самое, что и `set :option, false`
|
2187
|
-
disable :option
|
2188
|
-
|
2189
|
-
# у вас могут быть "динамические" опции с блоками
|
2190
|
-
set(:css_dir) { File.join(views, 'css') }
|
2191
|
-
end
|
2192
|
-
```
|
2193
|
-
|
2194
|
-
Следующий пример будет выполнен только тогда, когда окружение
|
2195
|
-
(переменная `APP_ENV`) будет задана как `:production`:
|
2196
|
-
|
2197
|
-
```ruby
|
2198
|
-
configure :production do
|
2199
|
-
...
|
2200
|
-
end
|
2201
|
-
```
|
2202
|
-
|
2203
|
-
Следующий код будет выполнен в том случае, когда окружение
|
2204
|
-
будет задано как `:production` или `:test`:
|
2205
|
-
|
2206
|
-
```ruby
|
2207
|
-
configure :production, :test do
|
2208
|
-
...
|
2209
|
-
end
|
2210
|
-
```
|
2211
|
-
|
2212
|
-
Вы можете получить доступ к этим опциям при помощи метода `settings`:
|
2213
|
-
|
2214
|
-
```ruby
|
2215
|
-
configure do
|
2216
|
-
set :foo, 'bar'
|
2217
|
-
end
|
2218
|
-
|
2219
|
-
get '/' do
|
2220
|
-
settings.foo? # => true
|
2221
|
-
settings.foo # => 'bar'
|
2222
|
-
...
|
2223
|
-
end
|
2224
|
-
```
|
2225
|
-
|
2226
|
-
### Настройка защиты от атак
|
2227
|
-
|
2228
|
-
Sinatra использует
|
2229
|
-
[Rack::Protection](https://github.com/sinatra/sinatra/tree/master/rack-protection#readme) для защиты
|
2230
|
-
приложения от простых атак. Вы можете легко выключить эту защиту (что сделает
|
2231
|
-
ваше приложение чрезвычайно уязвимым к большому числу различных уязвимостей):
|
2232
|
-
|
2233
|
-
```ruby
|
2234
|
-
disable :protection
|
2235
|
-
```
|
2236
|
-
|
2237
|
-
Чтобы отключить какой-либо конкретный уровень защиты, передайте хэш опций
|
2238
|
-
в параметр `protection`:
|
2239
|
-
|
2240
|
-
```ruby
|
2241
|
-
set :protection, :except => :path_traversal
|
2242
|
-
```
|
2243
|
-
|
2244
|
-
Вы также можете отключить сразу несколько уровней защиты:
|
2245
|
-
|
2246
|
-
```ruby
|
2247
|
-
set :protection, :except => [:path_traversal, :session_hijacking]
|
2248
|
-
```
|
2249
|
-
|
2250
|
-
По умолчанию Sinatra будет устанавливать `session based` защиту только если
|
2251
|
-
включена опция `:sessions`. См. ["Использование сессий""](#Использование-сессий).
|
2252
|
-
Иногда вы захотите настроить сессии "вне" приложения Sinatra, например, в
|
2253
|
-
config.ru или при помощи отдельного экземпляра `Rack::Builder`. В таком случае
|
2254
|
-
вы также можете настроить `session based` защиту, передав опцию `:session`:
|
2255
|
-
|
2256
|
-
```ruby
|
2257
|
-
set :protection, :session => true
|
2258
|
-
```
|
2259
|
-
|
2260
|
-
### Доступные настройки
|
2261
|
-
|
2262
|
-
<dl>
|
2263
|
-
<dt>absolute_redirects</dt>
|
2264
|
-
<dd>
|
2265
|
-
если отключено, то Sinatra будет позволять использование относительных
|
2266
|
-
перенаправлений, но при этом перестанет соответствовать RFC 2616 (HTTP
|
2267
|
-
1.1), который разрешает только абсолютные перенаправления.
|
2268
|
-
</dd>
|
2269
|
-
<dd>
|
2270
|
-
включайте эту опцию, если ваше приложение работает за обратным прокси,
|
2271
|
-
который настроен не совсем корректно. Обратите внимание на тот факт, что
|
2272
|
-
метод <tt>url</tt> всё равно будет генерировать абсолютные URL в том случае,
|
2273
|
-
если вы не передадите <tt>false</tt> вторым аргументом.
|
2274
|
-
</dd>
|
2275
|
-
<dd>отключено по умолчанию.</dd>
|
2276
|
-
|
2277
|
-
<dt>add_charset</dt>
|
2278
|
-
<dd>
|
2279
|
-
mime-типы, к которым метод <tt>content_type</tt> будет автоматически добавлять
|
2280
|
-
информацию о кодировке. Вам следует добавлять значения к этой опции
|
2281
|
-
вместо её переопределения: <tt>settings.add_charset << "application/foobar"</tt>
|
2282
|
-
</dd>
|
2283
|
-
|
2284
|
-
<dt>app_file</dt>
|
2285
|
-
<dd>
|
2286
|
-
путь к главному файлу приложения, используется для нахождения корневой
|
2287
|
-
директории проекта, директорий с шаблонами и статическими файлами,
|
2288
|
-
вложенных шаблонов.
|
2289
|
-
</dd>
|
2290
|
-
|
2291
|
-
<dt>bind</dt>
|
2292
|
-
<dd>
|
2293
|
-
используемый IP-адрес (по умолчанию: <tt>0.0.0.0</tt> <em>или</em>
|
2294
|
-
<tt>localhost</tt> если опция `environment` настроена на "development").
|
2295
|
-
Используется только встроенным сервером.
|
2296
|
-
</dd>
|
2297
|
-
|
2298
|
-
<dt>default_encoding</dt>
|
2299
|
-
<dd>кодировка, если неизвестна (по умолчанию: <tt>"utf-8"</tt>).</dd>
|
2300
|
-
|
2301
|
-
<dt>dump_errors</dt>
|
2302
|
-
<dd>отображать ошибки в логе.</dd>
|
2303
|
-
|
2304
|
-
<dt>environment</dt>
|
2305
|
-
<dd>
|
2306
|
-
текущее окружение, по умолчанию, значение <tt>ENV['APP_ENV']</tt> или
|
2307
|
-
<tt>"development"</tt>, если <tt>ENV['APP_ENV']</tt> недоступна.
|
2308
|
-
</dd>
|
2309
|
-
|
2310
|
-
<dt>logging</dt>
|
2311
|
-
<dd>использовать логер.</dd>
|
2312
|
-
|
2313
|
-
<dt>lock</dt>
|
2314
|
-
<dd>
|
2315
|
-
создаёт блокировку для каждого запроса, которая гарантирует обработку
|
2316
|
-
только одного запроса в текущий момент времени в Ruby процессе.
|
2317
|
-
</dd>
|
2318
|
-
<dd>
|
2319
|
-
включайте в том случае, если ваше приложение не потокобезопасно (thread-safe).
|
2320
|
-
Отключено по умолчанию.
|
2321
|
-
</dd>
|
2322
|
-
|
2323
|
-
<dt>method_override</dt>
|
2324
|
-
<dd>
|
2325
|
-
использовать "магический" параметр <tt>_method</tt> для поддержки
|
2326
|
-
PUT/DELETE форм в браузерах, которые не поддерживают данные методы.
|
2327
|
-
</dd>
|
2328
|
-
|
2329
|
-
<dt>mustermann_opts</dt>
|
2330
|
-
<dd>
|
2331
|
-
хэш настроек по умолчанию для перехода к Mustermann.new при компиляции
|
2332
|
-
маршрутов маршрутизации.
|
2333
|
-
</dd>
|
2334
|
-
|
2335
|
-
<dt>port</dt>
|
2336
|
-
<dd>
|
2337
|
-
порт, на котором будет работать сервер.
|
2338
|
-
Используется только встроенным сервером.
|
2339
|
-
</dd>
|
2340
|
-
|
2341
|
-
<dt>prefixed_redirects</dt>
|
2342
|
-
<dd>
|
2343
|
-
добавлять или нет параметр <tt>request.script_name</tt> к редиректам, если не
|
2344
|
-
задан абсолютный путь. Таким образом, <tt>redirect '/foo'</tt> будет вести себя
|
2345
|
-
как <tt>redirect to('/foo')</tt>. Отключено по умолчанию.
|
2346
|
-
</dd>
|
2347
|
-
|
2348
|
-
<dt>protection</dt>
|
2349
|
-
<dd>включена или нет защита от атак. Смотрите секцию защиты от атак выше.</dd>
|
2350
|
-
|
2351
|
-
<dt>public_dir</dt>
|
2352
|
-
<dd>алиас для <tt>public_folder</tt>.</dd>
|
2353
|
-
|
2354
|
-
<dt>public_folder</dt>
|
2355
|
-
<dd>
|
2356
|
-
путь к общедоступной директории, откуда будут раздаваться файлы.
|
2357
|
-
Используется, только если включена раздача статических файлов
|
2358
|
-
(см. опцию <tt>static</tt> ниже). Берётся из настройки <tt>app_file</tt>,
|
2359
|
-
если не установлена.
|
2360
|
-
</dd>
|
2361
|
-
|
2362
|
-
<dt>quiet</dt>
|
2363
|
-
<dd>
|
2364
|
-
отключает журналы, созданные командами запуска и остановки Sinatra.
|
2365
|
-
<tt>false</tt> по умолчанию.
|
2366
|
-
</dd>
|
2367
|
-
|
2368
|
-
<dt>reload_templates</dt>
|
2369
|
-
<dd>
|
2370
|
-
перезагружать или нет шаблоны на каждый запрос. Включено в режиме
|
2371
|
-
разработки.
|
2372
|
-
</dd>
|
2373
|
-
|
2374
|
-
<dt>root</dt>
|
2375
|
-
<dd>
|
2376
|
-
путь к корневой директории проекта. Берётся из настройки <tt>app_file</tt>,
|
2377
|
-
если не установлен.
|
2378
|
-
</dd>
|
2379
|
-
|
2380
|
-
<dt>raise_errors</dt>
|
2381
|
-
<dd>
|
2382
|
-
выбрасывать исключения (будет останавливать приложение).
|
2383
|
-
По умолчанию включено только в окружении <tt>"test"</tt>.
|
2384
|
-
</dd>
|
2385
|
-
|
2386
|
-
<dt>run</dt>
|
2387
|
-
<dd>
|
2388
|
-
если включено, Sinatra будет самостоятельно запускать веб-сервер. Не
|
2389
|
-
включайте, если используете rackup или аналогичные средства.
|
2390
|
-
</dd>
|
2391
|
-
|
2392
|
-
<dt>running</dt>
|
2393
|
-
<dd>работает ли сейчас встроенный сервер? Не меняйте эту опцию!</dd>
|
2394
|
-
|
2395
|
-
<dt>server</dt>
|
2396
|
-
<dd>
|
2397
|
-
сервер или список серверов, которые следует использовать в качестве
|
2398
|
-
встроенного сервера. Порядок задаёт приоритет, по умолчанию зависит
|
2399
|
-
от реализации Ruby.
|
2400
|
-
</dd>
|
2401
|
-
|
2402
|
-
<dt>server_settings</dt>
|
2403
|
-
<dd>
|
2404
|
-
Если вы используете в качестве сервера WEBrick, например для работы в
|
2405
|
-
режиме разработки, то вы можете передать набор опций для <tt>server_settings</tt>,
|
2406
|
-
таких как <tt>SSLEnable</tt> или <tt>SSLVerifyClient</tt>. Тем не менее, такие
|
2407
|
-
серверы как Puma или Thin не поддерживают эти параметры, поэтому вы можете
|
2408
|
-
устанавливать <tt>server_settings</tt> указав его как метод при вызове
|
2409
|
-
<tt>configure</tt>.
|
2410
|
-
</dd>
|
2411
|
-
|
2412
|
-
<dt>sessions</dt>
|
2413
|
-
<dd>
|
2414
|
-
включить сессии на основе кук (cookie) на базе <tt>Rack::Session::Cookie</tt>.
|
2415
|
-
Смотрите раздел "Использование сессий" выше.
|
2416
|
-
</dd>
|
2417
|
-
|
2418
|
-
<dt>session_store</dt>
|
2419
|
-
<dd>
|
2420
|
-
используемая Rack "прослойка" для сессии. По умолчанию <tt>Rack::Session::Cookie</tt>.
|
2421
|
-
Смотрите раздел "Использование сессий" выше.
|
2422
|
-
</dd>
|
2423
|
-
|
2424
|
-
<dt>show_exceptions</dt>
|
2425
|
-
<dd>
|
2426
|
-
показывать исключения/стек вызовов (stack trace) в браузере. По умолчанию
|
2427
|
-
включено только в окружении <tt>"development"</tt>.
|
2428
|
-
</dd>
|
2429
|
-
<dd>
|
2430
|
-
может также быть установлено в <tt>:after_handler</tt> для запуска специфичной
|
2431
|
-
для приложения обработки ошибок, перед показом трассировки стека в браузере.
|
2432
|
-
</dd>
|
2433
|
-
|
2434
|
-
<dt>static</dt>
|
2435
|
-
<dd>указывает, должна ли Sinatra осуществлять раздачу статических файлов.</dd>
|
2436
|
-
<dd>Отключите, если используете какой-либо веб-сервер для этой цели.</dd>
|
2437
|
-
<dd>Отключение значительно улучшит производительность приложения.</dd>
|
2438
|
-
<dd>По умолчанию включено в классических и отключено в модульных приложениях.</dd>
|
2439
|
-
|
2440
|
-
<dt>static_cache_control</dt>
|
2441
|
-
<dd>
|
2442
|
-
когда Sinatra раздаёт статические файлы, используйте эту опцию для того,
|
2443
|
-
чтобы добавить им заголовок <tt>Cache-Control</tt>. Для этого используется
|
2444
|
-
метод-помощник <tt>cache_control</tt>. По умолчанию отключено.
|
2445
|
-
</dd>
|
2446
|
-
<dd>
|
2447
|
-
используйте массив, когда надо задать несколько значений:
|
2448
|
-
<tt>set :static_cache_control, [:public, :max_age => 300]</tt>
|
2449
|
-
</dd>
|
2450
|
-
|
2451
|
-
<dt>threaded</dt>
|
2452
|
-
<dd>
|
2453
|
-
если включено, то Thin будет использовать <tt>EventMachine.defer</tt> для
|
2454
|
-
обработки запросов.
|
2455
|
-
</dd>
|
2456
|
-
|
2457
|
-
<dt>traps</dt>
|
2458
|
-
<dd>указывает, должна ли Sinatra обрабатывать системные сигналы.</tt></dd>
|
2459
|
-
|
2460
|
-
<dt>views</dt>
|
2461
|
-
<dd>
|
2462
|
-
путь к директории с шаблонами. Берётся из настройки <tt>app_file</tt> в том
|
2463
|
-
случае, если не установлен.
|
2464
|
-
</dd>
|
2465
|
-
|
2466
|
-
<dt>x_cascade</dt>
|
2467
|
-
<dd>
|
2468
|
-
Указывает, необходимо ли устанавливать заголовок X-Cascade если никакие маршруты не совпадают.
|
2469
|
-
<tt>true</tt> по умолчанию.
|
2470
|
-
</dd>
|
2471
|
-
</dl>
|
2472
|
-
|
2473
|
-
## Режим, окружение
|
2474
|
-
|
2475
|
-
Есть 3 предопределённых режима работы приложения (окружения): `"development"`,
|
2476
|
-
`"production"` и `"test"`. Режим может быть задан через переменную окружения `APP_ENV`.
|
2477
|
-
Значение по умолчанию — `"development"`. В этом режиме работы все шаблоны
|
2478
|
-
перезагружаются между запросами, а также задаются специальные обработчики
|
2479
|
-
`not_found` и `error`, чтобы вы могли увидеть стек вызовов. В окружениях
|
2480
|
-
`"production"` и `"test"` шаблоны по умолчанию кэшируются.
|
2481
|
-
|
2482
|
-
Для запуска приложения в определённом окружении установите переменную
|
2483
|
-
окружения `APP_ENV`:
|
2484
|
-
|
2485
|
-
```shell
|
2486
|
-
APP_ENV=production ruby my_app.rb
|
2487
|
-
```
|
2488
|
-
|
2489
|
-
Вы можете использовать предопределённые методы `development?`, `test?` и
|
2490
|
-
`production?`, чтобы определить текущее окружение.
|
2491
|
-
|
2492
|
-
```ruby
|
2493
|
-
get '/' do
|
2494
|
-
if settings.development?
|
2495
|
-
"development!"
|
2496
|
-
else
|
2497
|
-
"not development!"
|
2498
|
-
end
|
2499
|
-
end
|
2500
|
-
```
|
2501
|
-
|
2502
|
-
## Обработка ошибок
|
2503
|
-
|
2504
|
-
Обработчики ошибок исполняются в том же контексте, что и маршруты и
|
2505
|
-
`before`-фильтры, а это означает, что всякие прелести вроде `haml`, `erb`,
|
2506
|
-
`halt` и т.д. доступны и им.
|
2507
|
-
|
2508
|
-
### Not Found
|
2509
|
-
|
2510
|
-
В случае возникновения исключения `Sinatra::NotFound` или возврата кода ответа 404
|
2511
|
-
будет вызван обработчик `not_found`:
|
2512
|
-
|
2513
|
-
```ruby
|
2514
|
-
not_found do
|
2515
|
-
'This is nowhere to be found.'
|
2516
|
-
end
|
2517
|
-
```
|
2518
|
-
|
2519
|
-
### Error
|
2520
|
-
|
2521
|
-
Обработчик ошибок `error` будет вызван тогда, когда исключение выброшено из блока
|
2522
|
-
маршрута либо из фильтра. Тем не менее, обратите внимание на то, что в режиме разработки
|
2523
|
-
он будет запускаться только в том случае, если вы установите опцию "show exceptions"
|
2524
|
-
на `: after_handler`:
|
2525
|
-
|
2526
|
-
```ruby
|
2527
|
-
set :show_exceptions, :after_handler
|
2528
|
-
```
|
2529
|
-
|
2530
|
-
Объект-исключение доступен как переменная `sinatra.error` в Rack:
|
2531
|
-
|
2532
|
-
```ruby
|
2533
|
-
error do
|
2534
|
-
'Sorry there was a nasty error - ' + env['sinatra.error'].message
|
2535
|
-
end
|
2536
|
-
```
|
2537
|
-
|
2538
|
-
Пользовательские ошибки:
|
2539
|
-
|
2540
|
-
```ruby
|
2541
|
-
error MyCustomError do
|
2542
|
-
'So what happened was...' + env['sinatra.error'].message
|
2543
|
-
end
|
2544
|
-
```
|
2545
|
-
|
2546
|
-
Тогда, если это возникнет:
|
2547
|
-
|
2548
|
-
```ruby
|
2549
|
-
get '/' do
|
2550
|
-
raise MyCustomError, 'something bad'
|
2551
|
-
end
|
2552
|
-
```
|
2553
|
-
|
2554
|
-
То вы получите:
|
2555
|
-
|
2556
|
-
```
|
2557
|
-
So what happened was... something bad
|
2558
|
-
```
|
2559
|
-
|
2560
|
-
Также вы можете установить обработчик ошибок для кода состояния HTTP:
|
2561
|
-
|
2562
|
-
```ruby
|
2563
|
-
error 403 do
|
2564
|
-
'Access forbidden'
|
2565
|
-
end
|
2566
|
-
|
2567
|
-
get '/secret' do
|
2568
|
-
403
|
2569
|
-
end
|
2570
|
-
```
|
2571
|
-
|
2572
|
-
Либо набора кодов:
|
2573
|
-
|
2574
|
-
```ruby
|
2575
|
-
error 400..510 do
|
2576
|
-
'Boom'
|
2577
|
-
end
|
2578
|
-
```
|
2579
|
-
|
2580
|
-
Sinatra устанавливает специальные обработчики `not_found` и `error`, когда
|
2581
|
-
приложение запущено в режиме разработки (окружение `:development`) чтобы
|
2582
|
-
отображать информативные трассировки стека и дополнительную информацию об отладке
|
2583
|
-
в вашем браузере.
|
2584
|
-
|
2585
|
-
## Rack "прослойки"
|
2586
|
-
|
2587
|
-
Sinatra использует [Rack](https://rack.github.io/) - минимальный стандартный
|
2588
|
-
интерфейс для веб-фреймворков на Ruby. Одной из самых интересных для
|
2589
|
-
разработчиков возможностей Rack является поддержка "прослоек" ("middleware") —
|
2590
|
-
компонентов, находящихся "между" сервером и вашим приложением, которые
|
2591
|
-
отслеживают и/или манипулируют HTTP запросами/ответами для предоставления
|
2592
|
-
различной функциональности.
|
2593
|
-
|
2594
|
-
Sinatra позволяет очень просто создавать пайплайны из подобных Rack "прослоек"
|
2595
|
-
при помощи метода `use`:
|
2596
|
-
|
2597
|
-
```ruby
|
2598
|
-
require 'sinatra'
|
2599
|
-
require 'my_custom_middleware'
|
2600
|
-
|
2601
|
-
use Rack::Lint
|
2602
|
-
use MyCustomMiddleware
|
2603
|
-
|
2604
|
-
get '/hello' do
|
2605
|
-
'Hello World'
|
2606
|
-
end
|
2607
|
-
```
|
2608
|
-
|
2609
|
-
Семантика `use` идентична той, что определена для
|
2610
|
-
[Rack::Builder](http://www.rubydoc.info/github/rack/rack/master/Rack/Builder) DSL
|
2611
|
-
(чаще всего используется в rackup файлах). Так, например, метод `use` принимает как
|
2612
|
-
множественные переменные, так и блоки:
|
2613
|
-
|
2614
|
-
```ruby
|
2615
|
-
use Rack::Auth::Basic do |username, password|
|
2616
|
-
username == 'admin' && password == 'secret'
|
2617
|
-
end
|
2618
|
-
```
|
2619
|
-
|
2620
|
-
Rack распространяется с различными стандартными "прослойками" для логирования,
|
2621
|
-
отладки, маршрутизации URL, аутентификации, обработки сессий. Sinatra
|
2622
|
-
использует многие из этих компонентов автоматически, основываясь на
|
2623
|
-
конфигурации, чтобы вам не приходилось подключать их при помощи `use` вручную.
|
2624
|
-
|
2625
|
-
Вы можете найти полезные прослойки в
|
2626
|
-
[rack](https://github.com/rack/rack/tree/master/lib/rack),
|
2627
|
-
[rack-contrib](https://github.com/rack/rack-contrib#readme),
|
2628
|
-
или в [Rack wiki](https://github.com/rack/rack/wiki/List-of-Middleware).
|
2629
|
-
|
2630
|
-
## Тестирование
|
2631
|
-
|
2632
|
-
Тесты для Sinatra приложений могут быть написаны при помощи любых библиотек или
|
2633
|
-
фреймворков, поддерживающих тестирование Rack. Разработчики гема Sinatra рекомендуют
|
2634
|
-
использовать [Rack::Test](http://www.rubydoc.info/github/brynary/rack-test/master/frames):
|
2635
|
-
|
2636
|
-
```ruby
|
2637
|
-
require 'my_sinatra_app'
|
2638
|
-
require 'minitest/autorun'
|
2639
|
-
require 'rack/test'
|
2640
|
-
|
2641
|
-
class MyAppTest < Minitest::Test
|
2642
|
-
include Rack::Test::Methods
|
2643
|
-
|
2644
|
-
def app
|
2645
|
-
Sinatra::Application
|
2646
|
-
end
|
2647
|
-
|
2648
|
-
def test_my_default
|
2649
|
-
get '/'
|
2650
|
-
assert_equal 'Hello World!', last_response.body
|
2651
|
-
end
|
2652
|
-
|
2653
|
-
def test_with_params
|
2654
|
-
get '/meet', :name => 'Frank'
|
2655
|
-
assert_equal 'Hello Frank!', last_response.body
|
2656
|
-
end
|
2657
|
-
|
2658
|
-
def test_with_user_agent
|
2659
|
-
get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
|
2660
|
-
assert_equal "You're using Songbird!", last_response.body
|
2661
|
-
end
|
2662
|
-
end
|
2663
|
-
```
|
2664
|
-
|
2665
|
-
Примечание: если вы используете Sinatra в модульном стиле, замените
|
2666
|
-
`Sinatra::Application` в примере выше на имя класса вашего приложения.
|
2667
|
-
|
2668
|
-
## Sinatra::Base — "прослойки", библиотеки и модульные приложения
|
2669
|
-
|
2670
|
-
Описание вашего приложения на верхнем уровне хорошо работает для микроприложений,
|
2671
|
-
но имеет значительные недостатки при создании многоразовых компонентов, таких как
|
2672
|
-
Rack "прослойка", Rails metal, простые библиотеки с серверным компонентом или
|
2673
|
-
даже расширения Sinatra. Верхний уровень предполагает конфигурацию стиля
|
2674
|
-
микроприложений (например, одиночный файл приложения, `./public` и `./views`,
|
2675
|
-
каталоги, логирование, страницу подробных сведений об исключениях и т.д.).
|
2676
|
-
И тут на помощь приходит `Sinatra::Base`:
|
2677
|
-
|
2678
|
-
```ruby
|
2679
|
-
require 'sinatra/base'
|
2680
|
-
|
2681
|
-
class MyApp < Sinatra::Base
|
2682
|
-
set :sessions, true
|
2683
|
-
set :foo, 'bar'
|
2684
|
-
|
2685
|
-
get '/' do
|
2686
|
-
'Hello world!'
|
2687
|
-
end
|
2688
|
-
end
|
2689
|
-
```
|
2690
|
-
|
2691
|
-
Методы, доступные подклассам `Sinatra::Base` идентичны тем, что доступны
|
2692
|
-
приложениям при помощи DSL верхнего уровня. Большинство таких приложений могут быть
|
2693
|
-
конвертированы в `Sinatra::Base` компоненты при помощи двух модификаций:
|
2694
|
-
|
2695
|
-
* Вы должны подключать `sinatra/base` вместо `sinatra`, иначе все DSL методы,
|
2696
|
-
предоставляемые Sinatra, будут импортированы в глобальное пространство
|
2697
|
-
имён.
|
2698
|
-
* Поместите все маршруты, обработчики ошибок, фильтры и опции в подкласс
|
2699
|
-
`Sinatra::Base`.
|
2700
|
-
|
2701
|
-
`Sinatra::Base` — это чистый лист. Большинство опций, включая встроенный
|
2702
|
-
сервер, по умолчанию отключены. Смотрите
|
2703
|
-
[Опции и конфигурация](http://www.sinatrarb.com/configuration.html)
|
2704
|
-
для детальной информации об опциях и их поведении. Если вы хотите, чтобы
|
2705
|
-
поведение было более похоже на то, когда вы определяете своё приложение
|
2706
|
-
на верхнем уровне (также известно как классический стиль), вы можете
|
2707
|
-
унаследоваться от `Sinatra::Application`:
|
2708
|
-
|
2709
|
-
```ruby
|
2710
|
-
require 'sinatra/base'
|
2711
|
-
|
2712
|
-
class MyApp < Sinatra::Application
|
2713
|
-
get '/' do
|
2714
|
-
'Hello world!'
|
2715
|
-
end
|
2716
|
-
end
|
2717
|
-
```
|
2718
|
-
|
2719
|
-
### Модульные приложения против классических
|
2720
|
-
|
2721
|
-
Вопреки всеобщему убеждению, в классическом стиле (самом простом) нет ничего
|
2722
|
-
плохого. Если этот стиль подходит вашему приложению, вы не обязаны
|
2723
|
-
переписывать его в модульное приложение.
|
2724
|
-
|
2725
|
-
Основным недостатком классического стиля является тот факт, что у вас может
|
2726
|
-
быть только одно приложение Sinatra на один процесс Ruby. Если вы планируете
|
2727
|
-
использовать больше, переключайтесь на модульный стиль. Вы можете смело
|
2728
|
-
смешивать модульный и классический стили.
|
2729
|
-
|
2730
|
-
Переходя с одного стиля на другой, примите во внимание следующие изменения в
|
2731
|
-
настройках:
|
2732
|
-
|
2733
|
-
<table>
|
2734
|
-
<tr>
|
2735
|
-
<th>Опция</th>
|
2736
|
-
<th>Классический</th>
|
2737
|
-
<th>Модульный</th>
|
2738
|
-
<th>Модульный</th>
|
2739
|
-
</tr>
|
2740
|
-
|
2741
|
-
<tr>
|
2742
|
-
<td>app_file</td>
|
2743
|
-
<td>файл с приложением</td>
|
2744
|
-
<td>файл с подклассом Sinatra::Base</td>
|
2745
|
-
<td>файл с подклассом Sinatra::Application</td>
|
2746
|
-
</tr>
|
2747
|
-
|
2748
|
-
<tr>
|
2749
|
-
<td>run</td>
|
2750
|
-
<td>$0 == app_file</td>
|
2751
|
-
<td>false</td>
|
2752
|
-
<td>false</td>
|
2753
|
-
</tr>
|
2754
|
-
|
2755
|
-
<tr>
|
2756
|
-
<td>logging</td>
|
2757
|
-
<td>true</td>
|
2758
|
-
<td>false</td>
|
2759
|
-
<td>true</td>
|
2760
|
-
</tr>
|
2761
|
-
|
2762
|
-
<tr>
|
2763
|
-
<td>method_override</td>
|
2764
|
-
<td>true</td>
|
2765
|
-
<td>false</td>
|
2766
|
-
<td>true</td>
|
2767
|
-
</tr>
|
2768
|
-
|
2769
|
-
<tr>
|
2770
|
-
<td>inline_templates</td>
|
2771
|
-
<td>true</td>
|
2772
|
-
<td>false</td>
|
2773
|
-
<td>true</td>
|
2774
|
-
</tr>
|
2775
|
-
|
2776
|
-
<tr>
|
2777
|
-
<td>static</td>
|
2778
|
-
<td>true</td>
|
2779
|
-
<td>File.exist?(public_folder)</td>
|
2780
|
-
<td>true</td>
|
2781
|
-
</tr>
|
2782
|
-
</table>
|
2783
|
-
|
2784
|
-
### Запуск модульных приложений
|
2785
|
-
|
2786
|
-
Есть два общепринятых способа запускать модульные приложения: запуск напрямую
|
2787
|
-
при помощи `run!`:
|
2788
|
-
|
2789
|
-
```ruby
|
2790
|
-
# my_app.rb
|
2791
|
-
require 'sinatra/base'
|
2792
|
-
|
2793
|
-
class MyApp < Sinatra::Base
|
2794
|
-
# ... здесь код приложения ...
|
2795
|
-
|
2796
|
-
# запускаем сервер, если исполняется текущий файл
|
2797
|
-
run! if app_file == $0
|
2798
|
-
end
|
2799
|
-
```
|
2800
|
-
|
2801
|
-
Затем:
|
2802
|
-
|
2803
|
-
```shell
|
2804
|
-
ruby my_app.rb
|
2805
|
-
```
|
2806
|
-
|
2807
|
-
Или при помощи конфигурационного файла `config.ru`, который позволяет
|
2808
|
-
использовать любой Rack-совместимый сервер приложений:
|
2809
|
-
|
2810
|
-
```ruby
|
2811
|
-
# config.ru (запускается при помощи Rackup)
|
2812
|
-
require './my_app'
|
2813
|
-
run MyApp
|
2814
|
-
```
|
2815
|
-
|
2816
|
-
Запускаем:
|
2817
|
-
|
2818
|
-
```shell
|
2819
|
-
rackup -p 4567
|
2820
|
-
```
|
2821
|
-
|
2822
|
-
### Запуск классических приложений с config.ru
|
2823
|
-
|
2824
|
-
Файл приложения:
|
2825
|
-
|
2826
|
-
```ruby
|
2827
|
-
# app.rb
|
2828
|
-
require 'sinatra'
|
2829
|
-
|
2830
|
-
get '/' do
|
2831
|
-
'Hello world!'
|
2832
|
-
end
|
2833
|
-
```
|
2834
|
-
|
2835
|
-
И соответствующий `config.ru`:
|
2836
|
-
|
2837
|
-
```ruby
|
2838
|
-
require './app'
|
2839
|
-
run Sinatra::Application
|
2840
|
-
```
|
2841
|
-
|
2842
|
-
### Когда использовать config.ru?
|
2843
|
-
|
2844
|
-
Использование файла `config.ru` рекомендовано если:
|
2845
|
-
|
2846
|
-
* вы хотите разворачивать своё приложение на различных Rack-совместимых
|
2847
|
-
серверах (Passenger, Unicorn, Heroku, ...);
|
2848
|
-
* вы хотите использовать более одного подкласса `Sinatra::Base`;
|
2849
|
-
* вы хотите использовать Sinatra только в качестве "прослойки" Rack.
|
2850
|
-
|
2851
|
-
**Совсем необязательно переходить на использование `config.ru` лишь потому,
|
2852
|
-
что вы стали использовать модульный стиль приложения. И необязательно
|
2853
|
-
использовать модульный стиль, чтобы запускать приложение при помощи
|
2854
|
-
`config.ru`.**
|
2855
|
-
|
2856
|
-
### Использование Sinatra в качестве "прослойки"
|
2857
|
-
|
2858
|
-
Не только сама Sinatra может использовать "прослойки" Rack, но и любое Sinatra
|
2859
|
-
приложение само может быть добавлено к любому Rack endpoint в качестве
|
2860
|
-
"прослойки". Этим endpoint (конечной точкой) может быть другое Sinatra
|
2861
|
-
приложение или любое другое приложение, основанное на Rack (Rails/Hamami/Roda/...):
|
2862
|
-
|
2863
|
-
```ruby
|
2864
|
-
require 'sinatra/base'
|
2865
|
-
|
2866
|
-
class LoginScreen < Sinatra::Base
|
2867
|
-
enable :sessions
|
2868
|
-
|
2869
|
-
get('/login') { haml :login }
|
2870
|
-
|
2871
|
-
post('/login') do
|
2872
|
-
if params['name'] == 'admin' && params['password'] == 'admin'
|
2873
|
-
session['user_name'] = params['name']
|
2874
|
-
else
|
2875
|
-
redirect '/login'
|
2876
|
-
end
|
2877
|
-
end
|
2878
|
-
end
|
2879
|
-
|
2880
|
-
class MyApp < Sinatra::Base
|
2881
|
-
# "прослойка" будет запущена перед фильтрами
|
2882
|
-
use LoginScreen
|
2883
|
-
|
2884
|
-
before do
|
2885
|
-
unless session['user_name']
|
2886
|
-
halt "Access denied, please <a href='/login'>login</a>."
|
2887
|
-
end
|
2888
|
-
end
|
2889
|
-
|
2890
|
-
get('/') { "Hello #{session['user_name']}." }
|
2891
|
-
end
|
2892
|
-
```
|
2893
|
-
|
2894
|
-
### Создание приложений "на лету"
|
2895
|
-
|
2896
|
-
Иногда требуется создавать Sinatra приложения "на лету" (например, из другого
|
2897
|
-
приложения), не сохраняя их в константу. Это возможно при помощи `Sinatra.new`:
|
2898
|
-
|
2899
|
-
```ruby
|
2900
|
-
require 'sinatra/base'
|
2901
|
-
my_app = Sinatra.new { get('/') { "hi" } }
|
2902
|
-
my_app.run!
|
2903
|
-
```
|
2904
|
-
|
2905
|
-
Этот метод может принимать аргументом приложение, от которого следует
|
2906
|
-
наследоваться:
|
2907
|
-
|
2908
|
-
```ruby
|
2909
|
-
# config.ru (запускается при помощи Rackup)
|
2910
|
-
require 'sinatra/base'
|
2911
|
-
|
2912
|
-
controller = Sinatra.new do
|
2913
|
-
enable :logging
|
2914
|
-
helpers MyHelpers
|
2915
|
-
end
|
2916
|
-
|
2917
|
-
map('/a') do
|
2918
|
-
run Sinatra.new(controller) { get('/') { 'a' } }
|
2919
|
-
end
|
2920
|
-
|
2921
|
-
map('/b') do
|
2922
|
-
run Sinatra.new(controller) { get('/') { 'b' } }
|
2923
|
-
end
|
2924
|
-
```
|
2925
|
-
|
2926
|
-
Это особенно полезно для тестирования расширений Sinatra и при использовании
|
2927
|
-
Sinatra внутри вашей библиотеки.
|
2928
|
-
|
2929
|
-
Это также значительно упрощает использование Sinatra в качестве прослойки:
|
2930
|
-
|
2931
|
-
```ruby
|
2932
|
-
require 'sinatra/base'
|
2933
|
-
|
2934
|
-
use Sinatra do
|
2935
|
-
get('/') { ... }
|
2936
|
-
end
|
2937
|
-
|
2938
|
-
run RailsProject::Application
|
2939
|
-
```
|
2940
|
-
|
2941
|
-
## Области видимости и привязка
|
2942
|
-
|
2943
|
-
Текущая область видимости определяет методы и переменные, доступные в данный
|
2944
|
-
момент.
|
2945
|
-
|
2946
|
-
### Область видимости приложения / класса
|
2947
|
-
|
2948
|
-
Любое Sinatra приложение соответствует подклассу `Sinatra::Base`. Если вы
|
2949
|
-
используете DSL верхнего уровня (`require 'sinatra'`), то этим классом будет
|
2950
|
-
`Sinatra::Application`, иначе это будет подкласс, который вы создали вручную.
|
2951
|
-
На уровне класса вам будут доступны такие методы, как `get` или `before`, но
|
2952
|
-
вы не сможете получить доступ к объектам `request` или `session`, так как
|
2953
|
-
существует только один класс приложения для всех запросов.
|
2954
|
-
|
2955
|
-
Опции, созданные при помощи `set`, являются методами уровня класса:
|
2956
|
-
|
2957
|
-
```ruby
|
2958
|
-
class MyApp < Sinatra::Base
|
2959
|
-
# Я в области видимости приложения!
|
2960
|
-
set :foo, 42
|
2961
|
-
foo # => 42
|
2962
|
-
|
2963
|
-
get '/foo' do
|
2964
|
-
# Я больше не в области видимости приложения!
|
2965
|
-
end
|
2966
|
-
end
|
2967
|
-
```
|
2968
|
-
|
2969
|
-
У вас будет привязка к области видимости приложения внутри:
|
2970
|
-
|
2971
|
-
* тела вашего класса приложения;
|
2972
|
-
* методов, определённых расширениями;
|
2973
|
-
* блока, переданного в `helpers`;
|
2974
|
-
* блоков, использованных как значения для `set`;
|
2975
|
-
* блока, переданного в `Sinatra.new`.
|
2976
|
-
|
2977
|
-
Вы можете получить доступ к объекту области видимости (классу приложения)
|
2978
|
-
следующими способами:
|
2979
|
-
|
2980
|
-
* через объект, переданный блокам конфигурации (`configure { |c| ... }`);
|
2981
|
-
* `settings` внутри области видимости запроса.
|
2982
|
-
|
2983
|
-
### Область видимости запроса / экземпляра
|
2984
|
-
|
2985
|
-
Для каждого входящего запроса будет создан новый экземпляр вашего приложения,
|
2986
|
-
и все блоки обработчика будут запущены в этом контексте. В этой области
|
2987
|
-
видимости вам доступны `request` и `session` объекты, а также вызовы методов
|
2988
|
-
рендеринга, такие как `erb` или `haml`. Вы можете получить доступ к области
|
2989
|
-
видимости приложения из контекста запроса используя метод-помощник
|
2990
|
-
`settings`:
|
2991
|
-
|
2992
|
-
```ruby
|
2993
|
-
class MyApp < Sinatra::Base
|
2994
|
-
# Я в области видимости приложения!
|
2995
|
-
get '/define_route/:name' do
|
2996
|
-
# Область видимости запроса '/define_route/:name'
|
2997
|
-
@value = 42
|
2998
|
-
|
2999
|
-
settings.get("/#{params['name']}") do
|
3000
|
-
# Область видимости запроса "/#{params['name']}"
|
3001
|
-
@value # => nil (другой запрос)
|
3002
|
-
end
|
3003
|
-
|
3004
|
-
"Route defined!"
|
3005
|
-
end
|
3006
|
-
end
|
3007
|
-
```
|
3008
|
-
|
3009
|
-
У вас будет привязка к области видимости запроса в:
|
3010
|
-
|
3011
|
-
* get, head, post, put, delete, options, patch, link и unlink блоках;
|
3012
|
-
* before и after фильтрах;
|
3013
|
-
* методах-помощниках;
|
3014
|
-
* шаблонах/отображениях.
|
3015
|
-
|
3016
|
-
### Область видимости делегирования
|
3017
|
-
|
3018
|
-
Область видимости делегирования просто перенаправляет методы в область
|
3019
|
-
видимости класса. Однако, она не полностью ведет себя как область видимости
|
3020
|
-
класса, так как у вас нет привязки к классу. Только методы, явно помеченные
|
3021
|
-
для делегирования, будут доступны, а переменных/состояний области видимости
|
3022
|
-
класса не будет (иначе говоря, у вас будет другой `self` объект). Вы можете
|
3023
|
-
непосредственно добавить методы делегирования, используя
|
3024
|
-
`Sinatra::Delegator.delegate :method_name`.
|
3025
|
-
|
3026
|
-
У вас будет контекст делегирования внутри:
|
3027
|
-
|
3028
|
-
* привязки верхнего уровня, если вы сделали `require "sinatra"`;
|
3029
|
-
* объекта, расширенного при помощи `Sinatra::Delegator`.
|
3030
|
-
|
3031
|
-
Посмотрите сами в код: вот
|
3032
|
-
[примесь Sinatra::Delegator](https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/base.rb#L1609-1633)
|
3033
|
-
[расширяет главный объект](https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/main.rb#L28-30).
|
3034
|
-
|
3035
|
-
## Командная строка
|
3036
|
-
|
3037
|
-
Sinatra приложения могут быть запущены напрямую:
|
3038
|
-
|
3039
|
-
```shell
|
3040
|
-
ruby myapp.rb [-h] [-x] [-q] [-e ENVIRONMENT] [-p PORT] [-o HOST] [-s HANDLER]
|
3041
|
-
```
|
3042
|
-
|
3043
|
-
Поддерживаемые опции:
|
3044
|
-
|
3045
|
-
```
|
3046
|
-
-h # раздел помощи
|
3047
|
-
-p # указание порта (по умолчанию 4567)
|
3048
|
-
-o # указание хоста (по умолчанию 0.0.0.0)
|
3049
|
-
-e # указание окружения, режима (по умолчанию development)
|
3050
|
-
-s # указание rack сервера/обработчика (по умолчанию thin)
|
3051
|
-
-q # включить тихий режим для сервера (по умолчанию выключен)
|
3052
|
-
-x # включить мьютекс-блокировку (по умолчанию выключена)
|
3053
|
-
```
|
3054
|
-
|
3055
|
-
### Многопоточность
|
3056
|
-
|
3057
|
-
_Данный раздел является перефразированным [ответом пользователя Konstantin](https://stackoverflow.com/a/6282999/5245129) на StackOverflow_
|
3058
|
-
|
3059
|
-
Sinatra не навязывает каких-либо моделей параллелизма, но для этих целей можно
|
3060
|
-
использовать любой Rack обработчик (сервер), например Thin, Puma или WEBrick. Сама
|
3061
|
-
по себе Sinatra потокобезопасна, поэтому нет никаких проблем в использовании
|
3062
|
-
поточной модели параллелизма в Rack обработчике. Это означает, что когда
|
3063
|
-
запускается сервер, вы должны указать правильный метод вызова для конкретного
|
3064
|
-
Rack обработчика. Пример ниже показывает, как можно запустить мультипоточный
|
3065
|
-
Thin сервер:
|
3066
|
-
|
3067
|
-
```ruby
|
3068
|
-
# app.rb
|
3069
|
-
|
3070
|
-
require 'sinatra/base'
|
3071
|
-
|
3072
|
-
class App < Sinatra::Base
|
3073
|
-
get '/' do
|
3074
|
-
"Hello, World"
|
3075
|
-
end
|
3076
|
-
end
|
3077
|
-
|
3078
|
-
App.run!
|
3079
|
-
|
3080
|
-
```
|
3081
|
-
|
3082
|
-
Для запуска сервере выполните следующую команду:
|
3083
|
-
|
3084
|
-
```shell
|
3085
|
-
thin --threaded start
|
3086
|
-
```
|
3087
|
-
|
3088
|
-
## Системные требования
|
3089
|
-
|
3090
|
-
Следующие версии Ruby официально поддерживаются:
|
3091
|
-
<dl>
|
3092
|
-
<dt>Ruby 2.3</dt>
|
3093
|
-
<dd>
|
3094
|
-
Версия 2.3 полностью поддерживается и рекомендуется. В настоящее время нет
|
3095
|
-
планов отказаться от официальной поддержки.
|
3096
|
-
</dd>
|
3097
|
-
|
3098
|
-
<dt>Rubinius</dt>
|
3099
|
-
<dd>
|
3100
|
-
Rubinius официально поддерживается (Rubinius >= 2.x). Рекомендуется
|
3101
|
-
выполнить <tt>gem install puma</tt>.
|
3102
|
-
</dd>
|
3103
|
-
|
3104
|
-
<dt>JRuby</dt>
|
3105
|
-
<dd>
|
3106
|
-
Официально поддерживается последний стабильный релиз JRuby. Не
|
3107
|
-
рекомендуется использовать расширений на C в JRuby. Рекомендуется
|
3108
|
-
выполнить <tt>gem install trinidad</tt>.
|
3109
|
-
</dd>
|
3110
|
-
</dl>
|
3111
|
-
|
3112
|
-
Версии Ruby ниже 2.2.2 более не поддерживаются в Sinatra 2.0.
|
3113
|
-
|
3114
|
-
Мы также следим за предстоящими к выходу версиями Ruby.
|
3115
|
-
|
3116
|
-
Следующие реализации Ruby не поддерживаются официально, однако известно, что
|
3117
|
-
на них запускается Sinatra:
|
3118
|
-
|
3119
|
-
* старые версии JRuby и Rubinius;
|
3120
|
-
* Ruby Enterprise Edition;
|
3121
|
-
* MacRuby, Maglev, IronRuby;
|
3122
|
-
* Ruby 1.9.0 и 1.9.1 (настоятельно не рекомендуются к использованию).
|
3123
|
-
|
3124
|
-
То, что версия официально не поддерживается, означает, что, если что-то не
|
3125
|
-
работает на этой версии, а на поддерживаемой работает — это не наша проблема,
|
3126
|
-
а их.
|
3127
|
-
|
3128
|
-
Мы также запускаем наши CI-тесты на ruby-head (будущие версии MRI), но мы не
|
3129
|
-
можем ничего гарантировать, так как ведётся постоянная разработка.
|
3130
|
-
Предполагается, что предстоящие релизы 2.x будут полностью поддерживаться.
|
3131
|
-
|
3132
|
-
Sinatra должна работать на любой операционной системе, в которой есть одна из
|
3133
|
-
указанных выше версий Ruby.
|
3134
|
-
|
3135
|
-
Если вы запускаете MacRuby, вы должны выполнить `gem install control_tower`.
|
3136
|
-
|
3137
|
-
Пока невозможно запустить Sinatra на Cardinal, SmallRuby, BlueRuby и на любой
|
3138
|
-
версии Ruby ниже 2.2.
|
3139
|
-
|
3140
|
-
## Самая свежая версия
|
3141
|
-
|
3142
|
-
Если вы хотите использовать самый последний релиз Sinatra, не бойтесь запускать
|
3143
|
-
своё приложение вместе с кодом из master ветки Sinatra, так как она весьма стабильна.
|
3144
|
-
|
3145
|
-
Мы также время от времени выпускаем предварительные версии, которые вы можете
|
3146
|
-
установить следующим образом:
|
3147
|
-
|
3148
|
-
```shell
|
3149
|
-
gem install sinatra --pre
|
3150
|
-
```
|
3151
|
-
|
3152
|
-
таким образом вы сможете воспользоваться некоторыми самыми последними возможностями.
|
3153
|
-
|
3154
|
-
### При помощи Bundler
|
3155
|
-
|
3156
|
-
Если вы хотите запускать своё приложение с последней версией Sinatra, то
|
3157
|
-
рекомендуем использовать [Bundler](http://bundler.io).
|
3158
|
-
|
3159
|
-
Для начала установите Bundler, если у вас его ещё нет:
|
3160
|
-
|
3161
|
-
```shell
|
3162
|
-
gem install bundler
|
3163
|
-
```
|
3164
|
-
|
3165
|
-
Затем создайте файл `Gemfile` в директории вашего проекта:
|
3166
|
-
|
3167
|
-
```ruby
|
3168
|
-
source 'https://rubygems.org'
|
3169
|
-
gem 'sinatra', :github => 'sinatra/sinatra'
|
3170
|
-
|
3171
|
-
# другие зависимости
|
3172
|
-
gem 'haml' # в том случае, если используете haml
|
3173
|
-
```
|
3174
|
-
|
3175
|
-
Имейте ввиду, что вам необходимо будет указывать все зависимости вашего приложения
|
3176
|
-
в `Gemfile`. Необходимые зависимости самой библиотеки Sinatra (Rack и Tilt)
|
3177
|
-
будут автоматически скачаны и добавлены Bundler.
|
3178
|
-
|
3179
|
-
Теперь вы можете запускать своё приложение следующим образом:
|
3180
|
-
|
3181
|
-
```shell
|
3182
|
-
bundle exec ruby myapp.rb
|
3183
|
-
```
|
3184
|
-
|
3185
|
-
## Версии
|
3186
|
-
|
3187
|
-
Sinatra использует [Semantic Versioning](https://semver.org/): как SemVer, так и
|
3188
|
-
SemVerTag.
|
3189
|
-
|
3190
|
-
## Дальнейшее чтение
|
3191
|
-
|
3192
|
-
* [Веб-сайт проекта](http://www.sinatrarb.com/) — Дополнительная
|
3193
|
-
документация, новости и ссылки на другие ресурсы.
|
3194
|
-
* [Участие в проекте](http://www.sinatrarb.com/contributing) — Обнаружили
|
3195
|
-
баг? Нужна помощь? Написали патч?
|
3196
|
-
* [Отслеживание проблем/ошибок](https://github.com/sinatra/sinatra/issues)
|
3197
|
-
* [Twitter](https://twitter.com/sinatra)
|
3198
|
-
* [Группы рассылки](https://groups.google.com/forum/#!forum/sinatrarb)
|
3199
|
-
* IRC: [#sinatra](irc://chat.freenode.net/#sinatra) на [Freenode](https://freenode.net)
|
3200
|
-
* [Sinatra и Друзья](https://sinatrarb.slack.com) на Slack, а так же
|
3201
|
-
[ссылка для инвайта](https://sinatra-slack.herokuapp.com/).
|
3202
|
-
* [Sinatra Book](https://github.com/sinatra/sinatra-book) учебник и сборник рецептов
|
3203
|
-
* [Sinatra Recipes](http://recipes.sinatrarb.com/) сборник рецептов
|
3204
|
-
* API документация к [последнему релизу](http://www.rubydoc.info/gems/sinatra)
|
3205
|
-
или [текущему HEAD](http://www.rubydoc.info/github/sinatra/sinatra) на
|
3206
|
-
http://www.rubydoc.info/
|
3207
|
-
* [Сервер непрерывной интеграции](https://travis-ci.org/sinatra/sinatra)
|