sinatra 2.2.2 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sinatra might be problematic. Click here for more details.

data/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)