sinatra 2.2.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
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)