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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +5 -5
  3. data/lib/padrino-core.rb +3 -9
  4. data/lib/padrino-core/application.rb +39 -35
  5. data/lib/padrino-core/application/flash.rb +7 -7
  6. data/lib/padrino-core/application/rendering.rb +136 -139
  7. data/lib/padrino-core/application/rendering/extensions/erubis.rb +15 -6
  8. data/lib/padrino-core/application/routing.rb +371 -369
  9. data/lib/padrino-core/application/showexceptions.rb +13 -12
  10. data/lib/padrino-core/caller.rb +40 -40
  11. data/lib/padrino-core/cli/adapter.rb +4 -4
  12. data/lib/padrino-core/cli/base.rb +40 -39
  13. data/lib/padrino-core/cli/rake.rb +2 -2
  14. data/lib/padrino-core/cli/rake_tasks.rb +2 -4
  15. data/lib/padrino-core/command.rb +2 -2
  16. data/lib/padrino-core/loader.rb +14 -15
  17. data/lib/padrino-core/locale/cs.yml +0 -1
  18. data/lib/padrino-core/locale/da.yml +0 -1
  19. data/lib/padrino-core/locale/de.yml +0 -1
  20. data/lib/padrino-core/locale/en.yml +0 -1
  21. data/lib/padrino-core/locale/es.yml +1 -2
  22. data/lib/padrino-core/locale/fr.yml +2 -3
  23. data/lib/padrino-core/locale/hu.yml +1 -2
  24. data/lib/padrino-core/locale/it.yml +0 -1
  25. data/lib/padrino-core/locale/ja.yml +1 -2
  26. data/lib/padrino-core/locale/lv.yml +0 -1
  27. data/lib/padrino-core/locale/nl.yml +0 -1
  28. data/lib/padrino-core/locale/no.yml +0 -2
  29. data/lib/padrino-core/locale/pl.yml +0 -1
  30. data/lib/padrino-core/locale/pt_br.yml +0 -1
  31. data/lib/padrino-core/locale/ro.yml +0 -1
  32. data/lib/padrino-core/locale/ru.yml +0 -1
  33. data/lib/padrino-core/locale/sv.yml +0 -1
  34. data/lib/padrino-core/locale/tr.yml +0 -1
  35. data/lib/padrino-core/locale/uk.yml +0 -1
  36. data/lib/padrino-core/locale/zh_cn.yml +0 -1
  37. data/lib/padrino-core/locale/zh_tw.yml +0 -1
  38. data/lib/padrino-core/logger.rb +26 -27
  39. data/lib/padrino-core/module.rb +3 -3
  40. data/lib/padrino-core/mounter.rb +59 -59
  41. data/lib/padrino-core/reloader.rb +23 -23
  42. data/lib/padrino-core/router.rb +10 -13
  43. data/lib/padrino-core/server.rb +17 -19
  44. data/lib/padrino-core/tasks.rb +3 -3
  45. data/lib/padrino-core/version.rb +1 -1
  46. data/padrino-core.gemspec +1 -1
  47. data/test/test_application.rb +7 -7
  48. data/test/test_rendering.rb +15 -2
  49. data/test/test_routing.rb +34 -10
  50. 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} || ActiveSupport::SafeBuffer.new)"].join("\n")
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 Padrino::Erubis::Template, :erb
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 } if @route.custom_conditions
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
- #Monkey patching the Request class. Using Rack::Utils.unescape rather than
128
- #URI.unescape which can't handle utf-8 chars
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(path).split(/\//)
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 # @private
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 # @private
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 affect other controllers or the main app.
323
- # In a controller, layouts are scoped and don't affect other controllers or the main app.
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 add_filter(type, &block)
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 occurency
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 {HttpRouter}, for features and configurations.
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.empty?
489
- router
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 ||= Hash[ROUTE_PRIORITY.values.sort.map{|p| [p, []]}]
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) # @private
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
- # Parse params from the url method
583
- def value_to_param(value)
584
- case value
585
- when Array
586
- value.map { |v| value_to_param(v) }.compact
587
- when Hash
588
- value.inject({}) do |memo, (k,v)|
589
- v = value_to_param(v)
590
- memo[k] = v unless v.nil?
591
- memo
592
- end
593
- when nil then nil
594
- else value.respond_to?(:to_param) ? value.to_param : value
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
- # Add prefix slash if its not present and remove trailing slashes.
599
- def conform_uri(uri_string)
600
- uri_string.gsub(/^(?!\/)(.*)/, '/\1').gsub(/[\/]+$/, '')
601
- end
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
- # Rewrite default routes.
605
- #
606
- # @example
607
- # get :index # => "/"
608
- # get :index, "/" # => "/"
609
- # get :index, :map => "/" # => "/"
610
- # get :show, "/show-me" # => "/show-me"
611
- # get :show, :map => "/show-me" # => "/show-me"
612
- # get "/foo/bar" # => "/show"
613
- # get :index, :parent => :user # => "/user/:user_id/index"
614
- # get :show, :with => :id, :parent => :user # => "/user/:user_id/show/:id"
615
- # get :show, :with => :id # => "/show/:id"
616
- # get [:show, :id] # => "/show/:id"
617
- # get :show, :with => [:id, :name] # => "/show/:id/:name"
618
- # get [:show, :id, :name] # => "/show/:id/:name"
619
- # get :list, :provides => :js # => "/list.{:format,js)"
620
- # get :list, :provides => :any # => "/list(.:format)"
621
- # get :list, :provides => [:js, :json] # => "/list.{!format,js|json}"
622
- # get :list, :provides => [:html, :js, :json] # => "/list(.{!format,js|json})"
623
- # get :list, :priority => :low # Defers route to be last
624
- # get /pattern/, :name => :foo, :generate_with => '/foo' # Generates :foo as /foo
625
- def route(verb, path, *args, &block)
626
- options = case args.size
627
- when 2
628
- args.last.merge(:map => args.first)
629
- when 1
630
- map = args.shift if args.first.is_a?(String)
631
- if args.first.is_a?(Hash)
632
- map ? args.first.merge(:map => map) : args.first
633
- else
634
- {:map => map || args.first}
635
- end
636
- when 0
637
- {}
638
- else raise
639
- end
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
- # Do padrino parsing. We dup options so we can build HEAD request correctly
642
- route_options = options.dup
643
- route_options[:provides] = @_provides if @_provides
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
- # CSRF protection is always active except when explicitly switched off
646
- if allow_disabled_csrf
647
- unless route_options[:csrf_protection] == false
648
- route_options[:csrf_protection] = true
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
- path, *route_options[:with] = path if path.is_a?(Array)
653
- action = path
654
- path, name, route_parents, options, route_options = *parse_route(path, route_options, verb)
655
- options.reverse_merge!(@_conditions) if @_conditions
656
-
657
- # Sinatra defaults
658
- method_name = "#{verb} #{path}"
659
- unbound_method = generate_method(method_name, &block)
660
-
661
- block = block.arity != 0 ?
662
- proc { |a,p| unbound_method.bind(a).call(*p) } :
663
- proc { |a,p| unbound_method.bind(a).call }
664
-
665
- invoke_hook(:route_added, verb, path, block)
666
-
667
- # HTTPRouter route construction
668
- route = router.add(path, route_options)
669
- route.name = name if name
670
- route.action = action
671
- priority_name = options.delete(:priority) || :normal
672
- priority = ROUTE_PRIORITY[priority_name] or raise("Priority #{priority_name} not recognized, try #{ROUTE_PRIORITY.keys.join(', ')}")
673
- route.cache = options.key?(:cache) ? options.delete(:cache) : @_cache
674
- route.parent = route_parents ? (route_parents.count == 1 ? route_parents.first : route_parents) : route_parents
675
- route.add_request_method(verb.downcase.to_sym)
676
- route.host = options.delete(:host) if options.key?(:host)
677
- route.user_agent = options.delete(:agent) if options.key?(:agent)
678
- if options.key?(:default_values)
679
- defaults = options.delete(:default_values)
680
- route.add_default_values(defaults) if defaults
681
- end
682
- options.delete_if do |option, args|
683
- if route.significant_variable_names.include?(option)
684
- route.add_match_with(option => Array(args).first)
685
- true
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
- # Add Sinatra conditions
690
- options.each { |o, a| route.respond_to?(o) ? route.send(o, *a) : send(o, *a) }
691
- conditions, @conditions = @conditions, []
692
- route.custom_conditions.concat(conditions)
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
- # Add Application defaults
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
- deferred_routes[priority] << [route, block]
705
-
706
- route
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
- # Build our controller
731
- controller = Array(@_controller).map { |c| c.to_s }
714
+ route
715
+ end
732
716
 
