padrino-core 0.16.0.pre4 → 0.16.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.
- checksums.yaml +4 -4
- data/README.rdoc +8 -8
- data/Rakefile +1 -1
- data/bin/padrino +1 -1
- data/lib/padrino-core/application/application_setup.rb +28 -26
- data/lib/padrino-core/application/authenticity_token.rb +3 -2
- data/lib/padrino-core/application/flash.rb +4 -5
- data/lib/padrino-core/application/params_protection.rb +34 -37
- data/lib/padrino-core/application/routing.rb +165 -164
- data/lib/padrino-core/application/show_exceptions.rb +5 -7
- data/lib/padrino-core/application.rb +4 -4
- data/lib/padrino-core/caller.rb +6 -7
- data/lib/padrino-core/cli/adapter.rb +4 -4
- data/lib/padrino-core/cli/base.rb +31 -32
- data/lib/padrino-core/cli/binstub.rb +9 -8
- data/lib/padrino-core/cli/console.rb +1 -1
- data/lib/padrino-core/cli/launcher.rb +45 -42
- data/lib/padrino-core/cli/rake.rb +16 -14
- data/lib/padrino-core/cli/rake_tasks.rb +18 -20
- data/lib/padrino-core/command.rb +1 -1
- data/lib/padrino-core/ext/sinatra.rb +3 -2
- data/lib/padrino-core/filter.rb +3 -3
- data/lib/padrino-core/loader.rb +10 -12
- data/lib/padrino-core/logger.rb +85 -77
- data/lib/padrino-core/mounter/application_extension.rb +2 -2
- data/lib/padrino-core/mounter.rb +33 -34
- data/lib/padrino-core/path_router/compiler.rb +8 -8
- data/lib/padrino-core/path_router/matcher.rb +11 -11
- data/lib/padrino-core/path_router/route.rb +15 -15
- data/lib/padrino-core/path_router.rb +4 -3
- data/lib/padrino-core/reloader/rack.rb +1 -1
- data/lib/padrino-core/reloader/storage.rb +12 -11
- data/lib/padrino-core/reloader.rb +18 -19
- data/lib/padrino-core/router.rb +14 -14
- data/lib/padrino-core/server.rb +20 -24
- data/lib/padrino-core/tasks.rb +0 -1
- data/lib/padrino-core/version.rb +1 -1
- data/lib/padrino-core.rb +9 -10
- data/padrino-core.gemspec +18 -18
- data/test/fixtures/app_gem/app_gem.gemspec +8 -7
- data/test/fixtures/app_gem/lib/app_gem/version.rb +1 -1
- data/test/fixtures/apps/complex.rb +6 -6
- data/test/fixtures/apps/concerned/app.rb +1 -1
- data/test/fixtures/apps/custom_dependencies/custom_dependencies.rb +3 -3
- data/test/fixtures/apps/demo_app.rb +1 -1
- data/test/fixtures/apps/demo_demo.rb +1 -1
- data/test/fixtures/apps/demo_project/api/app.rb +1 -1
- data/test/fixtures/apps/demo_project/app.rb +1 -1
- data/test/fixtures/apps/helpers/class_methods_helpers.rb +1 -0
- data/test/fixtures/apps/helpers/instance_methods_helpers.rb +1 -0
- data/test/fixtures/apps/helpers/system_helpers.rb +0 -1
- data/test/fixtures/apps/lib/myklass/mysubklass.rb +2 -2
- data/test/fixtures/apps/mountable_apps/rack_apps.rb +7 -7
- data/test/fixtures/apps/precompiled_app.rb +6 -5
- data/test/fixtures/apps/simple.rb +5 -5
- data/test/fixtures/apps/static.rb +2 -2
- data/test/fixtures/apps/stealthy/app.rb +1 -1
- data/test/fixtures/apps/stealthy/helpers/stealthy_class_helpers.rb +1 -1
- data/test/fixtures/apps/system.rb +1 -1
- data/test/fixtures/apps/system_class_methods_demo.rb +1 -1
- data/test/fixtures/apps/system_instance_methods_demo.rb +1 -1
- data/test/fixtures/dependencies/a.rb +1 -1
- data/test/fixtures/dependencies/b.rb +1 -1
- data/test/fixtures/dependencies/c.rb +1 -1
- data/test/fixtures/dependencies/circular/e.rb +2 -1
- data/test/fixtures/dependencies/d.rb +1 -1
- data/test/fixtures/dependencies/linear/i.rb +1 -1
- data/test/fixtures/dependencies/nested/l.rb +2 -2
- data/test/fixtures/dependencies/nested/m.rb +1 -1
- data/test/fixtures/dependencies/nested/qqq.rb +2 -2
- data/test/fixtures/dependencies/nested/rrr.rb +1 -1
- data/test/fixtures/dependencies/nested/sss.rb +1 -1
- data/test/fixtures/reloadable_apps/external/app/app.rb +0 -1
- data/test/fixtures/reloadable_apps/external/app/controllers/base.rb +1 -2
- data/test/fixtures/reloadable_apps/main/app.rb +2 -2
- data/test/helper.rb +2 -2
- data/test/test_application.rb +59 -60
- data/test/test_configuration.rb +2 -2
- data/test/test_core.rb +13 -13
- data/test/test_csrf_protection.rb +67 -63
- data/test/test_dependencies.rb +33 -34
- data/test/test_filters.rb +46 -47
- data/test/test_flash.rb +14 -14
- data/test/test_locale.rb +2 -2
- data/test/test_logger.rb +64 -64
- data/test/test_mounter.rb +133 -123
- data/test/test_params_protection.rb +40 -40
- data/test/test_reloader_complex.rb +23 -23
- data/test/test_reloader_external.rb +10 -10
- data/test/test_reloader_simple.rb +26 -23
- data/test/test_reloader_storage.rb +9 -12
- data/test/test_reloader_system.rb +29 -29
- data/test/test_restful_routing.rb +19 -19
- data/test/test_router.rb +126 -145
- data/test/test_routing.rb +882 -894
- metadata +6 -6
|
@@ -14,9 +14,9 @@ module Padrino
|
|
|
14
14
|
#
|
|
15
15
|
module Routing
|
|
16
16
|
# Defines common content-type alias mappings.
|
|
17
|
-
CONTENT_TYPE_ALIASES = { :
|
|
17
|
+
CONTENT_TYPE_ALIASES = { htm: :html } unless defined?(CONTENT_TYPE_ALIASES)
|
|
18
18
|
# Defines the available route priorities supporting route deferrals.
|
|
19
|
-
ROUTE_PRIORITY = {:
|
|
19
|
+
ROUTE_PRIORITY = { high: 0, normal: 1, low: 2 } unless defined?(ROUTE_PRIORITY)
|
|
20
20
|
|
|
21
21
|
# Raised when a route was invalid or cannot be processed.
|
|
22
22
|
class UnrecognizedException < RuntimeError; end
|
|
@@ -30,13 +30,11 @@ module Padrino
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
class Parent < String
|
|
33
|
-
attr_reader :map
|
|
34
|
-
attr_reader :optional
|
|
35
|
-
attr_reader :options
|
|
33
|
+
attr_reader :map, :optional, :options
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
alias optional? optional
|
|
38
36
|
|
|
39
|
-
def initialize(value, options={})
|
|
37
|
+
def initialize(value, options = {})
|
|
40
38
|
super(value.to_s)
|
|
41
39
|
@map = options.delete(:map)
|
|
42
40
|
@optional = options.delete(:optional)
|
|
@@ -52,7 +50,7 @@ module Padrino
|
|
|
52
50
|
app.send(:include, InstanceMethods)
|
|
53
51
|
app.extend(ClassMethods)
|
|
54
52
|
end
|
|
55
|
-
alias
|
|
53
|
+
alias included registered
|
|
56
54
|
end
|
|
57
55
|
|
|
58
56
|
# Class methods responsible for enhanced routing for controllers.
|
|
@@ -70,20 +68,20 @@ module Padrino
|
|
|
70
68
|
# @example
|
|
71
69
|
# controller :admin do
|
|
72
70
|
# get :index do; ...; end
|
|
73
|
-
# get :show, :
|
|
71
|
+
# get :show, with: :id do; ...; end
|
|
74
72
|
# end
|
|
75
73
|
#
|
|
76
74
|
# url(:admin_index) # => "/admin"
|
|
77
|
-
# url(:admin_show, :
|
|
75
|
+
# url(:admin_show, id: 1) # "/admin/show/1"
|
|
78
76
|
#
|
|
79
77
|
# @example Using named routes follow the sinatra way:
|
|
80
|
-
# controller
|
|
81
|
-
# get
|
|
82
|
-
# get
|
|
78
|
+
# controller '/admin' do
|
|
79
|
+
# get '/index' do; ...; end
|
|
80
|
+
# get '/show/:id' do; ...; end
|
|
83
81
|
# end
|
|
84
82
|
#
|
|
85
83
|
# @example Supply +:provides+ to all controller routes:
|
|
86
|
-
# controller :
|
|
84
|
+
# controller provides: [:html, :xml, :json] do
|
|
87
85
|
# get :index do; "respond to html, xml and json"; end
|
|
88
86
|
# post :index do; "respond to html, xml and json"; end
|
|
89
87
|
# get :foo do; "respond to html, xml and json"; end
|
|
@@ -93,40 +91,42 @@ module Padrino
|
|
|
93
91
|
# controllers :product, :parent => :user do
|
|
94
92
|
# get :index do
|
|
95
93
|
# # url is generated as "/user/#{params[:user_id]}/product"
|
|
96
|
-
# # url_for(:product, :index, :
|
|
94
|
+
# # url_for(:product, :index, user_id: 5) => "/user/5/product"
|
|
97
95
|
# end
|
|
98
|
-
# get :show, :
|
|
96
|
+
# get :show, with: :id do
|
|
99
97
|
# # url is generated as "/user/#{params[:user_id]}/product/show/#{params[:id]}"
|
|
100
|
-
# # url_for(:product, :show, :
|
|
98
|
+
# # url_for(:product, :show, user_id: 5, id: 10) => "/user/5/product/show/10"
|
|
101
99
|
# end
|
|
102
100
|
# end
|
|
103
101
|
#
|
|
104
102
|
# @example Specify conditions to run for all routes:
|
|
105
|
-
# controller :
|
|
103
|
+
# controller conditions: { protect: true } do
|
|
106
104
|
# def self.protect(protected)
|
|
107
105
|
# condition do
|
|
108
|
-
# halt 403,
|
|
106
|
+
# halt 403, 'No secrets for you!' unless params[:key] == 's3cr3t'
|
|
109
107
|
# end if protected
|
|
110
108
|
# end
|
|
111
109
|
#
|
|
112
110
|
# # This route will only return "secret stuff" if the user goes to
|
|
113
111
|
# # `/private?key=s3cr3t`.
|
|
114
|
-
# get("/private") {
|
|
112
|
+
# get("/private") { 'secret stuff' }
|
|
115
113
|
#
|
|
116
114
|
# # And this one, too!
|
|
117
|
-
# get("/also-private") {
|
|
115
|
+
# get("/also-private") { 'secret stuff' }
|
|
118
116
|
#
|
|
119
117
|
# # But you can override the conditions for each route as needed.
|
|
120
118
|
# # This route will be publicly accessible without providing the
|
|
121
119
|
# # secret key.
|
|
122
|
-
# get :index, :
|
|
123
|
-
#
|
|
120
|
+
# get :index, protect: false do
|
|
121
|
+
# 'Welcome!'
|
|
124
122
|
# end
|
|
125
123
|
# end
|
|
126
124
|
#
|
|
127
125
|
# @example Supply default values:
|
|
128
|
-
# controller :
|
|
129
|
-
# get :index, :
|
|
126
|
+
# controller lang: :de do
|
|
127
|
+
# get :index, map: '/:lang' do
|
|
128
|
+
# params[:lang] == :de
|
|
129
|
+
# end
|
|
130
130
|
# end
|
|
131
131
|
#
|
|
132
132
|
# In a controller, before and after filters are scoped and don't
|
|
@@ -144,11 +144,11 @@ module Padrino
|
|
|
144
144
|
def controller(*args, &block)
|
|
145
145
|
if block_given?
|
|
146
146
|
with_new_options(*args) { instance_eval(&block) }
|
|
147
|
-
|
|
148
|
-
include(*args)
|
|
147
|
+
elsif extensions.any?
|
|
148
|
+
include(*args)
|
|
149
149
|
end
|
|
150
150
|
end
|
|
151
|
-
alias
|
|
151
|
+
alias controllers controller
|
|
152
152
|
|
|
153
153
|
##
|
|
154
154
|
# Add a before filter hook.
|
|
@@ -208,18 +208,18 @@ module Padrino
|
|
|
208
208
|
# # => match only path that are +/+ or contains +main+
|
|
209
209
|
#
|
|
210
210
|
# @example filtering everything except an occurrence
|
|
211
|
-
# before :
|
|
211
|
+
# before except: :index do; ...; end
|
|
212
212
|
#
|
|
213
213
|
# @example you can also filter using a request param
|
|
214
|
-
# before :
|
|
214
|
+
# before agent: /IE/ do; ...; end
|
|
215
215
|
# # => match +HTTP_USER_AGENT+ containing +IE+
|
|
216
216
|
#
|
|
217
217
|
# @see http://padrinorb.com/guides/controllers/route-filters/
|
|
218
218
|
#
|
|
219
219
|
def construct_filter(*args, &block)
|
|
220
220
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
|
221
|
-
if except = options.delete(:except)
|
|
222
|
-
|
|
221
|
+
if (except = options.delete(:except))
|
|
222
|
+
raise 'You cannot use :except with other options specified' unless args.empty? && options.empty?
|
|
223
223
|
except = Array(except)
|
|
224
224
|
options = except.last.is_a?(Hash) ? except.pop : {}
|
|
225
225
|
end
|
|
@@ -237,22 +237,22 @@ module Padrino
|
|
|
237
237
|
#
|
|
238
238
|
# @example
|
|
239
239
|
# controllers :product do
|
|
240
|
-
# parent :shop, :
|
|
241
|
-
# parent :category, :
|
|
242
|
-
# get :show, :
|
|
240
|
+
# parent :shop, optional: true, map: "/my/stand"
|
|
241
|
+
# parent :category, optional: true
|
|
242
|
+
# get :show, with: :id do
|
|
243
243
|
# # generated urls:
|
|
244
244
|
# # "/product/show/#{params[:id]}"
|
|
245
245
|
# # "/my/stand/#{params[:shop_id]}/product/show/#{params[:id]}"
|
|
246
246
|
# # "/my/stand/#{params[:shop_id]}/category/#{params[:category_id]}/product/show/#{params[:id]}"
|
|
247
|
-
# # url_for(:product, :show, :
|
|
248
|
-
# # url_for(:product, :show, :
|
|
249
|
-
# # url_for(:product, :show, :
|
|
247
|
+
# # url_for(:product, :show, id: 10) => "/product/show/10"
|
|
248
|
+
# # url_for(:product, :show, shop_id: 5, id: 10) => "/my/stand/5/product/show/10"
|
|
249
|
+
# # url_for(:product, :show, shop_id: 5, category_id: 1, id: 10) => "/my/stand/5/category/1/product/show/10"
|
|
250
250
|
# end
|
|
251
251
|
# end
|
|
252
252
|
#
|
|
253
|
-
def parent(name = nil, options={})
|
|
253
|
+
def parent(name = nil, options = {})
|
|
254
254
|
return super() unless name
|
|
255
|
-
defaults = { :
|
|
255
|
+
defaults = { optional: false, map: name.to_s }
|
|
256
256
|
options = defaults.merge(options)
|
|
257
257
|
@_parent = Array(@_parent) unless @_parent.is_a?(Array)
|
|
258
258
|
@_parent << Parent.new(name, options)
|
|
@@ -269,7 +269,7 @@ module Padrino
|
|
|
269
269
|
@router ||= PathRouter.new
|
|
270
270
|
block_given? ? yield(@router) : @router
|
|
271
271
|
end
|
|
272
|
-
alias
|
|
272
|
+
alias urls router
|
|
273
273
|
|
|
274
274
|
def compiled_router
|
|
275
275
|
if @deferred_routes
|
|
@@ -286,7 +286,7 @@ module Padrino
|
|
|
286
286
|
end
|
|
287
287
|
|
|
288
288
|
def deferred_routes
|
|
289
|
-
@deferred_routes ||= ROUTE_PRIORITY.map{[]}
|
|
289
|
+
@deferred_routes ||= ROUTE_PRIORITY.map { [] }
|
|
290
290
|
end
|
|
291
291
|
|
|
292
292
|
def reset_router!
|
|
@@ -305,16 +305,16 @@ module Padrino
|
|
|
305
305
|
#
|
|
306
306
|
# @example Giving a controller like:
|
|
307
307
|
# controller :foo do
|
|
308
|
-
# get :bar, :
|
|
308
|
+
# get :bar, map: 'foo-bar-:id'; ...; end
|
|
309
309
|
# end
|
|
310
310
|
#
|
|
311
311
|
# @example You should be able to reverse:
|
|
312
|
-
# MyApp.url(:foo_bar, :
|
|
312
|
+
# MyApp.url(:foo_bar, id: :mine)
|
|
313
313
|
# # => /foo-bar-mine
|
|
314
314
|
#
|
|
315
315
|
# @example Into this:
|
|
316
316
|
# MyApp.recognize_path('foo-bar-mine')
|
|
317
|
-
# # => [:foo_bar, :
|
|
317
|
+
# # => [:foo_bar, { id: :mine }]
|
|
318
318
|
#
|
|
319
319
|
def recognize_path(path)
|
|
320
320
|
responses = @router.recognize_path(path)
|
|
@@ -330,12 +330,12 @@ module Padrino
|
|
|
330
330
|
# Synonym for fragment.
|
|
331
331
|
#
|
|
332
332
|
# @example
|
|
333
|
-
# url(:show, :
|
|
334
|
-
# url(:show, :
|
|
333
|
+
# url(:show, id: 1)
|
|
334
|
+
# url(:show, name: 'test', id: 24)
|
|
335
335
|
# url(:show, 1)
|
|
336
|
-
# url(:controller_name, :show, :
|
|
337
|
-
# url(:controller_show, :
|
|
338
|
-
# url(:index, :
|
|
336
|
+
# url(:controller_name, :show, id: 21)
|
|
337
|
+
# url(:controller_show, id: 29)
|
|
338
|
+
# url(:index, fragment: 'comments')
|
|
339
339
|
#
|
|
340
340
|
def url(*args)
|
|
341
341
|
params = args.last.is_a?(Hash) ? args.pop : {}
|
|
@@ -343,7 +343,7 @@ module Padrino
|
|
|
343
343
|
path = make_path_with_params(args, value_to_param(params))
|
|
344
344
|
rebase_url(fragment ? path << '#' << fragment.to_s : path)
|
|
345
345
|
end
|
|
346
|
-
alias
|
|
346
|
+
alias url_for url
|
|
347
347
|
|
|
348
348
|
##
|
|
349
349
|
# Returns absolute url. By default adds 'http://localhost' before generated url.
|
|
@@ -393,22 +393,22 @@ module Padrino
|
|
|
393
393
|
part
|
|
394
394
|
end
|
|
395
395
|
|
|
396
|
-
[parent_prefix, path].flatten.join(
|
|
396
|
+
[parent_prefix, path].flatten.join('')
|
|
397
397
|
end
|
|
398
398
|
|
|
399
399
|
private
|
|
400
400
|
|
|
401
401
|
# temporary variables named @_parent, @_provides, @_use_format, @_cache, @_expires, @_map, @_conditions, @_accepts, @_params
|
|
402
|
-
CONTROLLER_OPTIONS = [
|
|
402
|
+
CONTROLLER_OPTIONS = %i[parent provides use_format cache expires map conditions accepts params].freeze
|
|
403
403
|
|
|
404
404
|
# Saves controller options, yields the block, restores controller options.
|
|
405
405
|
def with_new_options(*args)
|
|
406
406
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
|
407
407
|
|
|
408
|
-
CONTROLLER_OPTIONS.each{ |key| replace_instance_variable("@_#{key}", options.delete(key)) }
|
|
408
|
+
CONTROLLER_OPTIONS.each { |key| replace_instance_variable("@_#{key}", options.delete(key)) }
|
|
409
409
|
replace_instance_variable(:@_controller, args)
|
|
410
410
|
replace_instance_variable(:@_defaults, options)
|
|
411
|
-
replace_instance_variable(:@filters, :
|
|
411
|
+
replace_instance_variable(:@filters, before: @filters[:before].dup, after: @filters[:after].dup)
|
|
412
412
|
replace_instance_variable(:@layout, @layout)
|
|
413
413
|
|
|
414
414
|
yield
|
|
@@ -427,8 +427,8 @@ module Padrino
|
|
|
427
427
|
|
|
428
428
|
# Searches compiled router for a path responding to args and makes a path with params.
|
|
429
429
|
def make_path_with_params(args, params)
|
|
430
|
-
names, params_array = args.partition{ |arg| arg.is_a?(Symbol) }
|
|
431
|
-
name = names[0, 2].join(
|
|
430
|
+
names, params_array = args.partition { |arg| arg.is_a?(Symbol) }
|
|
431
|
+
name = names[0, 2].join(' ').to_sym
|
|
432
432
|
compiled_router.path(name, *(params_array << params))
|
|
433
433
|
rescue PathRouter::InvalidRouteException
|
|
434
434
|
raise Padrino::Routing::UnrecognizedException, "Route mapping for url(#{name.inspect}) could not be found"
|
|
@@ -444,7 +444,8 @@ module Padrino
|
|
|
444
444
|
next all if value.nil?
|
|
445
445
|
all[key] = value_to_param(value)
|
|
446
446
|
end
|
|
447
|
-
when
|
|
447
|
+
when NilClass
|
|
448
|
+
nil
|
|
448
449
|
else
|
|
449
450
|
object.respond_to?(:to_param) ? object.to_param : object
|
|
450
451
|
end
|
|
@@ -452,46 +453,47 @@ module Padrino
|
|
|
452
453
|
|
|
453
454
|
# Add prefix slash if its not present and remove trailing slashes.
|
|
454
455
|
def conform_uri(uri_string)
|
|
455
|
-
uri_string.gsub(
|
|
456
|
+
uri_string.gsub(%r{^(?!/)(.*)}, '/\1').gsub(%r{/+$}, '')
|
|
456
457
|
end
|
|
457
458
|
|
|
458
459
|
##
|
|
459
460
|
# Rewrite default routes.
|
|
460
461
|
#
|
|
461
462
|
# @example
|
|
462
|
-
# get :index
|
|
463
|
-
# get :index,
|
|
464
|
-
# get :index, :
|
|
465
|
-
# get :show,
|
|
466
|
-
# get :show, :
|
|
467
|
-
# get
|
|
468
|
-
# get :index, :
|
|
469
|
-
# get :show, :
|
|
470
|
-
# get :show, :
|
|
471
|
-
# get [:show, :id]
|
|
472
|
-
# get :show, :
|
|
473
|
-
# get [:show, :id, :name]
|
|
474
|
-
# get :list, :
|
|
475
|
-
# get :list, :
|
|
476
|
-
# get :list, :
|
|
477
|
-
# get :list, :
|
|
478
|
-
# get :list, :
|
|
479
|
-
# get /pattern/, :
|
|
463
|
+
# get :index # => "/"
|
|
464
|
+
# get :index, '/' # => "/"
|
|
465
|
+
# get :index, map: '/' # => "/"
|
|
466
|
+
# get :show, '/show-me' # => "/show-me"
|
|
467
|
+
# get :show, map: '/show-me' # => "/show-me"
|
|
468
|
+
# get '/foo/bar' # => "/show"
|
|
469
|
+
# get :index, parent: :user # => "/user/:user_id/index"
|
|
470
|
+
# get :show, with: :id, parent: :user # => "/user/:user_id/show/:id"
|
|
471
|
+
# get :show, with: :id # => "/show/:id"
|
|
472
|
+
# get [:show, :id] # => "/show/:id"
|
|
473
|
+
# get :show, with: [:id, :name] # => "/show/:id/:name"
|
|
474
|
+
# get [:show, :id, :name] # => "/show/:id/:name"
|
|
475
|
+
# get :list, provides: :js # => "/list.{:format,js)"
|
|
476
|
+
# get :list, provides: :any # => "/list(.:format)"
|
|
477
|
+
# get :list, provides: [:js, :json] # => "/list.{!format,js|json}"
|
|
478
|
+
# get :list, provides: [:html, :js, :json] # => "/list(.{!format,js|json})"
|
|
479
|
+
# get :list, priority: :low # Defers route to be last
|
|
480
|
+
# get /pattern/, name: :foo, generate_with: '/foo' # Generates :foo as /foo
|
|
480
481
|
def route(verb, path, *args, &block)
|
|
481
|
-
options =
|
|
482
|
+
options =
|
|
483
|
+
case args.size
|
|
482
484
|
when 2
|
|
483
|
-
args.last.merge(:
|
|
485
|
+
args.last.merge(map: args.first)
|
|
484
486
|
when 1
|
|
485
487
|
map = args.shift if args.first.is_a?(String)
|
|
486
488
|
if args.first.is_a?(Hash)
|
|
487
|
-
map ? args.first.merge(:
|
|
489
|
+
map ? args.first.merge(map: map) : args.first
|
|
488
490
|
else
|
|
489
|
-
{:
|
|
491
|
+
{ map: map || args.first }
|
|
490
492
|
end
|
|
491
493
|
when 0
|
|
492
494
|
{}
|
|
493
495
|
else raise
|
|
494
|
-
|
|
496
|
+
end
|
|
495
497
|
|
|
496
498
|
route_options = options.dup
|
|
497
499
|
route_options[:provides] = @_provides if @_provides
|
|
@@ -500,9 +502,7 @@ module Padrino
|
|
|
500
502
|
|
|
501
503
|
# Add Sinatra condition to check rack-protection failure.
|
|
502
504
|
if respond_to?(:protect_from_csrf) && protect_from_csrf && (report_csrf_failure || allow_disabled_csrf)
|
|
503
|
-
|
|
504
|
-
route_options[:csrf_protection] = true
|
|
505
|
-
end
|
|
505
|
+
route_options[:csrf_protection] = route_options.fetch(:csrf_protection, true)
|
|
506
506
|
end
|
|
507
507
|
|
|
508
508
|
path, *route_options[:with] = path if path.is_a?(Array)
|
|
@@ -514,15 +514,15 @@ module Padrino
|
|
|
514
514
|
unbound_method = generate_method(method_name.to_sym, &block)
|
|
515
515
|
|
|
516
516
|
block_arity = block.arity
|
|
517
|
-
block = if block_arity
|
|
518
|
-
proc{ |request, _| unbound_method.bind(request).call }
|
|
517
|
+
block = if block_arity.zero?
|
|
518
|
+
proc { |request, _| unbound_method.bind(request).call }
|
|
519
519
|
else
|
|
520
|
-
proc{ |request, block_params| unbound_method.bind(request).call(*block_params) }
|
|
520
|
+
proc { |request, block_params| unbound_method.bind(request).call(*block_params) }
|
|
521
521
|
end
|
|
522
522
|
|
|
523
523
|
invoke_hook(:route_added, verb, path, block)
|
|
524
524
|
|
|
525
|
-
path[0, 0] =
|
|
525
|
+
path[0, 0] = '/' if path == '(.:format)?'
|
|
526
526
|
route = router.add(verb, path, route_options)
|
|
527
527
|
route.name = name if name
|
|
528
528
|
route.action = action
|
|
@@ -530,14 +530,16 @@ module Padrino
|
|
|
530
530
|
priority = ROUTE_PRIORITY[priority_name] or raise("Priority #{priority_name} not recognized, try #{ROUTE_PRIORITY.keys.join(', ')}")
|
|
531
531
|
route.cache = options.key?(:cache) ? options.delete(:cache) : @_cache
|
|
532
532
|
route.cache_expires = options.key?(:expires) ? options.delete(:expires) : @_expires
|
|
533
|
-
route.parent = route_parents
|
|
533
|
+
route.parent = route_parents&.count == 1 ? route_parents.first : route_parents
|
|
534
534
|
route.host = options.delete(:host) if options.key?(:host)
|
|
535
535
|
route.user_agent = options.delete(:agent) if options.key?(:agent)
|
|
536
|
+
|
|
536
537
|
if options.key?(:default_values)
|
|
537
538
|
defaults = options.delete(:default_values)
|
|
538
|
-
#route.options[:default_values] = defaults if defaults
|
|
539
|
+
# route.options[:default_values] = defaults if defaults
|
|
539
540
|
route.default_values = defaults if defaults
|
|
540
541
|
end
|
|
542
|
+
|
|
541
543
|
options.delete_if do |option, captures|
|
|
542
544
|
if route.significant_variable_names.include?(option.to_s)
|
|
543
545
|
route.capture[option] = Array(captures).first
|
|
@@ -546,18 +548,19 @@ module Padrino
|
|
|
546
548
|
end
|
|
547
549
|
|
|
548
550
|
# Add Sinatra conditions.
|
|
549
|
-
options.each do |option,
|
|
551
|
+
options.each do |option, args|
|
|
550
552
|
option = :provides_format if option == :provides
|
|
551
|
-
route.respond_to?(option) ? route.send(option, *
|
|
553
|
+
route.respond_to?(option) ? route.send(option, *args) : send(option, *args)
|
|
552
554
|
end
|
|
555
|
+
|
|
553
556
|
conditions, @conditions = @conditions, []
|
|
554
557
|
route.custom_conditions.concat(conditions)
|
|
555
558
|
|
|
556
559
|
invoke_hook(:padrino_route_added, route, verb, path, args, options, block)
|
|
557
560
|
|
|
558
561
|
block_parameter_length = route.block_parameter_length
|
|
559
|
-
if block_arity
|
|
560
|
-
|
|
562
|
+
if block_arity.positive? && block_parameter_length != block_arity
|
|
563
|
+
raise BlockArityError.new(route.path, block_arity, block_parameter_length)
|
|
561
564
|
end
|
|
562
565
|
|
|
563
566
|
# Add Application defaults.
|
|
@@ -580,7 +583,7 @@ module Padrino
|
|
|
580
583
|
# controllers, parents, 'with' parameters, and other options.
|
|
581
584
|
#
|
|
582
585
|
def parse_route(path, options, verb)
|
|
583
|
-
path = path.dup if path.
|
|
586
|
+
path = path.dup if path.is_a?(String)
|
|
584
587
|
route_options = {}
|
|
585
588
|
|
|
586
589
|
if options[:params] == true
|
|
@@ -594,9 +597,9 @@ module Padrino
|
|
|
594
597
|
map = options.delete(:map)
|
|
595
598
|
|
|
596
599
|
# path i.e :index or :show
|
|
597
|
-
if path.
|
|
600
|
+
if path.is_a?(Symbol)
|
|
598
601
|
name = path
|
|
599
|
-
path = map
|
|
602
|
+
path = map&.dup || (path == :index ? '/' : path.to_s)
|
|
600
603
|
end
|
|
601
604
|
|
|
602
605
|
# Build our controller
|
|
@@ -605,13 +608,13 @@ module Padrino
|
|
|
605
608
|
case path
|
|
606
609
|
when String # path i.e "/index" or "/show"
|
|
607
610
|
# Now we need to parse our 'with' params
|
|
608
|
-
if with_params = options.delete(:with)
|
|
611
|
+
if (with_params = options.delete(:with))
|
|
609
612
|
path = process_path_for_with_params(path, with_params)
|
|
610
613
|
end
|
|
611
614
|
|
|
612
615
|
# Now we need to parse our provides
|
|
613
616
|
options.delete(:provides) if options[:provides].nil?
|
|
614
|
-
|
|
617
|
+
|
|
615
618
|
options.delete(:accepts) if options[:accepts].nil?
|
|
616
619
|
|
|
617
620
|
if @_use_format || options[:provides]
|
|
@@ -620,19 +623,17 @@ module Padrino
|
|
|
620
623
|
# options[:add_match_with][:format] = /[^\.]+/
|
|
621
624
|
end
|
|
622
625
|
|
|
623
|
-
absolute_map = map && map[0] ==
|
|
626
|
+
absolute_map = map && map[0] == '/'
|
|
624
627
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
path = File.join(controller_path, path) unless @_map
|
|
631
|
-
end
|
|
628
|
+
# Now we need to add our controller path only if not mapped directly
|
|
629
|
+
if controller.any? && !map && !absolute_map
|
|
630
|
+
controller_path = controller.join('/')
|
|
631
|
+
path.gsub!(%r{^\(/\)|/\?}, '')
|
|
632
|
+
path = File.join(controller_path, path) unless @_map
|
|
632
633
|
end
|
|
633
634
|
|
|
634
635
|
# Now we need to parse our 'parent' params and parent scope.
|
|
635
|
-
if !absolute_map
|
|
636
|
+
if !absolute_map && (parent_params = options.delete(:parent) || @_parent)
|
|
636
637
|
parent_params = (Array(@_parent) + Array(parent_params)).uniq
|
|
637
638
|
path = process_path_for_parent_params(path, parent_params)
|
|
638
639
|
end
|
|
@@ -641,11 +642,11 @@ module Padrino
|
|
|
641
642
|
path = "#{@_map}/#{path}".squeeze('/') unless absolute_map || !@_map
|
|
642
643
|
|
|
643
644
|
# Small reformats
|
|
644
|
-
path.gsub!(%r{/\?$}, '(/)')
|
|
645
|
-
path.gsub!(%r{//$}, '/')
|
|
646
|
-
path[0,0] =
|
|
647
|
-
path.sub!(%r{/(\))?$}, '\\1') if path !=
|
|
648
|
-
path.gsub!(
|
|
645
|
+
path.gsub!(%r{/\?$}, '(/)') # Remove index path
|
|
646
|
+
path.gsub!(%r{//$}, '/') # Remove index path
|
|
647
|
+
path[0, 0] = '/' if path !~ %r{^\(?/} # Paths must start with a /
|
|
648
|
+
path.sub!(%r{/(\))?$}, '\\1') if path != '/' # Remove latest trailing delimiter
|
|
649
|
+
path.gsub!(%r{/(\(\.|$)}, '\\1') # Remove trailing slashes
|
|
649
650
|
path.squeeze!('/')
|
|
650
651
|
when Regexp
|
|
651
652
|
route_options[:path_for_generation] = options.delete(:generate_with) if options.key?(:generate_with)
|
|
@@ -654,11 +655,11 @@ module Padrino
|
|
|
654
655
|
name = options.delete(:route_name) if name.nil? && options.key?(:route_name)
|
|
655
656
|
name = options.delete(:name) if name.nil? && options.key?(:name)
|
|
656
657
|
if name
|
|
657
|
-
controller_name = controller.join(
|
|
658
|
+
controller_name = controller.join('_')
|
|
658
659
|
name = "#{controller_name} #{name}".to_sym unless controller_name.empty?
|
|
659
660
|
end
|
|
660
661
|
|
|
661
|
-
options[:default_values] = @_defaults unless options.
|
|
662
|
+
options[:default_values] = @_defaults unless options.key?(:default_values)
|
|
662
663
|
|
|
663
664
|
[path, name, parent_params, options, route_options]
|
|
664
665
|
end
|
|
@@ -669,8 +670,8 @@ module Padrino
|
|
|
669
670
|
#
|
|
670
671
|
def process_path_for_with_params(path, with_params)
|
|
671
672
|
File.join(path, Array(with_params).map do |step|
|
|
672
|
-
step.
|
|
673
|
-
end.join(
|
|
673
|
+
step.is_a?(String) ? step : step.inspect
|
|
674
|
+
end.join('/'))
|
|
674
675
|
end
|
|
675
676
|
|
|
676
677
|
##
|
|
@@ -678,7 +679,7 @@ module Padrino
|
|
|
678
679
|
# Used for calculating path in route method.
|
|
679
680
|
#
|
|
680
681
|
def process_path_for_provides(path)
|
|
681
|
-
path <<
|
|
682
|
+
path << '(.:format)?' unless path[-11, 11] == '(.:format)?'
|
|
682
683
|
end
|
|
683
684
|
|
|
684
685
|
##
|
|
@@ -695,17 +696,17 @@ module Padrino
|
|
|
695
696
|
# returned.
|
|
696
697
|
#
|
|
697
698
|
# @example
|
|
698
|
-
# get "/a", :
|
|
699
|
+
# get "/a", provides: [:html, :js]
|
|
699
700
|
# # => GET /a => :html
|
|
700
701
|
# # => GET /a.js => :js
|
|
701
702
|
# # => GET /a.xml => 404
|
|
702
703
|
#
|
|
703
|
-
# get "/b", :
|
|
704
|
+
# get "/b", provides: [:html]
|
|
704
705
|
# # => GET /b; ACCEPT: html => html
|
|
705
706
|
# # => GET /b; ACCEPT: js => 406
|
|
706
707
|
#
|
|
707
708
|
# enable :treat_format_as_accept
|
|
708
|
-
# get "/c", :
|
|
709
|
+
# get "/c", provides: [:html, :js]
|
|
709
710
|
# # => GET /c.xml => 406
|
|
710
711
|
#
|
|
711
712
|
def provides(*types)
|
|
@@ -714,18 +715,18 @@ module Padrino
|
|
|
714
715
|
end
|
|
715
716
|
|
|
716
717
|
def provides_format(*types)
|
|
717
|
-
mime_types = types.map{ |type| mime_type(CONTENT_TYPE_ALIASES[type] || type) }
|
|
718
|
+
mime_types = types.map { |type| mime_type(CONTENT_TYPE_ALIASES[type] || type) }
|
|
718
719
|
condition do
|
|
719
720
|
return provides_format?(types, params[:format].to_sym) if params[:format]
|
|
720
721
|
|
|
721
722
|
accepts = request.accept.map(&:to_str)
|
|
722
723
|
# Per rfc2616-sec14:
|
|
723
724
|
# Assume */* if no ACCEPT header is given.
|
|
724
|
-
catch_all = accepts.delete(
|
|
725
|
+
catch_all = accepts.delete('*/*')
|
|
725
726
|
|
|
726
727
|
return provides_any?(accepts) if types.include?(:any)
|
|
727
728
|
|
|
728
|
-
accepts = accepts.empty? ? mime_types.slice(0,1) : (accepts & mime_types)
|
|
729
|
+
accepts = accepts.empty? ? mime_types.slice(0, 1) : (accepts & mime_types)
|
|
729
730
|
|
|
730
731
|
type = accepts.first && mime_symbol(accepts.first)
|
|
731
732
|
type ||= catch_all && types.first
|
|
@@ -743,13 +744,13 @@ module Padrino
|
|
|
743
744
|
# Allows routing by Media type.
|
|
744
745
|
#
|
|
745
746
|
# @example
|
|
746
|
-
# get "/a", :
|
|
747
|
+
# get "/a", accepts: [:html, :js]
|
|
747
748
|
# # => GET /a CONTENT_TYPE text/html => :html
|
|
748
749
|
# # => GET /a CONTENT_TYPE application/javascript => :js
|
|
749
750
|
# # => GET /a CONTENT_TYPE application/xml => 406
|
|
750
751
|
#
|
|
751
752
|
def accepts(*types)
|
|
752
|
-
mime_types = types.map{ |type| mime_type(CONTENT_TYPE_ALIASES[type] || type) }
|
|
753
|
+
mime_types = types.map { |type| mime_type(CONTENT_TYPE_ALIASES[type] || type) }
|
|
753
754
|
condition do
|
|
754
755
|
halt 406 unless mime_types.include?(request.media_type)
|
|
755
756
|
content_type(mime_symbol(request.media_type))
|
|
@@ -761,13 +762,13 @@ module Padrino
|
|
|
761
762
|
# `report_csrf_failure` is enabled.
|
|
762
763
|
#
|
|
763
764
|
# @example
|
|
764
|
-
# post("/", :
|
|
765
|
+
# post("/", csrf_protection: false)
|
|
765
766
|
#
|
|
766
767
|
def csrf_protection(enabled)
|
|
767
768
|
return unless enabled
|
|
768
769
|
condition do
|
|
769
770
|
if request.env['protection.csrf.failed']
|
|
770
|
-
message = settings.protect_from_csrf.
|
|
771
|
+
message = settings.protect_from_csrf.is_a?(Hash) && settings.protect_from_csrf[:message] || 'Forbidden'
|
|
771
772
|
halt(403, message)
|
|
772
773
|
end
|
|
773
774
|
end
|
|
@@ -782,8 +783,8 @@ module Padrino
|
|
|
782
783
|
# Instance method for URL generation.
|
|
783
784
|
#
|
|
784
785
|
# @example
|
|
785
|
-
# url(:show, :
|
|
786
|
-
# url(:show, :
|
|
786
|
+
# url(:show, id: 1)
|
|
787
|
+
# url(:show, name: :test)
|
|
787
788
|
# url(:show, 1)
|
|
788
789
|
# url("/foo", false, false)
|
|
789
790
|
#
|
|
@@ -804,16 +805,16 @@ module Padrino
|
|
|
804
805
|
settings.url(*args)
|
|
805
806
|
end
|
|
806
807
|
end
|
|
807
|
-
alias
|
|
808
|
+
alias url_for url
|
|
808
809
|
|
|
809
810
|
##
|
|
810
811
|
# Returns absolute url. Calls Sinatra::Helpers#uri to generate protocol version, hostname and port.
|
|
811
812
|
#
|
|
812
813
|
# @example
|
|
813
|
-
# absolute_url(:show, :
|
|
814
|
-
# absolute_url(:show, 24)
|
|
815
|
-
# absolute_url('/foo/bar')
|
|
816
|
-
# absolute_url('baz')
|
|
814
|
+
# absolute_url(:show, id: 1) # => http://example.com/show?id=1
|
|
815
|
+
# absolute_url(:show, 24) # => https://example.com/admin/show/24
|
|
816
|
+
# absolute_url('/foo/bar') # => https://example.com/admin/foo/bar
|
|
817
|
+
# absolute_url('baz') # => https://example.com/admin/foo/baz
|
|
817
818
|
#
|
|
818
819
|
def absolute_url(*args)
|
|
819
820
|
url_path = args.shift
|
|
@@ -857,7 +858,7 @@ module Padrino
|
|
|
857
858
|
# serving files from the public directory.
|
|
858
859
|
#
|
|
859
860
|
def static_file?(path_info)
|
|
860
|
-
return unless public_dir = settings.public_folder
|
|
861
|
+
return unless (public_dir = settings.public_folder)
|
|
861
862
|
public_dir = File.expand_path(public_dir)
|
|
862
863
|
path = File.expand_path(public_dir + unescape(path_info))
|
|
863
864
|
return unless path.start_with?(public_dir)
|
|
@@ -869,7 +870,7 @@ module Padrino
|
|
|
869
870
|
# Method for deliver static files.
|
|
870
871
|
#
|
|
871
872
|
def static!(options = {})
|
|
872
|
-
if path = static_file?(request.path_info)
|
|
873
|
+
if (path = static_file?(request.path_info))
|
|
873
874
|
env['sinatra.static_file'] = path
|
|
874
875
|
cache_control(*settings.static_cache_control) if settings.static_cache_control?
|
|
875
876
|
send_file(path, options)
|
|
@@ -893,7 +894,7 @@ module Padrino
|
|
|
893
894
|
# end
|
|
894
895
|
# end
|
|
895
896
|
#
|
|
896
|
-
def content_type(type=nil, params={})
|
|
897
|
+
def content_type(type = nil, params = {})
|
|
897
898
|
return @_content_type unless type
|
|
898
899
|
super(type, params)
|
|
899
900
|
@_content_type = type
|
|
@@ -919,10 +920,10 @@ module Padrino
|
|
|
919
920
|
end
|
|
920
921
|
|
|
921
922
|
def mime_symbol(media_type)
|
|
922
|
-
::Rack::Mime::MIME_TYPES.key(media_type).sub(/\./,'').to_sym
|
|
923
|
+
::Rack::Mime::MIME_TYPES.key(media_type).sub(/\./, '').to_sym
|
|
923
924
|
end
|
|
924
925
|
|
|
925
|
-
def filter!(type, base=settings)
|
|
926
|
+
def filter!(type, base = settings)
|
|
926
927
|
filter! type, base.superclass if base.superclass.respond_to?(:filters)
|
|
927
928
|
base.filters[type].each { |block| instance_eval(&block) }
|
|
928
929
|
end
|
|
@@ -934,14 +935,14 @@ module Padrino
|
|
|
934
935
|
static! if settings.static? && (request.get? || request.head?)
|
|
935
936
|
route!
|
|
936
937
|
end
|
|
937
|
-
rescue ::Exception =>
|
|
938
|
-
filter! :before if
|
|
939
|
-
invoke { @boom_handled = handle_exception!(
|
|
938
|
+
rescue ::Exception => e
|
|
939
|
+
filter! :before if e.is_a? ::Sinatra::NotFound
|
|
940
|
+
invoke { @boom_handled = handle_exception!(e) }
|
|
940
941
|
ensure
|
|
941
|
-
@boom_handled
|
|
942
|
-
filter! :after
|
|
943
|
-
rescue ::Exception =>
|
|
944
|
-
invoke { handle_exception!(
|
|
942
|
+
@boom_handled || begin
|
|
943
|
+
filter! :after unless env['sinatra.static_file']
|
|
944
|
+
rescue ::Exception => e
|
|
945
|
+
invoke { handle_exception!(e) } unless @env['sinatra.error']
|
|
945
946
|
end
|
|
946
947
|
end
|
|
947
948
|
|
|
@@ -950,7 +951,7 @@ module Padrino
|
|
|
950
951
|
first_time = true
|
|
951
952
|
|
|
952
953
|
routes = base.compiled_router.call(@request) do |route, params|
|
|
953
|
-
next if route.user_agent &&
|
|
954
|
+
next if route.user_agent && route.user_agent !~ @request.user_agent
|
|
954
955
|
original_params, parent_layout = @params.dup, @layout
|
|
955
956
|
returned_pass_block = invoke_route(route, params, first_time)
|
|
956
957
|
pass_block = returned_pass_block if returned_pass_block
|
|
@@ -960,9 +961,9 @@ module Padrino
|
|
|
960
961
|
|
|
961
962
|
unless routes.empty?
|
|
962
963
|
verb = request.request_method
|
|
963
|
-
candidacies, allows = routes.partition{|route| route.verb == verb }
|
|
964
|
+
candidacies, allows = routes.partition { |route| route.verb == verb }
|
|
964
965
|
if candidacies.empty?
|
|
965
|
-
response[
|
|
966
|
+
response['Allows'] = allows.map(&:verb).join(', ')
|
|
966
967
|
halt 405
|
|
967
968
|
end
|
|
968
969
|
end
|
|
@@ -982,9 +983,11 @@ module Padrino
|
|
|
982
983
|
captured_params = captures_from_params(params)
|
|
983
984
|
|
|
984
985
|
# Should not overwrite params by given query
|
|
985
|
-
|
|
986
|
-
@
|
|
987
|
-
|
|
986
|
+
unless params.empty?
|
|
987
|
+
@params.merge!(params) do |key, original, newval|
|
|
988
|
+
@route.significant_variable_names.include?(key) ? newval : original
|
|
989
|
+
end
|
|
990
|
+
end
|
|
988
991
|
|
|
989
992
|
@params[:format] = params[:format] if params[:format]
|
|
990
993
|
@params[:captures] = captured_params if !captured_params.empty? && route.path.is_a?(Regexp)
|
|
@@ -992,16 +995,14 @@ module Padrino
|
|
|
992
995
|
filter! :before if first_time
|
|
993
996
|
|
|
994
997
|
catch(:pass) do
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
(route.after_filters - settings.filters[:after]).each {|block| instance_eval(&block) }
|
|
1004
|
-
|
|
998
|
+
(route.before_filters - settings.filters[:before]).each { |block| instance_eval(&block) }
|
|
999
|
+
@layout = route.use_layout if route.use_layout
|
|
1000
|
+
route.custom_conditions.each { |block| pass if block.bind(self).call == false }
|
|
1001
|
+
route_response = route.block[self, captured_params]
|
|
1002
|
+
@_response_buffer = route_response.instance_of?(Array) ? route_response.last : route_response
|
|
1003
|
+
halt(route_response)
|
|
1004
|
+
ensure
|
|
1005
|
+
(route.after_filters - settings.filters[:after]).each { |block| instance_eval(&block) }
|
|
1005
1006
|
end
|
|
1006
1007
|
end
|
|
1007
1008
|
|