sinatra 1.1.4 → 1.2.0.a
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sinatra might be problematic. Click here for more details.
- data/AUTHORS +0 -9
- data/CHANGES +6 -29
- data/README.de.rdoc +23 -0
- data/README.es.rdoc +87 -205
- data/README.fr.rdoc +13 -0
- data/README.jp.rdoc +13 -0
- data/README.rdoc +86 -258
- data/README.ru.rdoc +63 -95
- data/README.zh.rdoc +13 -0
- data/Rakefile +21 -55
- data/lib/sinatra/base.rb +43 -44
- data/sinatra.gemspec +7 -4
- data/test/filter_test.rb +105 -1
- data/test/helpers_test.rb +7 -3
- data/test/markaby_test.rb +21 -0
- data/test/routing_test.rb +6 -18
- data/test/slim_test.rb +97 -0
- data/test/templates_test.rb +14 -4
- data/test/views/hello.slim +1 -0
- data/test/views/layout2.slim +3 -0
- metadata +98 -12
- data/test/views/calc.html.erb +0 -1
data/README.ru.rdoc
CHANGED
@@ -39,6 +39,10 @@ Sinatra — это предметно-ориентированный язык (D
|
|
39
39
|
.. что-то удалить ..
|
40
40
|
end
|
41
41
|
|
42
|
+
options '/' do
|
43
|
+
.. что-то ответить ..
|
44
|
+
end
|
45
|
+
|
42
46
|
Маршруты сверяются с запросом по очередности определения. Первый же совпавший с запросом маршрут и будет вызван.
|
43
47
|
|
44
48
|
Шаблоны маршрутов могут включать в себя параметры доступные в
|
@@ -90,7 +94,7 @@ Sinatra — это предметно-ориентированный язык (D
|
|
90
94
|
end
|
91
95
|
|
92
96
|
get '/foo' do
|
93
|
-
# соответствует non-songbird браузерам
|
97
|
+
# соответствует с non-songbird браузерам
|
94
98
|
end
|
95
99
|
|
96
100
|
Другими доступными условиями являются +host_name+ и +provides+:
|
@@ -122,7 +126,7 @@ Sinatra — это предметно-ориентированный язык (D
|
|
122
126
|
=== Возвращаемые значения
|
123
127
|
|
124
128
|
Возвращаемое значение блока маршрута ограничивается телом ответа, которое будет передано HTTP клиенту,
|
125
|
-
или следующей
|
129
|
+
или следующей подпрограммой (middleware) в Rack стеке. Чаще всего это строка, как в вышеизложенных примерах.
|
126
130
|
Но и другие значения также приемлемы.
|
127
131
|
|
128
132
|
Вы можете вернуть любой объект, который будет либо корректным Rack ответом, Rack
|
@@ -334,31 +338,16 @@ rdiscount gem/библиотека необходима для рендерин
|
|
334
338
|
Отрисует <tt>./views/index.markdown</tt> (+md+ и +mkd+ также являются допустимыми файловыми
|
335
339
|
расширениями).
|
336
340
|
|
337
|
-
В
|
338
|
-
|
339
|
-
движком рендеринга:
|
341
|
+
В markdown невозможно вызывать методы или передавать локальные переменные. Следовательно, вам скорее всего придется
|
342
|
+
использовать этот шаблон совместно с другим движком рендеринга:
|
340
343
|
|
341
344
|
erb :overview, :locals => { :text => markdown(:introduction) }
|
342
345
|
|
343
|
-
Заметьте, что вы можете вызывать метод
|
346
|
+
Заметьте, что вы можете вызывать метод markdown из других шаблонов:
|
344
347
|
|
345
348
|
%h1 Hello From Haml!
|
346
349
|
%p= markdown(:greetings)
|
347
350
|
|
348
|
-
Также возможно обрабатывать Markdown с помощью BlueCloth, а не RDiscount:
|
349
|
-
|
350
|
-
require 'bluecloth'
|
351
|
-
|
352
|
-
Tilt.register 'markdown', BlueClothTemplate
|
353
|
-
Tilt.register 'mkd', BlueClothTemplate
|
354
|
-
Tilt.register 'md', BlueClothTemplate
|
355
|
-
|
356
|
-
get '/' do
|
357
|
-
markdown :index
|
358
|
-
end
|
359
|
-
|
360
|
-
Отрисует <tt>./views/index.md</tt> с помощью BlueCloth.
|
361
|
-
|
362
351
|
=== Textile шаблоны
|
363
352
|
|
364
353
|
RedCloth gem/библиотека необходима для рендеринга Textile шаблонов:
|
@@ -436,6 +425,26 @@ markaby gem/библиотека необходима для рендеринг
|
|
436
425
|
|
437
426
|
Отрисует <tt>./views/index.mab</tt>.
|
438
427
|
|
428
|
+
Если у вас установлен Tilt версии 1.2 или выше, то вы также можете использовать внутристроковые
|
429
|
+
markaby шаблоны:
|
430
|
+
|
431
|
+
get '/' do
|
432
|
+
markaby { h1 "Welcome!" }
|
433
|
+
end
|
434
|
+
|
435
|
+
=== Slim шаблоны
|
436
|
+
|
437
|
+
slim gem/библиотека необходима для рендеринга slim шаблонов:
|
438
|
+
|
439
|
+
## Вам нужно будет подключить slim в приложении
|
440
|
+
require 'slim'
|
441
|
+
|
442
|
+
get '/' do
|
443
|
+
slim :index
|
444
|
+
end
|
445
|
+
|
446
|
+
Отрисует <tt>./views/index.slim</tt>.
|
447
|
+
|
439
448
|
=== CoffeeScript шаблоны
|
440
449
|
|
441
450
|
coffee-script gem/библиотека и `coffee` бинарный файл необходимы для рендеринга CoffeeScript шаблонов:
|
@@ -449,13 +458,13 @@ coffee-script gem/библиотека и `coffee` бинарный файл н
|
|
449
458
|
|
450
459
|
Отрисует <tt>./views/application.coffee</tt>.
|
451
460
|
|
452
|
-
===
|
461
|
+
=== Внутристроковые шаблоны
|
453
462
|
|
454
463
|
get '/' do
|
455
464
|
haml '%div.title Hello World'
|
456
465
|
end
|
457
466
|
|
458
|
-
Отрисует
|
467
|
+
Отрисует внутристроковый шаблон.
|
459
468
|
|
460
469
|
=== Доступ к переменным в шаблонах
|
461
470
|
|
@@ -516,8 +525,7 @@ coffee-script gem/библиотека и `coffee` бинарный файл н
|
|
516
525
|
end
|
517
526
|
|
518
527
|
Если шаблон с именем "layout" существует, то он будет использован каждый раз,
|
519
|
-
когда шаблоны будут отрисовываться. Вы можете
|
520
|
-
<tt>:layout => false</tt> или отключить его для всего приложения, например, так: <tt>set :haml, :layout => false</tt>.
|
528
|
+
когда шаблоны будут отрисовываться. Вы можете отключить layout-шаблон с помощью <tt>:layout => false</tt>.
|
521
529
|
|
522
530
|
get '/' do
|
523
531
|
haml :index, :layout => !request.xhr?
|
@@ -570,6 +578,16 @@ After-фильтры выполняются после каждого запро
|
|
570
578
|
session[:last_slug] = slug
|
571
579
|
end
|
572
580
|
|
581
|
+
Как и маршруты, фильтры могут использовать условия:
|
582
|
+
|
583
|
+
before :agent => /Songbird/ do
|
584
|
+
# ...
|
585
|
+
end
|
586
|
+
|
587
|
+
after '/blog/*', :host_name => 'example.com' do
|
588
|
+
# ...
|
589
|
+
end
|
590
|
+
|
573
591
|
== Прерывание
|
574
592
|
|
575
593
|
Чтобы незамедлительно прервать обработку запроса внутри фильтра или маршрута, используйте:
|
@@ -745,15 +763,15 @@ Sinatra устанавливает специальные <tt>not_found</tt> и
|
|
745
763
|
|
746
764
|
content_type :foo
|
747
765
|
|
748
|
-
== Rack
|
766
|
+
== Rack подпрограммы
|
749
767
|
|
750
768
|
Sinatra использует Rack[http://rack.rubyforge.org/], минимальный стандартный
|
751
769
|
интерфейс для веб-фреймворков на Ruby. Одной из самых интересных для разработчиков возможностей Rack
|
752
|
-
является поддержка
|
770
|
+
является поддержка подпрограмм ("middleware") -- компонентов,
|
753
771
|
"сидящих" между сервером и вашим приложением, которые отслеживают и/или манипулируют
|
754
772
|
HTTP запросами/ответами для предоставления различной функциональности.
|
755
773
|
|
756
|
-
В Sinatra очень просто использовать такие
|
774
|
+
В Sinatra очень просто использовать такие Rack подпрограммы с помощью метода +use+:
|
757
775
|
|
758
776
|
require 'sinatra'
|
759
777
|
require 'my_custom_middleware'
|
@@ -774,7 +792,7 @@ Rack::Builder[http://rack.rubyforge.org/doc/classes/Rack/Builder.html] DSL
|
|
774
792
|
username == 'admin' && password == 'secret'
|
775
793
|
end
|
776
794
|
|
777
|
-
Rack распространяется с различными стандартными
|
795
|
+
Rack распространяется с различными стандартными подпрограммами
|
778
796
|
для логирования, отладки, маршрутизации URL, аутентификации, обработки сессий. Sinatra использует
|
779
797
|
многие из этих компонентов автоматически, основываясь на конфигурации, чтобы вам не приходилось
|
780
798
|
регистрировать/использовать (+use+) их вручную.
|
@@ -814,12 +832,13 @@ Rack распространяется с различными стандартн
|
|
814
832
|
Заметьте: Встроенные модули Sinatra::Test и Sinatra::TestHarness являются
|
815
833
|
устаревшими, начиная с 0.9.2 релиза.
|
816
834
|
|
817
|
-
== Sinatra::Base
|
835
|
+
== Sinatra::Base - Подпрограммы, библиотеки и модульные приложения
|
818
836
|
|
819
837
|
Описание своего приложения самым простейшим способом (с помощью DSL верхнего уровня, как в примерах выше)
|
820
|
-
работает отлично для крохотных приложений, но имеет множество недостатков, когда надо
|
821
|
-
|
822
|
-
|
838
|
+
работает отлично для крохотных приложений, но имеет множество недостатков, когда надо
|
839
|
+
создать компоненты, такие как Rack
|
840
|
+
middleware, Rails metal, простые библиотеки с серверными компонентами,
|
841
|
+
Sinatra расширения.
|
823
842
|
DSL верхнего уровня загрязняет пространство имен <tt>Object</tt> и подразумевает стиль конфигурации
|
824
843
|
микро-приложения (например, единый файл приложения, ./public и
|
825
844
|
./views директории, создание логов, страницу деталей об исключениях
|
@@ -836,6 +855,13 @@ DSL верхнего уровня загрязняет пространство
|
|
836
855
|
end
|
837
856
|
end
|
838
857
|
|
858
|
+
MyApp класс является независимым Rack компонентом, который может исполнять роли
|
859
|
+
Rack подпрограммы, Rack приложения, Rails metal. Вы можете +use+ (использовать) или
|
860
|
+
+run+ (запустить) этот класс из rackup файла +config.ru+; или контролировать серверную
|
861
|
+
часть из библиотеки:
|
862
|
+
|
863
|
+
MyApp.run! :host => 'localhost', :port => 9090
|
864
|
+
|
839
865
|
Методы, доступные Sinatra::Base сабклассам идентичны тем, что доступны
|
840
866
|
в DSL верхнего уровня. Большинство приложений верхнего уровня могут быть
|
841
867
|
конвертированы в Sinatra::Base компоненты с помощью двух модификаций:
|
@@ -848,68 +874,10 @@ DSL верхнего уровня загрязняет пространство
|
|
848
874
|
Смотрите {Опции и Конфигурация}[http://www.sinatrarb.com/configuration.html] для детальной информации
|
849
875
|
об опциях и их поведении.
|
850
876
|
|
851
|
-
===
|
852
|
-
|
853
|
-
Есть два общепринятых способа запускать модульные приложения: запуск напрямую с помощью <tt>run!</tt>:
|
854
|
-
|
855
|
-
# my_app.rb
|
856
|
-
require 'sinatra/base'
|
857
|
-
|
858
|
-
class MyApp < Sinatra::Base
|
859
|
-
# ... здесь код приложения ...
|
860
|
-
|
861
|
-
# запускаем сервер, если исполняется текущий файл
|
862
|
-
run! if app_file == $0
|
863
|
-
end
|
864
|
-
|
865
|
-
И запускаем с помощью:
|
866
|
-
|
867
|
-
ruby my_app.rb
|
868
|
-
|
869
|
-
Или с помощью конфигурационного файла <tt>config.ru</tt>, который позволяет использовать любой
|
870
|
-
Rack-совместимый сервер приложений.
|
871
|
-
|
872
|
-
# config.ru
|
873
|
-
require 'my_app'
|
874
|
-
run MyApp
|
875
|
-
|
876
|
-
Запускаем:
|
877
|
-
|
878
|
-
rackup -p 4567
|
879
|
-
|
880
|
-
=== Запуск "классических" приложений с config.ru
|
881
|
-
|
882
|
-
Файл приложения:
|
883
|
-
|
884
|
-
# app.rb
|
885
|
-
require 'sinatra'
|
886
|
-
|
887
|
-
get '/' do
|
888
|
-
'Hello world!'
|
889
|
-
end
|
890
|
-
|
891
|
-
И соответствующий <tt>config.ru</tt>:
|
892
|
-
|
893
|
-
require 'app'
|
894
|
-
run Sinatra::Application
|
895
|
-
|
896
|
-
=== Когда использовать config.ru?
|
897
|
-
|
898
|
-
Вот несколько причин, по которым вы, возможно, захотите использовать <tt>config.ru</tt>:
|
899
|
-
|
900
|
-
* вы хотите разворачивать свое приложение на различных Rack-совместимых серверах (Passenger, Unicorn,
|
901
|
-
Heroku, ...).
|
902
|
-
* вы хотите использовать более одного сабкласса <tt>Sinatra::Base</tt>.
|
903
|
-
* вы хотите использовать Sinatra только в качестве "прослойки" Rack.
|
904
|
-
|
905
|
-
<b>Совсем необязательно переходить на использование <tt>config.ru</tt> лишь потому, что вы стали
|
906
|
-
использовать модульный стиль приложения. И необязательно использовать модульный стиль, чтобы
|
907
|
-
запускать приложение с помощью <tt>config.ru</tt>.</b>
|
908
|
-
|
909
|
-
=== Использование Sinatra в качестве "прослойки"
|
877
|
+
=== Использование Sinatra как подпрограммы
|
910
878
|
|
911
|
-
Не только сама Sinatra может использовать
|
912
|
-
само может быть добавлено к любому Rack эндпоинту в качестве
|
879
|
+
Не только сама Sinatra может использовать подпрограммы Rack, любое Sinatra приложение
|
880
|
+
само может быть добавлено к любому Rack эндпоинту в качестве подпрограммы. Этим эндпоинтом
|
913
881
|
может быть другое Sinatra приложение, или приложение, основанное на Rack (Rails/Ramaze/Camping/...).
|
914
882
|
|
915
883
|
require 'sinatra/base'
|
@@ -929,7 +897,7 @@ Rack-совместимый сервер приложений.
|
|
929
897
|
end
|
930
898
|
|
931
899
|
class MyApp < Sinatra::Base
|
932
|
-
#
|
900
|
+
# подпрограмма будет запущена перед фильтрами
|
933
901
|
use LoginScreen
|
934
902
|
|
935
903
|
before do
|
@@ -1005,7 +973,7 @@ Sinatra::Application, иначе это будет сабкласс, котор
|
|
1005
973
|
|
1006
974
|
У вас будет область видимости запроса внутри:
|
1007
975
|
|
1008
|
-
* get/head/post/put/delete блоков
|
976
|
+
* get/head/post/put/delete/options блоков
|
1009
977
|
* before/after фильтрах
|
1010
978
|
* методах помощниках
|
1011
979
|
* шаблонах/видах
|
data/README.zh.rdoc
CHANGED
@@ -420,6 +420,19 @@ Rack body对象或者HTTP状态码:
|
|
420
420
|
|
421
421
|
渲染 <tt>./views/index.mab</tt>。
|
422
422
|
|
423
|
+
=== Slim 模板
|
424
|
+
|
425
|
+
需要引入 slim gem/library 来渲染 Slim 模板:
|
426
|
+
|
427
|
+
## 需要在你的应用中引入 slim
|
428
|
+
require 'slim'
|
429
|
+
|
430
|
+
get '/' do
|
431
|
+
slim :index
|
432
|
+
end
|
433
|
+
|
434
|
+
渲染 <tt>./views/index.slim</tt>。
|
435
|
+
|
423
436
|
=== CoffeeScript 模板
|
424
437
|
|
425
438
|
需要引入 coffee-script gem/library 并在路径中存在 `coffee` 二进制文件以渲染
|
data/Rakefile
CHANGED
@@ -6,48 +6,45 @@ require 'date'
|
|
6
6
|
task :default => :test
|
7
7
|
task :spec => :test
|
8
8
|
|
9
|
-
CLEAN.include "**/*.rbc"
|
10
|
-
|
11
9
|
def source_version
|
12
|
-
|
13
|
-
|
14
|
-
line.match(/.*VERSION = '(.*)'/)[1]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def prev_feature
|
19
|
-
source_version.gsub(/^(\d\.)(\d+)\..*$/) { $1 + ($2.to_i - 1).to_s }
|
20
|
-
end
|
21
|
-
|
22
|
-
def prev_version
|
23
|
-
return prev_feature + '.0' if source_version.end_with? '.0'
|
24
|
-
source_version.gsub(/\d+$/) { |s| s.to_i - 1 }
|
10
|
+
line = File.read('lib/sinatra/base.rb')[/^\s*VERSION = .*/]
|
11
|
+
line.match(/.*VERSION = '(.*)'/)[1]
|
25
12
|
end
|
26
13
|
|
27
14
|
# SPECS ===============================================================
|
28
|
-
|
29
15
|
task :test do
|
30
16
|
ENV['LANG'] = 'C'
|
31
17
|
ENV.delete 'LC_CTYPE'
|
32
18
|
end
|
33
19
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
20
|
+
if !ENV['NO_TEST_FIX'] and RUBY_VERSION == '1.9.2' and RUBY_PATCHLEVEL == 0
|
21
|
+
# Avoids seg fault
|
22
|
+
task(:test) do
|
23
|
+
second_run = %w[settings rdoc markaby templates static textile].map { |l| "test/#{l}_test.rb" }
|
24
|
+
first_run = Dir.glob('test/*_test.rb') - second_run
|
25
|
+
[first_run, second_run].each { |f| sh "testrb #{f.join ' '}" }
|
26
|
+
end
|
27
|
+
else
|
28
|
+
Rake::TestTask.new(:test) do |t|
|
29
|
+
t.test_files = FileList['test/*_test.rb']
|
30
|
+
t.ruby_opts = ['-rubygems'] if defined? Gem
|
31
|
+
t.ruby_opts << '-I.'
|
32
|
+
end
|
38
33
|
end
|
39
34
|
|
40
35
|
# Rcov ================================================================
|
41
|
-
|
42
36
|
namespace :test do
|
43
37
|
desc 'Mesures test coverage'
|
44
38
|
task :coverage do
|
45
39
|
rm_f "coverage"
|
46
|
-
|
40
|
+
rcov = "rcov --text-summary -Ilib"
|
41
|
+
system("#{rcov} --no-html --no-color test/*_test.rb")
|
47
42
|
end
|
48
43
|
end
|
49
44
|
|
50
45
|
# Website =============================================================
|
46
|
+
# Building docs requires HAML and the hanna gem:
|
47
|
+
# gem install mislav-hanna --source=http://gems.github.com
|
51
48
|
|
52
49
|
desc 'Generate RDoc under doc/api'
|
53
50
|
task 'doc' => ['doc:api']
|
@@ -55,7 +52,6 @@ task('doc:api') { sh "yardoc -o doc/api" }
|
|
55
52
|
CLEAN.include 'doc/api'
|
56
53
|
|
57
54
|
# README ===============================================================
|
58
|
-
|
59
55
|
task :add_template, [:name] do |t, args|
|
60
56
|
Dir.glob('README.*') do |file|
|
61
57
|
code = File.read(file)
|
@@ -75,36 +71,6 @@ task :add_template, [:name] do |t, args|
|
|
75
71
|
end
|
76
72
|
end
|
77
73
|
|
78
|
-
# Thanks in announcement ===============================================
|
79
|
-
|
80
|
-
team = ["Ryan Tomayko", "Blake Mizerany", "Simon Rozet", "Konstantin Haase"]
|
81
|
-
desc "list of contributors"
|
82
|
-
task :thanks, [:release,:backports] do |t, a|
|
83
|
-
a.with_defaults :release => "#{prev_version}..HEAD",
|
84
|
-
:backports => "#{prev_feature}.0..#{prev_feature}.x"
|
85
|
-
included = `git log --format=format:"%aN\t%s" #{a.release}`.lines.to_a
|
86
|
-
excluded = `git log --format=format:"%aN\t%s" #{a.backports}`.lines.to_a
|
87
|
-
commits = (included - excluded).group_by { |c| c[/^[^\t]+/] }
|
88
|
-
authors = commits.keys.sort_by { |n| - commits[n].size } - team
|
89
|
-
puts authors[0..-2].join(', ') << " and " << authors.last,
|
90
|
-
"(based on commits included in #{a.release}, but not in #{a.backports})"
|
91
|
-
end
|
92
|
-
|
93
|
-
task :authors, [:format, :sep] do |t, a|
|
94
|
-
a.with_defaults :format => "%s (%d)", :sep => ', '
|
95
|
-
authors = Hash.new { |h,k| h[k] = 0 }
|
96
|
-
blake = "Blake Mizerany"
|
97
|
-
mapping = {
|
98
|
-
"blake.mizerany@gmail.com" => blake, "bmizerany" => blake,
|
99
|
-
"a_user@mac.com" => blake, "ichverstehe" => "Harry Vangberg",
|
100
|
-
"Wu Jiang (nouse)" => "Wu Jiang" }
|
101
|
-
`git shortlog -s`.lines.map do |line|
|
102
|
-
num, name = line.split("\t", 2).map(&:strip)
|
103
|
-
authors[mapping[name] || name] += num.to_i
|
104
|
-
end
|
105
|
-
puts authors.sort_by { |n,c| -c }.map { |e| a.format % e }.join(a.sep)
|
106
|
-
end
|
107
|
-
|
108
74
|
# PACKAGING ============================================================
|
109
75
|
|
110
76
|
if defined?(Gem)
|
@@ -169,8 +135,8 @@ if defined?(Gem)
|
|
169
135
|
sh <<-SH
|
170
136
|
gem install #{package('.gem')} --local &&
|
171
137
|
gem push #{package('.gem')} &&
|
172
|
-
git
|
173
|
-
git
|
138
|
+
git add sinatra.gemspec &&
|
139
|
+
git commit --allow-empty -m '#{source_version} release' &&
|
174
140
|
git tag -s #{source_version} -m '#{source_version} release' &&
|
175
141
|
git push && (git push sinatra || true) &&
|
176
142
|
git push --tags && (git push sinatra --tags || true)
|
data/lib/sinatra/base.rb
CHANGED
@@ -7,7 +7,7 @@ require 'sinatra/showexceptions'
|
|
7
7
|
require 'tilt'
|
8
8
|
|
9
9
|
module Sinatra
|
10
|
-
VERSION = '1.
|
10
|
+
VERSION = '1.2.0.a'
|
11
11
|
|
12
12
|
# The request object. See Rack::Request for more info:
|
13
13
|
# http://rack.rubyforge.org/doc/classes/Rack/Request.html
|
@@ -164,7 +164,7 @@ module Sinatra
|
|
164
164
|
# Use the contents of the file at +path+ as the response body.
|
165
165
|
def send_file(path, opts={})
|
166
166
|
stat = File.stat(path)
|
167
|
-
last_modified stat.mtime
|
167
|
+
last_modified(opts[:last_modified] || stat.mtime)
|
168
168
|
|
169
169
|
if opts[:type] or not response['Content-Type']
|
170
170
|
content_type opts[:type] || File.extname(path), :default => 'application/octet-stream'
|
@@ -324,17 +324,10 @@ module Sinatra
|
|
324
324
|
# with a '304 Not Modified' response.
|
325
325
|
def last_modified(time)
|
326
326
|
return unless time
|
327
|
-
if time.respond_to?(:to_time)
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
## if this fails, this should throw an ArgumentError, then the
|
332
|
-
# rescue will result in an http 200, which should be safe
|
333
|
-
time = Time.parse(time.to_s)
|
334
|
-
end
|
335
|
-
response['Last-Modified'] = time.httpdate
|
336
|
-
# compare based on seconds since epoch
|
337
|
-
halt 304 if Time.httpdate(request.env['HTTP_IF_MODIFIED_SINCE']).to_i >= time.to_i
|
327
|
+
time = time.to_time if time.respond_to?(:to_time)
|
328
|
+
time = Time.parse time.strftime('%FT%T%:z') if time.respond_to?(:strftime)
|
329
|
+
response['Last-Modified'] = time.respond_to?(:httpdate) ? time.httpdate : time.to_s
|
330
|
+
halt 304 if Time.httpdate(request.env['HTTP_IF_MODIFIED_SINCE']) >= time
|
338
331
|
rescue ArgumentError
|
339
332
|
end
|
340
333
|
|
@@ -383,8 +376,6 @@ module Sinatra
|
|
383
376
|
attr_accessor :content_type
|
384
377
|
end
|
385
378
|
|
386
|
-
include Tilt::CompileSite
|
387
|
-
|
388
379
|
def erb(template, options={}, locals={})
|
389
380
|
render :erb, template, options, locals
|
390
381
|
end
|
@@ -413,7 +404,8 @@ module Sinatra
|
|
413
404
|
end
|
414
405
|
|
415
406
|
def builder(template=nil, options={}, locals={}, &block)
|
416
|
-
|
407
|
+
options[:default_content_type] = :xml
|
408
|
+
render_ruby(:builder, template, options, locals, &block)
|
417
409
|
end
|
418
410
|
|
419
411
|
def liquid(template, options={}, locals={})
|
@@ -436,8 +428,8 @@ module Sinatra
|
|
436
428
|
render :radius, template, options, locals
|
437
429
|
end
|
438
430
|
|
439
|
-
def markaby(template, options={}, locals={})
|
440
|
-
|
431
|
+
def markaby(template=nil, options={}, locals={}, &block)
|
432
|
+
render_ruby(:mab, template, options, locals, &block)
|
441
433
|
end
|
442
434
|
|
443
435
|
def coffee(template, options={}, locals={})
|
@@ -446,14 +438,17 @@ module Sinatra
|
|
446
438
|
end
|
447
439
|
|
448
440
|
def nokogiri(template=nil, options={}, locals={}, &block)
|
449
|
-
options[:
|
450
|
-
|
441
|
+
options[:default_content_type] = :xml
|
442
|
+
render_ruby(:nokogiri, template, options, locals, &block)
|
443
|
+
end
|
444
|
+
|
445
|
+
def slim(template, options={}, locals={})
|
446
|
+
render :slim, template, options, locals
|
451
447
|
end
|
452
448
|
|
453
449
|
private
|
454
450
|
# logic shared between builder and nokogiri
|
455
|
-
def
|
456
|
-
options[:default_content_type] = :xml
|
451
|
+
def render_ruby(engine, template, options={}, locals={}, &block)
|
457
452
|
options, template = template, nil if template.is_a?(Hash)
|
458
453
|
template = Proc.new { block } if template.nil?
|
459
454
|
render engine, template, options, locals
|
@@ -472,7 +467,8 @@ module Sinatra
|
|
472
467
|
layout = options.delete(:layout)
|
473
468
|
eat_errors = layout.nil?
|
474
469
|
layout = @default_layout if layout.nil? or layout == true
|
475
|
-
content_type = options.delete(:content_type)
|
470
|
+
content_type = options.delete(:content_type) || options.delete(:default_content_type)
|
471
|
+
layout_engine = options.delete(:layout_engine) || engine
|
476
472
|
|
477
473
|
# compile and render template
|
478
474
|
layout_was = @default_layout
|
@@ -484,7 +480,7 @@ module Sinatra
|
|
484
480
|
# render layout
|
485
481
|
if layout
|
486
482
|
options = options.merge(:views => views, :layout => false, :eat_errors => eat_errors)
|
487
|
-
catch(:layout_missing) { output = render(
|
483
|
+
catch(:layout_missing) { output = render(layout_engine, layout, options, locals) { output }}
|
488
484
|
end
|
489
485
|
|
490
486
|
output.extend(ContentTyped).content_type = content_type if content_type
|
@@ -505,12 +501,13 @@ module Sinatra
|
|
505
501
|
template.new(path, line.to_i, options) { body }
|
506
502
|
else
|
507
503
|
found = false
|
504
|
+
path = ::File.join(views, "#{data}.#{engine}")
|
508
505
|
Tilt.mappings.each do |ext, klass|
|
509
|
-
next unless Array(klass).include? template
|
510
|
-
path = ::File.join(views, "#{data}.#{ext}")
|
511
506
|
break if found = File.exists?(path)
|
507
|
+
next unless klass == template
|
508
|
+
path = ::File.join(views, "#{data}.#{ext}")
|
512
509
|
end
|
513
|
-
throw :layout_missing if eat_errors and
|
510
|
+
throw :layout_missing if eat_errors and !found
|
514
511
|
template.new(path, 1, options)
|
515
512
|
end
|
516
513
|
when data.is_a?(Proc) || data.is_a?(String)
|
@@ -956,21 +953,22 @@ module Sinatra
|
|
956
953
|
# Define a before filter; runs before all requests within the same
|
957
954
|
# context as route handlers and may access/modify the request and
|
958
955
|
# response.
|
959
|
-
def before(path = nil, &block)
|
960
|
-
add_filter(:before, path, &block)
|
956
|
+
def before(path = nil, options = {}, &block)
|
957
|
+
add_filter(:before, path, options, &block)
|
961
958
|
end
|
962
959
|
|
963
960
|
# Define an after filter; runs after all requests within the same
|
964
961
|
# context as route handlers and may access/modify the request and
|
965
962
|
# response.
|
966
|
-
def after(path = nil, &block)
|
967
|
-
add_filter(:after, path, &block)
|
963
|
+
def after(path = nil, options = {}, &block)
|
964
|
+
add_filter(:after, path, options, &block)
|
968
965
|
end
|
969
966
|
|
970
967
|
# add a filter
|
971
|
-
def add_filter(type, path = nil, &block)
|
968
|
+
def add_filter(type, path = nil, options = {}, &block)
|
972
969
|
return filters[type] << block unless path
|
973
|
-
|
970
|
+
path, options = //, path if path.respond_to?(:each_pair)
|
971
|
+
block, *arguments = compile!(type, path, block, options)
|
974
972
|
add_filter(type) do
|
975
973
|
process_route(*arguments) { instance_eval(&block) }
|
976
974
|
end
|
@@ -992,7 +990,7 @@ module Sinatra
|
|
992
990
|
# Will set params[:agent].
|
993
991
|
def user_agent(pattern)
|
994
992
|
condition do
|
995
|
-
if request.user_agent
|
993
|
+
if request.user_agent =~ pattern
|
996
994
|
@params[:agent] = $~[1..-1]
|
997
995
|
true
|
998
996
|
else
|
@@ -1009,7 +1007,7 @@ module Sinatra
|
|
1009
1007
|
condition do
|
1010
1008
|
matching_types = (request.accept & types)
|
1011
1009
|
unless matching_types.empty?
|
1012
|
-
|
1010
|
+
response.headers['Content-Type'] = matching_types.first
|
1013
1011
|
true
|
1014
1012
|
else
|
1015
1013
|
false
|
@@ -1028,18 +1026,18 @@ module Sinatra
|
|
1028
1026
|
route('HEAD', path, opts, &block)
|
1029
1027
|
end
|
1030
1028
|
|
1031
|
-
def put(path, opts={}, &bk)
|
1032
|
-
def post(path, opts={}, &bk)
|
1033
|
-
def delete(path, opts={}, &bk)
|
1034
|
-
def head(path, opts={}, &bk)
|
1029
|
+
def put(path, opts={}, &bk) route 'PUT', path, opts, &bk end
|
1030
|
+
def post(path, opts={}, &bk) route 'POST', path, opts, &bk end
|
1031
|
+
def delete(path, opts={}, &bk) route 'DELETE', path, opts, &bk end
|
1032
|
+
def head(path, opts={}, &bk) route 'HEAD', path, opts, &bk end
|
1033
|
+
def options(path, opts={}, &bk) route 'OPTIONS', path, opts, &bk end
|
1035
1034
|
|
1036
1035
|
private
|
1037
1036
|
def route(verb, path, options={}, &block)
|
1038
1037
|
# Because of self.options.host
|
1039
1038
|
host_name(options.delete(:host)) if options.key?(:host)
|
1040
|
-
options.each { |option, args| send(option, *args) }
|
1041
1039
|
|
1042
|
-
block, pattern, keys, conditions = compile! verb, path, block
|
1040
|
+
block, pattern, keys, conditions = compile! verb, path, block, options
|
1043
1041
|
invoke_hook(:route_added, verb, path, block)
|
1044
1042
|
|
1045
1043
|
(@routes[verb] ||= []).
|
@@ -1050,7 +1048,8 @@ module Sinatra
|
|
1050
1048
|
extensions.each { |e| e.send(name, *args) if e.respond_to?(name) }
|
1051
1049
|
end
|
1052
1050
|
|
1053
|
-
def compile!(verb, path, block)
|
1051
|
+
def compile!(verb, path, block, options = {})
|
1052
|
+
options.each_pair { |option, args| send(option, *args) }
|
1054
1053
|
method_name = "#{verb} #{path}"
|
1055
1054
|
|
1056
1055
|
define_method(method_name, &block)
|
@@ -1068,7 +1067,7 @@ module Sinatra
|
|
1068
1067
|
def compile(path)
|
1069
1068
|
keys = []
|
1070
1069
|
if path.respond_to? :to_str
|
1071
|
-
special_chars = %w{. + ( )
|
1070
|
+
special_chars = %w{. + ( )}
|
1072
1071
|
pattern =
|
1073
1072
|
path.to_str.gsub(/((:\w+)|[\*#{special_chars.join}])/) do |match|
|
1074
1073
|
case match
|
@@ -1364,7 +1363,7 @@ module Sinatra
|
|
1364
1363
|
end
|
1365
1364
|
end
|
1366
1365
|
|
1367
|
-
delegate :get, :put, :post, :delete, :head, :template, :layout,
|
1366
|
+
delegate :get, :put, :post, :delete, :head, :options, :template, :layout,
|
1368
1367
|
:before, :after, :error, :not_found, :configure, :set, :mime_type,
|
1369
1368
|
:enable, :disable, :use, :development?, :test?, :production?,
|
1370
1369
|
:helpers, :settings
|