733
- case path
734
- when String # path i.e "/index" or "/show"
735
- # Now we need to parse our 'with' params
736
- if with_params = options.delete(:with)
737
- path = process_path_for_with_params(path, with_params)
738
- end
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
- # Now we need to parse our provides
741
- options.delete(:provides) if options[:provides].nil?
726
+ # We need check if path is a symbol, if that it's a named route.
727
+ map = options.delete(:map)
742
728
 
743
- if @_use_format or format_params = options[:provides]
744
- process_path_for_provides(path, format_params)
745
- # options[:add_match_with] ||= {}
746
- # options[:add_match_with][:format] = /[^\.]+/
747
- end
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
- absolute_map = map && map[0] == ?/
735
+ # Build our controller
736
+ controller = Array(@_controller).map(&:to_s)
750
737
 
751
- unless controller.empty?
752
- # Now we need to add our controller path only if not mapped directly
753
- if map.blank? and !absolute_map
754
- controller_path = controller.join("/")
755
- path.gsub!(%r{^\(/\)|/\?}, "")
756
- path = File.join(controller_path, path) unless @_map
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
- # Now we need to parse our 'parent' params and parent scope
762
- if !absolute_map and parent_params = options.delete(:parent) || @_parents
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
- # Add any controller level map to the front of the path
768
- path = "#{@_map}/#{path}".squeeze('/') unless absolute_map or @_map.blank?
769
-
770
- # Small reformats
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
- name = options.delete(:route_name) if name.nil? && options.key?(:route_name)
782
- name = options.delete(:name) if name.nil? && options.key?(:name)
783
- if name
784
- controller_name = controller.join("_")
785
- name = "#{controller_name}_#{name}".to_sym unless controller_name.blank?
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
- # Merge in option defaults
789
- options.reverse_merge!(:default_values => @_defaults)
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
- [path, name, parent_params, options, route_options]
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
- # Processes the existing path and appends the 'with' parameters onto the route
796
- # Used for calculating path in route method.
797
- #
798
- def process_path_for_with_params(path, with_params)
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
- # Processes the existing path and prepends the 'parent' parameters onto the route
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
- [parent_prefix, path].flatten.join("")
815
- end
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
- # Processes the existing path and appends the 'format' suffix onto the route
819
- # Used for calculating path in route method.
820
- #
821
- def process_path_for_provides(path, format_params)
822
- path << "(.:format)" unless path[-10, 10] == '(.:format)'
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
- # Allows routing by MIME-types specified in the URL or ACCEPT header.
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
- if !url_format && matching_types.first
868
- type = ::Rack::Mime::MIME_TYPES.find { |k, v| v == matching_types.first }[0].sub(/\./,'').to_sym
869
- accept_format = CONTENT_TYPE_ALIASES[type] || type
870
- elsif catch_all && !types.include?(:any)
871
- type = types.first
872
- accept_format = CONTENT_TYPE_ALIASES[type] || type
873
- end
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
- matched_format = types.include?(:any) ||
876
- types.include?(accept_format) ||
877
- types.include?(url_format) ||
878
- ((!url_format) && request.accept.empty? && types.include?(:html))
879
-
880
- # per rfc2616-sec14:
881
- # answer with 406 if accept is given but types to not match any
882
- # provided type
883
- halt 406 if
884
- (!url_format && !accepts.empty? && !matched_format) ||
885
- (settings.respond_to?(:treat_format_as_accept) && settings.treat_format_as_accept && url_format && !matched_format)
886
-
887
- if matched_format
888
- @_content_type = url_format || accept_format || :html
889
- content_type(@_content_type, :charset => 'utf-8')
890
- end
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
- matched_format
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
- # Implements CSRF checking when `allow_disabled_csrf` is set to true.
898
- #
899
- # This condition is always on, except when it is explicitly switched
900
- # off.
901
- #
902
- # @example
903
- # post("/", :csrf_protection => false)
904
- #
905
- def csrf_protection(on = true)
906
- if on
907
- condition { halt 403 if request.env['protection.csrf.failed'] }
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 url generation.
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 url generation
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 *settings.static_cache_control if settings.static_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
- def dispatch!
1033
- invoke do
1034
- static! if settings.static? && (request.get? || request.head?)
1035
- route!
1036
- end
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
- filter! :before if boom.kind_of? ::Sinatra::NotFound
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
- def route!(base=settings, pass_block=nil)
1049
- Thread.current['padrino.instance'] = self
1050
- if base.compiled_router and match = base.compiled_router.call(@request.env)
1051
- if match.respond_to?(:each)
1052
- route_eval do
1053
- match[1].each { |k,v| response[k] = v }
1054
- status match[0]
1055
- route_missing if match[0] == 404
1056
- route_missing if allow = response['Allow'] and allow.include?(request.env['REQUEST_METHOD'])
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
- # Run routes defined in superclass.
1064
- if base.superclass.respond_to?(:router)
1065
- route!(base.superclass, pass_block)
1066
- return
1067
- end
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
- route_eval(&pass_block) if pass_block
1071
+ route_eval(&pass_block) if pass_block
1070
1072
 
1071
- route_missing
1072
- end
1073
- end # InstanceMethods
1074
- end # Routing
1075
- end # Padrino
1073
+ route_missing
1074
+ end
1075
+ end
1076
+ end
1077
+ end