sinatra 2.0.7 → 2.2.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +119 -0
- data/Gemfile +9 -5
- data/MAINTENANCE.md +2 -15
- data/README.de.md +16 -16
- data/README.es.md +62 -33
- data/README.fr.md +182 -85
- data/README.hu.md +3 -3
- data/README.ja.md +62 -32
- data/README.ko.md +1 -1
- data/README.md +93 -60
- data/README.pt-br.md +2365 -338
- data/README.pt-pt.md +3 -3
- data/README.ru.md +3 -3
- data/README.zh.md +1 -1
- data/VERSION +1 -1
- data/examples/chat.rb +2 -1
- data/examples/rainbows.conf +3 -0
- data/examples/rainbows.rb +20 -0
- data/examples/stream.ru +4 -4
- data/lib/sinatra/base.rb +118 -76
- data/lib/sinatra/indifferent_hash.rb +27 -9
- data/lib/sinatra/main.rb +5 -5
- data/lib/sinatra/show_exceptions.rb +2 -37
- data/lib/sinatra/version.rb +1 -1
- data/sinatra.gemspec +4 -10
- metadata +10 -21
data/README.pt-pt.md
CHANGED
@@ -121,7 +121,7 @@ Arquivos estáticos são disponibilizados a partir do directório
|
|
121
121
|
`:public_folder`
|
122
122
|
|
123
123
|
```ruby
|
124
|
-
set :public_folder,
|
124
|
+
set :public_folder, __dir__ + '/estatico'
|
125
125
|
```
|
126
126
|
|
127
127
|
Note que o nome do directório público não é incluido no URL. Um arquivo
|
@@ -134,7 +134,7 @@ Templates presumem-se estar localizados sob o directório `./views`. Para
|
|
134
134
|
utilizar um directório de views diferente:
|
135
135
|
|
136
136
|
```ruby
|
137
|
-
set :views,
|
137
|
+
set :views, __dir__ + '/modelo'
|
138
138
|
```
|
139
139
|
|
140
140
|
Uma coisa importante a ser lembrada é que você sempre tem as referências
|
@@ -757,7 +757,7 @@ Alternativamente, pode adicionar o directório do `sinatra/lib` no
|
|
757
757
|
`LOAD_PATH` do seu aplicativo:
|
758
758
|
|
759
759
|
```ruby
|
760
|
-
$LOAD_PATH.unshift
|
760
|
+
$LOAD_PATH.unshift __dir__ + '/sinatra/lib'
|
761
761
|
require 'rubygems'
|
762
762
|
require 'sinatra'
|
763
763
|
|
data/README.ru.md
CHANGED
@@ -431,7 +431,7 @@ end
|
|
431
431
|
месторасположение при помощи опции `:public_folder`:
|
432
432
|
|
433
433
|
```ruby
|
434
|
-
set :public_folder,
|
434
|
+
set :public_folder, __dir__ + '/static'
|
435
435
|
```
|
436
436
|
|
437
437
|
Учтите, что имя директории со статическими файлами не включено в URL.
|
@@ -3089,9 +3089,9 @@ thin --threaded start
|
|
3089
3089
|
|
3090
3090
|
Следующие версии Ruby официально поддерживаются:
|
3091
3091
|
<dl>
|
3092
|
-
<dt>Ruby 2.
|
3092
|
+
<dt>Ruby 2.3</dt>
|
3093
3093
|
<dd>
|
3094
|
-
Версия 2.
|
3094
|
+
Версия 2.3 полностью поддерживается и рекомендуется. В настоящее время нет
|
3095
3095
|
планов отказаться от официальной поддержки.
|
3096
3096
|
</dd>
|
3097
3097
|
|
data/README.zh.md
CHANGED
@@ -393,7 +393,7 @@ end
|
|
393
393
|
静态文件从 `./public` 目录提供服务。可以通过设置`:public_folder` 选项设定一个不同的位置:
|
394
394
|
|
395
395
|
```ruby
|
396
|
-
set :public_folder,
|
396
|
+
set :public_folder, __dir__ + '/static'
|
397
397
|
```
|
398
398
|
|
399
399
|
请注意 public 目录名并没有包含在 URL 中。文件 `./public/css/style.css` 可以通过
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.0
|
1
|
+
2.2.0
|
data/examples/chat.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rainbows'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Handler
|
5
|
+
class Rainbows
|
6
|
+
def self.run(app, **options)
|
7
|
+
rainbows_options = {
|
8
|
+
listeners: ["#{options[:Host]}:#{options[:Port]}"],
|
9
|
+
worker_processes: 1,
|
10
|
+
timeout: 30,
|
11
|
+
config_file: ::File.expand_path('rainbows.conf', __dir__),
|
12
|
+
}
|
13
|
+
|
14
|
+
::Rainbows::HttpServer.new(app, rainbows_options).start.join
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
register :rainbows, ::Rack::Handler::Rainbows
|
19
|
+
end
|
20
|
+
end
|
data/examples/stream.ru
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
#
|
3
3
|
# run *one* of these:
|
4
4
|
#
|
5
|
-
# rackup -s mongrel stream.ru
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
5
|
+
# rackup -s mongrel stream.ru # gem install mongrel
|
6
|
+
# unicorn stream.ru # gem install unicorn
|
7
|
+
# puma stream.ru # gem install puma
|
8
|
+
# rainbows -c rainbows.conf stream.ru # gem install rainbows eventmachine
|
9
9
|
|
10
10
|
require 'sinatra/base'
|
11
11
|
|
data/lib/sinatra/base.rb
CHANGED
@@ -43,12 +43,11 @@ module Sinatra
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def preferred_type(*types)
|
46
|
-
|
47
|
-
return accepts.first if types.empty?
|
46
|
+
return accept.first if types.empty?
|
48
47
|
types.flatten!
|
49
|
-
return types.first if
|
50
|
-
|
51
|
-
type = types.detect { |t|
|
48
|
+
return types.first if accept.empty?
|
49
|
+
accept.detect do |accept_header|
|
50
|
+
type = types.detect { |t| MimeTypeEntry.new(t).accepts?(accept_header) }
|
52
51
|
return type if type
|
53
52
|
end
|
54
53
|
end
|
@@ -79,10 +78,10 @@ module Sinatra
|
|
79
78
|
super
|
80
79
|
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
81
80
|
raise BadRequest, "Invalid query parameters: #{Rack::Utils.escape_html(e.message)}"
|
81
|
+
rescue EOFError => e
|
82
|
+
raise BadRequest, "Invalid multipart/form-data: #{Rack::Utils.escape_html(e.message)}"
|
82
83
|
end
|
83
84
|
|
84
|
-
private
|
85
|
-
|
86
85
|
class AcceptEntry
|
87
86
|
attr_accessor :params
|
88
87
|
attr_reader :entry
|
@@ -125,6 +124,35 @@ module Sinatra
|
|
125
124
|
to_str.send(*args, &block)
|
126
125
|
end
|
127
126
|
end
|
127
|
+
|
128
|
+
class MimeTypeEntry
|
129
|
+
attr_reader :params
|
130
|
+
|
131
|
+
def initialize(entry)
|
132
|
+
params = entry.scan(HEADER_PARAM).map! do |s|
|
133
|
+
key, value = s.strip.split('=', 2)
|
134
|
+
value = value[1..-2].gsub(/\\(.)/, '\1') if value.start_with?('"')
|
135
|
+
[key, value]
|
136
|
+
end
|
137
|
+
|
138
|
+
@type = entry[/[^;]+/].delete(' ')
|
139
|
+
@params = Hash[params]
|
140
|
+
end
|
141
|
+
|
142
|
+
def accepts?(entry)
|
143
|
+
File.fnmatch(entry, self) && matches_params?(entry.params)
|
144
|
+
end
|
145
|
+
|
146
|
+
def to_str
|
147
|
+
@type
|
148
|
+
end
|
149
|
+
|
150
|
+
def matches_params?(params)
|
151
|
+
return true if @params.empty?
|
152
|
+
|
153
|
+
params.all? { |k,v| !@params.has_key?(k) || @params[k] == v }
|
154
|
+
end
|
155
|
+
end
|
128
156
|
end
|
129
157
|
|
130
158
|
# The response object. See Rack::Response and Rack::Response::Helpers for
|
@@ -133,10 +161,6 @@ module Sinatra
|
|
133
161
|
# http://rubydoc.info/github/rack/rack/master/Rack/Response/Helpers
|
134
162
|
class Response < Rack::Response
|
135
163
|
DROP_BODY_RESPONSES = [204, 304]
|
136
|
-
def initialize(*)
|
137
|
-
super
|
138
|
-
headers['Content-Type'] ||= 'text/html'
|
139
|
-
end
|
140
164
|
|
141
165
|
def body=(value)
|
142
166
|
value = value.body while Rack::Response === value
|
@@ -163,10 +187,10 @@ module Sinatra
|
|
163
187
|
if calculate_content_length?
|
164
188
|
# if some other code has already set Content-Length, don't muck with it
|
165
189
|
# currently, this would be the static file-handler
|
166
|
-
headers["Content-Length"] = body.
|
190
|
+
headers["Content-Length"] = body.map(&:bytesize).reduce(0, :+).to_s
|
167
191
|
end
|
168
192
|
|
169
|
-
[status
|
193
|
+
[status, headers, result]
|
170
194
|
end
|
171
195
|
|
172
196
|
private
|
@@ -176,15 +200,15 @@ module Sinatra
|
|
176
200
|
end
|
177
201
|
|
178
202
|
def drop_content_info?
|
179
|
-
|
203
|
+
informational? or drop_body?
|
180
204
|
end
|
181
205
|
|
182
206
|
def drop_body?
|
183
|
-
DROP_BODY_RESPONSES.include?(status
|
207
|
+
DROP_BODY_RESPONSES.include?(status)
|
184
208
|
end
|
185
209
|
end
|
186
210
|
|
187
|
-
# Some Rack handlers (
|
211
|
+
# Some Rack handlers (Rainbows!) implement an extended body object protocol, however,
|
188
212
|
# some middleware (namely Rack::Lint) will break it by not mirroring the methods in question.
|
189
213
|
# This middleware will detect an extended body object and will make sure it reaches the
|
190
214
|
# handler directly. We do this here, so our middleware and middleware set up by the app will
|
@@ -451,7 +475,7 @@ module Sinatra
|
|
451
475
|
#
|
452
476
|
# The close parameter specifies whether Stream#close should be called
|
453
477
|
# after the block has been executed. This is only relevant for evented
|
454
|
-
# servers like
|
478
|
+
# servers like Rainbows.
|
455
479
|
def stream(keep_open = false)
|
456
480
|
scheduler = env['async.callback'] ? EventMachine : Stream
|
457
481
|
current = @params.dup
|
@@ -647,8 +671,6 @@ module Sinatra
|
|
647
671
|
end
|
648
672
|
end
|
649
673
|
|
650
|
-
private
|
651
|
-
|
652
674
|
# Template rendering methods. Each method takes the name of a template
|
653
675
|
# to render as a Symbol and returns a String with the rendered output,
|
654
676
|
# as well as an optional hash with additional options.
|
@@ -849,12 +871,12 @@ module Sinatra
|
|
849
871
|
|
850
872
|
def compile_template(engine, data, options, views)
|
851
873
|
eat_errors = options.delete :eat_errors
|
852
|
-
|
853
|
-
|
854
|
-
raise "Template engine not found: #{engine}" if template.nil?
|
874
|
+
template = Tilt[engine]
|
875
|
+
raise "Template engine not found: #{engine}" if template.nil?
|
855
876
|
|
856
|
-
|
857
|
-
|
877
|
+
case data
|
878
|
+
when Symbol
|
879
|
+
template_cache.fetch engine, data, options, views do
|
858
880
|
body, path, line = settings.templates[data]
|
859
881
|
if body
|
860
882
|
body = body.call if body.respond_to?(:call)
|
@@ -872,17 +894,24 @@ module Sinatra
|
|
872
894
|
throw :layout_missing if eat_errors and not found
|
873
895
|
template.new(path, 1, options)
|
874
896
|
end
|
875
|
-
when Proc, String
|
876
|
-
body = data.is_a?(String) ? Proc.new { data } : data
|
877
|
-
caller = settings.caller_locations.first
|
878
|
-
path = options[:path] || caller[0]
|
879
|
-
line = options[:line] || caller[1]
|
880
|
-
template.new(path, line.to_i, options, &body)
|
881
|
-
else
|
882
|
-
raise ArgumentError, "Sorry, don't know how to render #{data.inspect}."
|
883
897
|
end
|
898
|
+
when Proc
|
899
|
+
compile_block_template(template, options, &data)
|
900
|
+
when String
|
901
|
+
template_cache.fetch engine, data, options, views do
|
902
|
+
compile_block_template(template, options) { data }
|
903
|
+
end
|
904
|
+
else
|
905
|
+
raise ArgumentError, "Sorry, don't know how to render #{data.inspect}."
|
884
906
|
end
|
885
907
|
end
|
908
|
+
|
909
|
+
def compile_block_template(template, options, &body)
|
910
|
+
caller = settings.caller_locations.first
|
911
|
+
path = options[:path] || caller[0]
|
912
|
+
line = options[:line] || caller[1]
|
913
|
+
template.new(path, line.to_i, options, &body)
|
914
|
+
end
|
886
915
|
end
|
887
916
|
|
888
917
|
# Base class for all Sinatra applications and middleware.
|
@@ -896,10 +925,11 @@ module Sinatra
|
|
896
925
|
attr_accessor :app, :env, :request, :response, :params
|
897
926
|
attr_reader :template_cache
|
898
927
|
|
899
|
-
def initialize(app = nil)
|
928
|
+
def initialize(app = nil, **kwargs)
|
900
929
|
super()
|
901
930
|
@app = app
|
902
931
|
@template_cache = Tilt::Cache.new
|
932
|
+
@pinned_response = nil # whether a before! filter pinned the content-type
|
903
933
|
yield self if block_given?
|
904
934
|
end
|
905
935
|
|
@@ -913,17 +943,17 @@ module Sinatra
|
|
913
943
|
@params = IndifferentHash.new
|
914
944
|
@request = Request.new(env)
|
915
945
|
@response = Response.new
|
946
|
+
@pinned_response = nil
|
916
947
|
template_cache.clear if settings.reload_templates
|
917
948
|
|
918
|
-
@response['Content-Type'] = nil
|
919
949
|
invoke { dispatch! }
|
920
950
|
invoke { error_block!(response.status) } unless @env['sinatra.error']
|
921
951
|
|
922
952
|
unless @response['Content-Type']
|
923
|
-
if Array === body
|
953
|
+
if Array === body && body[0].respond_to?(:content_type)
|
924
954
|
content_type body[0].content_type
|
925
|
-
|
926
|
-
content_type
|
955
|
+
elsif default = settings.default_content_type
|
956
|
+
content_type default
|
927
957
|
end
|
928
958
|
end
|
929
959
|
|
@@ -973,15 +1003,21 @@ module Sinatra
|
|
973
1003
|
private
|
974
1004
|
|
975
1005
|
# Run filters defined on the class and all superclasses.
|
976
|
-
|
977
|
-
|
978
|
-
base.
|
1006
|
+
# Accepts an optional block to call after each filter is applied.
|
1007
|
+
def filter!(type, base = settings, &block)
|
1008
|
+
filter!(type, base.superclass, &block) if base.superclass.respond_to?(:filters)
|
1009
|
+
base.filters[type].each do |args|
|
1010
|
+
result = process_route(*args)
|
1011
|
+
block.call(result) if block_given?
|
1012
|
+
end
|
979
1013
|
end
|
980
1014
|
|
981
1015
|
# Run routes defined on the class and all superclasses.
|
982
1016
|
def route!(base = settings, pass_block = nil)
|
983
1017
|
if routes = base.routes[@request.request_method]
|
984
1018
|
routes.each do |pattern, conditions, block|
|
1019
|
+
response.delete_header('Content-Type') unless @pinned_response
|
1020
|
+
|
985
1021
|
returned_pass_block = process_route(pattern, conditions) do |*args|
|
986
1022
|
env['sinatra.route'] = "#{@request.request_method} #{pattern}"
|
987
1023
|
route_eval { block[*args] }
|
@@ -1019,7 +1055,7 @@ module Sinatra
|
|
1019
1055
|
|
1020
1056
|
params.delete("ignore") # TODO: better params handling, maybe turn it into "smart" object or detect changes
|
1021
1057
|
force_encoding(params)
|
1022
|
-
|
1058
|
+
@params = @params.merge(params) if params.any?
|
1023
1059
|
|
1024
1060
|
regexp_exists = pattern.is_a?(Mustermann::Regular) || (pattern.respond_to?(:patterns) && pattern.patterns.any? {|subpattern| subpattern.is_a?(Mustermann::Regular)} )
|
1025
1061
|
if regexp_exists
|
@@ -1038,7 +1074,8 @@ module Sinatra
|
|
1038
1074
|
@env['sinatra.error.params'] = @params
|
1039
1075
|
raise
|
1040
1076
|
ensure
|
1041
|
-
|
1077
|
+
params ||= {}
|
1078
|
+
params.each { |k, _| @params.delete(k) } unless @env['sinatra.error.params']
|
1042
1079
|
end
|
1043
1080
|
|
1044
1081
|
# No matching route was found or all routes passed. The default
|
@@ -1050,7 +1087,7 @@ module Sinatra
|
|
1050
1087
|
if @app
|
1051
1088
|
forward
|
1052
1089
|
else
|
1053
|
-
raise NotFound
|
1090
|
+
raise NotFound, "#{request.request_method} #{request.path_info}"
|
1054
1091
|
end
|
1055
1092
|
end
|
1056
1093
|
|
@@ -1058,7 +1095,11 @@ module Sinatra
|
|
1058
1095
|
# a matching file is found, returns nil otherwise.
|
1059
1096
|
def static!(options = {})
|
1060
1097
|
return if (public_dir = settings.public_folder).nil?
|
1061
|
-
path =
|
1098
|
+
path = "#{public_dir}#{URI_INSTANCE.unescape(request.path_info)}"
|
1099
|
+
return unless valid_path?(path)
|
1100
|
+
|
1101
|
+
path = File.expand_path(path)
|
1102
|
+
return unless path.start_with?(File.expand_path(public_dir) + '/')
|
1062
1103
|
return unless File.file?(path)
|
1063
1104
|
|
1064
1105
|
env['sinatra.static_file'] = path
|
@@ -1093,7 +1134,9 @@ module Sinatra
|
|
1093
1134
|
|
1094
1135
|
invoke do
|
1095
1136
|
static! if settings.static? && (request.get? || request.head?)
|
1096
|
-
filter! :before
|
1137
|
+
filter! :before do
|
1138
|
+
@pinned_response = !response['Content-Type'].nil?
|
1139
|
+
end
|
1097
1140
|
route!
|
1098
1141
|
end
|
1099
1142
|
rescue ::Exception => boom
|
@@ -1113,7 +1156,7 @@ module Sinatra
|
|
1113
1156
|
end
|
1114
1157
|
@env['sinatra.error'] = boom
|
1115
1158
|
|
1116
|
-
if boom.respond_to? :http_status
|
1159
|
+
if boom.respond_to? :http_status and boom.http_status.between? 400, 599
|
1117
1160
|
status(boom.http_status)
|
1118
1161
|
elsif settings.use_code? and boom.respond_to? :code and boom.code.between? 400, 599
|
1119
1162
|
status(boom.code)
|
@@ -1121,21 +1164,27 @@ module Sinatra
|
|
1121
1164
|
status(500)
|
1122
1165
|
end
|
1123
1166
|
|
1124
|
-
status(500) unless status.between? 400, 599
|
1125
|
-
|
1126
|
-
boom_message = boom.message if boom.message && boom.message != boom.class.name
|
1127
1167
|
if server_error?
|
1128
1168
|
dump_errors! boom if settings.dump_errors?
|
1129
1169
|
raise boom if settings.show_exceptions? and settings.show_exceptions != :after_handler
|
1130
1170
|
elsif not_found?
|
1131
1171
|
headers['X-Cascade'] = 'pass' if settings.x_cascade?
|
1132
|
-
body boom_message || '<h1>Not Found</h1>'
|
1133
|
-
elsif bad_request?
|
1134
|
-
body boom_message || '<h1>Bad Request</h1>'
|
1135
1172
|
end
|
1136
1173
|
|
1137
|
-
res = error_block!(boom.class, boom) || error_block!(status, boom)
|
1138
|
-
|
1174
|
+
if res = error_block!(boom.class, boom) || error_block!(status, boom)
|
1175
|
+
return res
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
if not_found? || bad_request?
|
1179
|
+
if boom.message && boom.message != boom.class.name
|
1180
|
+
body Rack::Utils.escape_html(boom.message)
|
1181
|
+
else
|
1182
|
+
content_type 'text/html'
|
1183
|
+
body '<h1>' + (not_found? ? 'Not Found' : 'Bad Request') + '</h1>'
|
1184
|
+
end
|
1185
|
+
end
|
1186
|
+
|
1187
|
+
return unless server_error?
|
1139
1188
|
raise boom if settings.raise_errors? or settings.show_exceptions?
|
1140
1189
|
error_block! Exception, boom
|
1141
1190
|
end
|
@@ -1345,19 +1394,19 @@ module Sinatra
|
|
1345
1394
|
# context as route handlers and may access/modify the request and
|
1346
1395
|
# response.
|
1347
1396
|
def before(path = /.*/, **options, &block)
|
1348
|
-
add_filter(:before, path, options, &block)
|
1397
|
+
add_filter(:before, path, **options, &block)
|
1349
1398
|
end
|
1350
1399
|
|
1351
1400
|
# Define an after filter; runs after all requests within the same
|
1352
1401
|
# context as route handlers and may access/modify the request and
|
1353
1402
|
# response.
|
1354
1403
|
def after(path = /.*/, **options, &block)
|
1355
|
-
add_filter(:after, path, options, &block)
|
1404
|
+
add_filter(:after, path, **options, &block)
|
1356
1405
|
end
|
1357
1406
|
|
1358
1407
|
# add a filter
|
1359
1408
|
def add_filter(type, path = /.*/, **options, &block)
|
1360
|
-
filters[type] << compile!(type, path, block, options)
|
1409
|
+
filters[type] << compile!(type, path, block, **options)
|
1361
1410
|
end
|
1362
1411
|
|
1363
1412
|
# Add a route condition. The route is considered non-matching when the
|
@@ -1431,6 +1480,7 @@ module Sinatra
|
|
1431
1480
|
@prototype = nil
|
1432
1481
|
@middleware << [middleware, args, block]
|
1433
1482
|
end
|
1483
|
+
ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
|
1434
1484
|
|
1435
1485
|
# Stop the self-hosted server if running.
|
1436
1486
|
def quit!
|
@@ -1445,12 +1495,12 @@ module Sinatra
|
|
1445
1495
|
alias_method :stop!, :quit!
|
1446
1496
|
|
1447
1497
|
# Run the Sinatra app as a self-hosted server using
|
1448
|
-
#
|
1498
|
+
# Puma, Mongrel, or WEBrick (in that order). If given a block, will call
|
1449
1499
|
# with the constructed handler once we have taken the stage.
|
1450
1500
|
def run!(options = {}, &block)
|
1451
1501
|
return if running?
|
1452
1502
|
set options
|
1453
|
-
handler =
|
1503
|
+
handler = Rack::Handler.pick(server)
|
1454
1504
|
handler_name = handler.name.gsub(/.*::/, '')
|
1455
1505
|
server_settings = settings.respond_to?(:server_settings) ? settings.server_settings : {}
|
1456
1506
|
server_settings.merge!(:Port => port, :Host => bind)
|
@@ -1483,8 +1533,8 @@ module Sinatra
|
|
1483
1533
|
# Create a new instance of the class fronted by its middleware
|
1484
1534
|
# pipeline. The object is guaranteed to respond to #call but may not be
|
1485
1535
|
# an instance of the class new was called on.
|
1486
|
-
def new(*args, &bk)
|
1487
|
-
instance = new!(*args, &bk)
|
1536
|
+
def new(*args, **kwargs, &bk)
|
1537
|
+
instance = new!(*args, **kwargs, &bk)
|
1488
1538
|
Wrapper.new(build(instance).to_app, instance)
|
1489
1539
|
end
|
1490
1540
|
|
@@ -1522,7 +1572,7 @@ module Sinatra
|
|
1522
1572
|
# behavior, by ensuring an instance exists:
|
1523
1573
|
prototype
|
1524
1574
|
# Run the instance we created:
|
1525
|
-
handler.run(self, server_settings) do |server|
|
1575
|
+
handler.run(self, **server_settings) do |server|
|
1526
1576
|
unless suppress_messages?
|
1527
1577
|
$stderr.puts "== Sinatra (v#{Sinatra::VERSION}) has taken the stage on #{port} for #{environment} with backup from #{handler_name}"
|
1528
1578
|
end
|
@@ -1601,7 +1651,7 @@ module Sinatra
|
|
1601
1651
|
|
1602
1652
|
def route(verb, path, options = {}, &block)
|
1603
1653
|
enable :empty_path_info if path == "" and empty_path_info.nil?
|
1604
|
-
signature = compile!(verb, path, block, options)
|
1654
|
+
signature = compile!(verb, path, block, **options)
|
1605
1655
|
(@routes[verb] ||= []) << signature
|
1606
1656
|
invoke_hook(:route_added, verb, path, block)
|
1607
1657
|
signature
|
@@ -1638,7 +1688,7 @@ module Sinatra
|
|
1638
1688
|
end
|
1639
1689
|
|
1640
1690
|
def compile(path, route_mustermann_opts = {})
|
1641
|
-
Mustermann.new(path, mustermann_opts.merge(route_mustermann_opts))
|
1691
|
+
Mustermann.new(path, **mustermann_opts.merge(route_mustermann_opts))
|
1642
1692
|
end
|
1643
1693
|
|
1644
1694
|
def setup_default_middleware(builder)
|
@@ -1704,17 +1754,6 @@ module Sinatra
|
|
1704
1754
|
builder.use session_store, options
|
1705
1755
|
end
|
1706
1756
|
|
1707
|
-
def detect_rack_handler
|
1708
|
-
servers = Array(server)
|
1709
|
-
servers.each do |server_name|
|
1710
|
-
begin
|
1711
|
-
return Rack::Handler.get(server_name.to_s)
|
1712
|
-
rescue LoadError, NameError
|
1713
|
-
end
|
1714
|
-
end
|
1715
|
-
fail "Server handler (#{servers.join(',')}) not found."
|
1716
|
-
end
|
1717
|
-
|
1718
1757
|
def inherited(subclass)
|
1719
1758
|
subclass.reset!
|
1720
1759
|
subclass.set :app_file, caller_files.first unless subclass.app_file?
|
@@ -1776,6 +1815,7 @@ module Sinatra
|
|
1776
1815
|
set :add_charset, %w[javascript xml xhtml+xml].map { |t| "application/#{t}" }
|
1777
1816
|
settings.add_charset << /^text\//
|
1778
1817
|
set :mustermann_opts, {}
|
1818
|
+
set :default_content_type, 'text/html'
|
1779
1819
|
|
1780
1820
|
# explicitly generating a session secret eagerly to play nice with preforking
|
1781
1821
|
begin
|
@@ -1836,7 +1876,7 @@ module Sinatra
|
|
1836
1876
|
|
1837
1877
|
configure :development do
|
1838
1878
|
get '/__sinatra__/:image.png' do
|
1839
|
-
filename =
|
1879
|
+
filename = __dir__ + "/images/#{params[:image].to_i}.png"
|
1840
1880
|
content_type :png
|
1841
1881
|
send_file filename
|
1842
1882
|
end
|
@@ -1917,6 +1957,8 @@ module Sinatra
|
|
1917
1957
|
return super(*args, &block) if respond_to? method_name
|
1918
1958
|
Delegator.target.send(method_name, *args, &block)
|
1919
1959
|
end
|
1960
|
+
# ensure keyword argument passing is compatible with ruby >= 2.7
|
1961
|
+
ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true)
|
1920
1962
|
private method_name
|
1921
1963
|
end
|
1922
1964
|
end
|
@@ -132,13 +132,17 @@ module Sinatra
|
|
132
132
|
super(*keys)
|
133
133
|
end
|
134
134
|
|
135
|
-
def merge!(
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
135
|
+
def merge!(*other_hashes)
|
136
|
+
other_hashes.each do |other_hash|
|
137
|
+
if other_hash.is_a?(self.class)
|
138
|
+
super(other_hash)
|
139
|
+
else
|
140
|
+
other_hash.each_pair do |key, value|
|
141
|
+
key = convert_key(key)
|
142
|
+
value = yield(key, self[key], value) if block_given? && key?(key)
|
143
|
+
self[key] = convert_value(value)
|
144
|
+
end
|
145
|
+
end
|
142
146
|
end
|
143
147
|
|
144
148
|
self
|
@@ -146,8 +150,8 @@ module Sinatra
|
|
146
150
|
|
147
151
|
alias_method :update, :merge!
|
148
152
|
|
149
|
-
def merge(
|
150
|
-
dup.merge!(
|
153
|
+
def merge(*other_hashes, &block)
|
154
|
+
dup.merge!(*other_hashes, &block)
|
151
155
|
end
|
152
156
|
|
153
157
|
def replace(other_hash)
|
@@ -176,6 +180,20 @@ module Sinatra
|
|
176
180
|
end
|
177
181
|
end
|
178
182
|
|
183
|
+
def select(*args, &block)
|
184
|
+
return to_enum(:select) unless block_given?
|
185
|
+
dup.tap { |hash| hash.select!(*args, &block) }
|
186
|
+
end
|
187
|
+
|
188
|
+
def reject(*args, &block)
|
189
|
+
return to_enum(:reject) unless block_given?
|
190
|
+
dup.tap { |hash| hash.reject!(*args, &block) }
|
191
|
+
end
|
192
|
+
|
193
|
+
def compact
|
194
|
+
dup.tap(&:compact!)
|
195
|
+
end if method_defined?(:compact) # Added in Ruby 2.4
|
196
|
+
|
179
197
|
private
|
180
198
|
|
181
199
|
def convert_key(key)
|
data/lib/sinatra/main.rb
CHANGED
@@ -4,11 +4,11 @@ module Sinatra
|
|
4
4
|
if ARGV.any?
|
5
5
|
require 'optparse'
|
6
6
|
parser = OptionParser.new { |op|
|
7
|
-
op.on('-p port', 'set the port (default is 4567)')
|
8
|
-
op.on('-s server', 'specify rack server/handler
|
9
|
-
op.on('-q', 'turn on quiet mode (default is off)')
|
10
|
-
op.on('-x', 'turn on the mutex lock (default is off)')
|
11
|
-
op.on('-e env', 'set the environment (default is development)')
|
7
|
+
op.on('-p port', 'set the port (default is 4567)') { |val| ParamsConfig[:port] = Integer(val) }
|
8
|
+
op.on('-s server', 'specify rack server/handler') { |val| ParamsConfig[:server] = val }
|
9
|
+
op.on('-q', 'turn on quiet mode (default is off)') { ParamsConfig[:quiet] = true }
|
10
|
+
op.on('-x', 'turn on the mutex lock (default is off)') { ParamsConfig[:lock] = true }
|
11
|
+
op.on('-e env', 'set the environment (default is development)') do |val|
|
12
12
|
ENV['RACK_ENV'] = val
|
13
13
|
ParamsConfig[:environment] = val.to_sym
|
14
14
|
end
|