sinatra 1.4.6 → 1.4.7

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

Potentially problematic release.


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

@@ -1,10 +1,97 @@
1
1
  # Sinatra
2
2
 
3
+ ## Содержание
4
+
5
+ * [Sinatra](#sinatra)
6
+ * [Маршруты](#Маршруты)
7
+ * [Условия](#Условия)
8
+ * [Возвращаемые значения](#Возвращаемые-значения)
9
+ * [Собственные детекторы совпадений для маршрутов](#Собственные-детекторы-совпадений-для-маршрутов)
10
+ * [Статические файлы](#Статические-файлы)
11
+ * [Представления / Шаблоны](#Представления--Шаблоны)
12
+ * [Буквальные шаблоны](#Буквальные-шаблоны)
13
+ * [Доступные шаблонизаторы](#Доступные-шаблонизаторы)
14
+ * [Haml шаблоны](#haml-шаблоны)
15
+ * [Erb шаблоны](#erb-шаблоны)
16
+ * [Builder шаблоны](#builder-шаблоны)
17
+ * [Nokogiri шаблоны](#nokogiri-шаблоны)
18
+ * [Sass шаблоны](#sass-шаблоны)
19
+ * [SCSS шаблоны](#scss-шаблоны)
20
+ * [Less шаблоны](#less-шаблоны)
21
+ * [Liquid шаблоны](#liquid-шаблоны)
22
+ * [Markdown шаблоны](#markdown-шаблоны)
23
+ * [Textile шаблоны](#textile-шаблоны)
24
+ * [RDoc шаблоны](#rdoc-шаблоны)
25
+ * [AsciiDoc шаблоны](#asciidoc-шаблоны)
26
+ * [Radius шаблоны](#radius-шаблоны)
27
+ * [Markaby шаблоны](#markaby-шаблоны)
28
+ * [RABL шаблоны](#rabl-шаблоны)
29
+ * [Slim шаблоны](#slim-шаблоны)
30
+ * [Creole шаблоны](#creole-шаблоны)
31
+ * [MediaWiki шаблоны](#mediawiki-шаблоны)
32
+ * [CoffeeScript шаблоны](#coffeescript-шаблоны)
33
+ * [Stylus шаблоны](#stylus-шаблоны)
34
+ * [Yajl шаблоны](#yajl-шаблоны)
35
+ * [WLang шаблоны](#wlang-шаблоны)
36
+ * [Доступ к переменным в шаблонах](#Доступ-к-переменным-в-шаблонах)
37
+ * [Шаблоны с `yield` и вложенные раскладки (layout)](#Шаблоны-с-yield-и-вложенные-раскладки-layout)
38
+ * [Включённые шаблоны](#Включённые-шаблоны)
39
+ * [Именованные шаблоны](#Именованные-шаблоны)
40
+ * [Привязка файловых расширений](#Привязка-файловых-расширений)
41
+ * [Добавление собственного движка рендеринга](#Добавление-собственного-движка-рендеринга)
42
+ * [Фильтры](#Фильтры)
43
+ * [Методы-помощники](#Методы-помощники)
44
+ * [Использование сессий](#Использование-сессий)
45
+ * [Прерывание](#Прерывание)
46
+ * [Передача](#Передача)
47
+ * [Вызов другого маршрута](#Вызов-другого-маршрута)
48
+ * [Задание тела, кода и заголовков ответа](#Задание-тела-кода-и-заголовков-ответа)
49
+ * [Стриминг ответов](#Стриминг-ответов)
50
+ * [Логирование](#Логирование)
51
+ * [Mime-типы](#mime-типы)
52
+ * [Генерирование URL](#Генерирование-url)
53
+ * [Перенаправление (редирект)](#Перенаправление-редирект)
54
+ * [Управление кэшированием](#Управление-кэшированием)
55
+ * [Отправка файлов](#Отправка-файлов)
56
+ * [Доступ к объекту запроса](#Доступ-к-объекту-запроса)
57
+ * [Вложения](#Вложения)
58
+ * [Работа со временем и датами](#Работа-со-временем-и-датами)
59
+ * [Поиск шаблонов](#Поиск-шаблонов)
60
+ * [Конфигурация](#Конфигурация)
61
+ * [Настройка защиты от атак](#Настройка-защиты-от-атак)
62
+ * [Доступные настройки](#Доступные-настройки)
63
+ * [Режим, окружение](#Режим-окружение)
64
+ * [Обработка ошибок](#Обработка-ошибок)
65
+ * [Not Found](#not-found)
66
+ * [Error](#error)
67
+ * [Rack "прослойки"](#rack-прослойки)
68
+ * [Тестирование](#Тестирование)
69
+ * [Sinatra::Base — "прослойки", библиотеки и модульные приложения](#sinatrabase--прослойки-библиотеки-и-модульные-приложения)
70
+ * [Модульные приложения против классических](#Модульные-приложения-против-классических)
71
+ * [Запуск модульных приложений](#Запуск-модульных-приложений)
72
+ * [Запуск классических приложений с config.ru](#Запуск-классических-приложений-с-configru)
73
+ * [Когда использовать config.ru?](#Когда-использовать-configru)
74
+ * [Использование Sinatra в качестве "прослойки"](#Использование-sinatra-в-качестве-прослойки)
75
+ * [Создание приложений "на лету"](#Создание-приложений-на-лету)
76
+ * [Области видимости и привязка](#Области-видимости-и-привязка)
77
+ * [Область видимости приложения / класса](#Область-видимости-приложения--класса)
78
+ * [Область видимости запроса / экземпляра](#Область-видимости-запроса--экземпляра)
79
+ * [Область видимости делегирования](#Область-видимости-делегирования)
80
+ * [Командная строка](#Командная-строка)
81
+ * [Multi-threading](#multi-threading)
82
+ * [Системные требования](#Системные-требования)
83
+ * [На острие](#На-острие)
84
+ * [С помощью Bundler](#С-помощью-bundler)
85
+ * [Вручную](#Вручную)
86
+ * [Установка глобально](#Установка-глобально)
87
+ * [Версии](#Версии)
88
+ * [Дальнейшее чтение](#Дальнейшее-чтение)
89
+
3
90
  *Внимание: Этот документ является переводом английской версии и может быть
4
91
  устаревшим*
5
92
 
6
93
  Sinatra — это предметно-ориентированный каркас
7
- ([DSL](http://ru.wikipedia.org/wiki/Предметно-ориентированный_язык_программирования))
94
+ ([DSL](https://ru.wikipedia.org/wiki/Предметно-ориентированный_язык))
8
95
  для быстрого создания функциональных веб-приложений на Ruby с минимумом усилий:
9
96
 
10
97
  ```ruby
@@ -18,17 +105,17 @@ end
18
105
 
19
106
  Установите gem:
20
107
 
21
- ``` shell
108
+ ```shell
22
109
  gem install sinatra
23
110
  ```
24
111
 
25
112
  и запустите приложение с помощью:
26
113
 
27
- ``` shell
114
+ ```shell
28
115
  ruby myapp.rb
29
116
  ```
30
117
 
31
- Оцените результат: http://localhost:4567
118
+ Оцените результат: [http://localhost:4567](http://localhost:4567)
32
119
 
33
120
  Рекомендуется также установить Thin, сделать это можно командой: `gem install
34
121
  thin`. Thin — это более производительный и функциональный сервер для
@@ -138,8 +225,8 @@ end
138
225
  Шаблоны маршрутов могут иметь необязательные параметры:
139
226
 
140
227
  ```ruby
141
- get '/posts.?:format?' do
142
- # соответствует "GET /posts", "GET /posts.json", "GET /posts.xml" и т.д.
228
+ get '/posts/:format?' do
229
+ # соответствует "GET /posts/", "GET /posts/json", "GET /posts/xml" и т.д.
143
230
  end
144
231
  ```
145
232
 
@@ -508,7 +595,7 @@ get('/') { markdown :index }
508
595
  <table>
509
596
  <tr>
510
597
  <td>Зависимости</td>
511
- <td><a href="http://nokogiri.org/" title="nokogiri">nokogiri</a></td>
598
+ <td><a href="http://www.nokogiri.org/" title="nokogiri">nokogiri</a></td>
512
599
  </tr>
513
600
  <tr>
514
601
  <td>Расширения файлов</td>
@@ -561,7 +648,7 @@ get('/') { markdown :index }
561
648
  <table>
562
649
  <tr>
563
650
  <td>Зависимости</td>
564
- <td><a href="http://www.lesscss.org/" title="less">less</a></td>
651
+ <td><a href="http://lesscss.org/" title="less">less</a></td>
565
652
  </tr>
566
653
  <tr>
567
654
  <td>Расширения файлов</td>
@@ -578,7 +665,7 @@ get('/') { markdown :index }
578
665
  <table>
579
666
  <tr>
580
667
  <td>Зависимости</td>
581
- <td><a href="http://www.liquidmarkup.org/" title="liquid">liquid</a></td>
668
+ <td><a href="http://liquidmarkup.org/" title="liquid">liquid</a></td>
582
669
  </tr>
583
670
  <tr>
584
671
  <td>Расширения файлов</td>
@@ -600,7 +687,7 @@ get('/') { markdown :index }
600
687
  <td>Зависимости</td>
601
688
  <td>
602
689
  Любая из библиотек:
603
- <a href="https://github.com/rtomayko/rdiscount" title="RDiscount">RDiscount</a>,
690
+ <a href="https://github.com/davidfstr/rdiscount" title="RDiscount">RDiscount</a>,
604
691
  <a href="https://github.com/vmg/redcarpet" title="RedCarpet">RedCarpet</a>,
605
692
  <a href="http://deveiate.org/projects/BlueCloth" title="BlueCloth">BlueCloth</a>,
606
693
  <a href="http://kramdown.gettalong.org/" title="kramdown">kramdown</a>,
@@ -756,7 +843,7 @@ erb :overview, :locals => { :text => rdoc(:introduction) }
756
843
  <table>
757
844
  <tr>
758
845
  <td>Зависимости</td>
759
- <td><a href="http://markaby.github.com/" title="Markaby">Markaby</a></td>
846
+ <td><a href="http://markaby.github.io/" title="Markaby">Markaby</a></td>
760
847
  </tr>
761
848
  <tr>
762
849
  <td>Расширения файлов</td>
@@ -908,7 +995,7 @@ erb :overview, :locals => { :text => mediawiki(:introduction) }
908
995
  <tr>
909
996
  <td>Зависимости</td>
910
997
  <td>
911
- <a href="https://github.com/lucasmazza/ruby-stylus" title="Ruby Stylus">
998
+ <a href="https://github.com/forgecrafted/ruby-stylus" title="Ruby Stylus">
912
999
  Stylus
913
1000
  </a> и
914
1001
  <a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
@@ -929,7 +1016,7 @@ erb :overview, :locals => { :text => mediawiki(:introduction) }
929
1016
  Перед тем, как использовать шаблоны стилус, загрузите `stylus` и
930
1017
  `stylus/tilt`:
931
1018
 
932
- ``` ruby
1019
+ ```ruby
933
1020
  require 'sinatra'
934
1021
  require 'stylus'
935
1022
  require 'stylus/tilt'
@@ -1293,7 +1380,7 @@ set :sessions, :domain => 'foo.com'
1293
1380
  Чтобы сделать сессию доступной другим приложениям, размещенным на поддоменах
1294
1381
  foo.com, добавьте *.* перед доменом:
1295
1382
 
1296
- ``` ruby
1383
+ ```ruby
1297
1384
  set :sessions, :domain => '.foo.com'
1298
1385
  ```
1299
1386
 
@@ -1439,17 +1526,17 @@ end
1439
1526
  ```
1440
1527
 
1441
1528
  Что позволяет вам реализовать стриминговые API,
1442
- [Server Sent Events](http://dev.w3.org/html5/eventsource/),
1443
- и может служить основой для [WebSockets](http://en.wikipedia.org/wiki/WebSocket).
1529
+ [Server Sent Events](https://w3c.github.io/eventsource/),
1530
+ и может служить основой для [WebSockets](https://en.wikipedia.org/wiki/WebSocket).
1444
1531
  Также такой подход можно использовать для увеличения производительности в случае,
1445
1532
  когда какая-то часть контента зависит от медленного ресурса.
1446
1533
 
1447
1534
  Заметьте, что возможности стриминга, особенно количество одновременно
1448
1535
  обслуживаемых запросов, очень сильно зависят от используемого веб-сервера.
1449
- Некоторые серверы, например, WEBRick, могут и вовсе не поддерживать стриминг.
1450
- Если сервер не поддерживает стриминг, то все данные будут отправлены за один
1451
- раз сразу после того, как блок, переданный в `stream`, завершится. Стриминг
1452
- вообще не работает при использовании Shotgun.
1536
+ Некоторые серверы могут и вовсе не поддерживать стриминг. Если сервер не
1537
+ поддерживает стриминг, то все данные будут отправлены за один раз сразу после
1538
+ того, как блок, переданный в `stream`, завершится. Стриминг вообще не работает
1539
+ при использовании Shotgun.
1453
1540
 
1454
1541
  Если метод используется с параметром `keep_open`, то он не будет вызывать
1455
1542
  `close` у объекта потока, что позволит вам закрыть его позже в любом другом
@@ -1567,7 +1654,7 @@ end
1567
1654
 
1568
1655
  ```ruby
1569
1656
  redirect to('/bar'), 303
1570
- redirect 'http://google.com', 'wrong place, buddy'
1657
+ redirect 'http://www.google.com/', 'wrong place, buddy'
1571
1658
  ```
1572
1659
 
1573
1660
  Вы также можете перенаправить пользователя обратно, на страницу, с которой он
@@ -1651,7 +1738,7 @@ end
1651
1738
  ```
1652
1739
 
1653
1740
  Также вы можете использовать
1654
- [weak ETag](http://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation):
1741
+ [weak ETag](https://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation):
1655
1742
 
1656
1743
  ```ruby
1657
1744
  etag @article.sha1, :weak
@@ -1968,7 +2055,7 @@ end
1968
2055
  ### Настройка защиты от атак
1969
2056
 
1970
2057
  Sinatra использует
1971
- [Rack::Protection](https://github.com/rkh/rack-protection#readme) для защиты
2058
+ [Rack::Protection](https://github.com/sinatra/rack-protection#readme) для защиты
1972
2059
  приложения от простых атак. Вы можете легко выключить эту защиту (что сделает
1973
2060
  ваше приложение чрезвычайно уязвимым):
1974
2061
 
@@ -2275,7 +2362,7 @@ end
2275
2362
  ```
2276
2363
 
2277
2364
  Семантика `use` идентична той, что определена для
2278
- [Rack::Builder](http://rubydoc.info/github/rack/rack/master/Rack/Builder) DSL
2365
+ [Rack::Builder](http://www.rubydoc.info/github/rack/rack/master/Rack/Builder) DSL
2279
2366
  (чаще всего используется в rackup файлах). Например, метод `use` принимает как
2280
2367
  множественные переменные, так и блоки:
2281
2368
 
@@ -2300,7 +2387,7 @@ Rack распространяется с различными стандартн
2300
2387
 
2301
2388
  Тесты для Sinatra приложений могут быть написаны с помощью библиотек,
2302
2389
  фреймворков, поддерживающих тестирование Rack.
2303
- [Rack::Test](http://rdoc.info/github/brynary/rack-test/master/frames)
2390
+ [Rack::Test](http://www.rubydoc.info/github/brynary/rack-test/master/frames)
2304
2391
  рекомендован:
2305
2392
 
2306
2393
  ```ruby
@@ -2392,7 +2479,7 @@ end
2392
2479
  logging true false
2393
2480
  method_override true false
2394
2481
  inline_templates true false
2395
- static true false
2482
+ static true File.exist?(public_folder)
2396
2483
 
2397
2484
  ### Запуск модульных приложений
2398
2485
 
@@ -2594,7 +2681,7 @@ end
2594
2681
  * через объект, переданный блокам конфигурации (`configure { |c| ... }`);
2595
2682
  * `settings` внутри области видимости запроса.
2596
2683
 
2597
- ### Область видимости запроса/экземпляра
2684
+ ### Область видимости запроса / экземпляра
2598
2685
 
2599
2686
  Для каждого входящего запроса будет создан новый экземпляр вашего приложения,
2600
2687
  и все блоки обработчика будут запущены в этом контексте. В этой области
@@ -2665,6 +2752,40 @@ ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-o HOST] [-s HANDLER]
2665
2752
  -x # включить мьютекс-блокировку (по умолчанию выключена)
2666
2753
  ```
2667
2754
 
2755
+ ### Multi-threading
2756
+
2757
+ _Данный раздел является перефразированным [ответом пользователя Konstantin][so-answer] на StackOverflow_
2758
+
2759
+ Sinatra не навязывает каких-либо моделей параллелизма, но для этих целей можно
2760
+ использовать любой Rack обработчик, например Thin, Puma или WEBrick. Сама
2761
+ по себе Sinatra потокобезопасна, поэтому нет никаких проблем в использовании
2762
+ поточной модели параллелизма в Rack обработчике. Это означает, что когда
2763
+ запускается сервер, вы должны указать правильный метод вызова для конкретного
2764
+ Rack обработчика. Пример ниже показывает, как можно запустить мультитредовый
2765
+ Thin сервер:
2766
+
2767
+ ```ruby
2768
+ # app.rb
2769
+
2770
+ require 'sinatra/base'
2771
+
2772
+ class App < Sinatra::Base
2773
+ get '/' do
2774
+ "Hello, World"
2775
+ end
2776
+ end
2777
+
2778
+ App.run!
2779
+ ```
2780
+
2781
+ Чтобы запустить сервер, вы должны выполнить следующую команду:
2782
+
2783
+ ```shell
2784
+ thin --threaded start
2785
+ ```
2786
+
2787
+ [so-answer]: http://stackoverflow.com/questions/6278817/is-sinatra-multi-threaded/6282999#6282999)
2788
+
2668
2789
  ## Системные требования
2669
2790
 
2670
2791
  Следующие версии Ruby официально поддерживаются:
@@ -2747,7 +2868,7 @@ gem install sinatra --pre
2747
2868
  ### С помощью Bundler
2748
2869
 
2749
2870
  Если вы хотите запускать свое приложение с последней версией Sinatra, то
2750
- рекомендуем использовать [Bundler](http://gembundler.com/).
2871
+ рекомендуем использовать [Bundler](http://bundler.io).
2751
2872
 
2752
2873
  Сначала установите Bundler, если у вас его еще нет:
2753
2874
 
@@ -2823,13 +2944,15 @@ SemVerTag.
2823
2944
  документация, новости и ссылки на другие ресурсы.
2824
2945
  * [Участие в проекте](http://www.sinatrarb.com/contributing) — Обнаружили
2825
2946
  баг? Нужна помощь? Написали патч?
2826
- * [Слежение за проблемами/ошибками](http://github.com/sinatra/sinatra/issues)
2827
- * [Twitter](http://twitter.com/sinatra)
2947
+ * [Отслеживание проблем/ошибок](https://github.com/sinatra/sinatra/issues)
2948
+ * [Twitter](https://twitter.com/sinatra)
2828
2949
  * [Группы рассылки](http://groups.google.com/group/sinatrarb/topics)
2829
- * [#sinatra](irc://chat.freenode.net/#sinatra) на http://freenode.net
2950
+ * IRC: [#sinatra](irc://chat.freenode.net/#sinatra) на http://freenode.net
2951
+ * [Sinatra и Друзья](https://sinatrarb.slack.com) на Slack, а так же
2952
+ [ссылка](https://sinatra-slack.herokuapp.com/) для инвайта.
2830
2953
  * [Sinatra Book](https://github.com/sinatra/sinatra-book/) учебник и сборник рецептов
2831
2954
  * [Sinatra Recipes](http://recipes.sinatrarb.com/) сборник рецептов
2832
- * API документация к [последнему релизу](http://rubydoc.info/gems/sinatra)
2833
- или [текущему HEAD](http://rubydoc.info/github/sinatra/sinatra) на
2834
- http://rubydoc.info
2835
- * [Сервер непрерывной интеграции](http://travis-ci.org/sinatra/sinatra)
2955
+ * API документация к [последнему релизу](http://www.rubydoc.info/gems/sinatra)
2956
+ или [текущему HEAD](http://www.rubydoc.info/github/sinatra/sinatra) на
2957
+ http://www.rubydoc.info/
2958
+ * [Сервер непрерывной интеграции](https://travis-ci.org/sinatra/sinatra)
@@ -1,45 +1,129 @@
1
1
  # Sinatra
2
2
 
3
- *注:本文档是英文版的翻译,内容更新有可能不及时。
4
- 如有不一致的地方,请以英文版为准。*
3
+ *注:本文档是英文版的翻译,内容更新有可能不及时。如有不一致的地方,请以英文版为准。*
5
4
 
6
- Sinatra是一个基于Ruby语言的[DSL](http://en.wikipedia.org/wiki/Domain-specific_language)(
7
- 领域专属语言),可以轻松、快速的创建web应用。
5
+ Sinatra 是一门基于
6
+ Ruby 的[领域专属语言](https://en.wikipedia.org/wiki/Domain-specific_language),致力于轻松、快速地创建网络应用:
8
7
 
9
- ~~~~ ruby
8
+ ```ruby
10
9
  # myapp.rb
11
10
  require 'sinatra'
12
11
 
13
12
  get '/' do
14
13
  'Hello world!'
15
14
  end
16
- ~~~~
15
+ ```
17
16
 
18
- 安装gem,然后运行:
17
+ 安装 Sinatra 这个 gem
19
18
 
20
- ~~~~ shell
19
+ ```shell
21
20
  gem install sinatra
22
- ruby myapp.rb
23
- ~~~~
24
-
25
- 在该地址查看: http://localhost:4567
26
-
27
- 这个时候访问地址将绑定到 127.0.0.1 和 localhost ,如果使用 vagrant 进行开发,访问会失败,此时就需要进行 ip 绑定了:
28
-
29
- ~~~~ shell
30
- ruby myapp.rb -o 0.0.0.0
31
- ~~~~
32
-
33
- ```-o``` 这个参数就是进行 Listening 时候监听的绑定,能从通过 IP、127.0.0.1、localhost + 端口号进行访问。
34
-
35
- 安装Sintra后,最好再运行`gem install thin`安装Thin。这样,Sinatra会优先选择Thin作为服务器。
21
+ ```
36
22
 
37
- ## 路由(route)
23
+ 然后运行 myapp.rb 中的代码:
38
24
 
39
- 在Sinatra中,一个路由分为两部分:HTTP方法(GET, POST等)和URL匹配范式。
40
- 每个路由都有一个要执行的代码块:
41
-
42
- ~~~~ ruby
25
+ ```shell
26
+ ruby myapp.rb
27
+ ```
28
+
29
+ 在该地址查看: [http://localhost:4567](http://localhost:4567)
30
+
31
+ 推荐运行 `gem install thin` 安装 Thin。这样,Sinatra 会优先选择 Thin 作为服务器。
32
+
33
+ ## 目录
34
+
35
+ * [Sinatra](#sinatra)
36
+ * [目录](#目录)
37
+ * [路由](#路由)
38
+ * [条件](#条件)
39
+ * [返回值](#返回值)
40
+ * [自定义路由匹配器](#自定义路由匹配器)
41
+ * [静态文件](#静态文件)
42
+ * [视图 / 模板](#视图--模板)
43
+ * [字面量模板](#字面量模板)
44
+ * [可选的模板语言](#可选的模板语言)
45
+ * [Haml 模板](#haml-模板)
46
+ * [Erb 模板](#erb-模板)
47
+ * [Builder 模板](#builder-模板)
48
+ * [Nokogiri 模板](#nokogiri-模板)
49
+ * [Sass 模板](#sass-模板)
50
+ * [SCSS 模板](#scss-模板)
51
+ * [Less 模板](#less-模板)
52
+ * [Liquid 模板](#liquid-模板)
53
+ * [Markdown 模板](#markdown-模板)
54
+ * [Textile 模板](#textile-模板)
55
+ * [RDoc 模板](#rdoc-模板)
56
+ * [AsciiDoc 模板](#asciidoc-模板)
57
+ * [Radius 模板](#radius-模板)
58
+ * [Markaby 模板](#markaby-模板)
59
+ * [RABL 模板](#rabl-模板)
60
+ * [Slim 模板](#slim-模板)
61
+ * [Creole 模板](#creole-模板)
62
+ * [MediaWiki 模板](#mediawiki-模板)
63
+ * [CoffeeScript 模板](#coffeescript-模板)
64
+ * [Stylus 模板](#stylus-模板)
65
+ * [Yajl 模板](#yajl-模板)
66
+ * [WLang 模板](#wlang-模板)
67
+ * [在模板中访问变量](#在模板中访问变量)
68
+ * [带 `yield` 的模板和嵌套布局](#带-yield-的模板和嵌套布局)
69
+ * [内联模板](#内联模板)
70
+ * [具名模板](#具名模板)
71
+ * [关联文件扩展名](#关联文件扩展名)
72
+ * [添加自定义模板引擎](#添加自定义模板引擎)
73
+ * [自定义模板查找逻辑](#自定义模板查找逻辑)
74
+ * [过滤器](#过滤器)
75
+ * [辅助方法](#辅助方法)
76
+ * [使用会话](#使用会话)
77
+ * [中断请求](#中断请求)
78
+ * [传递请求](#传递请求)
79
+ * [触发另一个路由](#触发另一个路由)
80
+ * [设置响应主体、状态码和响应首部](#设置响应主体状态码和响应首部)
81
+ * [响应的流式传输](#响应的流式传输)
82
+ * [日志](#日志)
83
+ * [媒体类型](#媒体类型)
84
+ * [生成 URL](#生成-url)
85
+ * [浏览器重定向](#浏览器重定向)
86
+ * [缓存控制](#缓存控制)
87
+ * [发送文件](#发送文件)
88
+ * [访问请求对象](#访问请求对象)
89
+ * [附件](#附件)
90
+ * [处理日期和时间](#处理日期和时间)
91
+ * [查找模板文件](#查找模板文件)
92
+ * [配置](#配置)
93
+ * [配置攻击防护](#配置攻击防护)
94
+ * [可选的设置](#可选的设置)
95
+ * [环境](#环境)
96
+ * [错误处理](#错误处理)
97
+ * [未找到](#未找到)
98
+ * [错误](#错误)
99
+ * [Rack 中间件](#rack-中间件)
100
+ * [测试](#测试)
101
+ * [Sinatra::Base - 中间件、库和模块化应用](#sinatrabase---中间件库和模块化应用)
102
+ * [模块化风格 vs. 经典风格](#模块化风格-vs-经典风格)
103
+ * [运行一个模块化应用](#运行一个模块化应用)
104
+ * [使用 config.ru 运行经典风格的应用](#使用-configru-运行经典风格的应用)
105
+ * [何时使用 config.ru?](#何时使用-configru)
106
+ * [把 Sinatra 当作中间件使用](#把-sinatra-当作中间件使用)
107
+ * [创建动态应用](#创建动态应用)
108
+ * [作用域和绑定](#作用域和绑定)
109
+ * [应用/类作用域](#应用类作用域)
110
+ * [请求/实例作用域](#请求实例作用域)
111
+ * [代理作用域](#代理作用域)
112
+ * [命令行](#命令行)
113
+ * [多线程](#多线程)
114
+ * [必要条件](#必要条件)
115
+ * [紧跟前沿](#紧跟前沿)
116
+ * [通过 Bundler 使用 Sinatra](#通过-bundler-使用-sinatra)
117
+ * [使用自己本地的 Sinatra](#使用自己本地的-sinatra)
118
+ * [全局安装](#全局安装)
119
+ * [版本](#版本)
120
+ * [更多资料](#更多资料)
121
+
122
+ ## 路由
123
+
124
+ 在 Sinatra 中,一个路由分为两部分:HTTP 方法和 URL 匹配范式。每个路由都有一个要执行的代码块:
125
+
126
+ ```ruby
43
127
  get '/' do
44
128
  .. 显示内容 ..
45
129
  end
@@ -49,7 +133,11 @@ post '/' do
49
133
  end
50
134
 
51
135
  put '/' do
52
- .. 更新内容 ..
136
+ .. 替换内容 ..
137
+ end
138
+
139
+ patch '/' do
140
+ .. 修改内容 ..
53
141
  end
54
142
 
55
143
  delete '/' do
@@ -67,77 +155,107 @@ end
67
155
  unlink '/' do
68
156
  .. 解除某种联系 ..
69
157
  end
158
+ ```
70
159
 
160
+ 路由按照它们定义时的顺序进行匹配。第一个与请求匹配的路由会被调用。
71
161
 
72
- ~~~~
73
-
74
- 路由按照它们被定义的顺序进行匹配。 第一个与请求匹配的路由会被调用。
75
-
76
- 路由范式可以包括具名参数,可通过`params`哈希表获得:
162
+ 路由范式可以包括具名参数,具名参数可以通过 `params` hash 访问:
77
163
 
78
- ~~~~ ruby
164
+ ```ruby
79
165
  get '/hello/:name' do
80
166
  # 匹配 "GET /hello/foo" 和 "GET /hello/bar"
81
167
  # params['name'] 的值是 'foo' 或者 'bar'
82
168
  "Hello #{params['name']}!"
83
169
  end
84
- ~~~~
170
+ ```
85
171
 
86
- 你同样可以通过代码块参数获得具名参数:
172
+ 也可以通过代码块参数访问具名参数:
87
173
 
88
- ~~~~ ruby
174
+ ```ruby
89
175
  get '/hello/:name' do |n|
176
+ # 匹配 "GET /hello/foo" 和 "GET /hello/bar"
177
+ # params['name'] 的值是 'foo' 或者 'bar'
178
+ # n 存储 params['name'] 的值
90
179
  "Hello #{n}!"
91
180
  end
92
- ~~~~
181
+ ```
93
182
 
94
- 路由范式也可以包含通配符参数, 可以通过`params['splat']`数组获得。
183
+ 路由范式也可以包含通配符参数, 参数值可以通过 `params['splat']` 数组访问。
95
184
 
96
- ~~~~ ruby
185
+ ```ruby
97
186
  get '/say/*/to/*' do
98
- # 匹配 /say/hello/to/world
187
+ # 匹配 "GET /say/hello/to/world"
99
188
  params['splat'] # => ["hello", "world"]
100
189
  end
101
190
 
102
191
  get '/download/*.*' do
103
- # 匹配 /download/path/to/file.xml
192
+ # 匹配 "GET /download/path/to/file.xml"
104
193
  params['splat'] # => ["path/to/file", "xml"]
105
194
  end
106
- ~~~~
195
+ ```
196
+
197
+ 或者通过代码块参数访问:
198
+
199
+ ```ruby
200
+ get '/download/*.*' do |path, ext|
201
+ [path, ext] # => ["path/to/file", "xml"]
202
+ end
203
+ ```
107
204
 
108
- 通过正则表达式匹配的路由:
205
+ 通过正则表达式匹配路由:
109
206
 
110
- ~~~~ ruby
207
+ ```ruby
111
208
  get /\A\/hello\/([\w]+)\z/ do
112
209
  "Hello, #{params['captures'].first}!"
113
210
  end
114
- ~~~~
211
+ ```
115
212
 
116
213
  或者使用代码块参数:
117
214
 
118
- ~~~~ ruby
215
+ ```ruby
119
216
  get %r{/hello/([\w]+)} do |c|
217
+ # 匹配 "GET /meta/hello/world"、"GET /hello/world/1234" 等
120
218
  "Hello, #{c}!"
121
219
  end
122
- ~~~~
220
+ ```
221
+
222
+ 路由范式可以包含可选参数:
223
+
224
+ ```ruby
225
+ get '/posts/:format?' do
226
+ # 匹配 "GET /posts/" 和任意扩展 "GET /posts/json"、"GET /posts/xml" 等
227
+ end
228
+ ```
229
+
230
+ 路由也可以使用查询参数:
231
+
232
+ ```ruby
233
+ get '/posts' do
234
+ # 匹配 "GET /posts?title=foo&author=bar"
235
+ title = params['title']
236
+ author = params['author']
237
+ # 使用 title 和 author 变量;对于 /posts 路由来说,查询字符串是可选的
238
+ end
239
+ ```
240
+ 顺便一提,除非你禁用了路径遍历攻击防护(见下文),请求路径可能在匹配路由前发生改变。
123
241
 
124
242
  ### 条件
125
243
 
126
- 路由也可以包含多样的匹配条件,比如user agent:
244
+ 路由可以包含各种匹配条件,比如 user agent:
127
245
 
128
- ~~~~ ruby
246
+ ```ruby
129
247
  get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
130
- "你正在使用Songbird,版本是 #{params['agent'][0]}"
248
+ "你正在使用 Songbird,版本是 #{params['agent'][0]}"
131
249
  end
132
250
 
133
251
  get '/foo' do
134
- # 匹配除Songbird以外的浏览器
252
+ # 匹配非 Songbird 浏览器
135
253
  end
136
- ~~~~
254
+ ```
137
255
 
138
- 其他可选的条件是 `host_name` 和 `provides`:
256
+ 其它可以使用的条件有 `host_name` 和 `provides`:
139
257
 
140
- ~~~~ ruby
258
+ ```ruby
141
259
  get '/', :host_name => /^admin\./ do
142
260
  "管理员区域,无权进入!"
143
261
  end
@@ -149,11 +267,13 @@ end
149
267
  get '/', :provides => ['rss', 'atom', 'xml'] do
150
268
  builder :feed
151
269
  end
152
- ~~~~
270
+ ```
271
+
272
+ `provides` 会搜索请求的 Accept 首部字段。
153
273
 
154
- 你也可以自定义条件:
274
+ 也可以轻易地使用自定义条件:
155
275
 
156
- ~~~~ ruby
276
+ ```ruby
157
277
  set(:probability) { |value| condition { rand <= value } }
158
278
 
159
279
  get '/win_a_car', :probability => 0.1 do
@@ -163,30 +283,44 @@ end
163
283
  get '/win_a_car' do
164
284
  "Sorry, you lost."
165
285
  end
166
- ~~~~
286
+ ```
167
287
 
168
- ### 返回值
288
+ 对于一个需要提供多个值的条件,可以使用 splat:
289
+
290
+ ```ruby
291
+ set(:auth) do |*roles| # <- 注意此处使用了 splat
292
+ condition do
293
+ unless logged_in? && roles.any? {|role| current_user.in_role? role }
294
+ redirect "/login/", 303
295
+ end
296
+ end
297
+ end
169
298
 
170
- 路由代码块的返回值至少决定了返回给HTTP客户端的响应体,
171
- 或者至少决定了在Rack堆栈中的下一个中间件。
172
- 大多数情况下,将是一个字符串,就像上面的例子中的一样。
173
- 但是其他值也是可以接受的。
299
+ get "/my/account/", :auth => [:user, :admin] do
300
+ "Your Account Details"
301
+ end
174
302
 
175
- 你可以返回任何对象,或者是一个合理的Rack响应, Rack
176
- body对象或者HTTP状态码:
303
+ get "/only/admin/", :auth => :admin do
304
+ "Only admins are allowed here!"
305
+ end
306
+ ```
177
307
 
178
- - 一个包含三个元素的数组:
179
- `[状态 (Fixnum), 头 (Hash), 响应体 (回应 #each)]`
308
+ ### 返回值
180
309
 
181
- - 一个包含两个元素的数组: `[状态 (Fixnum), 响应体 (回应 #each)]`
310
+ 路由代码块的返回值至少决定了返回给
311
+ HTTP 客户端的响应主体,或者至少决定了在
312
+ Rack 堆栈中的下一个中间件。大多数情况下,返回值是一个字符串,就像上面的例子中的一样。但是,其它类型的值也是可以接受的。
182
313
 
183
- - 一个能够回应 `#each` ,只传回字符串的对象
314
+ 你可以返回任何对象,该对象要么是一个合理的 Rack 响应,要么是一个 Rack body 对象,要么是 HTTP 状态码:
184
315
 
185
- - 一个代表状态码的数字
316
+ * 一个包含三个元素的数组: `[状态 (Fixnum), 响应首部 (Hash), 响应主体 (可以响应 #each 方法)]`
317
+ * 一个包含两个元素的数组: `[状态 (Fixnum), 响应主体 (可以响应 #each 方法)]`
318
+ * 一个响应 `#each` 方法,只传回字符串的对象
319
+ * 一个代表状态码的数字
186
320
 
187
- 那样,我们可以轻松的实现例如流式传输的例子:
321
+ 例如,我们可以轻松地实现流式传输:
188
322
 
189
- ~~~~ ruby
323
+ ```ruby
190
324
  class Stream
191
325
  def each
192
326
  100.times { |i| yield "#{i}\n" }
@@ -194,14 +328,16 @@ class Stream
194
328
  end
195
329
 
196
330
  get('/') { Stream.new }
197
- ~~~~
331
+ ```
332
+
333
+ 也可以使用 `stream` 辅助方法(见下文描述)以减少样板代码并在路由中直接使用流式传输。
198
334
 
199
335
  ### 自定义路由匹配器
200
336
 
201
- 如上显示,Sinatra内置了对于使用字符串和正则表达式作为路由匹配的支持。
202
- 但是,它并没有只限于此。 你可以非常容易地定义你自己的匹配器:
337
+ 如上文所示,Sinatra
338
+ 本身支持使用字符串和正则表达式作为路由匹配。但不限于此,你可以轻松地定义自己的匹配器:
203
339
 
204
- ~~~~ ruby
340
+ ```ruby
205
341
  class AllButPattern
206
342
  Match = Struct.new(:captures)
207
343
 
@@ -222,564 +358,758 @@ end
222
358
  get all_but("/index") do
223
359
  # ...
224
360
  end
225
- ~~~~
361
+ ```
226
362
 
227
- 上面的例子可能太繁琐了, 因为它也可以用更简单的方式表述:
363
+ 上面的例子可能太繁琐了, 因为它也可以用更简单的方式表述:
228
364
 
229
- ~~~~ ruby
365
+ ```ruby
230
366
  get // do
231
367
  pass if request.path_info == "/index"
232
368
  # ...
233
369
  end
234
- ~~~~
370
+ ```
235
371
 
236
372
  或者,使用消极向前查找:
237
373
 
238
- ~~~~ ruby
374
+ ```ruby
239
375
  get %r{^(?!/index$)} do
240
376
  # ...
241
377
  end
242
- ~~~~
378
+ ```
243
379
 
244
380
  ## 静态文件
245
381
 
246
- 静态文件是从 `./public_folder` 目录提供服务。你可以通过设置`:public`
247
- 选项设定一个不同的位置:
382
+ 静态文件从 `./public` 目录提供服务。可以通过设置`:public_folder` 选项设定一个不同的位置:
248
383
 
249
- ~~~~ ruby
384
+ ```ruby
250
385
  set :public_folder, File.dirname(__FILE__) + '/static'
251
- ~~~~
252
-
253
- 请注意public目录名并没有被包含在URL之中。文件
254
- `./public/css/style.css`是通过
255
- `http://example.com/css/style.css`地址访问的。
256
-
257
- ## 视图 / 模板
258
-
259
- 模板被假定直接位于`./views`目录。 要使用不同的视图目录:
260
-
261
- ~~~~ ruby
262
- set :views, File.dirname(__FILE__) + '/templates'
263
- ~~~~
264
-
265
- 重要提示:你只可以通过符号引用模板, 即使它们在子目录下
266
- (在这种情况下,使用 `:'subdir/template'`)。 如果你不用符号、而用字符串的话,
267
- 填充方法会只把你传入的字符串当成内容显示出来,而不调用模板。
268
-
269
- ### Haml模板
270
-
271
- 需要引入 `haml` gem/library以填充 HAML 模板:
272
-
273
- ~~~~ ruby
274
- # 你需要在你的应用中引入 haml
275
- require 'haml'
276
-
277
- get '/' do
278
- haml :index
279
- end
280
- ~~~~
281
-
282
- 填充 `./views/index.haml`。
386
+ ```
283
387
 
284
- [Haml的选项](http://haml.info/docs/yardoc/file.HAML_REFERENCE.html#options)
285
- 可以通过Sinatra的配置全局设定, 参见
286
- [选项和配置](http://www.sinatrarb.com/configuration.html),
287
- 也可以个别的被覆盖。
388
+ 请注意 public 目录名并没有包含在 URL 中。文件 `./public/css/style.css` 可以通过
389
+ `http://example.com/css/style.css` 访问。
288
390
 
289
- ~~~~ ruby
290
- set :haml, {:format => :html5 } # 默认的Haml输出格式是 :xhtml
391
+ 可以使用 `:static_cache_control` 设置(见下文)添加 `Cache-Control` 首部信息。
291
392
 
292
- get '/' do
293
- haml :index, :haml_options => {:format => :html4 } # 被覆盖,变成:html4
294
- end
295
- ~~~~
296
-
297
- ### Erb模板
393
+ ## 视图 / 模板
298
394
 
299
- ~~~~ ruby
300
- # 你需要在你的应用中引入 erb
301
- require 'erb'
395
+ 每一门模板语言都将自身的渲染方法暴露给
396
+ Sinatra 调用。这些渲染方法只是简单地返回字符串。
302
397
 
398
+ ```ruby
303
399
  get '/' do
304
400
  erb :index
305
401
  end
306
- ~~~~
307
-
308
- 这里调用的是 `./views/index.erb`
309
-
310
- ### Erubis
402
+ ```
311
403
 
312
- 需要引入 `erubis` gem/library以填充 erubis 模板:
404
+ 这段代码会渲染 `views/index.erb` 文件。
313
405
 
314
- ~~~~ ruby
315
- # 你需要在你的应用中引入 erubis
316
- require 'erubis'
406
+ 除了模板文件名,也可以直接传入模板内容:
317
407
 
408
+ ```ruby
318
409
  get '/' do
319
- erubis :index
410
+ code = "<%= Time.now %>"
411
+ erb code
320
412
  end
321
- ~~~~
413
+ ```
322
414
 
323
- 这里调用的是 `./views/index.erubis`
324
-
325
- 使用Erubis代替Erb也是可能的:
326
-
327
- ~~~~ ruby
328
- require 'erubis'
329
- Tilt.register :erb, Tilt[:erubis]
415
+ 渲染方法接受第二个参数,即选项 hash:
330
416
 
417
+ ```ruby
331
418
  get '/' do
332
- erb :index
419
+ erb :index, :layout => :post
333
420
  end
334
- ~~~~
421
+ ```
335
422
 
336
- 使用Erubis来填充 `./views/index.erb`。
423
+ 这段代码会将 `views/index.erb` 嵌入在 `views/post.erb`
424
+ 布局中并一起渲染(`views/layout.erb` 是默认的布局,如果它存在的话)。
337
425
 
338
- ### Builder 模板
339
-
340
- 需要引入 `builder` gem/library 以填充 builder templates:
341
-
342
- ~~~~ ruby
343
- # 需要在你的应用中引入builder
344
- require 'builder'
426
+ 任何 Sinatra 不能理解的选项都会传递给模板引擎。
345
427
 
428
+ ```ruby
346
429
  get '/' do
347
- builder :index
430
+ haml :index, :format => :html5
348
431
  end
349
- ~~~~
350
-
351
- 这里调用的是 `./views/index.builder`。
432
+ ```
352
433
 
353
- ### Nokogiri 模板
434
+ 也可以为每种模板语言设置通用的选项:
354
435
 
355
- 需要引入 `nokogiri` gem/library 以填充 nokogiri 模板:
356
-
357
- ~~~~ ruby
358
- # 需要在你的应用中引入 nokogiri
359
- require 'nokogiri'
436
+ ```ruby
437
+ set :haml, :format => :html5
360
438
 
361
439
  get '/' do
362
- nokogiri :index
363
- end
364
- ~~~~
365
-
366
- 这里调用的是 `./views/index.nokogiri`。
367
-
368
- ### Sass 模板
369
-
370
- 需要引入 `haml` 或者 `sass` gem/library 以填充 Sass 模板:
371
-
372
- ~~~~ ruby
373
- # 需要在你的应用中引入 haml 或者 sass
374
- require 'sass'
375
-
376
- get '/stylesheet.css' do
377
- sass :stylesheet
378
- end
379
- ~~~~
380
-
381
- 这里调用的是 `./views/stylesheet.sass`。
382
-
383
- [Sass
384
- 的选项](http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options)
385
- 可以通过Sinatra选项全局设定, 参考
386
- [选项和配置(英文)](http://www.sinatrarb.com/configuration.html),
387
- 也可以在个体的基础上覆盖。
388
-
389
- ~~~~ ruby
390
- set :sass, {:style => :compact } # 默认的 Sass 样式是 :nested
391
-
392
- get '/stylesheet.css' do
393
- sass :stylesheet, :style => :expanded # 覆盖
394
- end
395
- ~~~~
396
-
397
- ### Scss 模板
398
-
399
- 需要引入 `haml` 或者 `sass` gem/library 来填充 Scss templates:
400
-
401
- ~~~~ ruby
402
- # 需要在你的应用中引入 haml 或者 sass
403
- require 'sass'
404
-
405
- get '/stylesheet.css' do
406
- scss :stylesheet
407
- end
408
- ~~~~
409
-
410
- 这里调用的是 `./views/stylesheet.scss`。
411
-
412
- [Scss的选项](http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options)
413
- 可以通过Sinatra选项全局设定, 参考
414
- [选项和配置(英文)](http://www.sinatrarb.com/configuration.html),
415
- 也可以在个体的基础上覆盖。
416
-
417
- ~~~~ ruby
418
- set :scss, :style => :compact # default Scss style is :nested
419
-
420
- get '/stylesheet.css' do
421
- scss :stylesheet, :style => :expanded # overridden
422
- end
423
- ~~~~
424
-
425
- ### Less 模板
426
-
427
- 需要引入 `less` gem/library 以填充 Less 模板:
428
-
429
- ~~~~ ruby
430
- # 需要在你的应用中引入 less
431
- require 'less'
432
-
433
- get '/stylesheet.css' do
434
- less :stylesheet
440
+ haml :index
435
441
  end
436
- ~~~~
437
-
438
- 这里调用的是 `./views/stylesheet.less`。
439
-
440
- ### Liquid 模板
442
+ ```
441
443
 
442
- 需要引入 `liquid` gem/library 来填充 Liquid 模板:
444
+ 在渲染方法中传入的选项会覆盖通过 `set` 设置的通用选项。
443
445
 
444
- ~~~~ ruby
445
- # 需要在你的应用中引入 liquid
446
- require 'liquid'
446
+ 可用的选项:
447
447
 
448
- get '/' do
449
- liquid :index
450
- end
451
- ~~~~
452
-
453
- 这里调用的是 `./views/index.liquid`。
448
+ <dl>
449
+ <dt>locals</dt>
450
+ <dd>
451
+ 传递给模板文档的 locals 对象列表。对于 partials
452
+ 很方便。例如:<tt>erb "<%= foo %>", :locals => {:foo => "bar"}</tt>
453
+ </dd>
454
+
455
+ <dt>default_encoding</dt>
456
+ <dd>默认的字符编码。默认值为 <tt>settings.default_encoding</tt>。</dd>
457
+
458
+ <dt>views</dt>
459
+ <dd>存放模板文件的目录。默认为 <tt>settings.views</tt>。</dd>
460
+
461
+ <dt>layout</dt>
462
+ <dd>
463
+ 是否使用布局 (<tt>true</tt> 或 <tt>false</tt>)。
464
+ 如果使用一个符号类型的值,则是用于明确使用的模板。例如:
465
+ <tt>erb :index, :layout => !request.xhr?</tt>
466
+ </dd>
467
+
468
+ <dt>content_type</dt>
469
+ <dd>由模板生成的 Content-Type。默认值由模板语言决定。</dd>
470
+
471
+ <dt>scope</dt>
472
+ <dd>
473
+ 渲染模板时的作用域。默认值为应用类的实例对象。如果更改此项,实例变量和辅助方法将不可用。
474
+ </dd>
475
+
476
+ <dt>layout_engine</dt>
477
+ <dd>
478
+ 渲染布局所使用的模板引擎。用于不支持布局的模板语言。默认值为模板所使用的引擎。例如:
479
+ <tt>set :rdoc, :layout_engine => :erb</tt>
480
+ </dd>
481
+
482
+ <dt>layout_options</dt>
483
+ <dd>
484
+ 渲染布局的特殊选项。例如:
485
+ <tt>set :rdoc, :layout_options => { :views => 'views/layouts' }</tt>
486
+ </dd>
487
+ </dl>
454
488
 
455
- 因为你不能在Liquid 模板中调用 Ruby 方法 (除了 `yield`)
456
- 你几乎总是需要传递locals给它:
489
+ Sinatra 假定模板文件直接位于 `./views` 目录。要使用不同的视图目录:
457
490
 
458
- ~~~~ ruby
459
- liquid :index, :locals => { :key => 'value' }
460
- ~~~~
491
+ ```ruby
492
+ set :views, settings.root + '/templates'
493
+ ```
461
494
 
462
- ### Markdown 模板
463
495
 
464
- 需要引入 `rdiscount` gem/library 以填充 Markdown 模板:
496
+ 需要牢记的一点是,你必须通过符号引用模板, 即使它们存放在子目录下
497
+ (在这种情况下,使用 `:'subdir/template'` 或 `'subdir/template'.to_sym`)。
498
+ 如果你不使用符号,渲染方法会直接渲染你传入的任何字符串。
465
499
 
466
- ~~~~ ruby
467
- # 需要在你的应用中引入rdiscount
468
- require "rdiscount"
500
+ ### 字面量模板
469
501
 
502
+ ```ruby
470
503
  get '/' do
471
- markdown :index
504
+ haml '%div.title Hello World'
472
505
  end
473
- ~~~~
474
-
475
- 这里调用的是 `./views/index.markdown` (`md` 和 `mkd` 也是合理的文件扩展名)。
476
-
477
- 在markdown中是不可以调用方法的,也不可以传递 locals给它。
478
- 你因此一般会结合其他的填充引擎来使用它:
479
-
480
- ~~~~ ruby
506
+ ```
507
+
508
+ 这段代码直接渲染模板字符串。
509
+
510
+ ### 可选的模板语言
511
+
512
+ 一些语言有多种实现。为了确定使用哪种实现(以及保证线程安全),你应该首先引入该实现:
513
+
514
+ ```ruby
515
+ require 'rdiscount' # 或 require 'bluecloth'
516
+ get('/') { markdown :index }
517
+ ```
518
+
519
+ #### Haml 模板
520
+
521
+ <table>
522
+ <tr>
523
+ <td>依赖项</td>
524
+ <td><a href="http://haml.info/" title="haml">haml</a></td>
525
+ </tr>
526
+ <tr>
527
+ <td>文件扩展名</td>
528
+ <td><tt>.haml</tt></td>
529
+ </tr>
530
+ <tr>
531
+ <td>例子</td>
532
+ <td><tt>haml :index, :format => :html5</tt></td>
533
+ </tr>
534
+ </table>
535
+
536
+ #### Erb 模板
537
+
538
+ <table>
539
+ <tr>
540
+ <td>依赖项</td>
541
+ <td>
542
+ <a href="http://www.kuwata-lab.com/erubis/" title="erubis">erubis</a>
543
+ 或 erb (Ruby 标准库中已经包含)
544
+ </td>
545
+ </tr>
546
+ <tr>
547
+ <td>文件扩展名</td>
548
+ <td><tt>.erb</tt>, <tt>.rhtml</tt> or <tt>.erubis</tt> (仅用于 Erubis)</td>
549
+ </tr>
550
+ <tr>
551
+ <td>例子</td>
552
+ <td><tt>erb :index</tt></td>
553
+ </tr>
554
+ </table>
555
+
556
+ #### Builder 模板
557
+
558
+ <table>
559
+ <tr>
560
+ <td>依赖项</td>
561
+ <td>
562
+ <a href="https://github.com/jimweirich/builder" title="builder">builder</a>
563
+ </td>
564
+ </tr>
565
+ <tr>
566
+ <td>文件扩展名</td>
567
+ <td><tt>.builder</tt></td>
568
+ </tr>
569
+ <tr>
570
+ <td>例子</td>
571
+ <td><tt>builder { |xml| xml.em "hi" }</tt></td>
572
+ </tr>
573
+ </table>
574
+
575
+ `builder` 渲染方法也接受一个代码块,用于内联模板(见例子)。
576
+
577
+ #### Nokogiri 模板
578
+
579
+ <table>
580
+ <tr>
581
+ <td>依赖项</td>
582
+ <td><a href="http://www.nokogiri.org/" title="nokogiri">nokogiri</a></td>
583
+ </tr>
584
+ <tr>
585
+ <td>文件扩展名</td>
586
+ <td><tt>.nokogiri</tt></td>
587
+ </tr>
588
+ <tr>
589
+ <td>例子</td>
590
+ <td><tt>nokogiri { |xml| xml.em "hi" }</tt></td>
591
+ </tr>
592
+ </table>
593
+
594
+ `nokogiri` 渲染方法也接受一个代码块,用于内联模板(见例子)。
595
+
596
+ #### Sass 模板
597
+
598
+ <table>
599
+ <tr>
600
+ <td>依赖项</td>
601
+ <td><a href="http://sass-lang.com/" title="sass">sass</a></td>
602
+ </tr>
603
+ <tr>
604
+ <td>文件扩展名</td>
605
+ <td><tt>.sass</tt></td>
606
+ </tr>
607
+ <tr>
608
+ <td>例子</td>
609
+ <td><tt>sass :stylesheet, :style => :expanded</tt></td>
610
+ </tr>
611
+ </table>
612
+
613
+ #### SCSS 模板
614
+
615
+ <table>
616
+ <tr>
617
+ <td>依赖项</td>
618
+ <td><a href="http://sass-lang.com/" title="sass">sass</a></td>
619
+ </tr>
620
+ <tr>
621
+ <td>文件扩展名</td>
622
+ <td><tt>.scss</tt></td>
623
+ </tr>
624
+ <tr>
625
+ <td>例子</td>
626
+ <td><tt>scss :stylesheet, :style => :expanded</tt></td>
627
+ </tr>
628
+ </table>
629
+
630
+ #### Less 模板
631
+
632
+ <table>
633
+ <tr>
634
+ <td>依赖项</td>
635
+ <td><a href="http://lesscss.org/" title="less">less</a></td>
636
+ </tr>
637
+ <tr>
638
+ <td>文件扩展名</td>
639
+ <td><tt>.less</tt></td>
640
+ </tr>
641
+ <tr>
642
+ <td>例子</td>
643
+ <td><tt>less :stylesheet</tt></td>
644
+ </tr>
645
+ </table>
646
+
647
+ #### Liquid 模板
648
+
649
+ <table>
650
+ <tr>
651
+ <td>依赖项</td>
652
+ <td><a href="http://liquidmarkup.org/" title="liquid">liquid</a></td>
653
+ </tr>
654
+ <tr>
655
+ <td>文件扩展名</td>
656
+ <td><tt>.liquid</tt></td>
657
+ </tr>
658
+ <tr>
659
+ <td>例子</td>
660
+ <td><tt>liquid :index, :locals => { :key => 'value' }</tt></td>
661
+ </tr>
662
+ </table>
663
+
664
+ 因为不能在 Liquid 模板中调用 Ruby 方法(除了 `yield`),你几乎总是需要传递 locals 对象给它。
665
+
666
+ #### Markdown 模板
667
+
668
+ <table>
669
+ <tr>
670
+ <td>依赖项</td>
671
+ <td>
672
+ 下列任一:
673
+ <a href="https://github.com/davidfstr/rdiscount" title="RDiscount">RDiscount</a>,
674
+ <a href="https://github.com/vmg/redcarpet" title="RedCarpet">RedCarpet</a>,
675
+ <a href="http://deveiate.org/projects/BlueCloth" title="BlueCloth">BlueCloth</a>,
676
+ <a href="http://kramdown.gettalong.org/" title="kramdown">kramdown</a>,
677
+ <a href="https://github.com/bhollis/maruku" title="maruku">maruku</a>
678
+ </td>
679
+ </tr>
680
+ <tr>
681
+ <td>文件扩展名</td>
682
+ <td><tt>.markdown</tt>, <tt>.mkd</tt> and <tt>.md</tt></td>
683
+ </tr>
684
+ <tr>
685
+ <td>例子</td>
686
+ <td><tt>markdown :index, :layout_engine => :erb</tt></td>
687
+ </tr>
688
+ </table>
689
+
690
+ 不能在 markdown 中调用 Ruby 方法,也不能传递 locals 给它。
691
+ 因此,你一般会结合其它的渲染引擎来使用它:
692
+
693
+ ```ruby
481
694
  erb :overview, :locals => { :text => markdown(:introduction) }
482
- ~~~~
695
+ ```
483
696
 
484
- 请注意你也可以从其他模板中调用 markdown 方法:
697
+ 请注意你也可以在其它模板中调用 markdown 方法:
485
698
 
486
- ~~~~ ruby
699
+ ```ruby
487
700
  %h1 Hello From Haml!
488
701
  %p= markdown(:greetings)
489
- ~~~~
490
-
491
- 既然你不能在Markdown中调用Ruby,你不能使用Markdown编写的布局。
492
- 不过,使用其他填充引擎作为模版的布局是可能的,
493
- 通过传递`:layout_engine`选项:
494
-
495
- ~~~~ ruby
496
- get '/' do
497
- markdown :index, :layout_engine => :erb
498
- end
499
- ~~~~
500
-
501
- 这将会调用 `./views/index.md` 并使用 `./views/layout.erb` 作为布局。
502
-
503
- 请记住你可以全局设定这个选项:
504
-
505
- ~~~~ ruby
506
- set :markdown, :layout_engine => :haml, :layout => :post
507
-
508
- get '/' do
509
- markdown :index
510
- end
511
- ~~~~
512
-
513
- 这将会调用 `./views/index.markdown` (和任何其他的 Markdown 模版) 并使用
514
- `./views/post.haml` 作为布局.
515
-
516
- 也可能使用BlueCloth而不是RDiscount来解析Markdown文件:
517
-
518
- ~~~~ ruby
519
- require 'bluecloth'
520
-
521
- Tilt.register 'markdown', BlueClothTemplate
522
- Tilt.register 'mkd', BlueClothTemplate
523
- Tilt.register 'md', BlueClothTemplate
524
-
525
- get '/' do
526
- markdown :index
527
- end
528
- ~~~~
529
-
530
- 使用BlueCloth来填充 `./views/index.md` 。
531
-
532
- ### Textile 模板
533
-
534
- 需要引入 `RedCloth` gem/library 以填充 Textile 模板:
535
-
536
- ~~~~ ruby
537
- # 在你的应用中引入redcloth
538
- require "redcloth"
539
-
540
- get '/' do
541
- textile :index
542
- end
543
- ~~~~
544
-
545
- 这里调用的是 `./views/index.textile`。
546
-
547
- 在textile中是不可以调用方法的,也不可以传递 locals给它。
548
- 你因此一般会结合其他的填充引擎来使用它:
549
-
550
- ~~~~ ruby
702
+ ```
703
+
704
+ 因为不能在 Markdown 中使用 Ruby 语言,你不能使用 Markdown 书写的布局。
705
+ 不过,使用其它渲染引擎作为模板的布局是可能的,这需要通过传入 `:layout_engine` 选项。
706
+
707
+ #### Textile 模板
708
+
709
+ <table>
710
+ <tr>
711
+ <td>依赖项</td>
712
+ <td><a href="http://redcloth.org/" title="RedCloth">RedCloth</a></td>
713
+ </tr>
714
+ <tr>
715
+ <td>文件扩展名</td>
716
+ <td><tt>.textile</tt></td>
717
+ </tr>
718
+ <tr>
719
+ <td>例子</td>
720
+ <td><tt>textile :index, :layout_engine => :erb</tt></td>
721
+ </tr>
722
+ </table>
723
+
724
+ 不能在 textile 中调用 Ruby 方法,也不能传递 locals 给它。
725
+ 因此,你一般会结合其它的渲染引擎来使用它:
726
+
727
+ ```ruby
551
728
  erb :overview, :locals => { :text => textile(:introduction) }
552
- ~~~~
729
+ ```
553
730
 
554
- 请注意你也可以从其他模板中调用`textile`方法:
731
+ 请注意你也可以在其他模板中调用 `textile` 方法:
555
732
 
556
- ~~~~ ruby
733
+ ```ruby
557
734
  %h1 Hello From Haml!
558
735
  %p= textile(:greetings)
559
- ~~~~
560
-
561
- 既然你不能在Textile中调用Ruby,你不能使用Textile编写的布局。
562
- 不过,使用其他填充引擎作为模版的布局是可能的,
563
- 通过传递`:layout_engine`选项:
564
-
565
- ~~~~ ruby
566
- get '/' do
567
- textile :index, :layout_engine => :erb
568
- end
569
- ~~~~
570
-
571
- 这将会填充 `./views/index.textile` 并使用 `./views/layout.erb`
572
- 作为布局。
573
-
574
- 请记住你可以全局设定这个选项:
575
-
576
- ~~~~ ruby
577
- set :textile, :layout_engine => :haml, :layout => :post
578
-
579
- get '/' do
580
- textile :index
581
- end
582
- ~~~~
583
-
584
- 这将会调用 `./views/index.textile` (和任何其他的 Textile 模版) 并使用
585
- `./views/post.haml` 作为布局.
586
-
587
- ### RDoc 模板
588
-
589
- 需要引入 `RDoc` gem/library 以填充RDoc模板:
590
-
591
- ~~~~ ruby
592
- # 需要在你的应用中引入rdoc/markup/to_html
593
- require "rdoc"
594
- require "rdoc/markup/to_html"
595
-
596
- get '/' do
597
- rdoc :index
598
- end
599
- ~~~~
600
-
601
- 这里调用的是 `./views/index.rdoc`。
602
-
603
- 在rdoc中是不可以调用方法的,也不可以传递locals给它。
604
- 你因此一般会结合其他的填充引擎来使用它:
605
-
606
- ~~~~ ruby
736
+ ```
737
+
738
+ 因为不能在 Textile 中调用 Ruby 方法,你不能用 Textile 书写布局。
739
+ 不过,使用其它渲染引擎作为模版的布局是可能的,这需要通过传递 `:layout_engine` 选项。
740
+
741
+ #### RDoc 模板
742
+
743
+ <table>
744
+ <tr>
745
+ <td>依赖项</td>
746
+ <td><a href="http://rdoc.sourceforge.net/" title="RDoc">RDoc</a></td>
747
+ </tr>
748
+ <tr>
749
+ <td>文件扩展名</td>
750
+ <td><tt>.rdoc</tt></td>
751
+ </tr>
752
+ <tr>
753
+ <td>例子</td>
754
+ <td><tt>rdoc :README, :layout_engine => :erb</tt></td>
755
+ </tr>
756
+ </table>
757
+
758
+ 不能在 rdoc 中调用 Ruby 方法,也不能传递 locals 给它。
759
+ 因此,你一般会结合其它的渲染引擎来使用它:
760
+
761
+ ```ruby
607
762
  erb :overview, :locals => { :text => rdoc(:introduction) }
608
- ~~~~
763
+ ```
609
764
 
610
- 请注意你也可以从其他模板中调用`rdoc`方法:
765
+ 请注意你也可以在其他模板中调用 `rdoc` 方法:
611
766
 
612
- ~~~~ ruby
767
+ ```ruby
613
768
  %h1 Hello From Haml!
614
769
  %p= rdoc(:greetings)
615
- ~~~~
616
-
617
- 既然你不能在RDoc中调用Ruby,你不能使用RDoc编写的布局。
618
- 不过,使用其他填充引擎作为模版的布局是可能的,
619
- 通过传递`:layout_engine`选项:
620
-
621
- ~~~~ ruby
622
- get '/' do
623
- rdoc :index, :layout_engine => :erb
624
- end
625
- ~~~~
626
-
627
- 这将会调用 `./views/index.rdoc` 并使用 `./views/layout.erb` 作为布局。
628
-
629
- 请记住你可以全局设定这个选项:
630
-
631
- ~~~~ ruby
632
- set :rdoc, :layout_engine => :haml, :layout => :post
633
-
634
- get '/' do
635
- rdoc :index
636
- end
637
- ~~~~
638
-
639
- 这将会调用 `./views/index.rdoc` (和任何其他的 RDoc 模版) 并使用
640
- `./views/post.haml` 作为布局.
641
-
642
- ### Radius 模板
643
-
644
- 需要引入 `radius` gem/library 以填充 Radius 模板:
645
-
646
- ~~~~ ruby
647
- # 需要在你的应用中引入radius
648
- require 'radius'
649
-
650
- get '/' do
651
- radius :index
652
- end
653
- ~~~~
654
-
655
- 这里调用的是 `./views/index.radius`。
656
-
657
- 因为你不能在Radius 模板中调用 Ruby 方法 (除了 `yield`) ,
658
- 你几乎总是需要传递locals给它:
659
-
660
- ~~~~ ruby
661
- radius :index, :locals => { :key => 'value' }
662
- ~~~~
663
-
664
- ### Markaby 模板
665
-
666
- 需要引入`markaby` gem/library以填充Markaby模板:
667
-
668
- ~~~~ ruby
669
- #需要在你的应用中引入 markaby
670
- require 'markaby'
671
-
672
- get '/' do
673
- markaby :index
674
- end
675
- ~~~~
676
-
677
- 这里调用的是 `./views/index.mab`。
678
-
679
- 你也可以使用嵌入的 Markaby:
770
+ ```
771
+
772
+ 因为不能在 RDoc 中调用 Ruby 方法,你不能用 RDoc 书写布局。
773
+ 不过,使用其它渲染引擎作为模版的布局是可能的,这需要通过传递 `:layout_engine` 选项。
774
+
775
+ #### AsciiDoc 模板
776
+
777
+ <table>
778
+ <tr>
779
+ <td>依赖项</td>
780
+ <td><a href="http://asciidoctor.org/" title="Asciidoctor">Asciidoctor</a></td>
781
+ </tr>
782
+ <tr>
783
+ <td>文件扩展名</td>
784
+ <td><tt>.asciidoc</tt>, <tt>.adoc</tt> and <tt>.ad</tt></td>
785
+ </tr>
786
+ <tr>
787
+ <td>例子</td>
788
+ <td><tt>asciidoc :README, :layout_engine => :erb</tt></td>
789
+ </tr>
790
+ </table>
791
+
792
+ 因为不能在 AsciiDoc 模板中直接调用 Ruby 方法,你几乎总是需要传递 locals 对象给它。
793
+
794
+ #### Radius 模板
795
+
796
+ <table>
797
+ <tr>
798
+ <td>依赖项</td>
799
+ <td><a href="https://github.com/jlong/radius" title="Radius">Radius</a></td>
800
+ </tr>
801
+ <tr>
802
+ <td>文件扩展名</td>
803
+ <td><tt>.radius</tt></td>
804
+ </tr>
805
+ <tr>
806
+ <td>例子</td>
807
+ <td><tt>radius :index, :locals => { :key => 'value' }</tt></td>
808
+ </tr>
809
+ </table>
810
+
811
+ 因为不能在 Radius 模板中直接调用 Ruby 方法,你几乎总是可以传递 locals 对象给它。
812
+
813
+ #### Markaby 模板
814
+
815
+ <table>
816
+ <tr>
817
+ <td>依赖项</td>
818
+ <td><a href="http://markaby.github.io/" title="Markaby">Markaby</a></td>
819
+ </tr>
820
+ <tr>
821
+ <td>文件扩展名</td>
822
+ <td><tt>.mab</tt></td>
823
+ </tr>
824
+ <tr>
825
+ <td>例子</td>
826
+ <td><tt>markaby { h1 "Welcome!" }</tt></td>
827
+ </tr>
828
+ </table>
829
+
830
+ `markaby` 渲染方法也接受一个代码块,用于内联模板(见例子)。
831
+
832
+ #### RABL 模板
833
+
834
+ <table>
835
+ <tr>
836
+ <td>依赖项</td>
837
+ <td><a href="https://github.com/nesquena/rabl" title="Rabl">Rabl</a></td>
838
+ </tr>
839
+ <tr>
840
+ <td>文件扩展名</td>
841
+ <td><tt>.rabl</tt></td>
842
+ </tr>
843
+ <tr>
844
+ <td>例子</td>
845
+ <td><tt>rabl :index</tt></td>
846
+ </tr>
847
+ </table>
848
+
849
+ #### Slim 模板
850
+
851
+ <table>
852
+ <tr>
853
+ <td>依赖项</td>
854
+ <td><a href="http://slim-lang.com/" title="Slim Lang">Slim Lang</a></td>
855
+ </tr>
856
+ <tr>
857
+ <td>文件扩展名</td>
858
+ <td><tt>.slim</tt></td>
859
+ </tr>
860
+ <tr>
861
+ <td>例子</td>
862
+ <td><tt>slim :index</tt></td>
863
+ </tr>
864
+ </table>
865
+
866
+ #### Creole 模板
867
+
868
+ <table>
869
+ <tr>
870
+ <td>依赖项</td>
871
+ <td><a href="https://github.com/minad/creole" title="Creole">Creole</a></td>
872
+ </tr>
873
+ <tr>
874
+ <td>文件扩展名</td>
875
+ <td><tt>.creole</tt></td>
876
+ </tr>
877
+ <tr>
878
+ <td>例子</td>
879
+ <td><tt>creole :wiki, :layout_engine => :erb</tt></td>
880
+ </tr>
881
+ </table>
882
+
883
+ 不能在 creole 中调用 Ruby 方法,也不能传递 locals 对象给它。
884
+ 因此你一般会结合其它的渲染引擎来使用它:
885
+
886
+ ```ruby
887
+ erb :overview, :locals => { :text => creole(:introduction) }
888
+ ```
889
+
890
+ 注意你也可以在其它模板内调用 `creole` 方法:
891
+
892
+ ```ruby
893
+ %h1 Hello From Haml!
894
+ %p= creole(:greetings)
895
+ ```
896
+
897
+ 因为不能在 Creole 模板文件内调用 Ruby 方法,你不能用 Creole 书写布局文件。
898
+ 然而,使用其它渲染引擎作为模版的布局是可能的,这需要通过传递 `:layout_engine` 选项。
899
+
900
+ #### MediaWiki 模板
901
+
902
+ <table>
903
+ <tr>
904
+ <td>依赖项</td>
905
+ <td><a href="https://github.com/nricciar/wikicloth" title="WikiCloth">WikiCloth</a></td>
906
+ </tr>
907
+ <tr>
908
+ <td>文件扩展名</td>
909
+ <td><tt>.mediawiki</tt> and <tt>.mw</tt></td>
910
+ </tr>
911
+ <tr>
912
+ <td>例子</td>
913
+ <td><tt>mediawiki :wiki, :layout_engine => :erb</tt></td>
914
+ </tr>
915
+ </table>
916
+
917
+ 在 MediaWiki 标记文件内不能调用 Ruby 方法,也不能传递 locals 对象给它。
918
+ 因此你一般会结合其它的渲染引擎来使用它:
919
+
920
+ ```ruby
921
+ erb :overview, :locals => { :text => mediawiki(:introduction) }
922
+ ```
923
+
924
+ 注意你也可以在其它模板内调用 `mediawiki` 方法:
925
+
926
+ ```ruby
927
+ %h1 Hello From Haml!
928
+ %p= mediawiki(:greetings)
929
+ ```
930
+
931
+ 因为不能在 MediaWiki 文件内调用 Ruby 方法,你不能用 MediaWiki 书写布局文件。
932
+ 然而,使用其它渲染引擎作为模版的布局是可能的,这需要通过传递 `:layout_engine` 选项。
933
+
934
+ #### CoffeeScript 模板
935
+
936
+ <table>
937
+ <tr>
938
+ <td>依赖项</td>
939
+ <td>
940
+ <a href="https://github.com/josh/ruby-coffee-script" title="Ruby CoffeeScript">
941
+ CoffeeScript
942
+ </a> 以及一种
943
+ <a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
944
+ 执行 JavaScript 的方式
945
+ </a>
946
+ </td>
947
+ </tr>
948
+ <tr>
949
+ <td>文件扩展名</td>
950
+ <td><tt>.coffee</tt></td>
951
+ </tr>
952
+ <tr>
953
+ <td>例子</td>
954
+ <td><tt>coffee :index</tt></td>
955
+ </tr>
956
+ </table>
957
+
958
+ #### Stylus 模板
959
+
960
+ <table>
961
+ <tr>
962
+ <td>依赖项</td>
963
+ <td>
964
+ <a href="https://github.com/forgecrafted/ruby-stylus" title="Ruby Stylus">
965
+ Stylus
966
+ </a> 以及一种
967
+ <a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
968
+ 执行 JavaScript 的方式
969
+ </a>
970
+ </td>
971
+ </tr>
972
+ <tr>
973
+ <td>文件扩展名</td>
974
+ <td><tt>.styl</tt></td>
975
+ </tr>
976
+ <tr>
977
+ <td>例子</td>
978
+ <td><tt>stylus :index</tt></td>
979
+ </tr>
980
+ </table>
981
+
982
+ 在使用 Stylus 模板之前,你需要先加载 `stylus` 和 `stylus/tilt`:
983
+
984
+ ```ruby
985
+ require 'sinatra'
986
+ require 'stylus'
987
+ require 'stylus/tilt'
680
988
 
681
- ~~~~ ruby
682
989
  get '/' do
683
- markaby { h1 "Welcome!" }
684
- end
685
- ~~~~
990
+ stylus :example
991
+ end
992
+ ```
993
+
994
+ #### Yajl 模板
995
+
996
+ <table>
997
+ <tr>
998
+ <td>依赖项</td>
999
+ <td><a href="https://github.com/brianmario/yajl-ruby" title="yajl-ruby">yajl-ruby</a></td>
1000
+ </tr>
1001
+ <tr>
1002
+ <td>文件扩展名</td>
1003
+ <td><tt>.yajl</tt></td>
1004
+ </tr>
1005
+ <tr>
1006
+ <td>例子</td>
1007
+ <td>
1008
+ <tt>
1009
+ yajl :index,
1010
+ :locals => { :key => 'qux' },
1011
+ :callback => 'present',
1012
+ :variable => 'resource'
1013
+ </tt>
1014
+ </td>
1015
+ </tr>
1016
+ </table>
1017
+
1018
+ 模板文件的源码作为一个 Ruby 字符串被求值,得到的 json 变量是通过 `#to_json` 方法转换的:
1019
+
1020
+ ```ruby
1021
+ json = { :foo => 'bar' }
1022
+ json[:baz] = key
1023
+ ```
1024
+
1025
+ 可以使用 `:callback` 和 `:variable` 选项装饰被渲染的对象:
1026
+
1027
+ ```javascript
1028
+ var resource = {"foo":"bar","baz":"qux"};
1029
+ present(resource);
1030
+ ```
1031
+
1032
+ #### WLang 模板
1033
+
1034
+ <table>
1035
+ <tr>
1036
+ <td>依赖项</td>
1037
+ <td><a href="https://github.com/blambeau/wlang/" title="WLang">WLang</a></td>
1038
+ </tr>
1039
+ <tr>
1040
+ <td>文件扩展名</td>
1041
+ <td><tt>.wlang</tt></td>
1042
+ </tr>
1043
+ <tr>
1044
+ <td>例子</td>
1045
+ <td><tt>wlang :index, :locals => { :key => 'value' }</tt></td>
1046
+ </tr>
1047
+ </table>
1048
+
1049
+ 因为在 WLang 中调用 Ruby 方法不符合语言习惯,你几乎总是需要传递 locals 给 WLang 木板。
1050
+ 然而,可以用 WLang 编写布局文件,也可以在 WLang 中使用 `yield` 方法。
686
1051
 
687
- ### Slim 模板
688
-
689
- 需要引入 `slim` gem/library 来填充 Slim 模板:
1052
+ ### 在模板中访问变量
690
1053
 
691
- ~~~~ ruby
692
- # 需要在你的应用中引入 slim
693
- require 'slim'
1054
+ 模板的求值发生在路由处理器内部的上下文中。模板可以直接访问路由处理器中设置的实例变量。
694
1055
 
695
- get '/' do
696
- slim :index
1056
+ ```ruby
1057
+ get '/:id' do
1058
+ @foo = Foo.find(params['id'])
1059
+ haml '%h1= @foo.name'
697
1060
  end
698
- ~~~~
1061
+ ```
699
1062
 
700
- 这里调用的是 `./views/index.slim`。
1063
+ 或者,也可以显式地指定一个由局部变量组成的 locals 哈希:
701
1064
 
702
- ### Creole 模板
703
-
704
- 需要引入 `creole` gem/library 来填充 Creole 模板:
705
-
706
- ~~~~ ruby
707
- # 需要在你的应用中引入 creole
708
- require 'creole'
709
-
710
- get '/' do
711
- creole :index
1065
+ ```ruby
1066
+ get '/:id' do
1067
+ foo = Foo.find(params['id'])
1068
+ haml '%h1= foo.name', :locals => { :foo => foo }
712
1069
  end
713
- ~~~~
714
-
715
- 这里调用的是 `./views/index.creole`。
716
-
717
- ### CoffeeScript 模板
718
-
719
- 需要引入 `coffee-script` gem/library 并至少满足下面条件一项
720
- 以执行Javascript:
721
-
722
- - `node` (来自 Node.js) 在你的路径中
1070
+ ```
723
1071
 
724
- - 你正在运行 OSX
725
-
726
- - `therubyracer` gem/library
727
-
728
- 请察看
729
- [github.com/josh/ruby-coffee-script](http://github.com/josh/ruby-coffee-script)
730
- 获取更新的选项。
731
-
732
- 现在你可以调用 CoffeeScript 模版了:
733
-
734
- ~~~~ ruby
735
- # 需要在你的应用中引入coffee-script
736
- require 'coffee-script'
737
-
738
- get '/application.js' do
739
- coffee :application
740
- end
741
- ~~~~
1072
+ locals 哈希典型的使用情景是在别的模板中渲染 partials。
742
1073
 
743
- 这里调用的是 `./views/application.coffee`。
1074
+ ### 带 `yield` 的模板和嵌套布局
744
1075
 
745
- ### 嵌入模板字符串
1076
+ 布局通常就是使用了 `yield` 方法的模板。
1077
+ 这样的布局文件可以通过上面描述的 `:template` 选项指定,也可以通过下面的代码块渲染:
746
1078
 
747
- ~~~~ ruby
748
- get '/' do
749
- haml '%div.title Hello World'
1079
+ ```ruby
1080
+ erb :post, :layout => false do
1081
+ erb :index
750
1082
  end
751
- ~~~~
1083
+ ```
752
1084
 
753
- 调用嵌入模板字符串。
1085
+ 这段代码几乎完全等同于 `erb :index, :layout => :post`。
754
1086
 
755
- ### 在模板中访问变量
756
-
757
- 模板和路由执行器在同样的上下文求值。
758
- 在路由执行器中赋值的实例变量可以直接被模板访问。
1087
+ 向渲染方法传递代码块对于创建嵌套布局是最有用的:
759
1088
 
760
- ~~~~ ruby
761
- get '/:id' do
762
- @foo = Foo.find(params['id'])
763
- haml '%h1= @foo.name'
1089
+ ```ruby
1090
+ erb :main_layout, :layout => false do
1091
+ erb :admin_layout do
1092
+ erb :user
1093
+ end
764
1094
  end
765
- ~~~~
1095
+ ```
766
1096
 
767
- 或者,显式地指定一个本地变量的哈希:
1097
+ 代码行数可以更少:
768
1098
 
769
- ~~~~ ruby
770
- get '/:id' do
771
- foo = Foo.find(params['id'])
772
- haml '%h1= foo.name', :locals => { :foo => foo }
1099
+ ```ruby
1100
+ erb :admin_layout, :layout => :main_layout do
1101
+ erb :user
773
1102
  end
774
- ~~~~
1103
+ ```
775
1104
 
776
- 典型的使用情况是在别的模板中按照局部模板的方式来填充。
1105
+ 当前,以下的渲染方法接受一个代码块:`erb`、`haml`、`liquid`、`slim ` 和 `wlang`。
1106
+ 通用的 `render` 方法也接受。
777
1107
 
778
1108
  ### 内联模板
779
1109
 
780
1110
  模板可以在源文件的末尾定义:
781
1111
 
782
- ~~~~ ruby
1112
+ ```ruby
783
1113
  require 'sinatra'
784
1114
 
785
1115
  get '/' do
@@ -793,18 +1123,17 @@ __END__
793
1123
  = yield
794
1124
 
795
1125
  @@ index
796
- %div.title Hello world!!!!!
797
- ~~~~
1126
+ %div.title Hello world.
1127
+ ```
798
1128
 
799
- 注意:引入sinatra的源文件中定义的内联模板才能被自动载入。
800
- 如果你在其他源文件中有内联模板,
801
- 需要显式执行调用`enable :inline_templates`。
1129
+ 注意:在引入了 sinatra 的源文件中定义的内联模板会自动载入。
1130
+ 如果你在其他源文件中也有内联模板,需要显式调用 `enable :inline_templates`。
802
1131
 
803
1132
  ### 具名模板
804
1133
 
805
- 模板可以通过使用顶层 `template` 方法定义:
1134
+ 可以使用顶层 `template` 方法定义模板:
806
1135
 
807
- ~~~~ ruby
1136
+ ```ruby
808
1137
  template :layout do
809
1138
  "%html\n =yield\n"
810
1139
  end
@@ -816,33 +1145,32 @@ end
816
1145
  get '/' do
817
1146
  haml :index
818
1147
  end
819
- ~~~~
1148
+ ```
820
1149
 
821
- 如果存在名为“layout”的模板,该模板会在每个模板填充的时候被使用。
822
- 你可以单独地通过传送 `:layout => false`来禁用,
823
- 或者通过`set :haml, :layout => false`来禁用他们。
1150
+ 如果存在名为 “layout” 的模板,该模板会在每个模板渲染的时候作为布局使用。
1151
+ 你可以为渲染方法传送 `:layout => false` 来禁用该次渲染的布局,
1152
+ 也可以设置 `set :haml, :layout => false` 来默认禁用布局。
824
1153
 
825
- ~~~~ ruby
1154
+ ```ruby
826
1155
  get '/' do
827
1156
  haml :index, :layout => !request.xhr?
828
1157
  end
829
- ~~~~
1158
+ ```
830
1159
 
831
1160
  ### 关联文件扩展名
832
1161
 
833
- 为了关联一个文件扩展名到一个模版引擎,使用
834
- `Tilt.register`。比如,如果你喜欢使用 `tt`
835
- 作为Textile模版的扩展名,你可以这样做:
1162
+ 为了将一个文件扩展名到对应的模版引擎,要使用 `Tilt.register`。
1163
+ 比如,如果你喜欢使用 `tt` 作为 Textile 模版的扩展名,你可以这样做:
836
1164
 
837
- ~~~~ ruby
1165
+ ```ruby
838
1166
  Tilt.register :tt, Tilt[:textile]
839
- ~~~~
1167
+ ```
840
1168
 
841
- ### 添加你自己的模版引擎
1169
+ ### 添加自定义模板引擎
842
1170
 
843
- 首先,通过Tilt注册你自己的引擎,然后创建一个填充方法:
1171
+ 首先,通过 Tilt 注册你自定义的引擎,然后创建一个渲染方法:
844
1172
 
845
- ~~~~ ruby
1173
+ ```ruby
846
1174
  Tilt.register :myat, MyAwesomeTemplateEngine
847
1175
 
848
1176
  helpers do
@@ -852,18 +1180,33 @@ end
852
1180
  get '/' do
853
1181
  myat :index
854
1182
  end
855
- ~~~~
1183
+ ```
856
1184
 
857
- 这里调用的是 `./views/index.myat`。察看
858
- [github.com/rtomayko/tilt](https://github.com/rtomayko/tilt)
859
- 来更多了解Tilt.
1185
+ 这段代码将会渲染 `./views/index.myat` 文件。
1186
+ 查看 https://github.com/rtomayko/tilt 以了解更多关于 Tilt 的信息。
1187
+
1188
+ ### 自定义模板查找逻辑
1189
+
1190
+ 要实现自定义的模板查找机制,你可以构建自己的 `#find_template` 方法:
1191
+
1192
+ ```ruby
1193
+ configure do
1194
+ set :views, [ './views/a', './views/b' ]
1195
+ end
1196
+
1197
+ def find_template(views, name, engine, &block)
1198
+ Array(views).each do |v|
1199
+ super(v, name, engine, &block)
1200
+ end
1201
+ end
1202
+ ```
860
1203
 
861
1204
  ## 过滤器
862
1205
 
863
- 前置过滤器在每个请求前,在请求的上下文环境中被执行,
864
- 而且可以修改请求和响应。 在过滤器中设定的实例变量可以被路由和模板访问:
1206
+ `before` 过滤器在每个请求之前调用,调用的上下文与请求的上下文相同,并且可以修改请求和响应。
1207
+ 在过滤器中设置的变量可以被路由和模板访问:
865
1208
 
866
- ~~~~ ruby
1209
+ ```ruby
867
1210
  before do
868
1211
  @note = 'Hi!'
869
1212
  request.path_info = '/foo/bar/baz'
@@ -873,24 +1216,23 @@ get '/foo/*' do
873
1216
  @note #=> 'Hi!'
874
1217
  params['splat'] #=> 'bar/baz'
875
1218
  end
876
- ~~~~
1219
+ ```
877
1220
 
878
- 后置过滤器在每个请求之后,在请求的上下文环境中执行,
879
- 而且可以修改请求和响应。
880
- 在前置过滤器和路由中设定的实例变量可以被后置过滤器访问:
1221
+ `after` 过滤器在每个请求之后调用,调用上下文与请求的上下文相同,并且也会修改请求和响应。
1222
+ 在 `before` 过滤器和路由中设置的实例变量可以被 `after` 过滤器访问:
881
1223
 
882
- ~~~~ ruby
1224
+ ```ruby
883
1225
  after do
884
1226
  puts response.status
885
1227
  end
886
- ~~~~
1228
+ ```
887
1229
 
888
1230
  请注意:除非你显式使用 `body` 方法,而不是在路由中直接返回字符串,
889
- 消息体在后置过滤器是不可用的, 因为它在之后才会生成。
1231
+ 响应主体在 `after` 过滤器是不可访问的, 因为它在之后才会生成。
890
1232
 
891
1233
  过滤器可以可选地带有范式, 只有请求路径满足该范式时才会执行:
892
1234
 
893
- ~~~~ ruby
1235
+ ```ruby
894
1236
  before '/protected/*' do
895
1237
  authenticate!
896
1238
  end
@@ -898,11 +1240,11 @@ end
898
1240
  after '/create/:slug' do |slug|
899
1241
  session['last_slug'] = slug
900
1242
  end
901
- ~~~~
1243
+ ```
902
1244
 
903
- 和路由一样,过滤器也可以带有条件:
1245
+ 和路由一样,过滤器也可以带有条件:
904
1246
 
905
- ~~~~ ruby
1247
+ ```ruby
906
1248
  before :agent => /Songbird/ do
907
1249
  # ...
908
1250
  end
@@ -910,13 +1252,13 @@ end
910
1252
  after '/blog/*', :host_name => 'example.com' do
911
1253
  # ...
912
1254
  end
913
- ~~~~
1255
+ ```
914
1256
 
915
1257
  ## 辅助方法
916
1258
 
917
1259
  使用顶层的 `helpers` 方法来定义辅助方法, 以便在路由处理器和模板中使用:
918
1260
 
919
- ~~~~ ruby
1261
+ ```ruby
920
1262
  helpers do
921
1263
  def bar(name)
922
1264
  "#{name}bar"
@@ -926,14 +1268,29 @@ end
926
1268
  get '/:name' do
927
1269
  bar(params['name'])
928
1270
  end
929
- ~~~~
1271
+ ```
1272
+
1273
+ 也可以在多个分散的模块中定义辅助方法:
1274
+
1275
+ ```ruby
1276
+ module FooUtils
1277
+ def foo(name) "#{name}foo" end
1278
+ end
930
1279
 
931
- ### 使用 Sessions
1280
+ module BarUtils
1281
+ def bar(name) "#{name}bar" end
1282
+ end
932
1283
 
933
- Session被用来在请求之间保持状态。如果被激活,每一个用户会话
934
- 对应有一个session哈希:
1284
+ helpers FooUtils, BarUtils
1285
+ ```
935
1286
 
936
- ~~~~ ruby
1287
+ 以上代码块与在应用类中包含模块等效。
1288
+
1289
+ ### 使用会话
1290
+
1291
+ 会话用于在请求之间保持状态。如果激活了会话,每一个用户会话都对应一个会话 hash:
1292
+
1293
+ ```ruby
937
1294
  enable :sessions
938
1295
 
939
1296
  get '/' do
@@ -943,14 +1300,14 @@ end
943
1300
  get '/:value' do
944
1301
  session['value'] = params['value']
945
1302
  end
946
- ~~~~
1303
+ ```
947
1304
 
948
- 请注意 `enable :sessions` 实际上保存所有的数据在一个cookie之中。
949
- 这可能不会总是做你想要的(比如,保存大量的数据会增加你的流量)。
950
- 你可以使用任何的Rack session中间件,为了这么做, \*不要\*调用
951
- `enable :sessions`,而是 按照自己的需要引入你的中间件:
1305
+ 请注意 `enable :sessions` 实际将所有的数据保存在一个 cookie 中。
1306
+ 这可能并不总是你想要的(cookie 中存储大量的数据会增加你的流量)。
1307
+ 你可以使用任何 Rack session 中间件:要达到此目的,**不要**使用 `enable :sessions`,
1308
+ 而是按照自己的需要引入想使用的中间件:
952
1309
 
953
- ~~~~ ruby
1310
+ ```ruby
954
1311
  use Rack::Session::Pool, :expire_after => 2592000
955
1312
 
956
1313
  get '/' do
@@ -960,45 +1317,70 @@ end
960
1317
  get '/:value' do
961
1318
  session['value'] = params['value']
962
1319
  end
963
- ~~~~
1320
+ ```
1321
+
1322
+ 为提高安全性,cookie 中的会话数据会被一个会话密码保护。Sinatra 会为你生成一个随机的密码。
1323
+ 然而,每次启动应用时,该密码都会变化,你也可以自己设置该密码,以便所有的应用实例共享:
1324
+
1325
+ ```
1326
+ set :session_secret, 'super secret'
1327
+ ```
1328
+
1329
+ 如果你想进一步配置会话,可以在设置 `sessions` 时提供一个选项 hash 作为第二个参数:
964
1330
 
965
- ### 挂起
1331
+ ```
1332
+ set :sessions, :domain => 'foo.com'
1333
+ ```
966
1334
 
967
- 要想直接地停止请求,在过滤器或者路由中使用:
1335
+ 为了在 foo.com 的子域名间共享会话数据,可以在域名前添加一个 *.*:
968
1336
 
969
- ~~~~ ruby
1337
+ ```ruby
1338
+ set :sessions, :domain => '.foo.com'
1339
+ ```
1340
+
1341
+ ### 中断请求
1342
+
1343
+ 要想在过滤器或路由中立即中断一个请求:
1344
+
1345
+ ```ruby
970
1346
  halt
971
- ~~~~
1347
+ ```
972
1348
 
973
- 你也可以指定挂起时的状态码:
1349
+ 你也可以指定中断时的状态码:
974
1350
 
975
- ~~~~ ruby
1351
+ ```ruby
976
1352
  halt 410
977
- ~~~~
1353
+ ```
978
1354
 
979
- 或者消息体:
1355
+ 或者响应主体:
980
1356
 
981
- ~~~~ ruby
1357
+ ```ruby
982
1358
  halt 'this will be the body'
983
- ~~~~
1359
+ ```
984
1360
 
985
- 或者两者;
1361
+ 或者同时指定两者:
986
1362
 
987
- ~~~~ ruby
1363
+ ```ruby
988
1364
  halt 401, 'go away!'
989
- ~~~~
1365
+ ```
990
1366
 
991
- 也可以带消息头:
1367
+ 也可以指定响应首部:
992
1368
 
993
- ~~~~ ruby
1369
+ ```ruby
994
1370
  halt 402, {'Content-Type' => 'text/plain'}, 'revenge'
995
- ~~~~
1371
+ ```
1372
+
1373
+ 当然也可以使用模板:
1374
+
1375
+ ```
1376
+ halt erb(:error)
1377
+ ```
996
1378
 
997
- ### 让路
1379
+ ### 传递请求
998
1380
 
999
- 一个路由可以放弃处理,将处理让给下一个匹配的路由,使用 `pass`:
1381
+ 一个路由可以放弃对请求的处理并将处理让给下一个匹配的路由,这要通过 `pass` 实现:
1000
1382
 
1001
- ~~~~ ruby
1383
+ ```ruby
1002
1384
  get '/guess/:who' do
1003
1385
  pass unless params['who'] == 'Frank'
1004
1386
  'You got me!'
@@ -1007,17 +1389,17 @@ end
1007
1389
  get '/guess/*' do
1008
1390
  'You missed!'
1009
1391
  end
1010
- ~~~~
1392
+ ```
1011
1393
 
1012
- 路由代码块被直接退出,控制流继续前进到下一个匹配的路由。
1013
- 如果没有匹配的路由,将返回404。
1394
+ 执行 `pass` 后,控制流从该路由代码块直接退出,并继续前进到下一个匹配的路由。
1395
+ 如果没有匹配的路由,将返回 404。
1014
1396
 
1015
1397
  ### 触发另一个路由
1016
1398
 
1017
- 有些时候,`pass` 并不是你想要的,你希望得到的是另一个路由的结果
1018
- 。简单的使用 `call` 可以做到这一点:
1399
+ 有些时候,`pass` 并不是你想要的,你希望得到的是调用另一个路由的结果。
1400
+ 使用 `call` 就可以做到这一点:
1019
1401
 
1020
- ~~~~ ruby
1402
+ ```ruby
1021
1403
  get '/foo' do
1022
1404
  status, headers, body = call env.merge("PATH_INFO" => '/bar')
1023
1405
  [status, headers, body.map(&:upcase)]
@@ -1026,27 +1408,22 @@ end
1026
1408
  get '/bar' do
1027
1409
  "bar"
1028
1410
  end
1029
- ~~~~
1411
+ ```
1030
1412
 
1031
- 请注意在以上例子中,你可以更加简化测试并增加性能,只要简单的移动
1413
+ 请注意在以上例子中,你只需简单地移动 `"bar"` 到一个被 `/foo` 和 `/bar` 同时使用的辅助方法中,
1414
+ 就可以简化测试和增加性能。
1032
1415
 
1033
- <tt>"bar"</tt>到一个被<tt>/foo</tt>
1416
+ 如果你希望请求发送到同一个应用,而不是应用副本,应使用 `call!` 而不是 `call`。
1034
1417
 
1035
- `/bar`同时使用的helper。
1418
+ 如果想更多了解关于 `call` 的信息,请查看 Rack 规范。
1036
1419
 
1037
- 如果你希望请求被发送到同一个应用,而不是副本, 使用 `call!` 而不是
1038
- `call`.
1420
+ ### 设置响应主体、状态码和响应首部
1039
1421
 
1040
- 如果想更多了解 `call`,请察看 Rack specification。
1422
+ 推荐在路由代码块的返回值中设定状态码和响应主体。
1423
+ 但是,在某些场景下你可能想在别处设置响应主体,这时你可以使用 `body` 辅助方法。
1424
+ 设置之后,你可以在那以后使用该方法访问响应主体:
1041
1425
 
1042
- ### 设定 消息体,状态码和消息头
1043
-
1044
- 通过路由代码块的返回值来设定状态码和消息体不仅是可能的,而且是推荐的。
1045
- 但是,在某些场景中你可能想在作业流程中的特定点上设置消息体。 你可以通过
1046
- `body` 辅助方法这么做。 如果你这样做了,
1047
- 你可以在那以后使用该方法获得消息体:
1048
-
1049
- ~~~~ ruby
1426
+ ```ruby
1050
1427
  get '/foo' do
1051
1428
  body "bar"
1052
1429
  end
@@ -1054,14 +1431,14 @@ end
1054
1431
  after do
1055
1432
  puts body
1056
1433
  end
1057
- ~~~~
1434
+ ```
1058
1435
 
1059
- 也可以传一个代码块给 `body`,它将会被Rack处理器执行(
1060
- 这将可以被用来实现streaming,参见“返回值”)。
1436
+ 也可以传递一个代码块给 `body` 方法,
1437
+ 它会被 Rack 处理器执行(这可以用来实现流式传输,参见“返回值”)。
1061
1438
 
1062
- 和消息体类似,你也可以设定状态码和消息头:
1439
+ 与响应主体类似,你也可以设定状态码和响应首部:
1063
1440
 
1064
- ~~~~ ruby
1441
+ ```ruby
1065
1442
  get '/foo' do
1066
1443
  status 418
1067
1444
  headers \
@@ -1069,61 +1446,151 @@ get '/foo' do
1069
1446
  "Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
1070
1447
  body "I'm a tea pot!"
1071
1448
  end
1072
- ~~~~
1449
+ ```
1450
+
1451
+ 正如 `body` 方法,不带参数调用 `headers` 和 `status` 方法可以访问它们的当前值。
1452
+
1453
+ ### 响应的流式传输
1454
+
1455
+ 有时你可能想在完全生成响应主体前返回数据。
1456
+ 更极端的情况是,你希望在客户端关闭连接前一直发送数据。
1457
+ 为满足这些需求,可以使用 `stream` 辅助方法而不必重新造轮子:
1458
+
1459
+ ```ruby
1460
+ get '/' do
1461
+ stream do |out|
1462
+ out << "It's gonna be legen -\n"
1463
+ sleep 0.5
1464
+ out << " (wait for it) \n"
1465
+ sleep 1
1466
+ out << "- dary!\n"
1467
+ end
1468
+ end
1469
+ ```
1470
+
1471
+ `stream` 辅助方法允许你实现流式 API 和
1472
+ [服务器端发送事件](https://w3c.github.io/eventsource/),
1473
+ 同时它也是实现 [WebSockets](https://en.wikipedia.org/wiki/WebSocket) 的基础。
1474
+ 如果你应用的部分(不是全部)内容依赖于访问缓慢的资源,它也可以用来提高并发能力。
1475
+
1476
+ 请注意流式传输,尤其是并发请求数,高度依赖于应用所使用的服务器。
1477
+ 一些服务器可能根本不支持流式传输。
1478
+ 如果服务器不支持,传递给 `stream` 方法的代码块执行完毕之后,响应主体会一次性地发送给客户端。
1479
+ Shotgun 完全不支持流式传输。
1480
+
1481
+ 如果 `:keep_open` 作为可选参数传递给 `stream` 方法,将不会在流对象上调用 `close` 方法,
1482
+ 这允许你在控制流的下游某处手动关闭。该参数只对事件驱动的服务器(如 Thin 和 Rainbows)生效。
1483
+ 其它服务器仍会关闭流式传输:
1484
+
1485
+ ```ruby
1486
+ # 长轮询
1487
+
1488
+ set :server, :thin
1489
+ connections = []
1490
+
1491
+ get '/subscribe' do
1492
+ # 在服务器端的事件中注册客户端
1493
+ stream(:keep_open) do |out|
1494
+ connections << out
1495
+ # 清除关闭的连接
1496
+ connections.reject!(&:closed?)
1497
+ end
1498
+ end
1499
+
1500
+ post '/:message' do
1501
+ connections.each do |out|
1502
+ # 通知客户端有条新消息
1503
+ out << params['message'] << "\n"
1073
1504
 
1074
- 如同 `body`, 不带参数的 `headers` 和 `status` 可以用来访问
1075
- 他们你的当前值.
1505
+ # 使客户端重新连接
1506
+ out.close
1507
+ end
1508
+
1509
+ # 确认
1510
+ "message received"
1511
+ end
1512
+ ```
1076
1513
 
1077
- ### 媒体(MIME)类型
1514
+ ### 日志
1078
1515
 
1079
- 使用 `send_file` 或者静态文件的时候,Sinatra可能不能识别你的媒体类型。
1080
- 使用 `mime_type` 通过文件扩展名来注册它们:
1516
+ 在请求作用域下,`logger` 辅助方法会返回一个 `Logger` 类的实例:
1081
1517
 
1082
- ~~~~ ruby
1518
+ ```ruby
1519
+ get '/' do
1520
+ logger.info "loading data"
1521
+ # ...
1522
+ end
1523
+ ```
1524
+
1525
+ 该 `logger` 方法会自动参考 Rack 处理器的日志设置。
1526
+ 若日志被禁用,该方法会返回一个无关痛痒的对象,所以你完全不必担心这会影响路由和过滤器。
1527
+
1528
+ 注意只有 `Sinatra::Application` 默认开启了日志,若你的应用继承自 `Sinatra::Base`,
1529
+ 很可能需要手动开启:
1530
+
1531
+ ```ruby
1532
+ class MyApp < Sinatra::Base
1533
+ configure :production, :development do
1534
+ enable :logging
1535
+ end
1536
+ end
1537
+ ```
1538
+
1539
+ 为避免使用任何与日志有关的中间件,需要将 `logging` 设置项设为 `nil`。
1540
+ 然而,在这种情况下,`logger` 辅助方法会返回 `nil`。
1541
+ 一种常见的使用场景是你想要使用自己的日志工具。
1542
+ Sinatra 会使用 `env['rack.logger']` 的值作为日志工具,无论该值是什么。
1543
+
1544
+ ### 媒体类型
1545
+
1546
+ 使用 `send_file` 或者静态文件的时候,Sinatra 可能不会识别你的媒体类型。
1547
+ 使用 `mime_type` 通过文件扩展名来注册媒体类型:
1548
+
1549
+ ```ruby
1083
1550
  mime_type :foo, 'text/foo'
1084
- ~~~~
1551
+ ```
1085
1552
 
1086
1553
  你也可以使用 `content_type` 辅助方法:
1087
1554
 
1088
- ~~~~ ruby
1555
+ ```ruby
1089
1556
  get '/' do
1090
1557
  content_type :foo
1091
1558
  "foo foo foo"
1092
1559
  end
1093
- ~~~~
1560
+ ```
1094
1561
 
1095
1562
  ### 生成 URL
1096
1563
 
1097
- 为了生成URL,你需要使用 `url` 辅助方法, 例如,在Haml中:
1564
+ 为了生成 URL,你应当使用 `url` 辅助方法,例如,在 Haml 中:
1098
1565
 
1099
- ~~~~ ruby
1566
+ ```ruby
1100
1567
  %a{:href => url('/foo')} foo
1101
- ~~~~
1568
+ ```
1102
1569
 
1103
- 如果使用反向代理和Rack路由,生成URL的时候会考虑这些因素。
1570
+ 如果使用了反向代理和 Rack 路由,生成 URL 的时候会考虑这些因素。
1104
1571
 
1105
- 这个方法还有一个别名 `to` (见下面的例子).
1572
+ 这个方法还有一个别名 `to` (见下面的例子)
1106
1573
 
1107
1574
  ### 浏览器重定向
1108
1575
 
1109
- 你可以通过 `redirect` 辅助方法触发浏览器重定向:
1576
+ 你可以通过 `redirect` 辅助方法触发浏览器重定向:
1110
1577
 
1111
- ~~~~ ruby
1578
+ ```ruby
1112
1579
  get '/foo' do
1113
1580
  redirect to('/bar')
1114
1581
  end
1115
- ~~~~
1582
+ ```
1116
1583
 
1117
- 其他参数的用法,与 `halt`相同:
1584
+ 其他参数的用法,与 `halt` 相同:
1118
1585
 
1119
- ~~~~ ruby
1586
+ ```ruby
1120
1587
  redirect to('/bar'), 303
1121
- redirect 'http://google.com', 'wrong place, buddy'
1122
- ~~~~
1588
+ redirect 'http://www.google.com/', 'wrong place, buddy'
1589
+ ```
1123
1590
 
1124
- 用 `redirect back`可以把用户重定向到原始页面:
1591
+ 用 `redirect back` 可以把用户重定向到原始页面:
1125
1592
 
1126
- ~~~~ ruby
1593
+ ```ruby
1127
1594
  get '/foo' do
1128
1595
  "<a href='/bar'>do something</a>"
1129
1596
  end
@@ -1132,17 +1599,17 @@ get '/bar' do
1132
1599
  do_something
1133
1600
  redirect back
1134
1601
  end
1135
- ~~~~
1602
+ ```
1136
1603
 
1137
- 如果想传递参数给redirect,可以用query string:
1604
+ 如果想传递参数给 redirect,可以用查询字符串:
1138
1605
 
1139
- ~~~~ ruby
1606
+ ```ruby
1140
1607
  redirect to('/bar?sum=42')
1141
- ~~~~
1608
+ ```
1142
1609
 
1143
- 或者用session:
1610
+ 或者使用会话:
1144
1611
 
1145
- ~~~~ ruby
1612
+ ```ruby
1146
1613
  enable :sessions
1147
1614
 
1148
1615
  get '/foo' do
@@ -1153,65 +1620,61 @@ end
1153
1620
  get '/bar' do
1154
1621
  session['secret']
1155
1622
  end
1156
- ~~~~
1623
+ ```
1157
1624
 
1158
1625
  ### 缓存控制
1159
1626
 
1160
- 要使用HTTP缓存,必须正确地设定消息头。
1627
+ 正确设置响应首部是合理利用 HTTP 缓存的基础。
1161
1628
 
1162
- 你可以这样设定 Cache-Control 消息头:
1629
+ 可以这样设定 Cache-Control 首部字段:
1163
1630
 
1164
- ~~~~ ruby
1631
+ ```ruby
1165
1632
  get '/' do
1166
1633
  cache_control :public
1167
1634
  "cache it!"
1168
1635
  end
1169
- ~~~~
1636
+ ```
1170
1637
 
1171
- 核心提示: 在前置过滤器中设定缓存.
1638
+ 核心提示: 应当在 `before` 过滤器中设定缓存。
1172
1639
 
1173
- ~~~~ ruby
1640
+ ```ruby
1174
1641
  before do
1175
1642
  cache_control :public, :must_revalidate, :max_age => 60
1176
1643
  end
1177
- ~~~~
1644
+ ```
1178
1645
 
1179
- 如果你正在用 `expires` 辅助方法设定对应的消息头 `Cache-Control`
1180
- 会自动设定:
1646
+ 如果你使用 `expires` 辅助方法设定响应的响应首部, 会自动设定 `Cache-Control` 字段:
1181
1647
 
1182
- ~~~~ ruby
1648
+ ```ruby
1183
1649
  before do
1184
1650
  expires 500, :public, :must_revalidate
1185
1651
  end
1186
- ~~~~
1187
-
1188
- 为了合适地使用缓存,你应该考虑使用 `etag` 和 `last_modified`方法。
1189
- 推荐在执行繁重任务\*之前\*使用这些helpers,这样一来,
1190
- 如果客户端在缓存中已经有相关内容,就会立即得到显示。
1652
+ ```
1191
1653
 
1654
+ 为了合理使用缓存,你应该考虑使用 `etag` 或 `last_modified` 方法。
1655
+ 推荐在执行繁重任务*之前*使用这些辅助方法,这样一来,
1656
+ 如果客户端在缓存中已经有相关内容,就会立即得到响应:
1192
1657
 
1193
- ~~~~ ruby
1658
+ ```ruby
1194
1659
  get '/article/:id' do
1195
1660
  @article = Article.find params['id']
1196
1661
  last_modified @article.updated_at
1197
1662
  etag @article.sha1
1198
1663
  erb :article
1199
1664
  end
1200
- ~~~~
1665
+ ```
1201
1666
 
1202
- 使用 [weak
1203
- ETag](http://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation)
1204
- 也是有可能的:
1667
+ 也可以使用 [weak ETag](https://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation):
1205
1668
 
1206
- ~~~~ ruby
1669
+ ```ruby
1207
1670
  etag @article.sha1, :weak
1208
- ~~~~
1671
+ ```
1209
1672
 
1210
- 这些辅助方法并不会为你做任何缓存,而是将必要的信息传送给你的缓存
1211
- 如果你在寻找缓存的快速解决方案,试试
1212
- [rack-cache](https://github.com/rtomayko/rack-cache):
1673
+ 这些辅助方法并不会为你做任何缓存,而是将必要的信息发送给你的缓存。
1674
+ 如果你正在寻找快捷的反向代理缓存方案,可以尝试
1675
+ [rack-cache](https://github.com/rtomayko/rack-cache)
1213
1676
 
1214
- ~~~~ ruby
1677
+ ```ruby
1215
1678
  require "rack/cache"
1216
1679
  require "sinatra"
1217
1680
 
@@ -1222,138 +1685,201 @@ get '/' do
1222
1685
  sleep 5
1223
1686
  "hello"
1224
1687
  end
1225
- ~~~~
1688
+ ```
1689
+
1690
+ 使用 `:statis_cache_control` 设置(见下文)为静态文件添加 `Cache-Control` 首部字段。
1691
+
1692
+ 根据 RFC 2616,如果 If-Match 或 If-None-Match 首部设置为 `*`,根据所请求的资源存在与否,
1693
+ 你的应用应当有不同的行为。
1694
+ Sinatra 假设安全请求(如 GET)和幂等性请求(如 PUT)所访问的资源是已经存在的,
1695
+ 而其它请求(如 POST 请求)所访问的资源是新资源。
1696
+ 你可以通过传入 `:new_resource` 选项改变这一行为。
1697
+
1698
+ ```ruby
1699
+ get '/create' do
1700
+ etag '', :new_resource => true
1701
+ Article.create
1702
+ erb :new_article
1703
+ end
1704
+ ```
1705
+
1706
+ 如果你仍想使用 weak ETag,可以传入一个 `:kind` 选项:
1707
+
1708
+ ```ruby
1709
+ etag '', :new_resource => true, :kind => :weak
1710
+ ```
1226
1711
 
1227
1712
  ### 发送文件
1228
1713
 
1229
- 为了发送文件,你可以使用 `send_file` 辅助方法:
1714
+ 为了将文件的内容作为响应返回,可以使用 `send_file` 辅助方法:
1230
1715
 
1231
- ~~~~ ruby
1716
+ ```ruby
1232
1717
  get '/' do
1233
1718
  send_file 'foo.png'
1234
1719
  end
1235
- ~~~~
1720
+ ```
1236
1721
 
1237
- 也可以带一些选项:
1722
+ 该辅助方法接受一些选项:
1238
1723
 
1239
- ~~~~ ruby
1724
+ ```ruby
1240
1725
  send_file 'foo.png', :type => :jpg
1241
- ~~~~
1726
+ ```
1242
1727
 
1243
1728
  可用的选项有:
1244
1729
 
1245
1730
  <dl>
1246
- <dt>filename</dt>
1247
- <dd>响应中的文件名,默认是真实文件的名字。</dd>
1731
+ <dt>filename</dt>
1732
+ <dd>响应中使用的文件名,默认是真实的文件名。</dd>
1248
1733
 
1249
- <dt>last_modified</dt>
1250
- <dd>Last-Modified 消息头的值,默认是文件的mtime(修改时间)。</dd>
1734
+ <dt>last_modified</dt>
1735
+ <dd>Last-Modified 响应首部的值,默认是文件的 mtime (修改时间)。</dd>
1251
1736
 
1252
- <dt>type</dt>
1253
- <dd>使用的内容类型,如果没有会从文件扩展名猜测。</dd>
1737
+ <dt>type</dt>
1738
+ <dd>Content-Type 响应首部的值,如果未指定,会根据文件扩展名猜测。</dd>
1254
1739
 
1255
- <dt>disposition</dt>
1256
- <dd>
1257
- 用于 Content-Disposition,可能的包括: <tt>nil</tt> (默认), <tt>:attachment</tt> 和
1258
- <tt>:inline</tt>
1259
- </dd>
1740
+ <dt>disposition</dt>
1741
+ <dd>
1742
+ Content-Disposition 响应首部的值,
1743
+ 可选的值有: <tt>nil</tt> (默认)、<tt>:attachment</tt>
1744
+ <tt>:inline</tt>
1745
+ </dd>
1260
1746
 
1261
- <dt>length</dt>
1262
- <dd>Content-Length 的值,默认是文件的大小。</dd>
1263
- </dl>
1747
+ <dt>length</dt>
1748
+ <dd>Content-Length 响应首部的值,默认是文件的大小。</dd>
1264
1749
 
1265
- 如果Rack处理器支持的话,Ruby进程也能使用除streaming以外的方法。
1266
- 如果你使用这个辅助方法, Sinatra会自动处理range请求。
1750
+ <dt>status</dt>
1751
+ <dd>
1752
+ 将要返回的状态码。当以一个静态文件作为错误页面时,这很有用。
1753
+
1754
+ 如果 Rack 处理器支持的话,Ruby 进程也能使用除 streaming 以外的方法。
1755
+ 如果你使用这个辅助方法, Sinatra会自动处理 range 请求。
1756
+ </dd>
1757
+ </dl>
1267
1758
 
1268
1759
  ### 访问请求对象
1269
1760
 
1270
- 传入的请求对象可以在请求层(过滤器,路由,错误处理) 通过 `request`
1271
- 方法被访问:
1761
+ 传入的请求对象可以在请求层(过滤器、路由、错误处理器内部)通过 `request` 方法访问:
1272
1762
 
1273
- ~~~~ ruby
1763
+ ```ruby
1274
1764
  # 在 http://example.com/example 上运行的应用
1275
1765
  get '/foo' do
1276
- request.body # 被客户端设定的请求体(见下)
1277
- request.scheme # "http"
1278
- request.script_name # "/example"
1279
- request.path_info # "/foo"
1280
- request.port # 80
1281
- request.request_method # "GET"
1282
- request.query_string # ""
1283
- request.content_length # request.body的长度
1284
- request.media_type # request.body的媒体类型
1285
- request.host # "example.com"
1286
- request.get? # true (其他动词也具有类似方法)
1287
- request.form_data? # false
1288
- request["SOME_HEADER"] # SOME_HEADER header的值
1289
- request.referrer # 客户端的referrer 或者 '/'
1290
- request.user_agent # user agent (被 :agent 条件使用)
1291
- request.cookies # 浏览器 cookies 哈希
1292
- request.xhr? # 这是否是ajax请求?
1293
- request.url # "http://example.com/example/foo"
1294
- request.path # "/example/foo"
1295
- request.ip # 客户端IP地址
1296
- request.secure? # false(如果是ssl则为true)
1297
- request.forwarded? # true (如果是运行在反向代理之后)
1298
- request.env # Rack中使用的未处理的env哈希
1299
- end
1300
- ~~~~
1766
+ t = %w[text/css text/html application/javascript]
1767
+ request.accept # ['text/html', '*/*']
1768
+ request.accept? 'text/xml' # true
1769
+ request.preferred_type(t) # 'text/html'
1770
+ request.body # 客户端设定的请求主体(见下文)
1771
+ request.scheme # "http"
1772
+ request.script_name # "/example"
1773
+ request.path_info # "/foo"
1774
+ request.port # 80
1775
+ request.request_method # "GET"
1776
+ request.query_string # ""
1777
+ request.content_length # request.body 的长度
1778
+ request.media_type # request.body 的媒体类型
1779
+ request.host # "example.com"
1780
+ request.get? # true (其它动词也具有类似方法)
1781
+ request.form_data? # false
1782
+ request["some_param"] # some_param 参数的值。[] 是访问 params hash 的捷径
1783
+ request.referrer # 客户端的 referrer 或者 '/'
1784
+ request.user_agent # 用户代理 (:agent 条件使用该值)
1785
+ request.cookies # 浏览器 cookies 哈希
1786
+ request.xhr? # 这是否是 ajax 请求?
1787
+ request.url # "http://example.com/example/foo"
1788
+ request.path # "/example/foo"
1789
+ request.ip # 客户端 IP 地址
1790
+ request.secure? # false (如果是 ssl 则为 true)
1791
+ request.forwarded? # true (如果是运行在反向代理之后)
1792
+ request.env # Rack 中使用的未处理的 env hash
1793
+ end
1794
+ ```
1301
1795
 
1302
1796
  一些选项,例如 `script_name` 或者 `path_info` 也是可写的:
1303
1797
 
1304
- ~~~~ ruby
1798
+ ```ruby
1305
1799
  before { request.path_info = "/" }
1306
1800
 
1307
1801
  get "/" do
1308
1802
  "all requests end up here"
1309
1803
  end
1310
- ~~~~
1804
+ ```
1311
1805
 
1312
- `request.body` 是一个IO或者StringIO对象:
1806
+ `request.body` 是一个 IO 或者 StringIO 对象:
1313
1807
 
1314
- ~~~~ ruby
1808
+ ```ruby
1315
1809
  post "/api" do
1316
1810
  request.body.rewind # 如果已经有人读了它
1317
1811
  data = JSON.parse request.body.read
1318
1812
  "Hello #{data['name']}!"
1319
1813
  end
1320
- ~~~~
1814
+ ```
1321
1815
 
1322
1816
  ### 附件
1323
1817
 
1324
- 你可以使用 `attachment` 辅助方法来告诉浏览器响应
1325
- 应当被写入磁盘而不是在浏览器中显示。
1818
+ 你可以使用 `attachment` 辅助方法来告诉浏览器响应应当被写入磁盘而不是在浏览器中显示。
1326
1819
 
1327
- ~~~~ ruby
1820
+ ```ruby
1328
1821
  get '/' do
1329
1822
  attachment
1330
1823
  "store it!"
1331
1824
  end
1332
- ~~~~
1825
+ ```
1333
1826
 
1334
- 你也可以传递一个文件名:
1827
+ 你也可以传递给该方法一个文件名:
1335
1828
 
1336
- ~~~~ ruby
1829
+ ```ruby
1337
1830
  get '/' do
1338
1831
  attachment "info.txt"
1339
1832
  "store it!"
1340
1833
  end
1341
- ~~~~
1834
+ ```
1835
+
1836
+ ### 处理日期和时间
1837
+
1838
+ Sinatra 提供了一个 `time_for` 辅助方法,其目的是根据给定的值生成 Time 对象。
1839
+ 该方法也能够转换 `DateTime`、`Date` 和类似的类:
1840
+
1841
+ ```ruby
1842
+ get '/' do
1843
+ pass if Time.now > time_for('Dec 23, 2012')
1844
+ "still time"
1845
+ end
1846
+ ```
1847
+
1848
+ `expires`、`last_modified` 和类似方法都在内部使用了该方法。
1849
+ 因此,通过在应用中重写 `time_for` 方法,你可以轻松地扩展这些方法的行为:
1850
+
1851
+ ```ruby
1852
+ helpers do
1853
+ def time_for(value)
1854
+ case value
1855
+ when :yesterday then Time.now - 24*60*60
1856
+ when :tomorrow then Time.now + 24*60*60
1857
+ else super
1858
+ end
1859
+ end
1860
+ end
1861
+
1862
+ get '/' do
1863
+ last_modified :yesterday
1864
+ expires :tomorrow
1865
+ "hello"
1866
+ end
1867
+ ```
1342
1868
 
1343
1869
  ### 查找模板文件
1344
1870
 
1345
- `find_template` 辅助方法被用于在填充时查找模板文件:
1871
+ `find_template` 辅助方法用于在渲染时查找模板文件:
1346
1872
 
1347
- ~~~~ ruby
1873
+ ```ruby
1348
1874
  find_template settings.views, 'foo', Tilt[:haml] do |file|
1349
1875
  puts "could be #{file}"
1350
1876
  end
1351
- ~~~~
1877
+ ```
1352
1878
 
1353
- 这并不是很有用。但是在你需要重载这个方法
1354
- 来实现你自己的查找机制的时候有用。 比如,如果你想支持多于一个视图目录:
1879
+ 这其实并不是很有用,除非你需要重载这个方法来实现你自己的查找机制。
1880
+ 比如,如果你想使用不只一个视图目录:
1355
1881
 
1356
- ~~~~ ruby
1882
+ ```ruby
1357
1883
  set :views, ['views', 'templates']
1358
1884
 
1359
1885
  helpers do
@@ -1361,11 +1887,11 @@ helpers do
1361
1887
  Array(views).each { |v| super(v, name, engine, &block) }
1362
1888
  end
1363
1889
  end
1364
- ~~~~
1890
+ ```
1365
1891
 
1366
- 另一个例子是为不同的引擎使用不同的目录:
1892
+ 另一个例子是对不同的引擎使用不同的目录:
1367
1893
 
1368
- ~~~~ ruby
1894
+ ```ruby
1369
1895
  set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
1370
1896
 
1371
1897
  helpers do
@@ -1375,58 +1901,57 @@ helpers do
1375
1901
  super(folder, name, engine, &block)
1376
1902
  end
1377
1903
  end
1378
- ~~~~
1904
+ ```
1379
1905
 
1380
- 你可以很容易地包装成一个扩展然后与他人分享!
1906
+ 你可以很容易地封装成一个扩展,然后与他人分享!
1381
1907
 
1382
- 请注意 `find_template` 并不会检查文件真的存在,
1383
- 而是对任何可能的路径调用给入的代码块。这并不会带来性能问题, 因为
1384
- `render` 会在找到文件的时候马上使用 `break` 。
1385
- 同样的,模板的路径(和内容)会在除development mode以外的场合
1386
- 被缓存。你应该时刻提醒自己这一点, 如果你真的想写一个非常疯狂的方法。
1908
+ 请注意 `find_template` 并不会检查文件是否存在,而是为任何可能的路径调用传入的代码块。
1909
+ 这并不会导致性能问题,因为 `render` 会在找到文件的时候马上使用 `break`。
1910
+ 同样的,模板的路径(和内容)会在 development 以外的模式下被缓存。
1911
+ 你应该时刻提醒自己这一点, 如果你真的想写一个非常疯狂的方法的话。
1387
1912
 
1388
1913
  ## 配置
1389
1914
 
1390
- 运行一次,在启动的时候,在任何环境下:
1915
+ 在启动时运行一次,在任何环境下都是如此:
1391
1916
 
1392
- ~~~~ ruby
1917
+ ```ruby
1393
1918
  configure do
1394
- # setting one option
1919
+ # 设置一个选项
1395
1920
  set :option, 'value'
1396
1921
 
1397
- # setting multiple options
1922
+ # 设置多个选项
1398
1923
  set :a => 1, :b => 2
1399
1924
 
1400
- # same as `set :option, true`
1925
+ # 等同于 `set :option, true`
1401
1926
  enable :option
1402
1927
 
1403
- # same as `set :option, false`
1928
+ # 等同于 `set :option, false`
1404
1929
  disable :option
1405
1930
 
1406
- # you can also have dynamic settings with blocks
1931
+ # 也可以用代码块做动态设置
1407
1932
  set(:css_dir) { File.join(views, 'css') }
1408
1933
  end
1409
- ~~~~
1934
+ ```
1410
1935
 
1411
- 只当环境 (RACK\_ENV environment 变量) 被设定为 `:production`的时候运行:
1936
+ 只有当环境 (`RACK_ENV` 环境变量) 被设定为 `:production` 时才运行:
1412
1937
 
1413
- ~~~~ ruby
1938
+ ```ruby
1414
1939
  configure :production do
1415
1940
  ...
1416
1941
  end
1417
- ~~~~
1942
+ ```
1418
1943
 
1419
- 当环境被设定为 `:production` 或者 `:test`的时候运行:
1944
+ 当环境被设定为 `:production` 或者 `:test` 时运行:
1420
1945
 
1421
- ~~~~ ruby
1946
+ ```ruby
1422
1947
  configure :production, :test do
1423
1948
  ...
1424
1949
  end
1425
- ~~~~
1950
+ ```
1426
1951
 
1427
- 你可以使用 `settings` 获得这些配置:
1952
+ 你可以用 `settings` 访问这些配置项:
1428
1953
 
1429
- ~~~~ ruby
1954
+ ```ruby
1430
1955
  configure do
1431
1956
  set :foo, 'bar'
1432
1957
  end
@@ -1436,208 +1961,271 @@ get '/' do
1436
1961
  settings.foo # => 'bar'
1437
1962
  ...
1438
1963
  end
1439
- ~~~~
1964
+ ```
1965
+
1966
+ ### 配置攻击防护
1967
+
1968
+ Sinatra 使用 [Rack::Protection](https://github.com/sinatra/rack-protection#readme)
1969
+ 来抵御常见的攻击。你可以轻易地禁用该行为(但这会大大增加应用被攻击的概率)。
1970
+
1971
+ ```ruby
1972
+ disable :protection
1973
+ ```
1974
+
1975
+ 为了绕过某单层防护,可以设置 `protection` 为一个选项 hash:
1976
+
1977
+ ```ruby
1978
+ set :protection, :except => :path_traversal
1979
+ ```
1980
+
1981
+ 你可以传入一个数组,以禁用一系列防护措施:
1982
+
1983
+ ```ruby
1984
+ set :protection, :except => [:path_traversal, :session_hijacking]
1985
+ ```
1986
+
1987
+ 默认地,如果 `:sessions` 是启用的,Sinatra 只会使用基于会话的防护措施。
1988
+ 当然,有时你可能想根据自己的需要设置会话。
1989
+ 在这种情况下,你可以通过传入 `:session` 选项来开启基于会话的防护。
1990
+
1991
+ ```ruby
1992
+ use Rack::Session::Pool
1993
+ set :protection, :session => true
1994
+ ```
1440
1995
 
1441
1996
  ### 可选的设置
1442
1997
 
1443
1998
  <dl>
1444
- <dt>absolute_redirects</dt>
1445
- <dd>
1446
- <p>
1447
- 如果被禁用,Sinatra会允许使用相对路径重定向, 但是,Sinatra就不再遵守
1448
- RFC 2616标准 (HTTP 1.1), 该标准只允许绝对路径重定向。
1449
- </p>
1450
-
1451
- <p>
1452
- 如果你的应用运行在一个未恰当设置的反向代理之后,
1453
- 你需要启用这个选项。注意 <tt>url</tt> 辅助方法 仍然会生成绝对 URL,除非你传入
1454
- <tt>false</tt> 作为第二参数。
1455
- </p>
1456
- <p>
1457
- 默认禁用。
1458
- </p>
1459
- </dd>
1460
-
1461
- <dt>add_charset</dt>
1462
- <dd>
1463
- <p>
1464
- 设定 <tt>content_type</tt> 辅助方法会 自动加上字符集信息的多媒体类型。
1465
- </p>
1466
-
1467
- <p>
1468
- 你应该添加而不是覆盖这个选项:
1469
- <tt>settings.add_charset << "application/foobar"</tt>
1470
- </p>
1471
- </dd>
1472
-
1473
- <dt>app_file</dt>
1474
- <dd>
1475
- 主应用文件,用来检测项目的根路径, views和public文件夹和内联模板。
1476
- </dd>
1477
-
1478
- <dt>bind</dt>
1479
- <dd>
1480
- 绑定的IP 地址 (默认: 0.0.0.0)。 仅对于内置的服务器有用。
1481
- </dd>
1482
-
1483
- <dt>default_encoding</dt>
1484
- <dd>
1485
- 默认编码 (默认为 <tt>"utf-8"</tt>)。
1486
- </dd>
1487
-
1488
- <dt>dump_errors</dt>
1489
- <dd>
1490
- 在log中显示错误。
1491
- </dd>
1492
-
1493
- <dt>environment</dt>
1494
- <dd>
1495
- 当前环境,默认是 <tt>ENV['RACK_ENV']</tt>, 或者 <tt>"development"</tt> 如果不可用。
1496
- </dd>
1497
-
1498
- <dt>logging</dt>
1499
- <dd>
1500
- 使用logger
1501
- </dd>
1502
-
1503
- <dt>lock</dt>
1504
- <dd>
1505
- <p>
1506
- 对每一个请求放置一个锁, 只使用进程并发处理请求。
1507
- </p>
1508
-
1509
- <p>
1510
- 如果你的应用不是线程安全则需启动。 默认禁用。
1511
- </p>
1512
- </dd>
1513
-
1514
- <dt>method_override</dt>
1515
- <dd>
1516
- 使用 <tt>_method</tt> 魔法以允许在旧的浏览器中在 表单中使用 put/delete 方法
1517
- </dd>
1518
-
1519
- <dt>port</dt>
1520
- <dd>
1521
- 监听的端口号。只对内置服务器有用。
1522
- </dd>
1523
-
1524
- <dt>prefixed_redirects</dt>
1525
- <dd>
1526
- 是否添加 <tt>request.script_name</tt> 到
1527
- 重定向请求,如果没有设定绝对路径。那样的话 <tt>redirect '/foo'</tt> 会和
1528
- <tt>redirect to('/foo')</tt>起相同作用。默认禁用。
1529
- </dd>
1530
-
1531
- <dt>public_folder</dt>
1532
- <dd>
1533
- public文件夹的位置。
1534
- </dd>
1535
-
1536
- <dt>reload_templates</dt>
1537
- <dd>
1538
- 是否每个请求都重新载入模板。 在development mode和 Ruby 1.8.6
1539
- 中被企业(用来 消除一个Ruby内存泄漏的bug)。
1540
- </dd>
1541
-
1542
- <dt>root</dt>
1543
- <dd>
1544
- 项目的根目录。
1545
- </dd>
1546
-
1547
- <dt>raise_errors</dt>
1548
- <dd>
1549
- 抛出异常(应用会停下)。
1550
- </dd>
1551
-
1552
- <dt>run</dt>
1553
- <dd>
1554
- 如果启用,Sinatra会开启web服务器。 如果使用rackup或其他方式则不要启用。
1555
- </dd>
1556
-
1557
- <dt>running</dt>
1558
- <dd>
1559
- 内置的服务器在运行吗? 不要修改这个设置!
1560
- </dd>
1561
-
1562
- <dt>server</dt>
1563
- <dd>
1564
- 服务器,或用于内置服务器的列表。 默认是 [‘thin’, ‘mongrel’, ‘webrick’],
1565
- 顺序表明了 优先级。
1566
- </dd>
1567
-
1568
- <dt>sessions</dt>
1569
- <dd>
1570
- 开启基于cookie的sesson。
1571
- </dd>
1572
-
1573
- <dt>show_exceptions</dt>
1574
- <dd>
1575
- 在浏览器中显示一个stack trace。
1576
- </dd>
1577
-
1578
- <dt>static</dt>
1579
- <dd>
1580
- Sinatra是否处理静态文件。 当服务器能够处理则禁用。 禁用会增强性能。
1581
- 默认开启。
1582
- </dd>
1583
-
1584
- <dt>views</dt>
1585
- <dd>
1586
- views 文件夹。
1587
- </dd>
1999
+ <dt>absolute_redirects</dt>
2000
+ <dd>
2001
+ 如果被禁用,Sinatra 会允许使用相对路径重定向。
2002
+ 然而这样的话,Sinatra 就不再遵守 RFC 2616 (HTTP 1.1), 该协议只允许绝对路径重定向。
2003
+ </dd>
2004
+ <dd>
2005
+ 如果你的应用运行在一个未恰当设置的反向代理之后,你需要启用这个选项。
2006
+ 注意 <tt>url</tt> 辅助方法仍然会生成绝对 URL,除非你传入<tt>false</tt> 作为第二参数。
2007
+ </dd>
2008
+ <dd>默认禁用。</dd>
2009
+
2010
+ <dt>add_charset</dt>
2011
+ <dd>
2012
+ 设置 <tt>content_type</tt> 辅助方法会自动为媒体类型加上字符集信息。
2013
+ 你应该添加而不是覆盖这个选项:
2014
+ <tt>settings.add_charset << "application/foobar"</tt>
2015
+ </dd>
2016
+
2017
+ <dt>app_file</dt>
2018
+ <dd>
2019
+ 主应用文件的路径,用来检测项目的根路径, views public 文件夹和内联模板。
2020
+ </dd>
2021
+
2022
+ <dt>bind</dt>
2023
+ <dd>
2024
+ 绑定的 IP 地址 (默认: <tt>0.0.0.0</tt>,开发环境下为 <tt>localhost</tt>)。
2025
+ 仅对于内置的服务器有用。
2026
+ </dd>
2027
+
2028
+ <dt>default_encoding</dt>
2029
+ <dd>默认编码 (默认为 <tt>"utf-8"</tt>)。</dd>
2030
+
2031
+ <dt>dump_errors</dt>
2032
+ <dd>在日志中显示错误。</dd>
2033
+
2034
+ <dt>environment</dt>
2035
+ <dd>
2036
+ 当前环境,默认是 <tt>ENV['RACK_ENV']</tt>,
2037
+ 或者 <tt>"development"</tt> (如果 ENV['RACK_ENV'] 不可用)。
2038
+ </dd>
2039
+
2040
+ <dt>logging</dt>
2041
+ <dd>使用 logger。</dd>
2042
+
2043
+ <dt>lock</dt>
2044
+ <dd>对每一个请求放置一个锁,只使用进程并发处理请求。</dd>
2045
+ <dd>如果你的应用不是线程安全则需启动。默认禁用。</dd>
2046
+
2047
+ <dt>method_override</dt>
2048
+ <dd>
2049
+ 使用 <tt>_method</tt> 魔法,以允许在不支持的浏览器中在使用 put/delete 方法提交表单。
2050
+ </dd>
2051
+
2052
+ <dt>port</dt>
2053
+ <dd>监听的端口号。只对内置服务器有用。</dd>
2054
+
2055
+ <dt>prefixed_redirects</dt>
2056
+ <dd>
2057
+ 如果没有使用绝对路径,是否添加 <tt>request.script_name</tt> 到重定向请求。
2058
+ 如果添加,<tt>redirect '/foo'</tt> 会和 <tt>redirect to('/foo')</tt> 相同。
2059
+ 默认禁用。
2060
+ </dd>
2061
+
2062
+ <dt>protection</dt>
2063
+ <dd>是否启用网络攻击防护。参见上面的保护部分</dd>
2064
+
2065
+ <dt>public_dir</dt>
2066
+ <dd>public_folder 的别名。见下文。</dd>
2067
+
2068
+ <dt>public_folder</dt>
2069
+ <dd>
2070
+ public 文件存放的路径。只有启用了静态文件服务(见下文的 <tt>static</tt>)才会使用。
2071
+ 如果未设置,默认从 <tt>app_file</tt> 推断。
2072
+ </dd>
2073
+
2074
+ <dt>reload_templates</dt>
2075
+ <dd>
2076
+ 是否每个请求都重新载入模板。在开发模式下开启。
2077
+ </dd>
2078
+
2079
+ <dt>root</dt>
2080
+ <dd>到项目根目录的路径。默认从 <tt>app_file</tt> 设置推断。</dd>
2081
+
2082
+ <dt>raise_errors</dt>
2083
+ <dd>
2084
+ 抛出异常(会停止应用)。
2085
+ 当 <tt>environment</tt> 设置为 <tt>"test"</tt> 时会默认开启,其它环境下默认禁用。
2086
+ </dd>
2087
+
2088
+ <dt>run</dt>
2089
+ <dd>如果启用,Sinatra 会负责 web 服务器的启动。若使用 rackup 或其他方式则不要启用。</dd>
2090
+
2091
+ <dt>running</dt>
2092
+ <dd>内置的服务器在运行吗? 不要修改这个设置!</dd>
2093
+
2094
+ <dt>server</dt>
2095
+ <dd>服务器,或用于内置服务器的服务器列表。顺序表明了优先级,默认顺序依赖 Ruby 实现。</dd>
2096
+
2097
+ <dt>sessions</dt>
2098
+ <dd>
2099
+ 使用 <tt>Rack::Session::Cookie</tt>,启用基于 cookie 的会话。
2100
+ 查看“使用会话”部分以获得更多信息。
2101
+ </dd>
2102
+
2103
+ <dt>show_exceptions</dt>
2104
+ <dd>
2105
+ 当有异常发生时,在浏览器中显示一个 stack trace。
2106
+ 当 <tt>environment</tt> 设置为 <tt>"development"</tt> 时,默认启用,
2107
+ 否则默认禁用。
2108
+ </dd>
2109
+ <dd>
2110
+ 也可以设置为 <tt>:after_handler</tt>,
2111
+ 这会在浏览器中显示 stack trace 之前触发应用级别的错误处理。
2112
+ </dd>
2113
+
2114
+ <dt>static</dt>
2115
+ <dd>决定 Sinatra 是否服务静态文件。</dd>
2116
+ <dd>当服务器能够自行服务静态文件时,会禁用。</dd>
2117
+ <dd>禁用会增强性能。</dd>
2118
+ <dd>在经典风格中默认启用,在模块化应用中默认禁用。</dd>
2119
+
2120
+ <dt>static_cache_control</dt>
2121
+ <dd>
2122
+ 当 Sinatra 提供静态文件服务时,设置此选项为响应添加 <tt>Cache-Control</tt> 首部。
2123
+ 使用 <tt>cache_control</tt> 辅助方法。默认禁用。
2124
+ </dd>
2125
+ <dd>
2126
+ 当设置多个值时使用数组:
2127
+ <tt>set :static_cache_control, [:public, :max_age => 300]</tt>
2128
+ </dd>
2129
+
2130
+ <dt>threaded</dt>
2131
+ <dd>
2132
+ 若设置为 <tt>true</tt>,会告诉 Thin 使用 <tt>EventMachine.defer</tt> 处理请求。
2133
+ </dd>
2134
+
2135
+ <dt>traps</dt>
2136
+ <dd>Sinatra 是否应该处理系统信号。</dd>
2137
+
2138
+ <dt>views</dt>
2139
+ <dd>views 文件夹的路径。若未设置则会根据 <tt>app_file</tt> 推断。</dd>
2140
+
2141
+ <dt>x_cascade</dt>
2142
+ <dd>若没有路由匹配,是否设置 X-Cascade 首部。默认为 <tt>true</tt>。</dd>
1588
2143
  </dl>
1589
2144
 
2145
+ ## 环境
2146
+
2147
+ Sinatra 中有三种预先定义的环境:"development"、"production" 和 "test"。
2148
+ 环境可以通过 `RACK_ENV` 环境变量设置。默认值为 "development"。
2149
+ 在开发环境下,每次请求都会重新加载所有模板,
2150
+ 特殊的 `not_found` 和 `error` 错误处理器会在浏览器中显示 stack trace。
2151
+ 在测试和生产环境下,模板默认会缓存。
2152
+
2153
+ 在不同的环境下运行,设置 `RACK_ENV` 环境变量:
2154
+
2155
+ ```shell
2156
+ RACK_ENV=production ruby my_app.rb
2157
+ ```
2158
+
2159
+ 可以使用预定义的三种方法: `development?`、`test?` 和 `production?` 来检查当前环境:
2160
+
2161
+ ```ruby
2162
+ get '/' do
2163
+ if settings.development?
2164
+ "development!"
2165
+ else
2166
+ "not development"
2167
+ end
2168
+ end
2169
+ ```
1590
2170
 
1591
2171
  ## 错误处理
1592
2172
 
1593
- 错误处理在与路由和前置过滤器相同的上下文中运行,
2173
+ 错误处理器在与路由和 before 过滤器相同的上下文中运行,
1594
2174
  这意味着你可以使用许多好东西,比如 `haml`, `erb`, `halt`,等等。
1595
2175
 
1596
2176
  ### 未找到
1597
2177
 
1598
- 当一个 `Sinatra::NotFound` 错误被抛出的时候,
1599
- 或者响应状态码是404,`not_found` 处理器会被调用:
2178
+ 当一个 `Sinatra::NotFound` 错误被抛出时,或者当响应的状态码是 404 时,
2179
+ 会调用 `not_found` 处理器:
1600
2180
 
1601
- ~~~~ ruby
2181
+ ```ruby
1602
2182
  not_found do
1603
- 'This is nowhere to be found'
2183
+ 'This is nowhere to be found.'
1604
2184
  end
1605
- ~~~~
2185
+ ```
1606
2186
 
1607
2187
  ### 错误
1608
2188
 
1609
- `error` 处理器,在任何路由代码块或者过滤器抛出异常的时候会被调用。
1610
- 异常对象可以通过`sinatra.error` Rack 变量获得:
2189
+ 在任何路由代码块或过滤器抛出异常时,会调用 `error` 处理器。
2190
+ 但注意在开发环境下只有将 show exceptions 项设置为 `:after_handler` 时,才会生效。
2191
+
2192
+ ```ruby
2193
+ set :show_exceptions, :after_handler
2194
+ ```
1611
2195
 
1612
- ~~~~ ruby
2196
+ 可以用 Rack 变量 `sinatra.error` 访问异常对象:
2197
+
2198
+ ```ruby
1613
2199
  error do
1614
2200
  'Sorry there was a nasty error - ' + env['sinatra.error'].message
1615
2201
  end
1616
- ~~~~
2202
+ ```
1617
2203
 
1618
2204
  自定义错误:
1619
2205
 
1620
- ~~~~ ruby
2206
+ ```ruby
1621
2207
  error MyCustomError do
1622
2208
  'So what happened was...' + env['sinatra.error'].message
1623
2209
  end
1624
- ~~~~
2210
+ ```
1625
2211
 
1626
- 那么,当这个发生的时候:
2212
+ 当下面的代码执行时:
1627
2213
 
1628
- ~~~~ ruby
2214
+ ```ruby
1629
2215
  get '/' do
1630
2216
  raise MyCustomError, 'something bad'
1631
2217
  end
1632
- ~~~~
2218
+ ```
1633
2219
 
1634
- 你会得到:
2220
+ 你会得到错误信息:
1635
2221
 
1636
- So what happened was... something bad
2222
+ ```
2223
+ So what happened was... something bad
2224
+ ```
1637
2225
 
1638
- 另一种替代方法是,为一个状态码安装错误处理器:
2226
+ 或者,你也可以为状态码设置错误处理器:
1639
2227
 
1640
- ~~~~ ruby
2228
+ ```ruby
1641
2229
  error 403 do
1642
2230
  'Access forbidden'
1643
2231
  end
@@ -1645,29 +2233,28 @@ end
1645
2233
  get '/secret' do
1646
2234
  403
1647
2235
  end
1648
- ~~~~
2236
+ ```
1649
2237
 
1650
- 或者一个范围:
2238
+ 或者为某个范围内的状态码统一设置错误处理器:
1651
2239
 
1652
- ~~~~ ruby
2240
+ ```ruby
1653
2241
  error 400..510 do
1654
2242
  'Boom'
1655
2243
  end
1656
- ~~~~
2244
+ ```
1657
2245
 
1658
- 在运行在development环境下时,Sinatra会安装特殊的 `not_found` 和 `error`
1659
- 处理器。
2246
+ 在开发环境下,Sinatra会使用特殊的 `not_found` 和 `error` 处理器,
2247
+ 以便在浏览器中显示美观的 stack traces 和额外的调试信息。
1660
2248
 
1661
2249
  ## Rack 中间件
1662
2250
 
1663
- Sinatra 依靠 [Rack](http://rack.github.io/), 一个面向Ruby
1664
- web框架的最小标准接口。
1665
- Rack的一个最有趣的面向应用开发者的能力是支持“中间件”——坐落在服务器和你的应用之间,
1666
- 监视 并/或 操作HTTP请求/响应以 提供多样类型的常用功能。
2251
+ Sinatra 依赖 [Rack](http://rack.github.io/), 一个面向 Ruby 网络框架的最小化标准接口。
2252
+ Rack 最有趣的功能之一是支持“中间件”——位于服务器和你的应用之间的组件,
2253
+ 它们监控或操作 HTTP 请求/响应以提供多种常用功能。
1667
2254
 
1668
- Sinatra 让建立Rack中间件管道异常简单, 通过顶层的 `use` 方法:
2255
+ Sinatra 通过顶层的 `use` 方法,让建立 Rack 中间件管道异常简单:
1669
2256
 
1670
- ~~~~ ruby
2257
+ ```ruby
1671
2258
  require 'sinatra'
1672
2259
  require 'my_custom_middleware'
1673
2260
 
@@ -1677,29 +2264,33 @@ use MyCustomMiddleware
1677
2264
  get '/hello' do
1678
2265
  'Hello World'
1679
2266
  end
1680
- ~~~~
2267
+ ```
1681
2268
 
1682
- `use` 的语义和在
1683
- [Rack::Builder](http://rubydoc.info/github/rack/rack/master/Rack/Builder)
1684
- DSL(在rack文件中最频繁使用)中定义的完全一样。例如,`use` 方法接受
1685
- 多个/可变 参数,包括代码块:
2269
+ `use` 的语义和在 [Rack::Builder](http://www.rubydoc.info/github/rack/rack/master/Rack/Builder)
2270
+ DSL (在 rackup 文件中最频繁使用)中定义的完全一样。例如,`use` 方法接受
2271
+ 多个/可变参数,以及代码块:
1686
2272
 
1687
- ~~~~ ruby
2273
+ ```ruby
1688
2274
  use Rack::Auth::Basic do |username, password|
1689
2275
  username == 'admin' && password == 'secret'
1690
2276
  end
1691
- ~~~~
2277
+ ```
2278
+
2279
+ Rack 拥有有多种标准中间件,用于日志、调试、URL 路由、认证和会话处理。
2280
+ 根据配置,Sinatra 可以自动使用这里面的许多组件,
2281
+ 所以你一般不需要显式地 `use` 它们。
1692
2282
 
1693
- Rack中分布有多样的标准中间件,针对日志,
1694
- 调试,URL路由,认证和session处理。 Sinatra会自动使用这里面的大部分组件,
1695
- 所以你一般不需要显示地 `use` 他们。
2283
+ 你可以在 [rack](https://github.com/rack/rack/tree/master/lib/rack)、
2284
+ [rack-contrib](https://github.com/rack/rack-contrib#readm)
2285
+ [Rack wiki](https://github.com/rack/rack/wiki/List-of-Middleware)
2286
+ 中找到有用的中间件。
1696
2287
 
1697
2288
  ## 测试
1698
2289
 
1699
- Sinatra的测试可以使用任何基于Rack的测试程序库或者框架来编写。
1700
- [Rack::Test](http://gitrdoc.com/brynary/rack-test) 是推荐候选:
2290
+ 可以使用任何基于 Rack 的测试程序库或者框架来编写Sinatra的测试。
2291
+ 推荐使用 [Rack::Test](http://www.rubydoc.info/github/brynary/rack-test/master/frames)
1701
2292
 
1702
- ~~~~ ruby
2293
+ ```ruby
1703
2294
  require 'my_sinatra_app'
1704
2295
  require 'minitest/autorun'
1705
2296
  require 'rack/test'
@@ -1726,22 +2317,20 @@ class MyAppTest < Minitest::Test
1726
2317
  assert_equal "You're using Songbird!", last_response.body
1727
2318
  end
1728
2319
  end
1729
- ~~~~
2320
+ ```
1730
2321
 
1731
- 请注意: 内置的 Sinatra::Test 模块和 Sinatra::TestHarness 类 在 0.9.2
1732
- 版本已废弃。
2322
+ 注意:如果你使用 Sinatra 的模块化风格,应该用你应用的类名替代 `Sinatra::Application`。
1733
2323
 
1734
- ## Sinatra::Base - 中间件,程序库和模块化应用
2324
+ ## Sinatra::Base - 中间件、库和模块化应用
1735
2325
 
1736
- 把你的应用定义在顶层,对于微型应用这会工作得很好,
1737
- 但是在构建可复用的组件时候会带来客观的不利, 比如构建Rack中间件,Rails
1738
- metal,带有服务器组件的简单程序库,
1739
- 或者甚至是Sinatra扩展。顶层的DSL污染了Object命名空间,
1740
- 并假定了一个微型应用风格的配置 (例如, 单一的应用文件, ./public 和
1741
- ./views 目录,日志,异常细节页面,等等)。 这时应该让 Sinatra::Base
1742
- 走到台前了:
2326
+ 在顶层定义你的应用很适合微型项目,
2327
+ 但是在构建可复用的组件(如 Rack 中间件、Rails metal、带服务器组件的库或 Sinatra 扩展)时,
2328
+ 却有相当大的缺陷。
2329
+ 顶层 DSL 认为你采用的是微型应用风格的配置 (例如:唯一应用文件、
2330
+ `./public` `./views` 目录、日志、异常细节页面等)。
2331
+ 如果你的项目不采用微型应用风格,应该使用 `Sinatra::Base`:
1743
2332
 
1744
- ~~~~ ruby
2333
+ ```ruby
1745
2334
  require 'sinatra/base'
1746
2335
 
1747
2336
  class MyApp < Sinatra::Base
@@ -1752,120 +2341,167 @@ class MyApp < Sinatra::Base
1752
2341
  'Hello world!'
1753
2342
  end
1754
2343
  end
1755
- ~~~~
1756
-
1757
- Sinatra::Base子类可用的方法实际上就是通过顶层 DSL 可用的方法。
1758
- 大部分顶层应用可以通过两个改变转换成Sinatra::Base组件:
1759
-
1760
- - 你的文件应当引入 `sinatra/base` 而不是 `sinatra`;
1761
- 否则,所有的Sinatra的 DSL 方法将会被引进到 主命名空间。
1762
-
1763
- - 把你的应用的路由,错误处理,过滤器和选项放在
1764
- 一个Sinatra::Base的子类中。
1765
-
1766
- `+Sinatra::Base+` 是一张白纸。大部分的选项默认是禁用的,
1767
- 包含内置的服务器。参见
1768
- [选项和配置](http://sinatra.github.com/configuration.html)
1769
- 查看可用选项的具体细节和他们的行为。
2344
+ ```
1770
2345
 
1771
- ### 模块化 vs. 传统的方式
2346
+ Sinatra::Base 的子类可以使用的方法实际上就是顶层 DSL 中可以使用的方法。
2347
+ 大部分顶层应用可以通过两方面的改变转换为 Sinatra::Base 组件:
1772
2348
 
1773
- 与通常的认识相反,传统的方式没有任何错误。
1774
- 如果它适合你的应用,你不需要转换到模块化的应用。
2349
+ * 你的文件应当引入 `sinatra/base` 而不是 `sinatra`;
2350
+ 否则,Sinatra 的所有 DSL 方法将会被导入主命名空间。
1775
2351
 
1776
- 和模块化方式相比只有两个缺点:
2352
+ * 把应用的路由、错误处理器、过滤器和选项放在一个 Sinatra::Base 的子类中。
1777
2353
 
1778
- - 你对每个Ruby进程只能定义一个Sinatra应用,如果你需要更多,
1779
- 切换到模块化方式。
2354
+ `Sinatra::Base` 是一个白板。大部分选项(包括内置的服务器)默认是禁用的。
2355
+ 可以参考[配置](http://www.sinatrarb.com/configuration.html)
2356
+ 以查看可用选项的具体细节和它们的行为。如果你想让你的应用更像顶层定义的应用(即经典风格),
2357
+ 你可以继承 `Sinatra::Applicaiton`。
1780
2358
 
1781
- - 传统方式使用代理方法污染了 Object 。如果你打算 把你的应用封装进一个
1782
- library/gem,转换到模块化方式。
1783
-
1784
- 没有任何原因阻止你混合模块化和传统方式。
1785
-
1786
- 如果从一种转换到另一种,你需要注意settings中的 一些微小的不同:
1787
-
1788
- Setting Classic Modular
2359
+ ```ruby
2360
+ require 'sinatra/base'
1789
2361
 
1790
- app_file file loading sinatra nil
1791
- run $0 == app_file false
1792
- logging true false
1793
- method_override true false
1794
- inline_templates true false
2362
+ class MyApp < Sinatra::Application
2363
+ get '/' do
2364
+ 'Hello world!'
2365
+ end
2366
+ end
2367
+ ```
2368
+
2369
+ ### 模块化风格 vs. 经典风格
2370
+
2371
+ 与通常的认识相反,经典风格并没有任何错误。
2372
+ 如果它适合你的应用,你不需要切换到模块化风格。
2373
+
2374
+ 与模块化风格相比,经典风格的主要缺点在于,每个 Ruby 进程只能有一个 Sinatra 应用。
2375
+ 如果你计划使用多个 Sinatra 应用,应该切换到模块化风格。
2376
+ 你也完全可以混用模块化风格和经典风格。
2377
+
2378
+ 如果从一种风格转换到另一种,你需要注意默认设置中的一些细微差别:
2379
+
2380
+ <table>
2381
+ <tr>
2382
+ <th>设置</th>
2383
+ <th>经典风格</th>
2384
+ <th>模块化风格</th>
2385
+ <th>模块化风格</th>
2386
+ </tr>
2387
+
2388
+ <tr>
2389
+ <td>app_file</td>
2390
+ <td>加载 sinatra 的文件</td>
2391
+ <td>继承 Sinatra::Base 的文件</td>
2392
+ <td>继承 Sinatra::Application 的文件</td>
2393
+ </tr>
2394
+
2395
+ <tr>
2396
+ <td>run</td>
2397
+ <td>$0 == app_file</td>
2398
+ <td>false</td>
2399
+ <td>false</td>
2400
+ </tr>
2401
+
2402
+ <tr>
2403
+ <td>logging</td>
2404
+ <td>true</td>
2405
+ <td>false</td>
2406
+ <td>true</td>
2407
+ </tr>
2408
+
2409
+ <tr>
2410
+ <td>method_override</td>
2411
+ <td>true</td>
2412
+ <td>false</td>
2413
+ <td>true</td>
2414
+ </tr>
2415
+
2416
+ <tr>
2417
+ <td>inline_templates</td>
2418
+ <td>true</td>
2419
+ <td>false</td>
2420
+ <td>true</td>
2421
+ </tr>
2422
+
2423
+ <tr>
2424
+ <td>static</td>
2425
+ <td>true</td>
2426
+ <td>File.exist?(public_folder)</td>
2427
+ <td>true</td>
2428
+ </tr>
2429
+ </table>
1795
2430
 
1796
2431
  ### 运行一个模块化应用
1797
2432
 
1798
- 有两种方式运行一个模块化应用,使用 `run!`来运行:
2433
+ 模块化应用的启动有两种常见方式,其中之一是使用 `run!` 方法主动启动:
1799
2434
 
1800
- ~~~~ ruby
2435
+ ```ruby
1801
2436
  # my_app.rb
1802
2437
  require 'sinatra/base'
1803
2438
 
1804
2439
  class MyApp < Sinatra::Base
1805
- # ... app code here ...
2440
+ # ... 这里是应用代码 ...
1806
2441
 
1807
- # start the server if ruby file executed directly
2442
+ # 如果直接执行该文件,那么启动服务器
1808
2443
  run! if app_file == $0
1809
2444
  end
1810
- ~~~~
2445
+ ```
1811
2446
 
1812
- 运行:
2447
+ 执行该文件就会启动服务器:
1813
2448
 
1814
- ruby my_app.rb
2449
+ ```shell
2450
+ ruby my_app.rb
2451
+ ```
1815
2452
 
1816
- 或者使用一个 `config.ru`,允许你使用任何Rack处理器:
2453
+ 另一种方式是使用 `config.ru` 文件,这种方式允许你使用任何 Rack 处理器:
1817
2454
 
1818
- ~~~~ ruby
1819
- # config.ru
2455
+ ```ruby
2456
+ # config.ru (用 rackup 启动)
1820
2457
  require './my_app'
1821
2458
  run MyApp
1822
- ~~~~
2459
+ ```
1823
2460
 
1824
- 运行:
2461
+ 运行:
1825
2462
 
1826
- rackup -p 4567
2463
+ ```shell
2464
+ rackup -p 4567
2465
+ ```
1827
2466
 
1828
- ### 使用config.ru运行传统方式的应用
2467
+ ### 使用 config.ru 运行经典风格的应用
1829
2468
 
1830
2469
  编写你的应用:
1831
2470
 
1832
- ~~~~ ruby
2471
+ ```ruby
1833
2472
  # app.rb
1834
2473
  require 'sinatra'
1835
2474
 
1836
2475
  get '/' do
1837
2476
  'Hello world!'
1838
2477
  end
1839
- ~~~~
2478
+ ```
1840
2479
 
1841
- 加入相应的 `config.ru`:
2480
+ 添加相应的 `config.ru`:
1842
2481
 
1843
- ~~~~ ruby
2482
+ ```ruby
1844
2483
  require './app'
1845
2484
  run Sinatra::Application
1846
- ~~~~
1847
-
1848
- ### 什么时候用 config.ru?
2485
+ ```
1849
2486
 
1850
- 以下情况你可能需要使用 `config.ru`:
2487
+ ### 何时使用 config.ru
1851
2488
 
1852
- - 你要使用不同的 Rack 处理器部署 (Passenger, Unicorn, Heroku, …).
2489
+ 下列情况,推荐使用 `config.ru`:
1853
2490
 
1854
- - 你想使用一个或者多个 `Sinatra::Base`的子类.
2491
+ * 部署时使用不同的 Rack 处理器 (Passenger、Unicorn、Heroku 等)。
2492
+ * 使用多个 `Sinatra::Base` 的子类。
2493
+ * 把 Sinatra 当作中间件使用,而非端点。
1855
2494
 
1856
- - 你只想把Sinatra当作中间件使用,而不是端点。
2495
+ **你不必仅仅因为想使用模块化风格而切换到 `config.ru`,同样的,
2496
+ 你也不必仅仅因为要运行 `config.ru` 而切换到模块化风格。**
1857
2497
 
1858
- **你并不需要切换到`config.ru`仅仅因为你切换到模块化方式,
1859
- 你同样不需要切换到模块化方式, 仅仅因为要运行 `config.ru`.**
2498
+ ### 把 Sinatra 当作中间件使用
1860
2499
 
1861
- ### 把Sinatra当成中间件来使用
2500
+ Sinatra 可以使用其它 Rack 中间件,
2501
+ 反过来,任何 Sinatra 应用程序自身都可以被当作中间件,添加到任何 Rack 端点前面。
2502
+ 此端点可以是任何 Sinatra 应用,或任何基于 Rack 的应用程序 (Rails/Ramaze/Camping/...):
1862
2503
 
1863
- 不仅Sinatra有能力使用其他的Rack中间件,任何Sinatra
1864
- 应用程序都可以反过来自身被当作中间件,被加在任何Rack端点前面。
1865
- 这个端点可以是任何Sinatra应用,或者任何基于Rack的应用程序
1866
- (Rails/Ramaze/Camping/…)。
1867
-
1868
- ~~~~ ruby
2504
+ ```ruby
1869
2505
  require 'sinatra/base'
1870
2506
 
1871
2507
  class LoginScreen < Sinatra::Base
@@ -1874,7 +2510,7 @@ class LoginScreen < Sinatra::Base
1874
2510
  get('/login') { haml :login }
1875
2511
 
1876
2512
  post('/login') do
1877
- if params['name'] = 'admin' and params['password'] = 'admin'
2513
+ if params['name'] == 'admin' && params['password'] == 'admin'
1878
2514
  session['user_name'] = params['name']
1879
2515
  else
1880
2516
  redirect '/login'
@@ -1883,7 +2519,7 @@ class LoginScreen < Sinatra::Base
1883
2519
  end
1884
2520
 
1885
2521
  class MyApp < Sinatra::Base
1886
- # 在前置过滤器前运行中间件
2522
+ # 中间件的执行发生在 before 过滤器之前
1887
2523
  use LoginScreen
1888
2524
 
1889
2525
  before do
@@ -1894,273 +2530,343 @@ class MyApp < Sinatra::Base
1894
2530
 
1895
2531
  get('/') { "Hello #{session['user_name']}." }
1896
2532
  end
1897
- ~~~~
2533
+ ```
2534
+
2535
+ ### 创建动态应用
2536
+
2537
+ 有时你希望在运行时创建新应用,而不必把应用预先赋值给常量。这时可以使用 `Sinatra.new`:
2538
+
2539
+ ```ruby
2540
+ require 'sinatra/base'
2541
+ my_app = Sinatra.new { get('/') { "hi" } }
2542
+ my_app.run!
2543
+ ```
2544
+
2545
+ `Sinatra.new` 接受一个可选的参数,表示要继承的应用:
2546
+
2547
+ ```ruby
2548
+ # config.ru (用 rackup 启动)
2549
+ require 'sinatra/base'
2550
+
2551
+ controller = Sinatra.new do
2552
+ enable :logging
2553
+ helpers MyHelpers
2554
+ end
2555
+
2556
+ map('/a') do
2557
+ run Sinatra.new(controller) { get('/') { 'a' } }
2558
+ end
2559
+
2560
+ map('/b') do
2561
+ run Sinatra.new(controller) { get('/') { 'b' } }
2562
+ end
2563
+ ```
1898
2564
 
1899
- ## 变量域和绑定
2565
+ 当你测试 Sinatra 扩展或在自己的类库中使用 Sinatra 时,这非常有用。
1900
2566
 
1901
- 当前所在的变量域决定了哪些方法和变量是可用的。
2567
+ 这也让把 Sinatra 当作中间件使用变得极其容易:
1902
2568
 
1903
- ### 应用/类 变量域
2569
+ ```ruby
2570
+ require 'sinatra/base'
2571
+
2572
+ use Sinatra do
2573
+ get('/') { ... }
2574
+ end
2575
+
2576
+ run RailsProject::Application
2577
+ ```
2578
+
2579
+ ## 作用域和绑定
2580
+
2581
+ 当前作用域决定了可以使用的方法和变量。
1904
2582
 
1905
- 每个Sinatra应用相当与Sinatra::Base的一个子类。
1906
- 如果你在使用顶层DSL(`require 'sinatra'`),那么这个类就是
1907
- Sinatra::Application,或者这个类就是你显式创建的子类。
1908
- 在类层面,你具有的方法类似于 \`get\` 或者 \`before\`,但是你不能访问
1909
- \`request\` 对象或者 \`session\`, 因为对于所有的请求,
1910
- 只有单一的应用类。
2583
+ ### 应用/类作用域
1911
2584
 
1912
- 通过 \`set\` 创建的选项是类层面的方法:
2585
+ 每个 Sinatra 应用都对应 `Sinatra::Base` 类的一个子类。
2586
+ 如果你在使用顶层 DSL (`require 'sinatra'`),那么这个类就是 `Sinatra::Application`,
2587
+ 否则该类是你显式创建的子类。
2588
+ 在类层面,你可以使用 `get` 或 `before` 这样的方法,
2589
+ 但不能访问 `request` 或 `session` 对象, 因为对于所有的请求,只有单一的应用类。
1913
2590
 
1914
- ~~~~ ruby
2591
+ 通过 `set` 创建的选项是类方法:
2592
+
2593
+ ```ruby
1915
2594
  class MyApp < Sinatra::Base
1916
- # 嘿,我在应用变量域!
2595
+ # 嘿,我在应用作用域!
1917
2596
  set :foo, 42
1918
2597
  foo # => 42
1919
2598
 
1920
2599
  get '/foo' do
1921
- # 嘿,我不再处于应用变量域了!
2600
+ # 嘿,我已经不在应用作用域了!
1922
2601
  end
1923
2602
  end
1924
- ~~~~
1925
-
1926
- 在下列情况下你将拥有应用变量域的绑定:
1927
-
1928
- - 在应用类中
1929
-
1930
- - 在扩展中定义的方法
1931
-
1932
- - 传递给 \`helpers\` 的代码块
1933
-
1934
- - 用作\`set\`值的过程/代码块
2603
+ ```
1935
2604
 
1936
- 你可以访问变量域对象(就是应用类)就像这样:
2605
+ 下列位置绑定的是应用作用域:
1937
2606
 
1938
- - 通过传递给代码块的对象 (`configure { |c| ... }`)
2607
+ * 应用类内部
2608
+ * 通过扩展定义的方法内部
2609
+ * 传递给 `helpers` 方法的代码块内部
2610
+ * 作为 `set` 值的 procs/blocks 内部
2611
+ * 传递给 `Sinatra.new` 的代码块内部
1939
2612
 
1940
- - 在请求变量域中使用\`settings\`
2613
+ 你可以这样访问变量域对象(应用类):
2614
+ * 通过传递给 configure 代码块的对象 (`configure { |c| ... }`)
2615
+ * 在请求作用域中使用 `settings`
1941
2616
 
1942
- ### 请求/实例 变量域
2617
+ ### 请求/实例作用域
1943
2618
 
1944
- 对于每个进入的请求,一个新的应用类的实例会被创建
1945
- 所有的处理器代码块在该变量域被运行。在这个变量域中, 你可以访问
1946
- \`request\` \`session\` 对象,或者调用填充方法比如 \`erb\` 或者
1947
- \`haml\`。你可以在请求变量域当中通过\`settings\`辅助方法
1948
- 访问应用变量域:
2619
+ 对于每个请求,Sinatra 会创建应用类的一个新实例。所有的处理器代码块都在该实例对象的作用域中运行。
2620
+ 在该作用域中, 你可以访问 `request` 和 `session` 对象,
2621
+ 或调用渲染方法(如 `erb`、`haml`)。你可以在请求作用域中通过 `settings` 辅助方法
2622
+ 访问应用作用域:
1949
2623
 
1950
- ~~~~ ruby
2624
+ ```ruby
1951
2625
  class MyApp < Sinatra::Base
1952
- # 嘿,我在应用变量域!
2626
+ # 嘿,我在应用作用域!
1953
2627
  get '/define_route/:name' do
1954
- # 针对 '/define_route/:name' 的请求变量域
2628
+ # '/define_route/:name' 的请求作用域
1955
2629
  @value = 42
1956
2630
 
1957
2631
  settings.get("/#{params['name']}") do
1958
- # 针对 "/#{params['name']}" 的请求变量域
1959
- @value # => nil (并不是相同的请求)
2632
+ # "/#{params['name']}" 的请求作用域
2633
+ @value # => nil (并不是同一个请求)
1960
2634
  end
1961
2635
 
1962
2636
  "Route defined!"
1963
2637
  end
1964
2638
  end
1965
- ~~~~
2639
+ ```
1966
2640
 
1967
- 在以下情况将获得请求变量域:
2641
+ 以下位置绑定的是请求作用域:
1968
2642
 
1969
- - get/head/post/put/delete 代码块
2643
+ * getheadpostputdelete、options、patch、link 和 unlink 代码块内部
2644
+ * before 和 after 过滤器内部
2645
+ * 辅助方法内部
2646
+ * 模板/视图内部
1970
2647
 
1971
- - 前置/后置 过滤器
2648
+ ### 代理作用域
1972
2649
 
1973
- - 辅助方法
1974
-
1975
- - 模板/视图
1976
-
1977
- ### 代理变量域
1978
-
1979
- 代理变量域只是把方法转送到类变量域。可是,
1980
- 他并非表现得100%类似于类变量域, 因为你并不能获得类的绑定:
2650
+ 代理作用域只是把方法转送到类作用域。
2651
+ 然而,它与类作用域的行为并不完全相同, 因为你并不能在代理作用域获得类的绑定。
1981
2652
  只有显式地标记为供代理使用的方法才是可用的,
1982
- 而且你不能和类变量域共享变量/状态。(解释:你有了一个不同的 \`self\`)。
1983
- 你可以显式地增加方法代理,通过调用
1984
- `Sinatra::Delegator.delegate :method_name`。
2653
+ 而且你不能和类作用域共享变量/状态。(解释:你有了一个不同的 `self`)。
2654
+ 你可以通过调用 `Sinatra::Delegator.delegate :method_name` 显式地添加方法代理。
1985
2655
 
1986
- 在以下情况将获得代理变量域:
2656
+ 以下位置绑定的是代理变量域:
2657
+ * 顶层绑定,如果你执行了 `require "sinatra"`
2658
+ * 扩展了 `Sinatra::Delegator` 这一 mixin 的对象内部
1987
2659
 
1988
- - 顶层的绑定,如果你做过 `require "sinatra"`
1989
-
1990
- - 在扩展了 \`Sinatra::Delegator\` mixin的对象
1991
-
1992
- 自己在这里看一下代码: [Sinatra::Delegator
1993
- mixin](http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/base.rb#L1128)
2660
+ 自己在这里看一下源码:[Sinatra::Delegator
2661
+ mixin](https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/base.rb#L1609-1633)
1994
2662
  已经
1995
- [被包含进了主命名空间](http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/main.rb#L28)。
2663
+ [被扩展进了 main 对象](https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/main.rb#L28-30)。
1996
2664
 
1997
2665
  ## 命令行
1998
2666
 
1999
- Sinatra 应用可以被直接运行:
2667
+ 可以直接运行 Sinatra 应用:
2000
2668
 
2001
- ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-o HOST] [-s HANDLER]
2669
+ ```shell
2670
+ ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-o HOST] [-s HANDLER]
2671
+ ```
2002
2672
 
2003
2673
  选项是:
2004
2674
 
2005
- -h # help
2006
- -p # 设定端口 (默认是 4567)
2007
- -o # 设定主机名 (默认是 0.0.0.0)
2008
- -e # 设定环境 (默认是 development)
2009
- -s # 限定 rack 服务器/处理器 (默认是 thin)
2010
- -x # 打开互斥锁 (默认是 off)
2675
+ ```
2676
+ -h # 显示帮助
2677
+ -p # 设置端口号 (默认是 4567)
2678
+ -o # 设定主机名 (默认是 0.0.0.0)
2679
+ -e # 设置环境 (默认是 development)
2680
+ -s # 声明 rack 服务器/处理器 (默认是 thin)
2681
+ -x # 打开互斥锁 (默认是 off)
2682
+ ```
2011
2683
 
2012
- ## 必要条件
2684
+ ### 多线程
2013
2685
 
2014
- 推荐在 Ruby 1.8.7, 1.9.2, JRuby 或者 Rubinius 上安装Sinatra。
2686
+ _根据 Konstantin [这个 StackOverflow 答案] [so-answer] 改写_
2015
2687
 
2016
- 下面的Ruby版本是官方支持的:
2688
+ Sinatra 本身并不使用任何并发模型,而是将并发的任务留给底层的
2689
+ Rack 处理器(服务器),如 Thin、Puma 或 WEBrick。Sinatra 本身是线程安全的,所以
2690
+ Rack 处理器使用多线程并发模型并无任何问题。这意味着在启动服务器时,你必须指定特定
2691
+ Rack 处理器的正确调用方法。
2692
+ 下面的例子展示了如何启动一个多线程的 Thin 服务器:
2017
2693
 
2018
- <dl>
2019
- <dt>Ruby 1.8.6</dt>
2020
- <dd>
2021
- 不推荐在1.8.6上安装Sinatra, 但是直到Sinatra
2022
- 1.3.0发布才会放弃对它的支持。 RDoc 和
2023
- CoffeScript模板不被这个Ruby版本支持。
2024
- 1.8.6在它的Hash实现中包含一个内存泄漏问题,
2025
- 该问题会被1.1.1版本之前的Sinatra引发。
2026
- 当前版本使用性能下降的代价排除了这个问题。你需要把Rack降级到1.1.x,
2027
- 因为Rack \>= 1.2不再支持1.8.6。
2028
- </dd>
2029
-
2030
- <dt>Ruby 1.8.7</dt>
2031
- <dd>
2032
- 1.8.7 被完全支持,但是,如果没有特别原因, 我们推荐你升级到 1.9.2
2033
- 或者切换到 JRuby 或者 Rubinius.
2034
- </dd>
2035
-
2036
- <dt>Ruby 1.9.2</dt>
2037
- <dd>
2038
- 1.9.2 被支持而且推荐。注意 Radius 和 Markaby 模板并不和1.9兼容。不要使用
2039
- 1.9.2p0, 它被已知会产生 segmentation faults.
2040
- </dd>
2041
-
2042
- <dt>Rubinius</dt>
2043
- <dd>
2044
- Rubinius 被官方支持 (Rubinius \>= 1.2.2), 除了Textile模板。
2045
- </dd>
2046
-
2047
- <dt>JRuby</dt>
2048
- <dd>
2049
- JRuby 被官方支持 (JRuby \>= 1.5.6)。 目前未知和第三方模板库有关的问题,
2050
- 但是,如果你选择了JRuby,请查看一下JRuby rack 处理器, 因为 Thin web
2051
- 服务器还没有在JRuby上获得支持。
2052
- </dd>
2053
- </dl>
2694
+ ```ruby
2695
+ # app.rb
2054
2696
 
2055
- 我们也会时刻关注新的Ruby版本。
2697
+ require 'sinatra/base'
2056
2698
 
2057
- 下面的 Ruby 实现没有被官方支持, 但是已知可以运行 Sinatra:
2699
+ class App < Sinatra::Base
2700
+ get '/' do
2701
+ "Hello, World"
2702
+ end
2703
+ end
2058
2704
 
2059
- - JRuby 和 Rubinius 老版本
2705
+ App.run!
2060
2706
 
2061
- - MacRuby
2707
+ ```
2062
2708
 
2063
- - Maglev
2709
+ 启动服务器的命令是:
2064
2710
 
2065
- - IronRuby
2711
+ ```shell
2712
+ thin --threaded start
2713
+ ```
2066
2714
 
2067
- - Ruby 1.9.0 and 1.9.1
2068
2715
 
2069
- 不被官方支持的意思是,如果在不被支持的平台上有运行错误,
2070
- 我们假定不是我们的问题,而是平台的问题。
2716
+ [so-answer]: http://stackoverflow.com/questions/6278817/is-sinatra-multi-threaded/6282999#6282999)
2071
2717
 
2072
- Sinatra应该会运行在任何支持上述Ruby实现的操作系统。
2718
+ ## 必要条件
2073
2719
 
2074
- ## 紧追前沿
2720
+ 以下 Ruby 版本受官方支持:
2721
+ <dl>
2722
+ <dt>Ruby 1.8.7</dt>
2723
+ <dd>
2724
+ Sinatra 完全支持 1.8.7,但是,除非必要,我们推荐你升级或者切换到
2725
+ JRuby 或 Rubinius。Sinatra 2.0 之前都不会取消对 1.8.7
2726
+ 的支持。Ruby 1.8.6 目前已不受支持。
2727
+ </dd>
2728
+
2729
+ <dt>Ruby 1.9.2</dt>
2730
+ <dd>
2731
+ Sinatra 完全支持 1.9.2。
2732
+ 不要使用 1.9.2p0,它在运行 Sinatra 程序时会产生 segmentation faults 错误。
2733
+ 至少在 Sinatra 1.5 发布之前,官方对 1.9.2 的支持仍会继续。
2734
+ </dd>
2735
+
2736
+ <dt>Ruby 1.9.3</dt>
2737
+ <dd>
2738
+ Sinatra 完全支持并推荐使用 1.9.3。请注意从更早的版本迁移到 1.9.3 会使所有的会话失效。
2739
+ 直到 Sinatra 2.0 发布之前,官方仍然会支持 1.9.3。
2740
+ </dd>
2741
+
2742
+ <dt>Ruby 2.x</dt>
2743
+ <dd>
2744
+ Sinatra 完全支持并推荐使用 2.x。目前尚无停止支持 2.x 的计划。
2745
+ </dd>
2746
+
2747
+ <dt>Rubinius</dt>
2748
+ <dd>
2749
+ Sinatra 官方支持 Rubinius (Rubinius >= 2.x)。推荐 <tt>gem install puma</tt>。
2750
+ </dd>
2751
+
2752
+ <dt>JRuby</dt>
2753
+ <dd>
2754
+ Sinatra 官方支持 JRuby 的最新稳定版本,但不推荐在 JRuby 上使用 C 扩展。
2755
+ 推荐 <tt>gem install trinidad</tt>。
2756
+ </dd>
2757
+ </dl>
2075
2758
 
2076
- 如果你喜欢使用 Sinatra 的最新鲜的代码,请放心的使用 master
2077
- 分支来运行你的程序,它会非常的稳定。
2759
+ 我们也在时刻关注新的 Ruby 版本。
2078
2760
 
2079
- cd myapp
2080
- git clone git://github.com/sinatra/sinatra.git
2081
- ruby -Isinatra/lib myapp.rb
2761
+ 以下 Ruby 实现不受 Sinatra 官方支持,但可以运行 Sinatra:
2082
2762
 
2083
- 我们也会不定期的发布预发布gems,所以你也可以运行
2763
+ * 老版本 JRuby 和 Rubinius
2764
+ * Ruby 企业版
2765
+ * MacRuby、Maglev、IronRuby
2766
+ * Ruby 1.9.0 和 1.9.1 (不推荐使用)
2084
2767
 
2085
- gem install sinatra --pre
2768
+ 不受官方支持的意思是,如果仅在不受支持的 Ruby 实现上发生错误,我们认为不是我们的问题,而是该实现的问题。
2086
2769
 
2087
- 来获得最新的特性。
2770
+ 我们同时也针对 ruby-head (MRI 的未来版本)运行 CI,但由于 ruby-head 一直处在变化之中,
2771
+ 我们不能作任何保证。我们期望完全支持未来的 2.x 版本。
2088
2772
 
2089
- ### 通过Bundler
2773
+ Sinatra 应该会运行在任何支持上述 Ruby 实现的操作系统上。
2090
2774
 
2091
- 如果你想使用最新的Sinatra运行你的应用,通过
2092
- [Bundler](http://gembundler.com/) 是推荐的方式。
2775
+ 如果你使用 MacRuby,你应该 `gem install control_tower`。
2093
2776
 
2094
- 首先,安装bundler,如果你还没有安装:
2777
+ Sinatra 目前不支持 Cardinal、SmallRuby、BlueRuby 或其它 1.8.7 之前的 Ruby 版本。
2095
2778
 
2096
- gem install bundler
2779
+ ## 紧跟前沿
2097
2780
 
2098
- 然后,在你的项目目录下,创建一个 `Gemfile`:
2781
+ 如果你想使用 Sinatra 的最新代码,请放心使用 master 分支来运行你的程序,它是相当稳定的。
2099
2782
 
2100
- ~~~~ ruby
2101
- source :rubygems
2102
- gem 'sinatra', :git => "git://github.com/sinatra/sinatra.git"
2783
+ 我们也会不定期推出 prerelease gems,所以你也可以运行
2103
2784
 
2104
- # 其他的依赖关系
2105
- gem 'haml' # 举例,如果你想用haml
2106
- gem 'activerecord', '~> 3.0' # 也许你还需要 ActiveRecord 3.x
2107
- ~~~~
2785
+ ```shell
2786
+ gem install sinatra --pre
2787
+ ```
2108
2788
 
2109
- 请注意在这里你需要列出你的应用的所有依赖关系。 Sinatra的直接依赖关系
2110
- (Rack and Tilt) 将会, 自动被Bundler获取和添加。
2789
+ 来获得最新的特性。
2111
2790
 
2112
- 现在你可以像这样运行你的应用:
2791
+ ### 通过 Bundler 使用 Sinatra
2113
2792
 
2114
- bundle exec ruby myapp.rb
2793
+ 如果你想在应用中使用最新的 Sinatra,推荐使用 [Bundler](http://bundler.io)。
2115
2794
 
2116
- ### 使用自己的
2795
+ 首先,安装 Bundler,如果你还没有安装的话:
2117
2796
 
2118
- 创建一个本地克隆并通过 `sinatra/lib` 目录运行你的应用, 通过
2119
- `$LOAD_PATH`:
2797
+ ```shell
2798
+ gem install bundler
2799
+ ```
2120
2800
 
2121
- cd myapp
2122
- git clone git://github.com/sinatra/sinatra.git
2123
- ruby -Isinatra/lib myapp.rb
2801
+ 然后,在你的项目目录下创建一个 `Gemfile`:
2124
2802
 
2125
- 为了在未来更新 Sinatra 源代码:
2803
+ ```ruby
2804
+ source 'https://rubygems.org'
2805
+ gem 'sinatra', :github => "sinatra/sinatra"
2126
2806
 
2127
- cd myapp/sinatra
2128
- git pull
2807
+ # 其它依赖
2808
+ gem 'haml' # 假如你使用 haml
2809
+ gem 'activerecord', '~> 3.0' # 也许你还需要 ActiveRecord 3.x
2810
+ ```
2129
2811
 
2130
- ### 全局安装
2812
+ 请注意你必须在 `Gemfile` 中列出应用的所有依赖项。
2813
+ 然而, Sinatra 的直接依赖项 (Rack 和 Tilt) 则会被 Bundler 自动获取和添加。
2131
2814
 
2132
- 你可以自行编译 gem :
2815
+ 现在你可以这样运行你的应用:
2133
2816
 
2134
- git clone git://github.com/sinatra/sinatra.git
2135
- cd sinatra
2136
- rake sinatra.gemspec
2137
- rake install
2817
+ ```shell
2818
+ bundle exec ruby myapp.rb
2819
+ ```
2138
2820
 
2139
- 如果你以root身份安装 gems,最后一步应该是
2821
+ ### 使用自己本地的 Sinatra
2140
2822
 
2141
- sudo rake install
2823
+ 创建一个本地克隆,并通过 `$LOAD_PATH` 里的 `sinatra/lib` 目录运行你的应用:
2142
2824
 
2143
- ## 更多
2825
+ ```shell
2826
+ cd myapp
2827
+ git clone git://github.com/sinatra/sinatra.git
2828
+ ruby -I sinatra/lib myapp.rb
2829
+ ```
2144
2830
 
2145
- - [项目主页(英文)](http://www.sinatrarb.com/) - 更多的文档,
2146
- 新闻,和其他资源的链接。
2831
+ 为了在未来更新 Sinatra 源代码:
2147
2832
 
2148
- - [贡献](http://www.sinatrarb.com/contributing) - 找到了一个bug?
2149
- 需要帮助?有了一个 patch?
2833
+ ```shell
2834
+ cd myapp/sinatra
2835
+ git pull
2836
+ ```
2837
+
2838
+ ### 全局安装
2150
2839
 
2151
- - [问题追踪](http://github.com/sinatra/sinatra/issues)
2840
+ 你可以自行编译 Sinatra gem:
2152
2841
 
2153
- - [Twitter](http://twitter.com/sinatra)
2842
+ ```shell
2843
+ git clone git://github.com/sinatra/sinatra.git
2844
+ cd sinatra
2845
+ rake sinatra.gemspec
2846
+ rake install
2847
+ ```
2154
2848
 
2155
- - [邮件列表](http://groups.google.com/group/sinatrarb/topics)
2849
+ 如果你以 root 身份安装 gems,最后一步应该是:
2156
2850
 
2157
- - [IRC: \#sinatra](irc://chat.freenode.net/#sinatra) on
2158
- [freenode.net](http://freenode.net)
2851
+ ```shell
2852
+ sudo rake install
2853
+ ```
2159
2854
 
2160
- - [Sinatra宝典](https://github.com/sinatra/sinatra-book/) Cookbook教程
2855
+ ## 版本
2161
2856
 
2162
- - [Sinatra使用技巧](http://recipes.sinatrarb.com/) 网友贡献的实用技巧
2857
+ Sinatra 遵循[语义化版本](http://semver.org),无论是 SemVer 还是 SemVerTag。
2163
2858
 
2164
- - [最新版本](http://rubydoc.info/gems/sinatra)API文档;[http://rubydoc.info](http://rubydoc.info)的[当前HEAD](http://rubydoc.info/github/sinatra/sinatra)
2859
+ ## 更多资料
2165
2860
 
2166
- - [CI服务器](http://travis-ci.org/sinatra/sinatra)
2861
+ * [项目官网](http://www.sinatrarb.com/) - 更多文档、新闻和其它资源的链接。
2862
+ * [贡献](http://www.sinatrarb.com/contributing) - 找到一个 bug?需要帮助?有了一个 patch?
2863
+ * [问题追踪](https://github.com/sinatra/sinatra/issues)
2864
+ * [Twitter](https://twitter.com/sinatra)
2865
+ * [邮件列表](http://groups.google.com/group/sinatrarb/topics)
2866
+ * IRC: [#sinatra](irc://chat.freenode.net/#sinatra) on http://freenode.net
2867
+ * [Sinatra & Friends](https://sinatrarb.slack.com) on Slack,点击
2868
+ [这里](https://sinatra-slack.herokuapp.com/) 获得邀请。
2869
+ * [Sinatra Book](https://github.com/sinatra/sinatra-book/) Cookbook 教程
2870
+ * [Sinatra Recipes](http://recipes.sinatrarb.com/) 社区贡献的实用技巧
2871
+ * http://www.rubydoc.info/ 上[最新版本](http://www.rubydoc.info//gems/sinatra)或[当前 HEAD](http://www.rubydoc.info/github/sinatra/sinatra) 的 API 文档
2872
+ * [CI 服务器](https://travis-ci.org/sinatra/sinatra)