padrino-core 0.11.3 → 0.11.4
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 +7 -0
- data/README.rdoc +5 -5
- data/lib/padrino-core.rb +3 -9
- data/lib/padrino-core/application.rb +39 -35
- data/lib/padrino-core/application/flash.rb +7 -7
- data/lib/padrino-core/application/rendering.rb +136 -139
- data/lib/padrino-core/application/rendering/extensions/erubis.rb +15 -6
- data/lib/padrino-core/application/routing.rb +371 -369
- data/lib/padrino-core/application/showexceptions.rb +13 -12
- data/lib/padrino-core/caller.rb +40 -40
- data/lib/padrino-core/cli/adapter.rb +4 -4
- data/lib/padrino-core/cli/base.rb +40 -39
- data/lib/padrino-core/cli/rake.rb +2 -2
- data/lib/padrino-core/cli/rake_tasks.rb +2 -4
- data/lib/padrino-core/command.rb +2 -2
- data/lib/padrino-core/loader.rb +14 -15
- data/lib/padrino-core/locale/cs.yml +0 -1
- data/lib/padrino-core/locale/da.yml +0 -1
- data/lib/padrino-core/locale/de.yml +0 -1
- data/lib/padrino-core/locale/en.yml +0 -1
- data/lib/padrino-core/locale/es.yml +1 -2
- data/lib/padrino-core/locale/fr.yml +2 -3
- data/lib/padrino-core/locale/hu.yml +1 -2
- data/lib/padrino-core/locale/it.yml +0 -1
- data/lib/padrino-core/locale/ja.yml +1 -2
- data/lib/padrino-core/locale/lv.yml +0 -1
- data/lib/padrino-core/locale/nl.yml +0 -1
- data/lib/padrino-core/locale/no.yml +0 -2
- data/lib/padrino-core/locale/pl.yml +0 -1
- data/lib/padrino-core/locale/pt_br.yml +0 -1
- data/lib/padrino-core/locale/ro.yml +0 -1
- data/lib/padrino-core/locale/ru.yml +0 -1
- data/lib/padrino-core/locale/sv.yml +0 -1
- data/lib/padrino-core/locale/tr.yml +0 -1
- data/lib/padrino-core/locale/uk.yml +0 -1
- data/lib/padrino-core/locale/zh_cn.yml +0 -1
- data/lib/padrino-core/locale/zh_tw.yml +0 -1
- data/lib/padrino-core/logger.rb +26 -27
- data/lib/padrino-core/module.rb +3 -3
- data/lib/padrino-core/mounter.rb +59 -59
- data/lib/padrino-core/reloader.rb +23 -23
- data/lib/padrino-core/router.rb +10 -13
- data/lib/padrino-core/server.rb +17 -19
- data/lib/padrino-core/tasks.rb +3 -3
- data/lib/padrino-core/version.rb +1 -1
- data/padrino-core.gemspec +1 -1
- data/test/test_application.rb +7 -7
- data/test/test_rendering.rb +15 -2
- data/test/test_routing.rb +34 -10
- metadata +13 -27
@@ -13,7 +13,7 @@ begin
|
|
13
13
|
src << " #{@bufvar}.concat((" << code << ').to_s);'
|
14
14
|
end
|
15
15
|
|
16
|
-
def add_expr_escaped(src, code)
|
16
|
+
def add_expr_escaped(src, code)
|
17
17
|
src << " #{@bufvar}.safe_concat " << code << ';'
|
18
18
|
end
|
19
19
|
|
@@ -37,19 +37,28 @@ begin
|
|
37
37
|
#
|
38
38
|
# @api private
|
39
39
|
class Template < Tilt::ErubisTemplate
|
40
|
+
def render(*args)
|
41
|
+
app = args.first
|
42
|
+
app_class = app.class
|
43
|
+
@padrino_app = app.kind_of?(Padrino::Application) ||
|
44
|
+
(app_class.respond_to?(:erb) && app_class.erb[:engine_class] == Padrino::Erubis::SafeBufferTemplate)
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
40
48
|
def precompiled_preamble(locals)
|
49
|
+
buf = @padrino_app ? "ActiveSupport::SafeBuffer.new" : "''"
|
41
50
|
old_postamble = super.split("\n")[0..-2]
|
42
|
-
[old_postamble, "#{@outvar} = _buf = (#{@outvar} ||
|
51
|
+
[old_postamble, "#{@outvar} = _buf = (#{@outvar} || #{buf})"].join("\n")
|
43
52
|
end
|
44
53
|
end
|
45
54
|
end
|
46
55
|
end
|
47
|
-
|
48
|
-
Tilt.prefer
|
56
|
+
|
57
|
+
Tilt.prefer(Padrino::Erubis::Template, :erb)
|
49
58
|
|
50
59
|
if defined? Padrino::Rendering
|
51
|
-
Padrino::Rendering.engine_configurations[:erb] =
|
60
|
+
Padrino::Rendering.engine_configurations[:erb] =
|
52
61
|
{:engine_class => Padrino::Erubis::SafeBufferTemplate}
|
53
62
|
end
|
54
63
|
rescue LoadError
|
55
|
-
end
|
64
|
+
end
|
@@ -4,7 +4,6 @@ require 'padrino-core/support_lite' unless defined?(SupportLite)
|
|
4
4
|
##
|
5
5
|
# Adds to Sinatra +controller+ informations
|
6
6
|
#
|
7
|
-
# @private
|
8
7
|
class Sinatra::Request
|
9
8
|
attr_accessor :route_obj
|
10
9
|
|
@@ -16,10 +15,7 @@ class Sinatra::Request
|
|
16
15
|
end
|
17
16
|
end
|
18
17
|
|
19
|
-
|
20
|
-
# HttpRouter adapter
|
21
|
-
#
|
22
|
-
# @private
|
18
|
+
|
23
19
|
class HttpRouter
|
24
20
|
def rewrite_partial_path_info(env, request); end
|
25
21
|
def rewrite_path_info(env, request); end
|
@@ -49,7 +45,7 @@ class HttpRouter
|
|
49
45
|
filter! :before
|
50
46
|
(@route.before_filters - settings.filters[:before]).each { |block| instance_eval(&block) }
|
51
47
|
@layout = path.route.use_layout if path.route.use_layout
|
52
|
-
@route.custom_conditions.each { |block| pass if block.bind(self).call == false }
|
48
|
+
@route.custom_conditions.each { |block| pass if block.bind(self).call == false }
|
53
49
|
halt_response = catch(:halt) { route_eval { @route.dest[self, @block_params] } }
|
54
50
|
@_response_buffer = halt_response.is_a?(Array) ? halt_response.last : halt_response
|
55
51
|
successful = true
|
@@ -62,7 +58,6 @@ class HttpRouter
|
|
62
58
|
end
|
63
59
|
end
|
64
60
|
|
65
|
-
# @private
|
66
61
|
class Route
|
67
62
|
VALID_HTTP_VERBS.replace %w[GET POST PUT PATCH DELETE HEAD OPTIONS LINK UNLINK]
|
68
63
|
|
@@ -124,12 +119,30 @@ class HttpRouter
|
|
124
119
|
@routes.sort!{ |a, b| a.order <=> b.order }
|
125
120
|
end
|
126
121
|
|
127
|
-
|
128
|
-
|
122
|
+
class Node::SpanningRegex
|
123
|
+
def to_code
|
124
|
+
params_count = @ordered_indicies.size
|
125
|
+
whole_path_var = "whole_path#{root.next_counter}"
|
126
|
+
"#{whole_path_var} = request.joined_path
|
127
|
+
if match = #{@matcher.inspect}.match(#{whole_path_var}) and match.begin(0).zero?
|
128
|
+
_#{whole_path_var} = request.path.dup
|
129
|
+
" << param_capturing_code << "
|
130
|
+
remaining_path = #{whole_path_var}[match[0].size + (#{whole_path_var}[match[0].size] == ?/ ? 1 : 0), #{whole_path_var}.size]
|
131
|
+
request.path = remaining_path.split('/')
|
132
|
+
#{node_to_code}
|
133
|
+
request.path = _#{whole_path_var}
|
134
|
+
request.params.slice!(#{-params_count}, #{params_count})
|
135
|
+
end
|
136
|
+
"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Monkey patching the Request class. Using Rack::Utils.unescape rather than
|
141
|
+
# URI.unescape which can't handle utf-8 chars
|
129
142
|
class Request
|
130
143
|
def initialize(path, rack_request)
|
131
144
|
@rack_request = rack_request
|
132
|
-
@path = Rack::Utils.unescape(
|
145
|
+
@path = path.split(/\//).map{|part| Rack::Utils.unescape(part) }
|
133
146
|
@path.shift if @path.first == ''
|
134
147
|
@path.push('') if path[-1] == ?/
|
135
148
|
@extra_env = {}
|
@@ -170,7 +183,7 @@ class HttpRouter
|
|
170
183
|
end
|
171
184
|
|
172
185
|
module Padrino
|
173
|
-
class Filter
|
186
|
+
class Filter
|
174
187
|
attr_reader :block
|
175
188
|
|
176
189
|
def initialize(mode, scoped_controller, options, args, &block)
|
@@ -211,7 +224,7 @@ module Padrino
|
|
211
224
|
# which can be used to refer to the url throughout the application.
|
212
225
|
#
|
213
226
|
module Routing
|
214
|
-
# Defines common content-type alias mappings
|
227
|
+
# Defines common content-type alias mappings.
|
215
228
|
CONTENT_TYPE_ALIASES = { :htm => :html } unless defined?(CONTENT_TYPE_ALIASES)
|
216
229
|
# Defines the available route priorities supporting route deferrals.
|
217
230
|
ROUTE_PRIORITY = {:high => 0, :normal => 1, :low => 2} unless defined?(ROUTE_PRIORITY)
|
@@ -219,7 +232,7 @@ module Padrino
|
|
219
232
|
# Raised when a route was invalid or cannot be processed.
|
220
233
|
class UnrecognizedException < RuntimeError; end
|
221
234
|
|
222
|
-
class Parent < String
|
235
|
+
class Parent < String
|
223
236
|
attr_reader :map
|
224
237
|
attr_reader :optional
|
225
238
|
attr_reader :options
|
@@ -319,8 +332,10 @@ module Padrino
|
|
319
332
|
# get :index, :map => "/:lang" do; "params[:lang] == :de"; end
|
320
333
|
# end
|
321
334
|
#
|
322
|
-
# In a controller, before and after filters are scoped and don't
|
323
|
-
#
|
335
|
+
# In a controller, before and after filters are scoped and don't
|
336
|
+
# affect other controllers or the main app.
|
337
|
+
# In a controller, layouts are scoped and don't affect other
|
338
|
+
# controllers or the main app.
|
324
339
|
#
|
325
340
|
# @example
|
326
341
|
# controller :posts do
|
@@ -333,7 +348,7 @@ module Padrino
|
|
333
348
|
if block_given?
|
334
349
|
options = args.extract_options!
|
335
350
|
|
336
|
-
# Controller defaults
|
351
|
+
# Controller defaults.
|
337
352
|
@_controller, original_controller = args, @_controller
|
338
353
|
@_parents, original_parent = options.delete(:parent), @_parents
|
339
354
|
@_provides, original_provides = options.delete(:provides), @_provides
|
@@ -343,17 +358,17 @@ module Padrino
|
|
343
358
|
@_conditions, original_conditions = options.delete(:conditions), @_conditions
|
344
359
|
@_defaults, original_defaults = options, @_defaults
|
345
360
|
|
346
|
-
# Application defaults
|
361
|
+
# Application defaults.
|
347
362
|
@filters, original_filters = { :before => @filters[:before].dup, :after => @filters[:after].dup }, @filters
|
348
363
|
@layout, original_layout = nil, @layout
|
349
364
|
|
350
365
|
instance_eval(&block)
|
351
366
|
|
352
|
-
# Application defaults
|
367
|
+
# Application defaults.
|
353
368
|
@filters = original_filters
|
354
369
|
@layout = original_layout
|
355
370
|
|
356
|
-
# Controller defaults
|
371
|
+
# Controller defaults.
|
357
372
|
@_controller, @_parents, @_cache = original_controller, original_parent, original_cache
|
358
373
|
@_defaults, @_provides, @_map = original_defaults, original_provides, original_map
|
359
374
|
@_conditions, @_use_format = original_conditions, original_use_format
|
@@ -364,7 +379,7 @@ module Padrino
|
|
364
379
|
alias :controllers :controller
|
365
380
|
|
366
381
|
##
|
367
|
-
# Add a before filter hook
|
382
|
+
# Add a before filter hook.
|
368
383
|
#
|
369
384
|
# @see #construct_filter
|
370
385
|
#
|
@@ -373,7 +388,7 @@ module Padrino
|
|
373
388
|
end
|
374
389
|
|
375
390
|
##
|
376
|
-
# Add an after filter hook
|
391
|
+
# Add an after filter hook.
|
377
392
|
#
|
378
393
|
# @see #construct_filter
|
379
394
|
#
|
@@ -384,7 +399,7 @@ module Padrino
|
|
384
399
|
##
|
385
400
|
# Adds a filter hook to a request.
|
386
401
|
#
|
387
|
-
def
|
402
|
+
def add_filter(type, &block)
|
388
403
|
filters[type] << block
|
389
404
|
end
|
390
405
|
|
@@ -420,7 +435,7 @@ module Padrino
|
|
420
435
|
# before :index, /main/ do; ... end
|
421
436
|
# # => match only path that are +/+ or contains +main+
|
422
437
|
#
|
423
|
-
# @example filtering everything except an
|
438
|
+
# @example filtering everything except an occurrence
|
424
439
|
# before :except => :index do; ...; end
|
425
440
|
#
|
426
441
|
# @example you can also filter using a request param
|
@@ -469,7 +484,7 @@ module Padrino
|
|
469
484
|
end
|
470
485
|
|
471
486
|
##
|
472
|
-
# Using
|
487
|
+
# Using HttpRouter, for features and configurations.
|
473
488
|
#
|
474
489
|
# @example
|
475
490
|
# router.add('/greedy/:greed')
|
@@ -483,33 +498,26 @@ module Padrino
|
|
483
498
|
end
|
484
499
|
alias :urls :router
|
485
500
|
|
486
|
-
# Compiles the routes including deferred routes.
|
487
501
|
def compiled_router
|
488
|
-
if deferred_routes
|
489
|
-
|
490
|
-
else
|
491
|
-
deferred_routes.each { |_, routes| routes.each { |(route, dest)| route.to(dest) } }
|
502
|
+
if @deferred_routes
|
503
|
+
deferred_routes.each { |routes| routes.each { |(route, dest)| route.to(dest) } }
|
492
504
|
@deferred_routes = nil
|
493
505
|
router.sort!
|
494
|
-
router
|
495
506
|
end
|
507
|
+
router
|
496
508
|
end
|
497
509
|
|
498
|
-
# Returns all routes that were deferred based on their priority.
|
499
510
|
def deferred_routes
|
500
|
-
@deferred_routes ||=
|
511
|
+
@deferred_routes ||= ROUTE_PRIORITY.map{[]}
|
501
512
|
end
|
502
513
|
|
503
|
-
##
|
504
|
-
# Resets the http router and all deferred routes.
|
505
|
-
#
|
506
514
|
def reset_router!
|
507
515
|
@deferred_routes = nil
|
508
516
|
router.reset!
|
509
517
|
end
|
510
518
|
|
511
519
|
##
|
512
|
-
# Recognize a given path
|
520
|
+
# Recognize a given path.
|
513
521
|
#
|
514
522
|
# @param [String] path
|
515
523
|
# Path+Query to parse
|
@@ -570,7 +578,7 @@ module Padrino
|
|
570
578
|
end
|
571
579
|
alias :url_for :url
|
572
580
|
|
573
|
-
def get(path, *args, &block)
|
581
|
+
def get(path, *args, &block)
|
574
582
|
conditions = @conditions.dup
|
575
583
|
route('GET', path, *args, &block)
|
576
584
|
|
@@ -579,334 +587,330 @@ module Padrino
|
|
579
587
|
end
|
580
588
|
|
581
589
|
private
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
end
|
590
|
+
# Parse params from the url method
|
591
|
+
def value_to_param(value)
|
592
|
+
case value
|
593
|
+
when Array
|
594
|
+
value.map { |v| value_to_param(v) }.compact
|
595
|
+
when Hash
|
596
|
+
value.inject({}) do |memo, (k,v)|
|
597
|
+
v = value_to_param(v)
|
598
|
+
memo[k] = v unless v.nil?
|
599
|
+
memo
|
600
|
+
end
|
601
|
+
when nil then nil
|
602
|
+
else value.respond_to?(:to_param) ? value.to_param : value
|
596
603
|
end
|
604
|
+
end
|
597
605
|
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
606
|
+
# Add prefix slash if its not present and remove trailing slashes.
|
607
|
+
def conform_uri(uri_string)
|
608
|
+
uri_string.gsub(/^(?!\/)(.*)/, '/\1').gsub(/[\/]+$/, '')
|
609
|
+
end
|
602
610
|
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
611
|
+
##
|
612
|
+
# Rewrite default routes.
|
613
|
+
#
|
614
|
+
# @example
|
615
|
+
# get :index # => "/"
|
616
|
+
# get :index, "/" # => "/"
|
617
|
+
# get :index, :map => "/" # => "/"
|
618
|
+
# get :show, "/show-me" # => "/show-me"
|
619
|
+
# get :show, :map => "/show-me" # => "/show-me"
|
620
|
+
# get "/foo/bar" # => "/show"
|
621
|
+
# get :index, :parent => :user # => "/user/:user_id/index"
|
622
|
+
# get :show, :with => :id, :parent => :user # => "/user/:user_id/show/:id"
|
623
|
+
# get :show, :with => :id # => "/show/:id"
|
624
|
+
# get [:show, :id] # => "/show/:id"
|
625
|
+
# get :show, :with => [:id, :name] # => "/show/:id/:name"
|
626
|
+
# get [:show, :id, :name] # => "/show/:id/:name"
|
627
|
+
# get :list, :provides => :js # => "/list.{:format,js)"
|
628
|
+
# get :list, :provides => :any # => "/list(.:format)"
|
629
|
+
# get :list, :provides => [:js, :json] # => "/list.{!format,js|json}"
|
630
|
+
# get :list, :provides => [:html, :js, :json] # => "/list(.{!format,js|json})"
|
631
|
+
# get :list, :priority => :low # Defers route to be last
|
632
|
+
# get /pattern/, :name => :foo, :generate_with => '/foo' # Generates :foo as /foo
|
633
|
+
def route(verb, path, *args, &block)
|
634
|
+
options = case args.size
|
635
|
+
when 2
|
636
|
+
args.last.merge(:map => args.first)
|
637
|
+
when 1
|
638
|
+
map = args.shift if args.first.is_a?(String)
|
639
|
+
if args.first.is_a?(Hash)
|
640
|
+
map ? args.first.merge(:map => map) : args.first
|
641
|
+
else
|
642
|
+
{:map => map || args.first}
|
643
|
+
end
|
644
|
+
when 0
|
645
|
+
{}
|
646
|
+
else raise
|
647
|
+
end
|
640
648
|
|
641
|
-
|
642
|
-
|
643
|
-
|
649
|
+
# Do padrino parsing. We dup options so we can build HEAD request correctly.
|
650
|
+
route_options = options.dup
|
651
|
+
route_options[:provides] = @_provides if @_provides
|
644
652
|
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
end
|
653
|
+
# CSRF protection is always active except when explicitly switched off.
|
654
|
+
if allow_disabled_csrf
|
655
|
+
unless route_options[:csrf_protection] == false
|
656
|
+
route_options[:csrf_protection] = true
|
650
657
|
end
|
658
|
+
end
|
651
659
|
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
end
|
660
|
+
path, *route_options[:with] = path if path.is_a?(Array)
|
661
|
+
action = path
|
662
|
+
path, name, route_parents, options, route_options = *parse_route(path, route_options, verb)
|
663
|
+
options.reverse_merge!(@_conditions) if @_conditions
|
664
|
+
|
665
|
+
# Sinatra defaults
|
666
|
+
method_name = "#{verb} #{path}"
|
667
|
+
unbound_method = generate_method(method_name, &block)
|
668
|
+
|
669
|
+
block = block.arity != 0 ?
|
670
|
+
proc { |a,p| unbound_method.bind(a).call(*p) } :
|
671
|
+
proc { |a,p| unbound_method.bind(a).call }
|
672
|
+
|
673
|
+
invoke_hook(:route_added, verb, path, block)
|
674
|
+
|
675
|
+
# HTTPRouter route construction
|
676
|
+
route = router.add(path, route_options)
|
677
|
+
route.name = name if name
|
678
|
+
route.action = action
|
679
|
+
priority_name = options.delete(:priority) || :normal
|
680
|
+
priority = ROUTE_PRIORITY[priority_name] or raise("Priority #{priority_name} not recognized, try #{ROUTE_PRIORITY.keys.join(', ')}")
|
681
|
+
route.cache = options.key?(:cache) ? options.delete(:cache) : @_cache
|
682
|
+
route.parent = route_parents ? (route_parents.count == 1 ? route_parents.first : route_parents) : route_parents
|
683
|
+
route.add_request_method(verb.downcase.to_sym)
|
684
|
+
route.host = options.delete(:host) if options.key?(:host)
|
685
|
+
route.user_agent = options.delete(:agent) if options.key?(:agent)
|
686
|
+
if options.key?(:default_values)
|
687
|
+
defaults = options.delete(:default_values)
|
688
|
+
route.add_default_values(defaults) if defaults
|
689
|
+
end
|
690
|
+
options.delete_if do |option, _args|
|
691
|
+
if route.significant_variable_names.include?(option)
|
692
|
+
route.add_match_with(option => Array(_args).first)
|
693
|
+
true
|
687
694
|
end
|
695
|
+
end
|
688
696
|
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
invoke_hook(:padrino_route_added, route, verb, path, args, options, block)
|
697
|
+
# Add Sinatra conditions.
|
698
|
+
options.each { |o, a| route.respond_to?(o) ? route.send(o, *a) : send(o, *a) }
|
699
|
+
conditions, @conditions = @conditions, []
|
700
|
+
route.custom_conditions.concat(conditions)
|
695
701
|
|
696
|
-
|
697
|
-
route.before_filters.concat(@filters[:before])
|
698
|
-
route.after_filters.concat(@filters[:after])
|
699
|
-
if @_controller
|
700
|
-
route.use_layout = @layout
|
701
|
-
route.controller = Array(@_controller)[0].to_s
|
702
|
-
end
|
702
|
+
invoke_hook(:padrino_route_added, route, verb, path, args, options, block)
|
703
703
|
|
704
|
-
|
705
|
-
|
706
|
-
|
704
|
+
# Add Application defaults.
|
705
|
+
route.before_filters.concat(@filters[:before])
|
706
|
+
route.after_filters.concat(@filters[:after])
|
707
|
+
if @_controller
|
708
|
+
route.use_layout = @layout
|
709
|
+
route.controller = Array(@_controller)[0].to_s
|
707
710
|
end
|
708
711
|
|
709
|
-
|
710
|
-
# Returns the final parsed route details (modified to reflect all
|
711
|
-
# Padrino options) given the raw route. Raw route passed in could be
|
712
|
-
# a named alias or a string and is parsed to reflect provides formats,
|
713
|
-
# controllers, parents, 'with' parameters, and other options.
|
714
|
-
#
|
715
|
-
def parse_route(path, options, verb)
|
716
|
-
# We need save our originals path/options so we can perform correctly cache.
|
717
|
-
original = [path, options.dup]
|
718
|
-
|
719
|
-
# options for the route directly
|
720
|
-
route_options = {}
|
721
|
-
|
722
|
-
# We need check if path is a symbol, if that it's a named route
|
723
|
-
map = options.delete(:map)
|
724
|
-
|
725
|
-
if path.kind_of?(Symbol) # path i.e :index or :show
|
726
|
-
name = path # The route name
|
727
|
-
path = map ? map.dup : (path == :index ? '/' : path.to_s) # The route path
|
728
|
-
end
|
712
|
+
deferred_routes[priority] << [route, block]
|
729
713
|
|
730
|
-
|
731
|
-
|
714
|
+
route
|
715
|
+
end
|
732
716
|
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
717
|
+
##
|
718
|
+
# Returns the final parsed route details (modified to reflect all
|
719
|
+
# Padrino options) given the raw route. Raw route passed in could be
|
720
|
+
# a named alias or a string and is parsed to reflect provides formats,
|
721
|
+
# controllers, parents, 'with' parameters, and other options.
|
722
|
+
#
|
723
|
+
def parse_route(path, options, verb)
|
724
|
+
route_options = {}
|
739
725
|
|
740
|
-
|
741
|
-
|
726
|
+
# We need check if path is a symbol, if that it's a named route.
|
727
|
+
map = options.delete(:map)
|
742
728
|
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
729
|
+
# path i.e :index or :show
|
730
|
+
if path.kind_of?(Symbol)
|
731
|
+
name = path
|
732
|
+
path = map ? map.dup : (path == :index ? '/' : path.to_s)
|
733
|
+
end
|
748
734
|
|
749
|
-
|
735
|
+
# Build our controller
|
736
|
+
controller = Array(@_controller).map(&:to_s)
|
750
737
|
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
end
|
758
|
-
# Here we build the correct name route
|
759
|
-
end
|
738
|
+
case path
|
739
|
+
when String # path i.e "/index" or "/show"
|
740
|
+
# Now we need to parse our 'with' params
|
741
|
+
if with_params = options.delete(:with)
|
742
|
+
path = process_path_for_with_params(path, with_params)
|
743
|
+
end
|
760
744
|
|
761
|
-
|
762
|
-
|
763
|
-
parent_params = (Array(@_parents) + Array(parent_params)).uniq
|
764
|
-
path = process_path_for_parent_params(path, parent_params)
|
765
|
-
end
|
745
|
+
# Now we need to parse our provides
|
746
|
+
options.delete(:provides) if options[:provides].nil?
|
766
747
|
|
767
|
-
|
768
|
-
path
|
769
|
-
|
770
|
-
#
|
771
|
-
path.gsub!(%r{/\?$}, '(/)') # Remove index path
|
772
|
-
path.gsub!(%r{//$}, '/') # Remove index path
|
773
|
-
path[0,0] = "/" if path !~ %r{^\(?/} # Paths must start with a /
|
774
|
-
path.sub!(%r{/(\))?$}, '\\1') if path != "/" # Remove latest trailing delimiter
|
775
|
-
path.gsub!(/\/(\(\.|$)/, '\\1') # Remove trailing slashes
|
776
|
-
path.squeeze!('/')
|
777
|
-
when Regexp
|
778
|
-
route_options[:path_for_generation] = options.delete(:generate_with) if options.key?(:generate_with)
|
748
|
+
if @_use_format or format_params = options[:provides]
|
749
|
+
process_path_for_provides(path, format_params)
|
750
|
+
# options[:add_match_with] ||= {}
|
751
|
+
# options[:add_match_with][:format] = /[^\.]+/
|
779
752
|
end
|
780
753
|
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
754
|
+
absolute_map = map && map[0] == ?/
|
755
|
+
|
756
|
+
unless controller.empty?
|
757
|
+
# Now we need to add our controller path only if not mapped directly
|
758
|
+
if map.blank? and !absolute_map
|
759
|
+
controller_path = controller.join("/")
|
760
|
+
path.gsub!(%r{^\(/\)|/\?}, "")
|
761
|
+
path = File.join(controller_path, path) unless @_map
|
762
|
+
end
|
786
763
|
end
|
787
764
|
|
788
|
-
#
|
789
|
-
options.
|
765
|
+
# Now we need to parse our 'parent' params and parent scope.
|
766
|
+
if !absolute_map and parent_params = options.delete(:parent) || @_parents
|
767
|
+
parent_params = (Array(@_parents) + Array(parent_params)).uniq
|
768
|
+
path = process_path_for_parent_params(path, parent_params)
|
769
|
+
end
|
790
770
|
|
791
|
-
|
771
|
+
# Add any controller level map to the front of the path.
|
772
|
+
path = "#{@_map}/#{path}".squeeze('/') unless absolute_map or @_map.blank?
|
773
|
+
|
774
|
+
# Small reformats
|
775
|
+
path.gsub!(%r{/\?$}, '(/)') # Remove index path
|
776
|
+
path.gsub!(%r{//$}, '/') # Remove index path
|
777
|
+
path[0,0] = "/" if path !~ %r{^\(?/} # Paths must start with a /
|
778
|
+
path.sub!(%r{/(\))?$}, '\\1') if path != "/" # Remove latest trailing delimiter
|
779
|
+
path.gsub!(/\/(\(\.|$)/, '\\1') # Remove trailing slashes
|
780
|
+
path.squeeze!('/')
|
781
|
+
when Regexp
|
782
|
+
route_options[:path_for_generation] = options.delete(:generate_with) if options.key?(:generate_with)
|
792
783
|
end
|
793
784
|
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
File.join(path, Array(with_params).map(&:inspect).join("/"))
|
785
|
+
name = options.delete(:route_name) if name.nil? && options.key?(:route_name)
|
786
|
+
name = options.delete(:name) if name.nil? && options.key?(:name)
|
787
|
+
if name
|
788
|
+
controller_name = controller.join("_")
|
789
|
+
name = "#{controller_name}_#{name}".to_sym unless controller_name.blank?
|
800
790
|
end
|
801
791
|
|
802
|
-
|
803
|
-
|
804
|
-
# Used for calculating path in route method.
|
805
|
-
#
|
806
|
-
def process_path_for_parent_params(path, parent_params)
|
807
|
-
parent_prefix = parent_params.flatten.compact.uniq.map do |param|
|
808
|
-
map = (param.respond_to?(:map) && param.map ? param.map : param.to_s)
|
809
|
-
part = "#{map}/:#{param.to_s.singularize}_id/"
|
810
|
-
part = "(#{part})" if param.respond_to?(:optional) && param.optional?
|
811
|
-
part
|
812
|
-
end
|
792
|
+
# Merge in option defaults.
|
793
|
+
options.reverse_merge!(:default_values => @_defaults)
|
813
794
|
|
814
|
-
|
815
|
-
|
795
|
+
[path, name, parent_params, options, route_options]
|
796
|
+
end
|
797
|
+
|
798
|
+
##
|
799
|
+
# Processes the existing path and appends the 'with' parameters onto the route
|
800
|
+
# Used for calculating path in route method.
|
801
|
+
#
|
802
|
+
def process_path_for_with_params(path, with_params)
|
803
|
+
File.join(path, Array(with_params).map(&:inspect).join("/"))
|
804
|
+
end
|
816
805
|
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
806
|
+
##
|
807
|
+
# Processes the existing path and prepends the 'parent' parameters onto the route
|
808
|
+
# Used for calculating path in route method.
|
809
|
+
#
|
810
|
+
def process_path_for_parent_params(path, parent_params)
|
811
|
+
parent_prefix = parent_params.flatten.compact.uniq.map do |param|
|
812
|
+
map = (param.respond_to?(:map) && param.map ? param.map : param.to_s)
|
813
|
+
part = "#{map}/:#{param.to_s.singularize}_id/"
|
814
|
+
part = "(#{part})" if param.respond_to?(:optional) && param.optional?
|
815
|
+
part
|
823
816
|
end
|
824
817
|
|
825
|
-
|
826
|
-
|
827
|
-
#
|
828
|
-
# By default, if a non-provided mime-type is specified in a URL, the
|
829
|
-
# route will not match an thus return a 404.
|
830
|
-
#
|
831
|
-
# Setting the :treat_format_as_accept option to true allows treating
|
832
|
-
# missing mime types specified in the URL as if they were specified
|
833
|
-
# in the ACCEPT header and thus return 406.
|
834
|
-
#
|
835
|
-
# If no type is specified, the first in the provides-list will be
|
836
|
-
# returned.
|
837
|
-
#
|
838
|
-
# @example
|
839
|
-
# get "/a", :provides => [:html, :js]
|
840
|
-
# # => GET /a => :html
|
841
|
-
# # => GET /a.js => :js
|
842
|
-
# # => GET /a.xml => 404
|
843
|
-
#
|
844
|
-
# get "/b", :provides => [:html]
|
845
|
-
# # => GET /b; ACCEPT: html => html
|
846
|
-
# # => GET /b; ACCEPT: js => 406
|
847
|
-
#
|
848
|
-
# enable :treat_format_as_accept
|
849
|
-
# get "/c", :provides => [:html, :js]
|
850
|
-
# # => GET /c.xml => 406
|
851
|
-
#
|
852
|
-
def provides(*types)
|
853
|
-
@_use_format = true
|
854
|
-
condition do
|
855
|
-
mime_types = types.map { |t| mime_type(t) }.compact
|
856
|
-
url_format = params[:format].to_sym if params[:format]
|
857
|
-
accepts = request.accept.map { |a| a.to_str }
|
858
|
-
|
859
|
-
# per rfc2616-sec14:
|
860
|
-
# Assume */* if no ACCEPT header is given.
|
861
|
-
catch_all = (accepts.delete "*/*" || accepts.empty?)
|
862
|
-
matching_types = accepts.empty? ? mime_types.slice(0,1) : (accepts & mime_types)
|
863
|
-
if matching_types.empty? && types.include?(:any)
|
864
|
-
matching_types = accepts
|
865
|
-
end
|
818
|
+
[parent_prefix, path].flatten.join("")
|
819
|
+
end
|
866
820
|
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
821
|
+
##
|
822
|
+
# Processes the existing path and appends the 'format' suffix onto the route.
|
823
|
+
# Used for calculating path in route method.
|
824
|
+
#
|
825
|
+
def process_path_for_provides(path, format_params)
|
826
|
+
path << "(.:format)" unless path[-10, 10] == '(.:format)'
|
827
|
+
end
|
874
828
|
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
829
|
+
##
|
830
|
+
# Allows routing by MIME-types specified in the URL or ACCEPT header.
|
831
|
+
#
|
832
|
+
# By default, if a non-provided mime-type is specified in a URL, the
|
833
|
+
# route will not match an thus return a 404.
|
834
|
+
#
|
835
|
+
# Setting the :treat_format_as_accept option to true allows treating
|
836
|
+
# missing mime types specified in the URL as if they were specified
|
837
|
+
# in the ACCEPT header and thus return 406.
|
838
|
+
#
|
839
|
+
# If no type is specified, the first in the provides-list will be
|
840
|
+
# returned.
|
841
|
+
#
|
842
|
+
# @example
|
843
|
+
# get "/a", :provides => [:html, :js]
|
844
|
+
# # => GET /a => :html
|
845
|
+
# # => GET /a.js => :js
|
846
|
+
# # => GET /a.xml => 404
|
847
|
+
#
|
848
|
+
# get "/b", :provides => [:html]
|
849
|
+
# # => GET /b; ACCEPT: html => html
|
850
|
+
# # => GET /b; ACCEPT: js => 406
|
851
|
+
#
|
852
|
+
# enable :treat_format_as_accept
|
853
|
+
# get "/c", :provides => [:html, :js]
|
854
|
+
# # => GET /c.xml => 406
|
855
|
+
#
|
856
|
+
def provides(*types)
|
857
|
+
@_use_format = true
|
858
|
+
condition do
|
859
|
+
mime_types = types.map { |t| mime_type(t) }.compact
|
860
|
+
url_format = params[:format].to_sym if params[:format]
|
861
|
+
accepts = request.accept.map(&:to_str)
|
862
|
+
|
863
|
+
# Per rfc2616-sec14:
|
864
|
+
# Assume */* if no ACCEPT header is given.
|
865
|
+
catch_all = (accepts.delete "*/*" || accepts.empty?)
|
866
|
+
matching_types = accepts.empty? ? mime_types.slice(0,1) : (accepts & mime_types)
|
867
|
+
if matching_types.empty? && types.include?(:any)
|
868
|
+
matching_types = accepts
|
869
|
+
end
|
891
870
|
|
892
|
-
|
871
|
+
if !url_format && matching_types.first
|
872
|
+
type = ::Rack::Mime::MIME_TYPES.find { |k, v| v == matching_types.first }[0].sub(/\./,'').to_sym
|
873
|
+
accept_format = CONTENT_TYPE_ALIASES[type] || type
|
874
|
+
elsif catch_all && !types.include?(:any)
|
875
|
+
type = types.first
|
876
|
+
accept_format = CONTENT_TYPE_ALIASES[type] || type
|
893
877
|
end
|
894
|
-
end
|
895
878
|
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
879
|
+
matched_format = types.include?(:any) ||
|
880
|
+
types.include?(accept_format) ||
|
881
|
+
types.include?(url_format) ||
|
882
|
+
((!url_format) && request.accept.empty? && types.include?(:html))
|
883
|
+
|
884
|
+
# Per rfc2616-sec14:
|
885
|
+
# Answer with 406 if accept is given but types to not match any
|
886
|
+
# provided type.
|
887
|
+
halt 406 if
|
888
|
+
(!url_format && !accepts.empty? && !matched_format) ||
|
889
|
+
(settings.respond_to?(:treat_format_as_accept) && settings.treat_format_as_accept && url_format && !matched_format)
|
890
|
+
|
891
|
+
if matched_format
|
892
|
+
@_content_type = url_format || accept_format || :html
|
893
|
+
content_type(@_content_type, :charset => 'utf-8')
|
908
894
|
end
|
895
|
+
|
896
|
+
matched_format
|
909
897
|
end
|
898
|
+
end
|
899
|
+
|
900
|
+
##
|
901
|
+
# Implements CSRF checking when `allow_disabled_csrf` is set to true.
|
902
|
+
#
|
903
|
+
# This condition is always on, except when it is explicitly switched
|
904
|
+
# off.
|
905
|
+
#
|
906
|
+
# @example
|
907
|
+
# post("/", :csrf_protection => false)
|
908
|
+
#
|
909
|
+
def csrf_protection(on = true)
|
910
|
+
if on
|
911
|
+
condition { halt 403 if request.env['protection.csrf.failed'] }
|
912
|
+
end
|
913
|
+
end
|
910
914
|
end
|
911
915
|
|
912
916
|
##
|
@@ -914,7 +918,7 @@ module Padrino
|
|
914
918
|
#
|
915
919
|
module InstanceMethods
|
916
920
|
##
|
917
|
-
# Instance method for
|
921
|
+
# Instance method for URL generation.
|
918
922
|
#
|
919
923
|
# @example
|
920
924
|
# url(:show, :id => 1)
|
@@ -929,7 +933,7 @@ module Padrino
|
|
929
933
|
# http://www.sinatrarb.com/intro#Generating%20URLs
|
930
934
|
return super if args.first.is_a?(String) && !args[1].is_a?(Hash)
|
931
935
|
|
932
|
-
# Delegate to Padrino named route
|
936
|
+
# Delegate to Padrino named route URL generation.
|
933
937
|
settings.url(*args)
|
934
938
|
end
|
935
939
|
alias :url_for :url
|
@@ -945,9 +949,6 @@ module Padrino
|
|
945
949
|
uri url(*args), true, false
|
946
950
|
end
|
947
951
|
|
948
|
-
##
|
949
|
-
# Returns the recognized path for a route.
|
950
|
-
#
|
951
952
|
def recognize_path(path)
|
952
953
|
settings.recognize_path(path)
|
953
954
|
end
|
@@ -994,7 +995,7 @@ module Padrino
|
|
994
995
|
def static!
|
995
996
|
if path = static_file?(request.path_info)
|
996
997
|
env['sinatra.static_file'] = path
|
997
|
-
cache_control
|
998
|
+
cache_control(*settings.static_cache_control) if settings.static_cache_control?
|
998
999
|
send_file(path, :disposition => nil)
|
999
1000
|
end
|
1000
1001
|
end
|
@@ -1025,51 +1026,52 @@ module Padrino
|
|
1025
1026
|
end
|
1026
1027
|
|
1027
1028
|
private
|
1028
|
-
def filter!(type, base=settings)
|
1029
|
-
base.filters[type].each { |block| instance_eval(&block) }
|
1030
|
-
end
|
1031
1029
|
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1030
|
+
def filter!(type, base=settings)
|
1031
|
+
base.filters[type].each { |block| instance_eval(&block) }
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
def dispatch!
|
1035
|
+
invoke do
|
1036
|
+
static! if settings.static? && (request.get? || request.head?)
|
1037
|
+
route!
|
1038
|
+
end
|
1039
|
+
rescue ::Exception => boom
|
1040
|
+
filter! :before if boom.kind_of? ::Sinatra::NotFound
|
1041
|
+
invoke { @boom_handled = handle_exception!(boom) }
|
1042
|
+
ensure
|
1043
|
+
@boom_handled or begin
|
1044
|
+
filter! :after unless env['sinatra.static_file']
|
1037
1045
|
rescue ::Exception => boom
|
1038
|
-
|
1039
|
-
invoke { @boom_handled = handle_exception!(boom) }
|
1040
|
-
ensure
|
1041
|
-
@boom_handled or begin
|
1042
|
-
filter! :after unless env['sinatra.static_file']
|
1043
|
-
rescue ::Exception => boom
|
1044
|
-
invoke { handle_exception!(boom) } unless @env['sinatra.error']
|
1045
|
-
end
|
1046
|
+
invoke { handle_exception!(boom) } unless @env['sinatra.error']
|
1046
1047
|
end
|
1048
|
+
end
|
1047
1049
|
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
end
|
1050
|
+
def route!(base=settings, pass_block=nil)
|
1051
|
+
Thread.current['padrino.instance'] = self
|
1052
|
+
if base.compiled_router and match = base.compiled_router.call(@request.env)
|
1053
|
+
if match.respond_to?(:each)
|
1054
|
+
route_eval do
|
1055
|
+
match[1].each { |k,v| response[k] = v }
|
1056
|
+
status match[0]
|
1057
|
+
route_missing if match[0] == 404
|
1058
|
+
route_missing if allow = response['Allow'] and allow.include?(request.env['REQUEST_METHOD'])
|
1058
1059
|
end
|
1059
|
-
else
|
1060
|
-
filter! :before
|
1061
1060
|
end
|
1061
|
+
else
|
1062
|
+
filter! :before
|
1063
|
+
end
|
1062
1064
|
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1065
|
+
# Run routes defined in superclass.
|
1066
|
+
if base.superclass.respond_to?(:router)
|
1067
|
+
route!(base.superclass, pass_block)
|
1068
|
+
return
|
1069
|
+
end
|
1068
1070
|
|
1069
|
-
|
1071
|
+
route_eval(&pass_block) if pass_block
|
1070
1072
|
|
1071
|
-
|
1072
|
-
|
1073
|
-
end
|
1074
|
-
end
|
1075
|
-
end
|
1073
|
+
route_missing
|
1074
|
+
end
|
1075
|
+
end
|
1076
|
+
end
|
1077
|
+
end
|