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.
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