sinatra 1.1.4 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +5 -1
- data/CHANGES +47 -2
- data/Gemfile +53 -0
- data/README.de.rdoc +732 -85
- data/README.es.rdoc +725 -75
- data/README.fr.rdoc +29 -16
- data/README.hu.rdoc +4 -4
- data/README.jp.rdoc +29 -16
- data/README.pt-br.rdoc +6 -6
- data/README.rdoc +664 -91
- data/README.ru.rdoc +257 -75
- data/README.zh.rdoc +889 -111
- data/Rakefile +7 -32
- data/lib/sinatra/base.rb +133 -66
- data/lib/sinatra/showexceptions.rb +25 -0
- data/sinatra.gemspec +10 -18
- data/test/builder_test.rb +6 -0
- data/test/coffee_test.rb +1 -1
- data/test/encoding_test.rb +4 -3
- data/test/erubis_test.rb +6 -0
- data/test/filter_test.rb +105 -1
- data/test/haml_test.rb +2 -1
- data/test/helper.rb +2 -0
- data/test/helpers_test.rb +105 -13
- data/test/less_test.rb +6 -0
- data/test/liquid_test.rb +2 -1
- data/test/markaby_test.rb +23 -1
- data/test/markdown_test.rb +3 -2
- data/test/nokogiri_test.rb +2 -1
- data/test/radius_test.rb +3 -2
- data/test/rdoc_test.rb +3 -2
- data/test/routing_test.rb +38 -1
- data/test/sass_test.rb +1 -1
- data/test/scss_test.rb +1 -1
- data/test/slim_test.rb +98 -0
- data/test/templates_test.rb +53 -0
- data/test/textile_test.rb +2 -1
- data/test/views/a/in_a.str +1 -0
- data/test/views/{ascii.haml → ascii.erb} +1 -1
- data/test/views/b/in_b.str +1 -0
- data/test/views/hello.slim +1 -0
- data/test/views/layout2.slim +3 -0
- data/test/views/{utf8.haml → utf8.erb} +1 -1
- metadata +42 -161
data/Rakefile
CHANGED
|
@@ -15,15 +15,6 @@ def source_version
|
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
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 }
|
|
25
|
-
end
|
|
26
|
-
|
|
27
18
|
# SPECS ===============================================================
|
|
28
19
|
|
|
29
20
|
task :test do
|
|
@@ -78,33 +69,17 @@ end
|
|
|
78
69
|
# Thanks in announcement ===============================================
|
|
79
70
|
|
|
80
71
|
team = ["Ryan Tomayko", "Blake Mizerany", "Simon Rozet", "Konstantin Haase"]
|
|
81
|
-
desc "list of contributors"
|
|
72
|
+
desc "list of contributors: rake thanks[1.1.0..master,1.1.0..1.1.x]"
|
|
82
73
|
task :thanks, [:release,:backports] do |t, a|
|
|
83
|
-
a.with_defaults :release => "
|
|
84
|
-
:backports => "#{prev_feature}.0..#{prev_feature}.x"
|
|
74
|
+
a.with_defaults :release => "1.1.0..master", :backports => "1.1.0..1.1.x"
|
|
85
75
|
included = `git log --format=format:"%aN\t%s" #{a.release}`.lines.to_a
|
|
86
76
|
excluded = `git log --format=format:"%aN\t%s" #{a.backports}`.lines.to_a
|
|
87
|
-
commits
|
|
88
|
-
authors
|
|
77
|
+
commits = (included - excluded).group_by { |c| c[/^[^\t]+/] }
|
|
78
|
+
authors = commits.keys.sort_by { |n| - commits[n].size } - team
|
|
89
79
|
puts authors[0..-2].join(', ') << " and " << authors.last,
|
|
90
80
|
"(based on commits included in #{a.release}, but not in #{a.backports})"
|
|
91
81
|
end
|
|
92
82
|
|
|
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
83
|
# PACKAGING ============================================================
|
|
109
84
|
|
|
110
85
|
if defined?(Gem)
|
|
@@ -165,12 +140,12 @@ if defined?(Gem)
|
|
|
165
140
|
puts "updated #{f.name}"
|
|
166
141
|
end
|
|
167
142
|
|
|
168
|
-
task 'release' => package('.gem') do
|
|
143
|
+
task 'release' => ['test', package('.gem')] do
|
|
169
144
|
sh <<-SH
|
|
170
145
|
gem install #{package('.gem')} --local &&
|
|
171
146
|
gem push #{package('.gem')} &&
|
|
172
|
-
git
|
|
173
|
-
git
|
|
147
|
+
git add sinatra.gemspec &&
|
|
148
|
+
git commit --allow-empty -m '#{source_version} release' &&
|
|
174
149
|
git tag -s #{source_version} -m '#{source_version} release' &&
|
|
175
150
|
git push && (git push sinatra || true) &&
|
|
176
151
|
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'
|
|
11
11
|
|
|
12
12
|
# The request object. See Rack::Request for more info:
|
|
13
13
|
# http://rack.rubyforge.org/doc/classes/Rack/Request.html
|
|
@@ -29,6 +29,10 @@ module Sinatra
|
|
|
29
29
|
alias secure? ssl?
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
def forwarded?
|
|
33
|
+
@env.include? "HTTP_X_FORWARDED_HOST"
|
|
34
|
+
end
|
|
35
|
+
|
|
32
36
|
def route
|
|
33
37
|
@route ||= begin
|
|
34
38
|
path = Rack::Utils.unescape(path_info)
|
|
@@ -91,24 +95,37 @@ module Sinatra
|
|
|
91
95
|
|
|
92
96
|
# Halt processing and redirect to the URI provided.
|
|
93
97
|
def redirect(uri, *args)
|
|
94
|
-
if not uri =~ /^https?:\/\//
|
|
95
|
-
# According to RFC 2616 section 14.30, "the field value consists of a
|
|
96
|
-
# single absolute URI"
|
|
97
|
-
abs_uri = "#{request.scheme}://#{request.host}"
|
|
98
|
-
|
|
99
|
-
if request.scheme == 'https' && request.port != 443 ||
|
|
100
|
-
request.scheme == 'http' && request.port != 80
|
|
101
|
-
abs_uri << ":#{request.port}"
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
uri = (abs_uri << uri)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
98
|
status 302
|
|
108
|
-
|
|
99
|
+
|
|
100
|
+
# According to RFC 2616 section 14.30, "the field value consists of a
|
|
101
|
+
# single absolute URI"
|
|
102
|
+
response['Location'] = url(uri, settings.absolute_redirects?, settings.prefixed_redirects?)
|
|
109
103
|
halt(*args)
|
|
110
104
|
end
|
|
111
105
|
|
|
106
|
+
# Generates the absolute URI for a given path in the app.
|
|
107
|
+
# Takes Rack routers and reverse proxies into account.
|
|
108
|
+
def uri(addr = nil, absolute = true, add_script_name = true)
|
|
109
|
+
return addr if addr =~ /^https?:\/\//
|
|
110
|
+
uri = [host = ""]
|
|
111
|
+
if absolute
|
|
112
|
+
host << 'http'
|
|
113
|
+
host << 's' if request.secure?
|
|
114
|
+
host << "://"
|
|
115
|
+
if request.forwarded? or request.port != (request.secure? ? 443 : 80)
|
|
116
|
+
host << request.host_with_port
|
|
117
|
+
else
|
|
118
|
+
host << request.host
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
uri << request.script_name.to_s if add_script_name
|
|
122
|
+
uri << (addr ? addr : request.path_info).to_s
|
|
123
|
+
File.join uri
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
alias url uri
|
|
127
|
+
alias to uri
|
|
128
|
+
|
|
112
129
|
# Halt processing and return the error status provided.
|
|
113
130
|
def error(code, body=nil)
|
|
114
131
|
code, body = 500, code.to_str if code.respond_to? :to_str
|
|
@@ -164,7 +181,7 @@ module Sinatra
|
|
|
164
181
|
# Use the contents of the file at +path+ as the response body.
|
|
165
182
|
def send_file(path, opts={})
|
|
166
183
|
stat = File.stat(path)
|
|
167
|
-
last_modified stat.mtime
|
|
184
|
+
last_modified(opts[:last_modified] || stat.mtime)
|
|
168
185
|
|
|
169
186
|
if opts[:type] or not response['Content-Type']
|
|
170
187
|
content_type opts[:type] || File.extname(path), :default => 'application/octet-stream'
|
|
@@ -301,12 +318,12 @@ module Sinatra
|
|
|
301
318
|
def expires(amount, *values)
|
|
302
319
|
values << {} unless values.last.kind_of?(Hash)
|
|
303
320
|
|
|
304
|
-
if amount
|
|
305
|
-
|
|
306
|
-
time = amount.to_time
|
|
307
|
-
else
|
|
321
|
+
if Integer === amount
|
|
322
|
+
time = Time.now + amount
|
|
308
323
|
max_age = amount
|
|
309
|
-
|
|
324
|
+
else
|
|
325
|
+
time = time_for amount
|
|
326
|
+
max_age = time - Time.now
|
|
310
327
|
end
|
|
311
328
|
|
|
312
329
|
values.last.merge!(:max_age => max_age)
|
|
@@ -324,14 +341,7 @@ module Sinatra
|
|
|
324
341
|
# with a '304 Not Modified' response.
|
|
325
342
|
def last_modified(time)
|
|
326
343
|
return unless time
|
|
327
|
-
|
|
328
|
-
time = time.to_time
|
|
329
|
-
else
|
|
330
|
-
## make a best effort to convert something else to a time object
|
|
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
|
|
344
|
+
time = time_for time
|
|
335
345
|
response['Last-Modified'] = time.httpdate
|
|
336
346
|
# compare based on seconds since epoch
|
|
337
347
|
halt 304 if Time.httpdate(request.env['HTTP_IF_MODIFIED_SINCE']).to_i >= time.to_i
|
|
@@ -360,9 +370,39 @@ module Sinatra
|
|
|
360
370
|
end
|
|
361
371
|
end
|
|
362
372
|
|
|
363
|
-
|
|
364
|
-
def back
|
|
373
|
+
# Sugar for redirect (example: redirect back)
|
|
374
|
+
def back
|
|
375
|
+
request.referer
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
private
|
|
365
379
|
|
|
380
|
+
# Ruby 1.8 has no #to_time method.
|
|
381
|
+
# This can be removed and calls to it replaced with to_time,
|
|
382
|
+
# if 1.8 support is dropped.
|
|
383
|
+
def time_for(value)
|
|
384
|
+
if value.respond_to? :to_time
|
|
385
|
+
value.to_time
|
|
386
|
+
elsif Time === value
|
|
387
|
+
value
|
|
388
|
+
elsif value.respond_to? :new_offset
|
|
389
|
+
# DateTime#to_time does the same on 1.9
|
|
390
|
+
d = value.new_offset 0
|
|
391
|
+
t = Time.utc d.year, d.mon, d.mday, d.hour, d.min, d.sec + d.sec_fraction
|
|
392
|
+
t.getlocal
|
|
393
|
+
elsif value.respond_to? :mday
|
|
394
|
+
# Date#to_time does the same on 1.9
|
|
395
|
+
Time.local(value.year, value.mon, value.mday)
|
|
396
|
+
elsif Numeric === value
|
|
397
|
+
Time.at value
|
|
398
|
+
else
|
|
399
|
+
Time.parse value.to_s
|
|
400
|
+
end
|
|
401
|
+
rescue ArgumentError => boom
|
|
402
|
+
raise boom.to_s
|
|
403
|
+
rescue Exception
|
|
404
|
+
raise ArgumentError, "unable to convert #{value.inspect} to a Time object"
|
|
405
|
+
end
|
|
366
406
|
end
|
|
367
407
|
|
|
368
408
|
# Template rendering methods. Each method takes the name of a template
|
|
@@ -374,17 +414,20 @@ module Sinatra
|
|
|
374
414
|
# that will be rendered.
|
|
375
415
|
#
|
|
376
416
|
# Possible options are:
|
|
377
|
-
# :
|
|
378
|
-
#
|
|
379
|
-
#
|
|
380
|
-
#
|
|
417
|
+
# :content_type The content type to use, same arguments as content_type.
|
|
418
|
+
# :layout If set to false, no layout is rendered, otherwise
|
|
419
|
+
# the specified layout is used (Ignored for `sass` and `less`)
|
|
420
|
+
# :layout_engine Engine to use for rendering the layout.
|
|
421
|
+
# :locals A hash with local variables that should be available
|
|
422
|
+
# in the template
|
|
423
|
+
# :scope If set, template is evaluate with the binding of the given
|
|
424
|
+
# object rather than the application instance.
|
|
425
|
+
# :views Views directory to use.
|
|
381
426
|
module Templates
|
|
382
427
|
module ContentTyped
|
|
383
428
|
attr_accessor :content_type
|
|
384
429
|
end
|
|
385
430
|
|
|
386
|
-
include Tilt::CompileSite
|
|
387
|
-
|
|
388
431
|
def erb(template, options={}, locals={})
|
|
389
432
|
render :erb, template, options, locals
|
|
390
433
|
end
|
|
@@ -413,7 +456,8 @@ module Sinatra
|
|
|
413
456
|
end
|
|
414
457
|
|
|
415
458
|
def builder(template=nil, options={}, locals={}, &block)
|
|
416
|
-
|
|
459
|
+
options[:default_content_type] = :xml
|
|
460
|
+
render_ruby(:builder, template, options, locals, &block)
|
|
417
461
|
end
|
|
418
462
|
|
|
419
463
|
def liquid(template, options={}, locals={})
|
|
@@ -436,8 +480,8 @@ module Sinatra
|
|
|
436
480
|
render :radius, template, options, locals
|
|
437
481
|
end
|
|
438
482
|
|
|
439
|
-
def markaby(template, options={}, locals={})
|
|
440
|
-
|
|
483
|
+
def markaby(template=nil, options={}, locals={}, &block)
|
|
484
|
+
render_ruby(:mab, template, options, locals, &block)
|
|
441
485
|
end
|
|
442
486
|
|
|
443
487
|
def coffee(template, options={}, locals={})
|
|
@@ -446,14 +490,26 @@ module Sinatra
|
|
|
446
490
|
end
|
|
447
491
|
|
|
448
492
|
def nokogiri(template=nil, options={}, locals={}, &block)
|
|
449
|
-
options[:
|
|
450
|
-
|
|
493
|
+
options[:default_content_type] = :xml
|
|
494
|
+
render_ruby(:nokogiri, template, options, locals, &block)
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def slim(template, options={}, locals={})
|
|
498
|
+
render :slim, template, options, locals
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
# Calls the given block for every possible template file in views,
|
|
502
|
+
# named name.ext, where ext is registered on engine.
|
|
503
|
+
def find_template(views, name, engine)
|
|
504
|
+
Tilt.mappings.each do |ext, klass|
|
|
505
|
+
next unless klass == engine
|
|
506
|
+
yield ::File.join(views, "#{name}.#{ext}")
|
|
507
|
+
end
|
|
451
508
|
end
|
|
452
509
|
|
|
453
510
|
private
|
|
454
511
|
# logic shared between builder and nokogiri
|
|
455
|
-
def
|
|
456
|
-
options[:default_content_type] = :xml
|
|
512
|
+
def render_ruby(engine, template, options={}, locals={}, &block)
|
|
457
513
|
options, template = template, nil if template.is_a?(Hash)
|
|
458
514
|
template = Proc.new { block } if template.nil?
|
|
459
515
|
render engine, template, options, locals
|
|
@@ -472,19 +528,21 @@ module Sinatra
|
|
|
472
528
|
layout = options.delete(:layout)
|
|
473
529
|
eat_errors = layout.nil?
|
|
474
530
|
layout = @default_layout if layout.nil? or layout == true
|
|
475
|
-
content_type = options.delete(:content_type)
|
|
531
|
+
content_type = options.delete(:content_type) || options.delete(:default_content_type)
|
|
532
|
+
layout_engine = options.delete(:layout_engine) || engine
|
|
533
|
+
scope = options.delete(:scope) || self
|
|
476
534
|
|
|
477
535
|
# compile and render template
|
|
478
536
|
layout_was = @default_layout
|
|
479
537
|
@default_layout = false
|
|
480
538
|
template = compile_template(engine, data, options, views)
|
|
481
|
-
output = template.render(
|
|
539
|
+
output = template.render(scope, locals, &block)
|
|
482
540
|
@default_layout = layout_was
|
|
483
541
|
|
|
484
542
|
# render layout
|
|
485
543
|
if layout
|
|
486
|
-
options = options.merge(:views => views, :layout => false, :eat_errors => eat_errors)
|
|
487
|
-
catch(:layout_missing) { output = render(
|
|
544
|
+
options = options.merge(:views => views, :layout => false, :eat_errors => eat_errors, :scope => scope)
|
|
545
|
+
catch(:layout_missing) { output = render(layout_engine, layout, options, locals) { output }}
|
|
488
546
|
end
|
|
489
547
|
|
|
490
548
|
output.extend(ContentTyped).content_type = content_type if content_type
|
|
@@ -505,10 +563,12 @@ module Sinatra
|
|
|
505
563
|
template.new(path, line.to_i, options) { body }
|
|
506
564
|
else
|
|
507
565
|
found = false
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
566
|
+
find_template(views, data, template) do |file|
|
|
567
|
+
path ||= file # keep the initial path rather than the last one
|
|
568
|
+
if found = File.exists?(file)
|
|
569
|
+
path = file
|
|
570
|
+
break
|
|
571
|
+
end
|
|
512
572
|
end
|
|
513
573
|
throw :layout_missing if eat_errors and not found
|
|
514
574
|
template.new(path, 1, options)
|
|
@@ -956,21 +1016,22 @@ module Sinatra
|
|
|
956
1016
|
# Define a before filter; runs before all requests within the same
|
|
957
1017
|
# context as route handlers and may access/modify the request and
|
|
958
1018
|
# response.
|
|
959
|
-
def before(path = nil, &block)
|
|
960
|
-
add_filter(:before, path, &block)
|
|
1019
|
+
def before(path = nil, options = {}, &block)
|
|
1020
|
+
add_filter(:before, path, options, &block)
|
|
961
1021
|
end
|
|
962
1022
|
|
|
963
1023
|
# Define an after filter; runs after all requests within the same
|
|
964
1024
|
# context as route handlers and may access/modify the request and
|
|
965
1025
|
# response.
|
|
966
|
-
def after(path = nil, &block)
|
|
967
|
-
add_filter(:after, path, &block)
|
|
1026
|
+
def after(path = nil, options = {}, &block)
|
|
1027
|
+
add_filter(:after, path, options, &block)
|
|
968
1028
|
end
|
|
969
1029
|
|
|
970
1030
|
# add a filter
|
|
971
|
-
def add_filter(type, path = nil, &block)
|
|
1031
|
+
def add_filter(type, path = nil, options = {}, &block)
|
|
972
1032
|
return filters[type] << block unless path
|
|
973
|
-
|
|
1033
|
+
path, options = //, path if path.respond_to?(:each_pair)
|
|
1034
|
+
block, *arguments = compile!(type, path, block, options)
|
|
974
1035
|
add_filter(type) do
|
|
975
1036
|
process_route(*arguments) { instance_eval(&block) }
|
|
976
1037
|
end
|
|
@@ -1028,18 +1089,18 @@ module Sinatra
|
|
|
1028
1089
|
route('HEAD', path, opts, &block)
|
|
1029
1090
|
end
|
|
1030
1091
|
|
|
1031
|
-
def put(path, opts={}, &bk)
|
|
1032
|
-
def post(path, opts={}, &bk)
|
|
1033
|
-
def delete(path, opts={}, &bk)
|
|
1034
|
-
def head(path, opts={}, &bk)
|
|
1092
|
+
def put(path, opts={}, &bk) route 'PUT', path, opts, &bk end
|
|
1093
|
+
def post(path, opts={}, &bk) route 'POST', path, opts, &bk end
|
|
1094
|
+
def delete(path, opts={}, &bk) route 'DELETE', path, opts, &bk end
|
|
1095
|
+
def head(path, opts={}, &bk) route 'HEAD', path, opts, &bk end
|
|
1096
|
+
def options(path, opts={}, &bk) route 'OPTIONS', path, opts, &bk end
|
|
1035
1097
|
|
|
1036
1098
|
private
|
|
1037
1099
|
def route(verb, path, options={}, &block)
|
|
1038
1100
|
# Because of self.options.host
|
|
1039
1101
|
host_name(options.delete(:host)) if options.key?(:host)
|
|
1040
|
-
options.each { |option, args| send(option, *args) }
|
|
1041
1102
|
|
|
1042
|
-
block, pattern, keys, conditions = compile! verb, path, block
|
|
1103
|
+
block, pattern, keys, conditions = compile! verb, path, block, options
|
|
1043
1104
|
invoke_hook(:route_added, verb, path, block)
|
|
1044
1105
|
|
|
1045
1106
|
(@routes[verb] ||= []).
|
|
@@ -1050,7 +1111,8 @@ module Sinatra
|
|
|
1050
1111
|
extensions.each { |e| e.send(name, *args) if e.respond_to?(name) }
|
|
1051
1112
|
end
|
|
1052
1113
|
|
|
1053
|
-
def compile!(verb, path, block)
|
|
1114
|
+
def compile!(verb, path, block, options = {})
|
|
1115
|
+
options.each_pair { |option, args| send(option, *args) }
|
|
1054
1116
|
method_name = "#{verb} #{path}"
|
|
1055
1117
|
|
|
1056
1118
|
define_method(method_name, &block)
|
|
@@ -1085,6 +1147,8 @@ module Sinatra
|
|
|
1085
1147
|
[/^#{pattern}$/, keys]
|
|
1086
1148
|
elsif path.respond_to?(:keys) && path.respond_to?(:match)
|
|
1087
1149
|
[path, path.keys]
|
|
1150
|
+
elsif path.respond_to?(:names) && path.respond_to?(:match)
|
|
1151
|
+
[path, path.names]
|
|
1088
1152
|
elsif path.respond_to? :match
|
|
1089
1153
|
[path, keys]
|
|
1090
1154
|
else
|
|
@@ -1281,6 +1345,9 @@ module Sinatra
|
|
|
1281
1345
|
set :bind, '0.0.0.0'
|
|
1282
1346
|
set :port, 4567
|
|
1283
1347
|
|
|
1348
|
+
set :absolute_redirects, true
|
|
1349
|
+
set :prefixed_redirects, false
|
|
1350
|
+
|
|
1284
1351
|
set :app_file, nil
|
|
1285
1352
|
set :root, Proc.new { app_file && File.expand_path(File.dirname(app_file)) }
|
|
1286
1353
|
set :views, Proc.new { root && File.join(root, 'views') }
|
|
@@ -1364,7 +1431,7 @@ module Sinatra
|
|
|
1364
1431
|
end
|
|
1365
1432
|
end
|
|
1366
1433
|
|
|
1367
|
-
delegate :get, :put, :post, :delete, :head, :template, :layout,
|
|
1434
|
+
delegate :get, :put, :post, :delete, :head, :options, :template, :layout,
|
|
1368
1435
|
:before, :after, :error, :not_found, :configure, :set, :mime_type,
|
|
1369
1436
|
:enable, :disable, :use, :development?, :test?, :production?,
|
|
1370
1437
|
:helpers, :settings
|
|
@@ -8,11 +8,36 @@ module Sinatra
|
|
|
8
8
|
# Be careful when you use this on public-facing sites as it could reveal
|
|
9
9
|
# information helpful to attackers.
|
|
10
10
|
class ShowExceptions < Rack::ShowExceptions
|
|
11
|
+
@@eats_errors = Object.new
|
|
12
|
+
def @@eats_errors.flush(*) end
|
|
13
|
+
def @@eats_errors.puts(*) end
|
|
14
|
+
|
|
11
15
|
def initialize(app)
|
|
12
16
|
@app = app
|
|
13
17
|
@template = ERB.new(TEMPLATE)
|
|
14
18
|
end
|
|
15
19
|
|
|
20
|
+
def call(env)
|
|
21
|
+
@app.call(env)
|
|
22
|
+
rescue Exception => e
|
|
23
|
+
errors, env["rack.errors"] = env["rack.errors"], @@eats_errors
|
|
24
|
+
|
|
25
|
+
if respond_to?(:prefers_plain_text?) and prefers_plain_text?(env)
|
|
26
|
+
content_type = "text/plain"
|
|
27
|
+
body = [dump_exception(e)]
|
|
28
|
+
else
|
|
29
|
+
content_type = "text/html"
|
|
30
|
+
body = pretty(env, e)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
env["rack.errors"] = errors
|
|
34
|
+
|
|
35
|
+
[500,
|
|
36
|
+
{"Content-Type" => content_type,
|
|
37
|
+
"Content-Length" => Rack::Utils.bytesize(body.join).to_s},
|
|
38
|
+
body]
|
|
39
|
+
end
|
|
40
|
+
|
|
16
41
|
private
|
|
17
42
|
|
|
18
43
|
def frame_class(frame)
|
data/sinatra.gemspec
CHANGED
|
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
|
|
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
4
4
|
|
|
5
5
|
s.name = 'sinatra'
|
|
6
|
-
s.version = '1.
|
|
7
|
-
s.date = '2011-
|
|
6
|
+
s.version = '1.2.0'
|
|
7
|
+
s.date = '2011-03-03'
|
|
8
8
|
|
|
9
9
|
s.description = "Classy web-development dressed in a DSL"
|
|
10
10
|
s.summary = "Classy web-development dressed in a DSL"
|
|
@@ -16,6 +16,7 @@ Gem::Specification.new do |s|
|
|
|
16
16
|
s.files = %w[
|
|
17
17
|
AUTHORS
|
|
18
18
|
CHANGES
|
|
19
|
+
Gemfile
|
|
19
20
|
LICENSE
|
|
20
21
|
README.de.rdoc
|
|
21
22
|
README.es.rdoc
|
|
@@ -67,10 +68,13 @@ Gem::Specification.new do |s|
|
|
|
67
68
|
test/server_test.rb
|
|
68
69
|
test/settings_test.rb
|
|
69
70
|
test/sinatra_test.rb
|
|
71
|
+
test/slim_test.rb
|
|
70
72
|
test/static_test.rb
|
|
71
73
|
test/templates_test.rb
|
|
72
74
|
test/textile_test.rb
|
|
73
|
-
test/views/
|
|
75
|
+
test/views/a/in_a.str
|
|
76
|
+
test/views/ascii.erb
|
|
77
|
+
test/views/b/in_b.str
|
|
74
78
|
test/views/calc.html.erb
|
|
75
79
|
test/views/error.builder
|
|
76
80
|
test/views/error.erb
|
|
@@ -93,6 +97,7 @@ Gem::Specification.new do |s|
|
|
|
93
97
|
test/views/hello.rdoc
|
|
94
98
|
test/views/hello.sass
|
|
95
99
|
test/views/hello.scss
|
|
100
|
+
test/views/hello.slim
|
|
96
101
|
test/views/hello.str
|
|
97
102
|
test/views/hello.test
|
|
98
103
|
test/views/hello.textile
|
|
@@ -104,10 +109,11 @@ Gem::Specification.new do |s|
|
|
|
104
109
|
test/views/layout2.mab
|
|
105
110
|
test/views/layout2.nokogiri
|
|
106
111
|
test/views/layout2.radius
|
|
112
|
+
test/views/layout2.slim
|
|
107
113
|
test/views/layout2.str
|
|
108
114
|
test/views/layout2.test
|
|
109
115
|
test/views/nested.str
|
|
110
|
-
test/views/utf8.
|
|
116
|
+
test/views/utf8.erb
|
|
111
117
|
]
|
|
112
118
|
# = MANIFEST =
|
|
113
119
|
|
|
@@ -116,21 +122,7 @@ Gem::Specification.new do |s|
|
|
|
116
122
|
s.extra_rdoc_files = %w[README.rdoc README.de.rdoc README.jp.rdoc README.fr.rdoc README.es.rdoc README.hu.rdoc README.zh.rdoc LICENSE]
|
|
117
123
|
s.add_dependency 'rack', '~> 1.1'
|
|
118
124
|
s.add_dependency 'tilt', '>= 1.2.2', '< 2.0'
|
|
119
|
-
s.add_development_dependency 'rake'
|
|
120
125
|
s.add_development_dependency 'shotgun', '~> 0.6'
|
|
121
|
-
s.add_development_dependency 'rack-test', '>= 0.5.6'
|
|
122
|
-
s.add_development_dependency 'haml', '>= 3.0'
|
|
123
|
-
s.add_development_dependency 'builder'
|
|
124
|
-
s.add_development_dependency 'erubis'
|
|
125
|
-
s.add_development_dependency 'less'
|
|
126
|
-
s.add_development_dependency 'liquid'
|
|
127
|
-
s.add_development_dependency 'rdiscount'
|
|
128
|
-
s.add_development_dependency 'RedCloth'
|
|
129
|
-
s.add_development_dependency 'radius'
|
|
130
|
-
s.add_development_dependency 'markaby'
|
|
131
|
-
s.add_development_dependency 'coffee-script', '>= 2.0'
|
|
132
|
-
s.add_development_dependency 'rdoc'
|
|
133
|
-
s.add_development_dependency 'nokogiri'
|
|
134
126
|
|
|
135
127
|
s.has_rdoc = true
|
|
136
128
|
s.homepage = "http://sinatra.rubyforge.org"
|
data/test/builder_test.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
require File.dirname(__FILE__) + '/helper'
|
|
2
|
+
|
|
3
|
+
begin
|
|
2
4
|
require 'builder'
|
|
3
5
|
|
|
4
6
|
class BuilderTest < Test::Unit::TestCase
|
|
@@ -87,3 +89,7 @@ class BuilderTest < Test::Unit::TestCase
|
|
|
87
89
|
assert_raise(Errno::ENOENT) { get('/') }
|
|
88
90
|
end
|
|
89
91
|
end
|
|
92
|
+
|
|
93
|
+
rescue LoadError
|
|
94
|
+
warn "#{$!.to_s}: skipping builder tests"
|
|
95
|
+
end
|
data/test/coffee_test.rb
CHANGED
data/test/encoding_test.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# encoding: UTF-8
|
|
2
2
|
require File.dirname(__FILE__) + '/helper'
|
|
3
|
+
require 'erb'
|
|
3
4
|
|
|
4
5
|
class BaseTest < Test::Unit::TestCase
|
|
5
6
|
setup do
|
|
@@ -9,11 +10,11 @@ class BaseTest < Test::Unit::TestCase
|
|
|
9
10
|
|
|
10
11
|
it 'allows unicode strings in ascii templates per default (1.9)' do
|
|
11
12
|
next unless defined? Encoding
|
|
12
|
-
@base.new.
|
|
13
|
+
@base.new.erb(File.read(@base.views + "/ascii.erb").encode("ASCII"), {}, :value => "åkej")
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
it 'allows ascii strings in unicode templates per default (1.9)' do
|
|
16
17
|
next unless defined? Encoding
|
|
17
|
-
@base.new.
|
|
18
|
+
@base.new.erb(:utf8, {}, :value => "Some Lyrics".encode("ASCII"))
|
|
18
19
|
end
|
|
19
|
-
end
|
|
20
|
+
end
|
data/test/erubis_test.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
require File.dirname(__FILE__) + '/helper'
|
|
2
|
+
|
|
3
|
+
begin
|
|
2
4
|
require 'erubis'
|
|
3
5
|
|
|
4
6
|
class ERubisTest < Test::Unit::TestCase
|
|
@@ -80,3 +82,7 @@ class ERubisTest < Test::Unit::TestCase
|
|
|
80
82
|
assert_equal '<outer><inner>hi</inner></outer>', body
|
|
81
83
|
end
|
|
82
84
|
end
|
|
85
|
+
|
|
86
|
+
rescue LoadError
|
|
87
|
+
warn "#{$!.to_s}: skipping erubis tests"
|
|
88
|
+
end
|