sinatra 1.3.0.f → 1.3.0.g
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/CHANGES +7 -2
- data/Gemfile +4 -16
- data/README.es.rdoc +17 -0
- data/README.rdoc +17 -0
- data/lib/sinatra/base.rb +40 -13
- data/lib/sinatra/main.rb +1 -1
- data/lib/sinatra/version.rb +1 -1
- data/test/filter_test.rb +11 -0
- data/test/helper.rb +4 -0
- data/test/helpers_test.rb +625 -44
- data/test/rack_test.rb +45 -0
- metadata +48 -75
data/CHANGES
CHANGED
@@ -12,7 +12,7 @@
|
|
12
12
|
* Added support for HTTP PATCH requests. (Konstantin Haase)
|
13
13
|
|
14
14
|
* Use rack-protection to defend against common opportunistic attacks.
|
15
|
-
(Konstantin Haase)
|
15
|
+
(Josh Lane, Jacob Burkhart, Konstantin Haase)
|
16
16
|
|
17
17
|
* Support for Creole templates, Creole is a standardized wiki markup,
|
18
18
|
supported by many wiki implementations. (Konstanin Haase)
|
@@ -41,7 +41,7 @@
|
|
41
41
|
* The sessions setting may be an options hash now. (Konstantin Haase)
|
42
42
|
|
43
43
|
* Important: Ruby 1.8.6 support has been dropped. This version also depends
|
44
|
-
on at least Rack 1.3.0. This means that it is incompatible
|
44
|
+
on at least Rack 1.3.0. This means that it is incompatible with Rails prior
|
45
45
|
to 3.1.0. Please use 1.2.x if you require an earlier version of Ruby or
|
46
46
|
Rack, which we will continue to supply with bug fixes. (Konstantin Haase)
|
47
47
|
|
@@ -82,6 +82,11 @@
|
|
82
82
|
* Conditional requests on `etag` helper now work properly for unsafe HTTP
|
83
83
|
methods. (Matthew Schinckel, Konstantin Haase)
|
84
84
|
|
85
|
+
* The `last_modified` helper does not stop execution and change the status code
|
86
|
+
if the status code is something different than 200. (Konstantin Haase)
|
87
|
+
|
88
|
+
* Added support for If-Unmodified-Since header. (Konstantin Haase)
|
89
|
+
|
85
90
|
* `Sinatra::Base.run!` now prints to stderr rather than stdout. (Andrew
|
86
91
|
Armenia)
|
87
92
|
|
data/Gemfile
CHANGED
@@ -30,13 +30,7 @@ gem 'sass'
|
|
30
30
|
gem 'builder'
|
31
31
|
gem 'erubis'
|
32
32
|
gem 'less', '~> 1.0'
|
33
|
-
|
34
|
-
if RUBY_ENGINE == "maglev"
|
35
|
-
gem 'liquid', :git => "https://github.com/Shopify/liquid.git"
|
36
|
-
else
|
37
|
-
gem 'liquid'
|
38
|
-
end
|
39
|
-
|
33
|
+
gem 'liquid'
|
40
34
|
gem 'slim', '~> 1.0'
|
41
35
|
gem 'temple', '!= 0.3.3'
|
42
36
|
gem 'RedCloth' if RUBY_VERSION < "1.9.3" and not RUBY_ENGINE.start_with? 'ma'
|
@@ -49,7 +43,7 @@ gem 'creole'
|
|
49
43
|
if RUBY_ENGINE == 'jruby'
|
50
44
|
gem 'nokogiri', '!= 1.5.0'
|
51
45
|
gem 'jruby-openssl'
|
52
|
-
|
46
|
+
else
|
53
47
|
gem 'nokogiri'
|
54
48
|
end
|
55
49
|
|
@@ -62,16 +56,10 @@ unless RUBY_ENGINE == 'jruby' && JRUBY_VERSION < "1.6.1" && !ENV['TRAVIS']
|
|
62
56
|
#gem 'bluecloth'
|
63
57
|
end
|
64
58
|
|
65
|
-
|
66
|
-
gem 'json'
|
59
|
+
platforms :ruby_18, :jruby do
|
60
|
+
gem 'json'
|
67
61
|
gem 'markaby'
|
68
62
|
gem 'radius'
|
69
|
-
else
|
70
|
-
platforms :ruby_18, :jruby do
|
71
|
-
gem 'json'
|
72
|
-
gem 'markaby'
|
73
|
-
gem 'radius'
|
74
|
-
end
|
75
63
|
end
|
76
64
|
|
77
65
|
platforms :mri_18 do
|
data/README.es.rdoc
CHANGED
@@ -1055,6 +1055,23 @@ Usá la configuración <tt>:static_cache_control</tt> para agregar el encabezado
|
|
1055
1055
|
<tt>Cache-Control</tt> a archivos estáticos (ver la sección de configuración
|
1056
1056
|
para más detalles).
|
1057
1057
|
|
1058
|
+
De acuerdo con la RFC 2616 tu aplicación debería comportarse diferente si a las
|
1059
|
+
cabeceras If-Match o If-None-Match se le asigna el valor <tt>*</tt> cuando el
|
1060
|
+
recurso solicitado ya existe. Sinatra asume para peticiones seguras (como get)
|
1061
|
+
e idempotentes (como put) que el recurso existe, mientras que para el resto
|
1062
|
+
(como post), que no. Podes cambiar este comportamiento con la opción
|
1063
|
+
<tt>:new_resource</tt>:
|
1064
|
+
|
1065
|
+
get '/crear' do
|
1066
|
+
etag '', :new_resource => true
|
1067
|
+
Articulo.create
|
1068
|
+
erb :nuevo_articulo
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
Si querés seguir usando una weak ETag, indicalo con la opción <tt>:kind</tt>:
|
1072
|
+
|
1073
|
+
etag '', :new_resource => true, :kind => :weak
|
1074
|
+
|
1058
1075
|
=== Enviando Archivos
|
1059
1076
|
|
1060
1077
|
Para enviar archivos, podés usar el método <tt>send_file</tt>:
|
data/README.rdoc
CHANGED
@@ -1018,6 +1018,23 @@ try {rack-cache}[http://rtomayko.github.com/rack-cache/]:
|
|
1018
1018
|
Use the <tt>:static_cache_control</tt> setting (see below) to add
|
1019
1019
|
<tt>Cache-Control</tt> header info to static files.
|
1020
1020
|
|
1021
|
+
According to RFC 2616 your application should behave differently if the If-Match
|
1022
|
+
or If-None-Match header is set to <tt>*</tt> depending on whether the resource
|
1023
|
+
requested is already in existence. Sinatra assumes resources for safe (like get)
|
1024
|
+
and idempotent (like put) requests are already in existence, whereas other
|
1025
|
+
resources (for instance for post requests), are treated as new resources. You
|
1026
|
+
can change this behavior by passing in a <tt>:new_resource</tt> option:
|
1027
|
+
|
1028
|
+
get '/create' do
|
1029
|
+
etag '', :new_resource => true
|
1030
|
+
Article.create
|
1031
|
+
erb :new_article
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
If you still want to use a weak ETag, pass in a <tt>:kind</tt> option:
|
1035
|
+
|
1036
|
+
etag '', :new_resource => true, :kind => :weak
|
1037
|
+
|
1021
1038
|
=== Sending Files
|
1022
1039
|
|
1023
1040
|
For sending files, you can use the <tt>send_file</tt> helper method:
|
data/lib/sinatra/base.rb
CHANGED
@@ -355,8 +355,19 @@ module Sinatra
|
|
355
355
|
return unless time
|
356
356
|
time = time_for time
|
357
357
|
response['Last-Modified'] = time.httpdate
|
358
|
-
|
359
|
-
|
358
|
+
return if env['HTTP_IF_NONE_MATCH']
|
359
|
+
|
360
|
+
if status == 200 and env['HTTP_IF_MODIFIED_SINCE']
|
361
|
+
# compare based on seconds since epoch
|
362
|
+
since = Time.httpdate(env['HTTP_IF_MODIFIED_SINCE']).to_i
|
363
|
+
halt 304 if since >= time.to_i
|
364
|
+
end
|
365
|
+
|
366
|
+
if (success? or status == 412) and env['HTTP_IF_UNMODIFIED_SINCE']
|
367
|
+
# compare based on seconds since epoch
|
368
|
+
since = Time.httpdate(env['HTTP_IF_UNMODIFIED_SINCE']).to_i
|
369
|
+
halt 412 if since < time.to_i
|
370
|
+
end
|
360
371
|
rescue ArgumentError
|
361
372
|
end
|
362
373
|
|
@@ -369,18 +380,27 @@ module Sinatra
|
|
369
380
|
# When the current request includes an 'If-None-Match' header with a
|
370
381
|
# matching etag, execution is immediately halted. If the request method is
|
371
382
|
# GET or HEAD, a '304 Not Modified' response is sent.
|
372
|
-
def etag(value,
|
373
|
-
|
383
|
+
def etag(value, options = {})
|
384
|
+
# Before touching this code, please double check RFC 2616 14.24 and 14.26.
|
385
|
+
options = {:kind => options} unless Hash === options
|
386
|
+
kind = options[:kind] || :strong
|
387
|
+
new_resource = options.fetch(:new_resource) { request.post? }
|
388
|
+
|
389
|
+
unless [:strong, :weak].include?(kind)
|
390
|
+
raise ArgumentError, ":strong or :weak expected"
|
391
|
+
end
|
392
|
+
|
374
393
|
value = '"%s"' % value
|
375
394
|
value = 'W/' + value if kind == :weak
|
376
395
|
response['ETag'] = value
|
377
396
|
|
378
|
-
if
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
397
|
+
if success? or status == 304
|
398
|
+
if etag_matches? env['HTTP_IF_NONE_MATCH'], new_resource
|
399
|
+
halt(request.safe? ? 304 : 412)
|
400
|
+
end
|
401
|
+
|
402
|
+
if env['HTTP_IF_MATCH']
|
403
|
+
halt 412 unless etag_matches? env['HTTP_IF_MATCH'], new_resource
|
384
404
|
end
|
385
405
|
end
|
386
406
|
end
|
@@ -445,6 +465,14 @@ module Sinatra
|
|
445
465
|
rescue Exception
|
446
466
|
raise ArgumentError, "unable to convert #{value.inspect} to a Time object"
|
447
467
|
end
|
468
|
+
|
469
|
+
private
|
470
|
+
|
471
|
+
# Helper method checking if a ETag value list includes the current ETag.
|
472
|
+
def etag_matches?(list, new_resource = request.post?)
|
473
|
+
return !new_resource if list == '*'
|
474
|
+
list.to_s.split(/\s*,\s*/).include? response['ETag']
|
475
|
+
end
|
448
476
|
end
|
449
477
|
|
450
478
|
private
|
@@ -634,7 +662,7 @@ module Sinatra
|
|
634
662
|
path, line = settings.caller_locations.first
|
635
663
|
template.new(path, line.to_i, options, &body)
|
636
664
|
else
|
637
|
-
raise ArgumentError
|
665
|
+
raise ArgumentError, "Sorry, don't know how to render #{data.inspect}."
|
638
666
|
end
|
639
667
|
end
|
640
668
|
end
|
@@ -1184,7 +1212,6 @@ module Sinatra
|
|
1184
1212
|
def compile(path)
|
1185
1213
|
keys = []
|
1186
1214
|
if path.respond_to? :to_str
|
1187
|
-
special_chars = %w{. + ( ) $}
|
1188
1215
|
pattern = path.to_str.gsub(/[^\?\%\\\/\:\*\w]/) { |c| encoded(c) }
|
1189
1216
|
pattern.gsub! /((:\w+)|\*)/ do |match|
|
1190
1217
|
if match == "*"
|
@@ -1333,7 +1360,7 @@ module Sinatra
|
|
1333
1360
|
|
1334
1361
|
def setup_protection(builder)
|
1335
1362
|
return unless protection?
|
1336
|
-
options = Hash === protection ? protection.dup : {}
|
1363
|
+
options = Hash === protection ? protection.dup : {:except => [:escaped_params]}
|
1337
1364
|
options[:except] = Array options[:except]
|
1338
1365
|
options[:except] += [:session_hijacking, :remote_token] unless sessions?
|
1339
1366
|
builder.use Rack::Protection, options
|
data/lib/sinatra/main.rb
CHANGED
data/lib/sinatra/version.rb
CHANGED
data/test/filter_test.rb
CHANGED
@@ -97,6 +97,17 @@ class BeforeFilterTest < Test::Unit::TestCase
|
|
97
97
|
assert_equal 'cool', body
|
98
98
|
end
|
99
99
|
|
100
|
+
it "properly unescapes parameters" do
|
101
|
+
mock_app {
|
102
|
+
before { @foo = params['foo'] }
|
103
|
+
get('/foo') { @foo }
|
104
|
+
}
|
105
|
+
|
106
|
+
get '/foo?foo=bar%3Abaz%2Fbend'
|
107
|
+
assert ok?
|
108
|
+
assert_equal 'bar:baz/bend', body
|
109
|
+
end
|
110
|
+
|
100
111
|
it "runs filters defined in superclasses" do
|
101
112
|
base = Class.new(Sinatra::Base)
|
102
113
|
base.before { @foo = 'hello from superclass' }
|
data/test/helper.rb
CHANGED
@@ -72,6 +72,10 @@ class Test::Unit::TestCase
|
|
72
72
|
assert_equal value.lstrip.gsub(/\s*\n\s*/, ""), body.lstrip.gsub(/\s*\n\s*/, "")
|
73
73
|
end
|
74
74
|
|
75
|
+
def assert_status(expected)
|
76
|
+
assert_equal Integer(expected), Integer(status)
|
77
|
+
end
|
78
|
+
|
75
79
|
def assert_like(a,b)
|
76
80
|
pattern = /id=['"][^"']*["']|\s+/
|
77
81
|
assert_equal a.strip.gsub(pattern, ""), b.strip.gsub(pattern, "")
|
data/test/helpers_test.rb
CHANGED
@@ -858,6 +858,20 @@ class HelpersTest < Test::Unit::TestCase
|
|
858
858
|
assert ! response['Last-Modified']
|
859
859
|
end
|
860
860
|
|
861
|
+
it 'does not change a status other than 200' do
|
862
|
+
mock_app do
|
863
|
+
get '/' do
|
864
|
+
status 299
|
865
|
+
last_modified Time.at(0)
|
866
|
+
'ok'
|
867
|
+
end
|
868
|
+
end
|
869
|
+
|
870
|
+
get('/', {}, 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 26 Sep 2030 23:43:52 GMT')
|
871
|
+
assert_status 299
|
872
|
+
assert_body 'ok'
|
873
|
+
end
|
874
|
+
|
861
875
|
[Time.now, DateTime.now, Date.today, Time.now.to_i,
|
862
876
|
Struct.new(:to_time).new(Time.now) ].each do |last_modified_time|
|
863
877
|
describe "with #{last_modified_time.class.name}" do
|
@@ -955,74 +969,641 @@ class HelpersTest < Test::Unit::TestCase
|
|
955
969
|
assert_equal '', body
|
956
970
|
end
|
957
971
|
end
|
972
|
+
|
973
|
+
context "If-Unmodified-Since" do
|
974
|
+
it 'results in 200 if resource has not been modified' do
|
975
|
+
get '/', {}, { 'HTTP_IF_UNMODIFIED_SINCE' => 'Sun, 26 Sep 2030 23:43:52 GMT' }
|
976
|
+
assert_equal 200, status
|
977
|
+
assert_equal 'Boo!', body
|
978
|
+
end
|
979
|
+
|
980
|
+
it 'results in 412 if resource has been modified' do
|
981
|
+
get '/', {}, { 'HTTP_IF_UNMODIFIED_SINCE' => Time.at(0).httpdate }
|
982
|
+
assert_equal 412, status
|
983
|
+
assert_equal '', body
|
984
|
+
end
|
985
|
+
end
|
958
986
|
end
|
959
987
|
end
|
960
988
|
end
|
961
989
|
|
962
990
|
describe 'etag' do
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
991
|
+
context "safe requests" do
|
992
|
+
it 'returns 200 for normal requests' do
|
993
|
+
mock_app do
|
994
|
+
get '/' do
|
995
|
+
etag 'foo'
|
996
|
+
'ok'
|
997
|
+
end
|
969
998
|
end
|
970
999
|
|
971
|
-
|
972
|
-
|
973
|
-
|
1000
|
+
get('/')
|
1001
|
+
assert_status 200
|
1002
|
+
assert_body 'ok'
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
context "If-None-Match" do
|
1006
|
+
it 'returns 304 when If-None-Match is *' do
|
1007
|
+
mock_app do
|
1008
|
+
get '/' do
|
1009
|
+
etag 'foo'
|
1010
|
+
'ok'
|
1011
|
+
end
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
get('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
|
1015
|
+
assert_status 304
|
1016
|
+
assert_body ''
|
974
1017
|
end
|
975
|
-
}
|
976
|
-
end
|
977
1018
|
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
1019
|
+
it 'returns 200 when If-None-Match is * for new resources' do
|
1020
|
+
mock_app do
|
1021
|
+
get '/' do
|
1022
|
+
etag 'foo', :new_resource => true
|
1023
|
+
'ok'
|
1024
|
+
end
|
1025
|
+
end
|
982
1026
|
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
end
|
1027
|
+
get('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
|
1028
|
+
assert_status 200
|
1029
|
+
assert_body 'ok'
|
1030
|
+
end
|
988
1031
|
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
1032
|
+
it 'returns 304 when If-None-Match is * for existing resources' do
|
1033
|
+
mock_app do
|
1034
|
+
get '/' do
|
1035
|
+
etag 'foo', :new_resource => false
|
1036
|
+
'ok'
|
1037
|
+
end
|
1038
|
+
end
|
994
1039
|
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
end
|
1040
|
+
get('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
|
1041
|
+
assert_status 304
|
1042
|
+
assert_body ''
|
1043
|
+
end
|
1000
1044
|
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1045
|
+
it 'returns 304 when If-None-Match is the etag' do
|
1046
|
+
mock_app do
|
1047
|
+
get '/' do
|
1048
|
+
etag 'foo'
|
1049
|
+
'ok'
|
1050
|
+
end
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"')
|
1054
|
+
assert_status 304
|
1055
|
+
assert_body ''
|
1056
|
+
end
|
1057
|
+
|
1058
|
+
it 'returns 304 when If-None-Match includes the etag' do
|
1059
|
+
mock_app do
|
1060
|
+
get '/' do
|
1061
|
+
etag 'foo'
|
1062
|
+
'ok'
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar", "foo"')
|
1067
|
+
assert_status 304
|
1068
|
+
assert_body ''
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
it 'returns 200 when If-None-Match does not include the etag' do
|
1072
|
+
mock_app do
|
1073
|
+
get '/' do
|
1074
|
+
etag 'foo'
|
1075
|
+
'ok'
|
1076
|
+
end
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"')
|
1080
|
+
assert_status 200
|
1081
|
+
assert_body 'ok'
|
1082
|
+
end
|
1083
|
+
|
1084
|
+
it 'ignores If-Modified-Since if If-None-Match does not match' do
|
1085
|
+
mock_app do
|
1086
|
+
get '/' do
|
1087
|
+
etag 'foo'
|
1088
|
+
last_modified Time.at(0)
|
1089
|
+
'ok'
|
1090
|
+
end
|
1091
|
+
end
|
1092
|
+
|
1093
|
+
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"')
|
1094
|
+
assert_status 200
|
1095
|
+
assert_body 'ok'
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
it 'does not change a status code other than 2xx or 304' do
|
1099
|
+
mock_app do
|
1100
|
+
get '/' do
|
1101
|
+
status 499
|
1102
|
+
etag 'foo'
|
1103
|
+
'ok'
|
1104
|
+
end
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"')
|
1108
|
+
assert_status 499
|
1109
|
+
assert_body 'ok'
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
it 'does change 2xx status codes' do
|
1113
|
+
mock_app do
|
1114
|
+
get '/' do
|
1115
|
+
status 299
|
1116
|
+
etag 'foo'
|
1117
|
+
'ok'
|
1118
|
+
end
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"')
|
1122
|
+
assert_status 304
|
1123
|
+
assert_body ''
|
1124
|
+
end
|
1125
|
+
|
1126
|
+
it 'does not send a body on 304 status codes' do
|
1127
|
+
mock_app do
|
1128
|
+
get '/' do
|
1129
|
+
status 304
|
1130
|
+
etag 'foo'
|
1131
|
+
'ok'
|
1132
|
+
end
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"')
|
1136
|
+
assert_status 304
|
1137
|
+
assert_body ''
|
1138
|
+
end
|
1139
|
+
end
|
1140
|
+
|
1141
|
+
context "If-Match" do
|
1142
|
+
it 'returns 200 when If-Match is the etag' do
|
1143
|
+
mock_app do
|
1144
|
+
get '/' do
|
1145
|
+
etag 'foo'
|
1146
|
+
'ok'
|
1147
|
+
end
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
get('/', {}, 'HTTP_IF_MATCH' => '"foo"')
|
1151
|
+
assert_status 200
|
1152
|
+
assert_body 'ok'
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
it 'returns 200 when If-Match includes the etag' do
|
1156
|
+
mock_app do
|
1157
|
+
get '/' do
|
1158
|
+
etag 'foo'
|
1159
|
+
'ok'
|
1160
|
+
end
|
1161
|
+
end
|
1162
|
+
|
1163
|
+
get('/', {}, 'HTTP_IF_MATCH' => '"foo", "bar"')
|
1164
|
+
assert_status 200
|
1165
|
+
assert_body 'ok'
|
1166
|
+
end
|
1167
|
+
|
1168
|
+
it 'returns 200 when If-Match is *' do
|
1169
|
+
mock_app do
|
1170
|
+
get '/' do
|
1171
|
+
etag 'foo'
|
1172
|
+
'ok'
|
1173
|
+
end
|
1174
|
+
end
|
1175
|
+
|
1176
|
+
get('/', {}, 'HTTP_IF_MATCH' => '*')
|
1177
|
+
assert_status 200
|
1178
|
+
assert_body 'ok'
|
1179
|
+
end
|
1180
|
+
|
1181
|
+
it 'returns 412 when If-Match is * for new resources' do
|
1182
|
+
mock_app do
|
1183
|
+
get '/' do
|
1184
|
+
etag 'foo', :new_resource => true
|
1185
|
+
'ok'
|
1186
|
+
end
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
get('/', {}, 'HTTP_IF_MATCH' => '*')
|
1190
|
+
assert_status 412
|
1191
|
+
assert_body ''
|
1192
|
+
end
|
1193
|
+
|
1194
|
+
it 'returns 200 when If-Match is * for existing resources' do
|
1195
|
+
mock_app do
|
1196
|
+
get '/' do
|
1197
|
+
etag 'foo', :new_resource => false
|
1198
|
+
'ok'
|
1199
|
+
end
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
get('/', {}, 'HTTP_IF_MATCH' => '*')
|
1203
|
+
assert_status 200
|
1204
|
+
assert_body 'ok'
|
1205
|
+
end
|
1206
|
+
|
1207
|
+
it 'returns 412 when If-Match does not include the etag' do
|
1208
|
+
mock_app do
|
1209
|
+
get '/' do
|
1210
|
+
etag 'foo'
|
1211
|
+
'ok'
|
1212
|
+
end
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
get('/', {}, 'HTTP_IF_MATCH' => '"bar"')
|
1216
|
+
assert_status 412
|
1217
|
+
assert_body ''
|
1218
|
+
end
|
1219
|
+
end
|
1005
1220
|
end
|
1006
1221
|
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1222
|
+
context "idempotent requests" do
|
1223
|
+
it 'returns 200 for normal requests' do
|
1224
|
+
mock_app do
|
1225
|
+
put '/' do
|
1226
|
+
etag 'foo'
|
1227
|
+
'ok'
|
1228
|
+
end
|
1229
|
+
end
|
1230
|
+
|
1231
|
+
put('/')
|
1232
|
+
assert_status 200
|
1233
|
+
assert_body 'ok'
|
1234
|
+
end
|
1235
|
+
|
1236
|
+
context "If-None-Match" do
|
1237
|
+
it 'returns 412 when If-None-Match is *' do
|
1238
|
+
mock_app do
|
1239
|
+
put '/' do
|
1240
|
+
etag 'foo'
|
1241
|
+
'ok'
|
1242
|
+
end
|
1243
|
+
end
|
1244
|
+
|
1245
|
+
put('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
|
1246
|
+
assert_status 412
|
1247
|
+
assert_body ''
|
1248
|
+
end
|
1249
|
+
|
1250
|
+
it 'returns 200 when If-None-Match is * for new resources' do
|
1251
|
+
mock_app do
|
1252
|
+
put '/' do
|
1253
|
+
etag 'foo', :new_resource => true
|
1254
|
+
'ok'
|
1255
|
+
end
|
1256
|
+
end
|
1257
|
+
|
1258
|
+
put('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
|
1259
|
+
assert_status 200
|
1260
|
+
assert_body 'ok'
|
1261
|
+
end
|
1262
|
+
|
1263
|
+
it 'returns 412 when If-None-Match is * for existing resources' do
|
1264
|
+
mock_app do
|
1265
|
+
put '/' do
|
1266
|
+
etag 'foo', :new_resource => false
|
1267
|
+
'ok'
|
1268
|
+
end
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
put('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
|
1272
|
+
assert_status 412
|
1273
|
+
assert_body ''
|
1274
|
+
end
|
1275
|
+
|
1276
|
+
it 'returns 412 when If-None-Match is the etag' do
|
1277
|
+
mock_app do
|
1278
|
+
put '/' do
|
1279
|
+
etag 'foo'
|
1280
|
+
'ok'
|
1281
|
+
end
|
1282
|
+
end
|
1283
|
+
|
1284
|
+
put('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"')
|
1285
|
+
assert_status 412
|
1286
|
+
assert_body ''
|
1287
|
+
end
|
1288
|
+
|
1289
|
+
it 'returns 412 when If-None-Match includes the etag' do
|
1290
|
+
mock_app do
|
1291
|
+
put '/' do
|
1292
|
+
etag 'foo'
|
1293
|
+
'ok'
|
1294
|
+
end
|
1295
|
+
end
|
1296
|
+
|
1297
|
+
put('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar", "foo"')
|
1298
|
+
assert_status 412
|
1299
|
+
assert_body ''
|
1300
|
+
end
|
1301
|
+
|
1302
|
+
it 'returns 200 when If-None-Match does not include the etag' do
|
1303
|
+
mock_app do
|
1304
|
+
put '/' do
|
1305
|
+
etag 'foo'
|
1306
|
+
'ok'
|
1307
|
+
end
|
1308
|
+
end
|
1309
|
+
|
1310
|
+
put('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"')
|
1311
|
+
assert_status 200
|
1312
|
+
assert_body 'ok'
|
1313
|
+
end
|
1314
|
+
|
1315
|
+
it 'ignores If-Modified-Since if If-None-Match does not match' do
|
1316
|
+
mock_app do
|
1317
|
+
put '/' do
|
1318
|
+
etag 'foo'
|
1319
|
+
last_modified Time.at(0)
|
1320
|
+
'ok'
|
1321
|
+
end
|
1322
|
+
end
|
1323
|
+
|
1324
|
+
put('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"')
|
1325
|
+
assert_status 200
|
1326
|
+
assert_body 'ok'
|
1327
|
+
end
|
1328
|
+
end
|
1329
|
+
|
1330
|
+
context "If-Match" do
|
1331
|
+
it 'returns 200 when If-Match is the etag' do
|
1332
|
+
mock_app do
|
1333
|
+
put '/' do
|
1334
|
+
etag 'foo'
|
1335
|
+
'ok'
|
1336
|
+
end
|
1337
|
+
end
|
1338
|
+
|
1339
|
+
put('/', {}, 'HTTP_IF_MATCH' => '"foo"')
|
1340
|
+
assert_status 200
|
1341
|
+
assert_body 'ok'
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
it 'returns 200 when If-Match includes the etag' do
|
1345
|
+
mock_app do
|
1346
|
+
put '/' do
|
1347
|
+
etag 'foo'
|
1348
|
+
'ok'
|
1349
|
+
end
|
1350
|
+
end
|
1351
|
+
|
1352
|
+
put('/', {}, 'HTTP_IF_MATCH' => '"foo", "bar"')
|
1353
|
+
assert_status 200
|
1354
|
+
assert_body 'ok'
|
1355
|
+
end
|
1356
|
+
|
1357
|
+
it 'returns 200 when If-Match is *' do
|
1358
|
+
mock_app do
|
1359
|
+
put '/' do
|
1360
|
+
etag 'foo'
|
1361
|
+
'ok'
|
1362
|
+
end
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
put('/', {}, 'HTTP_IF_MATCH' => '*')
|
1366
|
+
assert_status 200
|
1367
|
+
assert_body 'ok'
|
1368
|
+
end
|
1369
|
+
|
1370
|
+
it 'returns 412 when If-Match is * for new resources' do
|
1371
|
+
mock_app do
|
1372
|
+
put '/' do
|
1373
|
+
etag 'foo', :new_resource => true
|
1374
|
+
'ok'
|
1375
|
+
end
|
1376
|
+
end
|
1377
|
+
|
1378
|
+
put('/', {}, 'HTTP_IF_MATCH' => '*')
|
1379
|
+
assert_status 412
|
1380
|
+
assert_body ''
|
1381
|
+
end
|
1382
|
+
|
1383
|
+
it 'returns 200 when If-Match is * for existing resources' do
|
1384
|
+
mock_app do
|
1385
|
+
put '/' do
|
1386
|
+
etag 'foo', :new_resource => false
|
1387
|
+
'ok'
|
1388
|
+
end
|
1389
|
+
end
|
1390
|
+
|
1391
|
+
put('/', {}, 'HTTP_IF_MATCH' => '*')
|
1392
|
+
assert_status 200
|
1393
|
+
assert_body 'ok'
|
1394
|
+
end
|
1395
|
+
|
1396
|
+
it 'returns 412 when If-Match does not include the etag' do
|
1397
|
+
mock_app do
|
1398
|
+
put '/' do
|
1399
|
+
etag 'foo'
|
1400
|
+
'ok'
|
1401
|
+
end
|
1402
|
+
end
|
1403
|
+
|
1404
|
+
put('/', {}, 'HTTP_IF_MATCH' => '"bar"')
|
1405
|
+
assert_status 412
|
1406
|
+
assert_body ''
|
1407
|
+
end
|
1408
|
+
end
|
1011
1409
|
end
|
1012
1410
|
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1411
|
+
context "post requests" do
|
1412
|
+
it 'returns 200 for normal requests' do
|
1413
|
+
mock_app do
|
1414
|
+
post '/' do
|
1415
|
+
etag 'foo'
|
1416
|
+
'ok'
|
1417
|
+
end
|
1418
|
+
end
|
1419
|
+
|
1420
|
+
post('/')
|
1421
|
+
assert_status 200
|
1422
|
+
assert_body 'ok'
|
1423
|
+
end
|
1424
|
+
|
1425
|
+
context "If-None-Match" do
|
1426
|
+
it 'returns 200 when If-None-Match is *' do
|
1427
|
+
mock_app do
|
1428
|
+
post '/' do
|
1429
|
+
etag 'foo'
|
1430
|
+
'ok'
|
1431
|
+
end
|
1432
|
+
end
|
1433
|
+
|
1434
|
+
post('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
|
1435
|
+
assert_status 200
|
1436
|
+
assert_body 'ok'
|
1437
|
+
end
|
1438
|
+
|
1439
|
+
it 'returns 200 when If-None-Match is * for new resources' do
|
1440
|
+
mock_app do
|
1441
|
+
post '/' do
|
1442
|
+
etag 'foo', :new_resource => true
|
1443
|
+
'ok'
|
1444
|
+
end
|
1445
|
+
end
|
1446
|
+
|
1447
|
+
post('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
|
1448
|
+
assert_status 200
|
1449
|
+
assert_body 'ok'
|
1450
|
+
end
|
1451
|
+
|
1452
|
+
it 'returns 412 when If-None-Match is * for existing resources' do
|
1453
|
+
mock_app do
|
1454
|
+
post '/' do
|
1455
|
+
etag 'foo', :new_resource => false
|
1456
|
+
'ok'
|
1457
|
+
end
|
1458
|
+
end
|
1459
|
+
|
1460
|
+
post('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
|
1461
|
+
assert_status 412
|
1462
|
+
assert_body ''
|
1463
|
+
end
|
1464
|
+
|
1465
|
+
it 'returns 412 when If-None-Match is the etag' do
|
1466
|
+
mock_app do
|
1467
|
+
post '/' do
|
1468
|
+
etag 'foo'
|
1469
|
+
'ok'
|
1470
|
+
end
|
1471
|
+
end
|
1472
|
+
|
1473
|
+
post('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"')
|
1474
|
+
assert_status 412
|
1475
|
+
assert_body ''
|
1476
|
+
end
|
1477
|
+
|
1478
|
+
it 'returns 412 when If-None-Match includes the etag' do
|
1479
|
+
mock_app do
|
1480
|
+
post '/' do
|
1481
|
+
etag 'foo'
|
1482
|
+
'ok'
|
1483
|
+
end
|
1484
|
+
end
|
1485
|
+
|
1486
|
+
post('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar", "foo"')
|
1487
|
+
assert_status 412
|
1488
|
+
assert_body ''
|
1489
|
+
end
|
1490
|
+
|
1491
|
+
it 'returns 200 when If-None-Match does not include the etag' do
|
1492
|
+
mock_app do
|
1493
|
+
post '/' do
|
1494
|
+
etag 'foo'
|
1495
|
+
'ok'
|
1496
|
+
end
|
1497
|
+
end
|
1498
|
+
|
1499
|
+
post('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"')
|
1500
|
+
assert_status 200
|
1501
|
+
assert_body 'ok'
|
1502
|
+
end
|
1503
|
+
|
1504
|
+
it 'ignores If-Modified-Since if If-None-Match does not match' do
|
1505
|
+
mock_app do
|
1506
|
+
post '/' do
|
1507
|
+
etag 'foo'
|
1508
|
+
last_modified Time.at(0)
|
1509
|
+
'ok'
|
1510
|
+
end
|
1511
|
+
end
|
1512
|
+
|
1513
|
+
post('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"')
|
1514
|
+
assert_status 200
|
1515
|
+
assert_body 'ok'
|
1516
|
+
end
|
1517
|
+
end
|
1518
|
+
|
1519
|
+
context "If-Match" do
|
1520
|
+
it 'returns 200 when If-Match is the etag' do
|
1521
|
+
mock_app do
|
1522
|
+
post '/' do
|
1523
|
+
etag 'foo'
|
1524
|
+
'ok'
|
1525
|
+
end
|
1526
|
+
end
|
1527
|
+
|
1528
|
+
post('/', {}, 'HTTP_IF_MATCH' => '"foo"')
|
1529
|
+
assert_status 200
|
1530
|
+
assert_body 'ok'
|
1531
|
+
end
|
1532
|
+
|
1533
|
+
it 'returns 200 when If-Match includes the etag' do
|
1534
|
+
mock_app do
|
1535
|
+
post '/' do
|
1536
|
+
etag 'foo'
|
1537
|
+
'ok'
|
1538
|
+
end
|
1539
|
+
end
|
1540
|
+
|
1541
|
+
post('/', {}, 'HTTP_IF_MATCH' => '"foo", "bar"')
|
1542
|
+
assert_status 200
|
1543
|
+
assert_body 'ok'
|
1544
|
+
end
|
1545
|
+
|
1546
|
+
it 'returns 412 when If-Match is *' do
|
1547
|
+
mock_app do
|
1548
|
+
post '/' do
|
1549
|
+
etag 'foo'
|
1550
|
+
'ok'
|
1551
|
+
end
|
1552
|
+
end
|
1553
|
+
|
1554
|
+
post('/', {}, 'HTTP_IF_MATCH' => '*')
|
1555
|
+
assert_status 412
|
1556
|
+
assert_body ''
|
1557
|
+
end
|
1558
|
+
|
1559
|
+
it 'returns 412 when If-Match is * for new resources' do
|
1560
|
+
mock_app do
|
1561
|
+
post '/' do
|
1562
|
+
etag 'foo', :new_resource => true
|
1563
|
+
'ok'
|
1564
|
+
end
|
1565
|
+
end
|
1566
|
+
|
1567
|
+
post('/', {}, 'HTTP_IF_MATCH' => '*')
|
1568
|
+
assert_status 412
|
1569
|
+
assert_body ''
|
1570
|
+
end
|
1571
|
+
|
1572
|
+
it 'returns 200 when If-Match is * for existing resources' do
|
1573
|
+
mock_app do
|
1574
|
+
post '/' do
|
1575
|
+
etag 'foo', :new_resource => false
|
1576
|
+
'ok'
|
1577
|
+
end
|
1578
|
+
end
|
1579
|
+
|
1580
|
+
post('/', {}, 'HTTP_IF_MATCH' => '*')
|
1581
|
+
assert_status 200
|
1582
|
+
assert_body 'ok'
|
1583
|
+
end
|
1584
|
+
|
1585
|
+
it 'returns 412 when If-Match does not include the etag' do
|
1586
|
+
mock_app do
|
1587
|
+
post '/' do
|
1588
|
+
etag 'foo'
|
1589
|
+
'ok'
|
1590
|
+
end
|
1591
|
+
end
|
1592
|
+
|
1593
|
+
post('/', {}, 'HTTP_IF_MATCH' => '"bar"')
|
1594
|
+
assert_status 412
|
1595
|
+
assert_body ''
|
1596
|
+
end
|
1597
|
+
end
|
1017
1598
|
end
|
1018
1599
|
|
1019
1600
|
it 'uses a weak etag with the :weak option' do
|
1020
|
-
mock_app
|
1601
|
+
mock_app do
|
1021
1602
|
get '/' do
|
1022
1603
|
etag 'FOO', :weak
|
1023
1604
|
"that's weak, dude."
|
1024
1605
|
end
|
1025
|
-
|
1606
|
+
end
|
1026
1607
|
get '/'
|
1027
1608
|
assert_equal 'W/"FOO"', response['ETag']
|
1028
1609
|
end
|
data/test/rack_test.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.expand_path('../helper', __FILE__)
|
2
|
+
require 'rack'
|
3
|
+
|
4
|
+
class RackTest < Test::Unit::TestCase
|
5
|
+
setup do
|
6
|
+
@foo = Sinatra.new { get('/foo') { 'foo' }}
|
7
|
+
@bar = Sinatra.new { get('/bar') { 'bar' }}
|
8
|
+
end
|
9
|
+
|
10
|
+
def build(*middleware)
|
11
|
+
endpoint = middleware.pop
|
12
|
+
@app = Rack::Builder.app do
|
13
|
+
middleware.each { |m| use m }
|
14
|
+
run endpoint
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def check(*middleware)
|
19
|
+
build(*middleware)
|
20
|
+
assert get('/foo').ok?
|
21
|
+
assert_body 'foo'
|
22
|
+
assert get('/bar').ok?
|
23
|
+
assert_body 'bar'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'works as middleware in front of Rack::Lock, with lock enabled' do
|
27
|
+
@foo.enable :lock
|
28
|
+
check(@foo, Rack::Lock, @bar)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'works as middleware behind Rack::Lock, with lock enabled' do
|
32
|
+
@foo.enable :lock
|
33
|
+
check(Rack::Lock, @foo, @bar)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'works as middleware in front of Rack::Lock, with lock disabled' do
|
37
|
+
@foo.disable :lock
|
38
|
+
check(@foo, Rack::Lock, @bar)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'works as middleware behind Rack::Lock, with lock disabled' do
|
42
|
+
@foo.disable :lock
|
43
|
+
check(Rack::Lock, @foo, @bar)
|
44
|
+
end
|
45
|
+
end
|
metadata
CHANGED
@@ -1,16 +1,10 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: sinatra
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.3.0.g
|
5
5
|
prerelease: 6
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 3
|
9
|
-
- 0
|
10
|
-
- f
|
11
|
-
version: 1.3.0.f
|
12
6
|
platform: ruby
|
13
|
-
authors:
|
7
|
+
authors:
|
14
8
|
- Blake Mizerany
|
15
9
|
- Ryan Tomayko
|
16
10
|
- Simon Rozet
|
@@ -18,62 +12,47 @@ authors:
|
|
18
12
|
autorequire:
|
19
13
|
bindir: bin
|
20
14
|
cert_chain: []
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
dependencies:
|
25
|
-
- !ruby/object:Gem::Dependency
|
15
|
+
date: 2011-09-25 00:00:00.000000000Z
|
16
|
+
dependencies:
|
17
|
+
- !ruby/object:Gem::Dependency
|
26
18
|
name: rack
|
27
|
-
|
28
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
requirement: &2158234720 !ruby/object:Gem::Requirement
|
29
20
|
none: false
|
30
|
-
requirements:
|
21
|
+
requirements:
|
31
22
|
- - ~>
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
|
34
|
-
segments:
|
35
|
-
- 1
|
36
|
-
- 3
|
37
|
-
version: "1.3"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: '1.3'
|
38
25
|
type: :runtime
|
39
|
-
version_requirements: *id001
|
40
|
-
- !ruby/object:Gem::Dependency
|
41
|
-
name: rack-protection
|
42
26
|
prerelease: false
|
43
|
-
|
27
|
+
version_requirements: *2158234720
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rack-protection
|
30
|
+
requirement: &2158234220 !ruby/object:Gem::Requirement
|
44
31
|
none: false
|
45
|
-
requirements:
|
32
|
+
requirements:
|
46
33
|
- - ~>
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
|
49
|
-
segments:
|
50
|
-
- 1
|
51
|
-
- 1
|
52
|
-
version: "1.1"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '1.1'
|
53
36
|
type: :runtime
|
54
|
-
version_requirements: *id002
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: tilt
|
57
37
|
prerelease: false
|
58
|
-
|
38
|
+
version_requirements: *2158234220
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
name: tilt
|
41
|
+
requirement: &2158233760 !ruby/object:Gem::Requirement
|
59
42
|
none: false
|
60
|
-
requirements:
|
43
|
+
requirements:
|
61
44
|
- - ~>
|
62
|
-
- !ruby/object:Gem::Version
|
63
|
-
|
64
|
-
segments:
|
65
|
-
- 1
|
66
|
-
- 3
|
67
|
-
version: "1.3"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.3'
|
68
47
|
type: :runtime
|
69
|
-
|
70
|
-
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: *2158233760
|
50
|
+
description: Sinatra is a DSL for quickly creating web applications in Ruby with minimal
|
51
|
+
effort.
|
71
52
|
email: sinatrarb@googlegroups.com
|
72
53
|
executables: []
|
73
|
-
|
74
54
|
extensions: []
|
75
|
-
|
76
|
-
extra_rdoc_files:
|
55
|
+
extra_rdoc_files:
|
77
56
|
- README.de.rdoc
|
78
57
|
- README.es.rdoc
|
79
58
|
- README.fr.rdoc
|
@@ -85,7 +64,7 @@ extra_rdoc_files:
|
|
85
64
|
- README.ru.rdoc
|
86
65
|
- README.zh.rdoc
|
87
66
|
- LICENSE
|
88
|
-
files:
|
67
|
+
files:
|
89
68
|
- .gitignore
|
90
69
|
- .travis.yml
|
91
70
|
- .yardopts
|
@@ -133,6 +112,7 @@ files:
|
|
133
112
|
- test/middleware_test.rb
|
134
113
|
- test/nokogiri_test.rb
|
135
114
|
- test/public/favicon.ico
|
115
|
+
- test/rack_test.rb
|
136
116
|
- test/radius_test.rb
|
137
117
|
- test/rdoc_test.rb
|
138
118
|
- test/readme_test.rb
|
@@ -191,48 +171,40 @@ files:
|
|
191
171
|
- test/views/layout2.test
|
192
172
|
- test/views/nested.str
|
193
173
|
- test/views/utf8.erb
|
194
|
-
has_rdoc: true
|
195
174
|
homepage: http://www.sinatrarb.com/
|
196
175
|
licenses: []
|
197
|
-
|
198
176
|
post_install_message:
|
199
|
-
rdoc_options:
|
177
|
+
rdoc_options:
|
200
178
|
- --line-numbers
|
201
179
|
- --inline-source
|
202
180
|
- --title
|
203
181
|
- Sinatra
|
204
182
|
- --main
|
205
183
|
- README.rdoc
|
206
|
-
require_paths:
|
184
|
+
require_paths:
|
207
185
|
- lib
|
208
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
186
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
209
187
|
none: false
|
210
|
-
requirements:
|
211
|
-
- -
|
212
|
-
- !ruby/object:Gem::Version
|
213
|
-
|
214
|
-
segments:
|
188
|
+
requirements:
|
189
|
+
- - ! '>='
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
version: '0'
|
192
|
+
segments:
|
215
193
|
- 0
|
216
|
-
|
217
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
194
|
+
hash: -519161154716123522
|
195
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
218
196
|
none: false
|
219
|
-
requirements:
|
220
|
-
- -
|
221
|
-
- !ruby/object:Gem::Version
|
222
|
-
hash: 1960248522488440439
|
223
|
-
segments:
|
224
|
-
- 1
|
225
|
-
- 3
|
226
|
-
- 1
|
197
|
+
requirements:
|
198
|
+
- - ! '>'
|
199
|
+
- !ruby/object:Gem::Version
|
227
200
|
version: 1.3.1
|
228
201
|
requirements: []
|
229
|
-
|
230
202
|
rubyforge_project:
|
231
|
-
rubygems_version: 1.
|
203
|
+
rubygems_version: 1.8.6
|
232
204
|
signing_key:
|
233
205
|
specification_version: 3
|
234
206
|
summary: Classy web-development dressed in a DSL
|
235
|
-
test_files:
|
207
|
+
test_files:
|
236
208
|
- test/base_test.rb
|
237
209
|
- test/builder_test.rb
|
238
210
|
- test/coffee_test.rb
|
@@ -251,6 +223,7 @@ test_files:
|
|
251
223
|
- test/markdown_test.rb
|
252
224
|
- test/middleware_test.rb
|
253
225
|
- test/nokogiri_test.rb
|
226
|
+
- test/rack_test.rb
|
254
227
|
- test/radius_test.rb
|
255
228
|
- test/rdoc_test.rb
|
256
229
|
- test/readme_test.rb
|