padrino-core 0.11.3 → 0.11.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|