padrino-core 0.12.2 → 0.12.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dec1c7a3513869018c0576596a7888261759d25c
4
- data.tar.gz: 6ba616394f122fc4bf166facc114554cbddf2331
3
+ metadata.gz: b0c4e1103a6097258ff654c266fbc979a4115409
4
+ data.tar.gz: be1ce195a701fc3a868069bdfee1847d87bfedfe
5
5
  SHA512:
6
- metadata.gz: 6507e1e6ae0a0d2ca472e740928b548d7d9340d5d046725c8c049ece42e595db33018b1f551c148c846a1618e5cc2dd583bca65d202b49e8e86aa669eb770c85
7
- data.tar.gz: bc2666c168ba2678e3045db54803ddcec24fd9c486a8b77e03e01c7eb0a01785ed15ac95c487955723f5b7ed864cbd5939a67d4252a5aff5a622ba3c1ba760e0
6
+ metadata.gz: 08c3823803340970a7c3e5138e0705439a7db34880f075de1f886725ac44792d1cba96f7c396aadb4f2fa7e153313dda9611468721a66d71bc80c4a9c4e31630
7
+ data.tar.gz: cf6e3a2954d7541a981318094e9600d266a593189852b3028a91d3c9316b03a39b2719087e231eac55f800ca65be5f9a7d455d55b9f2083f0ddbf462df1ccd8b
@@ -23,10 +23,9 @@ module Padrino
23
23
  set :default_builder, 'StandardFormBuilder'
24
24
 
25
25
  # TODO: Remove this hack after getting rid of thread-unsafe http_router:
26
- set :init_mutex, Mutex.new
27
-
28
- # TODO: Remove this line after sinatra version up.
29
- set :add_charset, %w[javascript xml xhtml+xml].map{ |type| "application/#{type}" }
26
+ if RUBY_PLATFORM == "java"
27
+ set :init_mutex, Mutex.new
28
+ end
30
29
 
31
30
  default_paths
32
31
  default_security
@@ -1,261 +1,9 @@
1
- require 'http_router' unless defined?(HttpRouter)
2
1
  require 'padrino-support'
3
-
4
- ##
5
- # Adds to Sinatra +controller+ informations
6
- #
7
- class Sinatra::Request
8
- attr_accessor :route_obj
9
-
10
- def controller
11
- route_obj && route_obj.controller
12
- end
13
- def action
14
- route_obj && route_obj.action
15
- end
16
- end
17
-
18
- ##
19
- # This patches Sinatra to accept UTF-8 urls on JRuby 1.7.6
20
- #
21
- if RUBY_ENGINE == 'jruby' && defined?(JRUBY_VERSION) && JRUBY_VERSION > '1.7.4'
22
- class Sinatra::Base
23
- class << self
24
- alias_method :old_generate_method, :generate_method
25
- def generate_method(method_name, &block)
26
- old_generate_method(method_name.to_sym, &block)
27
- end
28
- end
29
- end
30
- end
31
-
32
- class HttpRouter
33
- def rewrite_partial_path_info(env, request); end
34
- def rewrite_path_info(env, request); end
35
-
36
- def process_destination_path(path, env)
37
- Thread.current['padrino.instance'].instance_eval do
38
- request.route_obj = path.route
39
- @_response_buffer = nil
40
- @route = path.route
41
- @params ||= {}
42
- @params.update(env['router.params'])
43
- @block_params = if match_data = env['router.request'].extra_env['router.regex_match']
44
- params_list = match_data.to_a
45
- params_list.shift
46
- @params[:captures] = params_list
47
- params_list
48
- else
49
- env['router.request'].params
50
- end
51
- # Provide access to the current controller to the request
52
- # Now we can eval route, but because we have "throw halt" we need to be
53
- # (en)sure to reset old layout and run controller after filters.
54
- original_params = @params
55
- parent_layout = @layout
56
- successful = false
57
- begin
58
- filter! :before
59
- (@route.before_filters - settings.filters[:before]).each { |block| instance_eval(&block) }
60
- @layout = path.route.use_layout if path.route.use_layout
61
- @route.custom_conditions.each { |block| pass if block.bind(self).call == false }
62
- halt_response = catch(:halt) { route_eval { @route.dest[self, @block_params] } }
63
- @_response_buffer = halt_response.is_a?(Array) ? halt_response.last : halt_response
64
- successful = true
65
- halt halt_response
66
- ensure
67
- (@route.after_filters - settings.filters[:after]).each { |block| instance_eval(&block) } if successful
68
- @layout = parent_layout
69
- @params = original_params
70
- end
71
- end
72
- end
73
-
74
- class Route
75
- VALID_HTTP_VERBS.replace %w[GET POST PUT PATCH DELETE HEAD OPTIONS LINK UNLINK]
76
-
77
- attr_accessor :use_layout, :controller, :action, :cache, :cache_key, :cache_expires, :parent
78
-
79
- def before_filters(&block)
80
- @_before_filters ||= []
81
- @_before_filters << block if block_given?
82
-
83
- @_before_filters
84
- end
85
-
86
- def after_filters(&block)
87
- @_after_filters ||= []
88
- @_after_filters << block if block_given?
89
-
90
- @_after_filters
91
- end
92
-
93
- def custom_conditions(&block)
94
- @_custom_conditions ||= []
95
- @_custom_conditions << block if block_given?
96
-
97
- @_custom_conditions
98
- end
99
-
100
- def significant_variable_names
101
- @significant_variable_names ||= if @original_path.is_a?(String)
102
- @original_path.scan(/(^|[^\\])[:\*]([a-zA-Z0-9_]+)/).map{|p| p.last.to_sym}
103
- elsif @original_path.is_a?(Regexp) and @original_path.respond_to?(:named_captures)
104
- @original_path.named_captures.keys.map(&:to_sym)
105
- else
106
- []
107
- end
108
- end
109
-
110
- def to(dest = nil, &dest_block)
111
- @dest = dest || dest_block || raise("you didn't specify a destination")
112
-
113
- @router.current_order ||= 0
114
- @order = @router.current_order
115
- @router.current_order += 1
116
-
117
- if @dest.respond_to?(:url_mount=)
118
- urlmount = UrlMount.new(@path_for_generation, @default_values || {}) # TODO url mount should accept nil here.
119
- urlmount.url_mount = @router.url_mount if @router.url_mount
120
- @dest.url_mount = urlmount
121
- end
122
- self
123
- end
124
-
125
- attr_accessor :order
126
-
127
- end
128
-
129
- attr_accessor :current_order
130
-
131
- def sort!
132
- @routes.sort!{ |a, b| a.order <=> b.order }
133
- end
134
-
135
- class Node::Glob
136
- def to_code
137
- id = root.next_counter
138
- "request.params << (globbed_params#{id} = [])
139
- until request.path.empty?
140
- globbed_params#{id} << request.path.shift
141
- #{super}
142
- end
143
- request.path[0,0] = globbed_params#{id}
144
- request.params.pop"
145
- end
146
- end
147
-
148
- class Node::SpanningRegex
149
- def to_code
150
- params_count = @ordered_indicies.size
151
- whole_path_var = "whole_path#{root.next_counter}"
152
- "#{whole_path_var} = request.joined_path
153
- if match = #{@matcher.inspect}.match(#{whole_path_var}) and match.begin(0).zero?
154
- _#{whole_path_var} = request.path.dup
155
- " << param_capturing_code << "
156
- remaining_path = #{whole_path_var}[match[0].size + (#{whole_path_var}[match[0].size] == ?/ ? 1 : 0), #{whole_path_var}.size]
157
- request.path = remaining_path.split('/')
158
- #{node_to_code}
159
- request.path = _#{whole_path_var}
160
- request.params.slice!(#{-params_count}, #{params_count})
161
- end
162
- "
163
- end
164
- end
165
-
166
- # Monkey patching the Request class. Using Rack::Utils.unescape rather than
167
- # URI.unescape which can't handle utf-8 chars
168
- class Request
169
- def initialize(path, rack_request)
170
- @rack_request = rack_request
171
- @path = path.split(/\//).map{|part| Rack::Utils.unescape(part) }
172
- @path.shift if @path.first == ''
173
- @path.push('') if path[-1] == ?/
174
- @extra_env = {}
175
- @params = []
176
- @acceptable_methods = Set.new
177
- end
178
- end
179
-
180
- class Node::Path
181
- def to_code
182
- path_ivar = inject_root_ivar(self)
183
- "#{"if !callback && request.path.size == 1 && request.path.first == '' && (request.rack_request.head? || request.rack_request.get?) && request.rack_request.path_info[-1] == ?/
184
- catch(:pass) do
185
- response = ::Rack::Response.new
186
- response.redirect(request.rack_request.path_info[0, request.rack_request.path_info.size - 1], 302)
187
- return response.finish
188
- end
189
- end" if router.redirect_trailing_slash?}
190
-
191
- #{"if request.#{router.ignore_trailing_slash? ? 'path_finished?' : 'path.empty?'}" unless route.match_partially}
192
- catch(:pass) do
193
- if callback
194
- request.called = true
195
- callback.call(Response.new(request, #{path_ivar}))
196
- else
197
- env = request.rack_request.dup.env
198
- env['router.request'] = request
199
- env['router.params'] ||= {}
200
- #{"env['router.params'].merge!(Hash[#{param_names.inspect}.zip(request.params)])" if dynamic?}
201
- env['router.params'] = env['router.params'].with_indifferent_access
202
- @router.rewrite#{"_partial" if route.match_partially}_path_info(env, request)
203
- response = @router.process_destination_path(#{path_ivar}, env)
204
- return response unless router.pass_on_response(response)
205
- end
206
- end
207
- #{"end" unless route.match_partially}"
208
- end
209
- end
210
- end
2
+ require 'padrino-core/ext/sinatra'
3
+ require 'padrino-core/ext/http_router'
4
+ require 'padrino-core/filter'
211
5
 
212
6
  module Padrino
213
- class Filter
214
- attr_reader :block
215
-
216
- def initialize(mode, scoped_controller, options, args, &block)
217
- @mode, @scoped_controller, @options, @args, @block = mode, scoped_controller, options, args, block
218
- end
219
-
220
- def apply?(request)
221
- detect = match_with_arguments?(request) || match_with_options?(request)
222
- detect ^ !@mode
223
- end
224
-
225
- def to_proc
226
- if @args.empty? && @options.empty?
227
- block
228
- else
229
- filter = self
230
- proc { instance_eval(&filter.block) if filter.apply?(request) }
231
- end
232
- end
233
-
234
- private
235
-
236
- def scoped_controller_name
237
- @scoped_controller_name ||= Array(@scoped_controller).join("_")
238
- end
239
-
240
- def match_with_arguments?(request)
241
- route, path = request.route_obj, request.path_info
242
- @args.any? do |argument|
243
- if argument.instance_of?(Symbol)
244
- next unless route
245
- name = route.name
246
- argument == name || name == [scoped_controller_name, argument].join(" ").to_sym
247
- else
248
- argument === path
249
- end
250
- end
251
- end
252
-
253
- def match_with_options?(request)
254
- user_agent = request.user_agent
255
- @options.any?{|name, value| value === (name == :agent ? user_agent : request.send(name)) }
256
- end
257
- end
258
-
259
7
  ##
260
8
  # Padrino provides advanced routing definition support to make routes and
261
9
  # url generation much easier. This routing system supports named route
@@ -387,35 +135,7 @@ module Padrino
387
135
  #
388
136
  def controller(*args, &block)
389
137
  if block_given?
390
- options = args.extract_options!
391
-
392
- # Controller defaults.
393
- @_controller, original_controller = args, @_controller
394
- @_parents, original_parent = options.delete(:parent), @_parents
395
- @_provides, original_provides = options.delete(:provides), @_provides
396
- @_use_format, original_use_format = options.delete(:use_format), @_use_format
397
- @_cache, original_cache = options.delete(:cache), @_cache
398
- @_map, original_map = options.delete(:map), @_map
399
- @_conditions, original_conditions = options.delete(:conditions), @_conditions
400
- @_defaults, original_defaults = options, @_defaults
401
- @_accepts, original_accepts = options.delete(:accepts), @_accepts
402
- @_params, original_params = options.delete(:params), @_params
403
-
404
- # Application defaults.
405
- @filters, original_filters = { :before => @filters[:before].dup, :after => @filters[:after].dup }, @filters
406
- @layout, original_layout = nil, @layout
407
-
408
- instance_eval(&block)
409
-
410
- # Application defaults.
411
- @filters = original_filters
412
- @layout = original_layout
413
-
414
- # Controller defaults.
415
- @_controller, @_parents, @_cache = original_controller, original_parent, original_cache
416
- @_defaults, @_provides, @_map = original_defaults, original_provides, original_map
417
- @_conditions, @_use_format, @_accepts = original_conditions, original_use_format, original_accepts
418
- @_params = original_params
138
+ with_new_options(*args) { instance_eval(&block) }
419
139
  else
420
140
  include(*args) if extensions.any?
421
141
  end
@@ -489,10 +209,11 @@ module Padrino
489
209
  # @see http://www.padrinorb.com/guides/controllers#route-filters
490
210
  #
491
211
  def construct_filter(*args, &block)
492
- options = args.last.is_a?(Hash) ? args.pop : {}
493
- except = options.key?(:except) && Array(options.delete(:except))
494
- raise("You cannot use except with other options specified") if except && (!args.empty? || !options.empty?)
495
- options = except.last.is_a?(Hash) ? except.pop : {} if except
212
+ options = args.extract_options!
213
+ if except = options.delete(:except)
214
+ fail "You cannot use :except with other options specified" unless args.empty? && options.empty?
215
+ options = Array(except).extract_options!
216
+ end
496
217
  Filter.new(!except, @_controller, options, Array(except || args), &block)
497
218
  end
498
219
 
@@ -523,8 +244,8 @@ module Padrino
523
244
  def parent(name, options={})
524
245
  defaults = { :optional => false, :map => name.to_s }
525
246
  options = defaults.merge(options)
526
- @_parents = Array(@_parents) unless @_parents.is_a?(Array)
527
- @_parents << Parent.new(name, options)
247
+ @_parent = Array(@_parent) unless @_parent.is_a?(Array)
248
+ @_parent << Parent.new(name, options)
528
249
  end
529
250
 
530
251
  ##
@@ -612,20 +333,9 @@ module Padrino
612
333
  #
613
334
  def url(*args)
614
335
  params = args.extract_options!
615
- names, params_array = args.partition{|a| a.is_a?(Symbol)}
616
- name = names[0, 2].join(" ").to_sym # route name is concatenated with underscores
617
336
  fragment = params.delete(:fragment) || params.delete(:anchor)
618
- params = value_to_param(params.symbolize_keys)
619
- url =
620
- if params_array.empty?
621
- compiled_router.path(name, params)
622
- else
623
- compiled_router.path(name, *(params_array << params))
624
- end
625
- rebase_url(fragment ? url + '#' + fragment : url)
626
- rescue HttpRouter::InvalidRouteException
627
- route_error = "route mapping for url(#{name.inspect}) could not be found!"
628
- raise Padrino::Routing::UnrecognizedException.new(route_error)
337
+ path = make_path_with_params(args, value_to_param(params.symbolize_keys))
338
+ rebase_url(fragment ? path << '#' << fragment : path)
629
339
  end
630
340
  alias :url_for :url
631
341
 
@@ -637,6 +347,15 @@ module Padrino
637
347
  route('HEAD', path, *args, &block)
638
348
  end
639
349
 
350
+ def put(path, *args, &block) route 'PUT', path, *args, &block end
351
+ def post(path, *args, &block) route 'POST', path, *args, &block end
352
+ def delete(path, *args, &block) route 'DELETE', path, *args, &block end
353
+ def head(path, *args, &block) route 'HEAD', path, *args, &block end
354
+ def options(path, *args, &block) route 'OPTIONS', path, *args, &block end
355
+ def patch(path, *args, &block) route 'PATCH', path, *args, &block end
356
+ def link(path, *args, &block) route 'LINK', path, *args, &block end
357
+ def unlink(path, *args, &block) route 'UNLINK', path, *args, &block end
358
+
640
359
  def rebase_url(url)
641
360
  if url.start_with?('/')
642
361
  new_url = ''
@@ -649,19 +368,56 @@ module Padrino
649
368
  end
650
369
 
651
370
  private
371
+
372
+ CONTROLLER_OPTIONS = [ :parent, :provides, :use_format, :cache, :expires, :map, :conditions, :accepts, :params ].freeze
373
+
374
+ # Saves controller options, yields the block, restores controller options.
375
+ def with_new_options(*args)
376
+ options = args.extract_options!
377
+
378
+ CONTROLLER_OPTIONS.each{ |key| replace_instance_variable("@_#{key}", options.delete(key)) }
379
+ replace_instance_variable(:@_controller, args)
380
+ replace_instance_variable(:@_defaults, options)
381
+ replace_instance_variable(:@filters, :before => @filters[:before].dup, :after => @filters[:after].dup)
382
+ replace_instance_variable(:@layout, nil)
383
+
384
+ yield
385
+
386
+ @original_instance.each do |key, value|
387
+ instance_variable_set(key, value)
388
+ end
389
+ end
390
+
391
+ # Sets instance variable by name and saves the original value in @original_instance hash
392
+ def replace_instance_variable(name, value)
393
+ @original_instance ||= {}
394
+ @original_instance[name] = instance_variable_get(name)
395
+ instance_variable_set(name, value)
396
+ end
397
+
398
+ # Searches compiled router for a path responding to args and makes a path with params.
399
+ def make_path_with_params(args, params)
400
+ names, params_array = args.partition{ |arg| arg.is_a?(Symbol) }
401
+ name = names[0, 2].join(" ").to_sym
402
+ compiled_router.path(name, *(params_array << params))
403
+ rescue HttpRouter::InvalidRouteException
404
+ raise Padrino::Routing::UnrecognizedException, "Route mapping for url(#{name.inspect}) could not be found"
405
+ end
406
+
652
407
  # Parse params from the url method
653
- def value_to_param(value)
654
- case value
655
- when Array
656
- value.map { |v| value_to_param(v) }.compact
657
- when Hash
658
- value.inject({}) do |memo, (k,v)|
659
- v = value_to_param(v)
660
- memo[k] = v unless v.nil?
661
- memo
662
- end
663
- when nil then nil
664
- else value.respond_to?(:to_param) ? value.to_param : value
408
+ def value_to_param(object)
409
+ case object
410
+ when Array
411
+ object.map { |item| value_to_param(item) }.compact
412
+ when Hash
413
+ object.inject({}) do |all, (key, value)|
414
+ next all if value.nil?
415
+ all[key] = value_to_param(value)
416
+ all
417
+ end
418
+ when nil
419
+ else
420
+ object.respond_to?(:to_param) ? object.to_param : object
665
421
  end
666
422
  end
667
423
 
@@ -726,13 +482,14 @@ module Padrino
726
482
  path, name, route_parents, options, route_options = *parse_route(path, route_options, verb)
727
483
  options.reverse_merge!(@_conditions) if @_conditions
728
484
 
729
- # Sinatra defaults
730
485
  method_name = "#{verb} #{path}"
731
486
  unbound_method = generate_method(method_name, &block)
732
487
 
733
- block = block.arity != 0 ?
734
- proc { |a,p| unbound_method.bind(a).call(*p) } :
735
- proc { |a,p| unbound_method.bind(a).call }
488
+ block = if block.arity == 0
489
+ proc{ |request, _| unbound_method.bind(request).call }
490
+ else
491
+ proc{ |request, block_params| unbound_method.bind(request).call(*block_params) }
492
+ end
736
493
 
737
494
  invoke_hook(:route_added, verb, path, block)
738
495
 
@@ -743,6 +500,7 @@ module Padrino
743
500
  priority_name = options.delete(:priority) || :normal
744
501
  priority = ROUTE_PRIORITY[priority_name] or raise("Priority #{priority_name} not recognized, try #{ROUTE_PRIORITY.keys.join(', ')}")
745
502
  route.cache = options.key?(:cache) ? options.delete(:cache) : @_cache
503
+ route.cache_expires = options.key?(:expires) ? options.delete(:expires) : @_expires
746
504
  route.parent = route_parents ? (route_parents.count == 1 ? route_parents.first : route_parents) : route_parents
747
505
  route.add_request_method(verb.downcase.to_sym)
748
506
  route.host = options.delete(:host) if options.key?(:host)
@@ -759,7 +517,7 @@ module Padrino
759
517
  end
760
518
 
761
519
  # Add Sinatra conditions.
762
- options.each { |o, a| route.respond_to?(o) ? route.send(o, *a) : send(o, *a) }
520
+ options.each{ |option, args| route.respond_to?(option) ? route.send(option, *args) : send(option, *args) }
763
521
  conditions, @conditions = @conditions, []
764
522
  route.custom_conditions.concat(conditions)
765
523
 
@@ -836,8 +594,8 @@ module Padrino
836
594
  end
837
595
 
838
596
  # Now we need to parse our 'parent' params and parent scope.
839
- if !absolute_map and parent_params = options.delete(:parent) || @_parents
840
- parent_params = (Array(@_parents) + Array(parent_params)).uniq
597
+ if !absolute_map and parent_params = options.delete(:parent) || @_parent
598
+ parent_params = (Array(@_parent) + Array(parent_params)).uniq
841
599
  path = process_path_for_parent_params(path, parent_params)
842
600
  end
843
601
 
@@ -873,7 +631,9 @@ module Padrino
873
631
  # Used for calculating path in route method.
874
632
  #
875
633
  def process_path_for_with_params(path, with_params)
876
- File.join(path, Array(with_params).map(&:inspect).join("/"))
634
+ File.join(path, Array(with_params).map do |step|
635
+ step.kind_of?(String) ? step : step.inspect
636
+ end.join("/"))
877
637
  end
878
638
 
879
639
  ##
@@ -928,51 +688,29 @@ module Padrino
928
688
  #
929
689
  def provides(*types)
930
690
  @_use_format = true
691
+ mime_types = types.map{ |type| mime_type(CONTENT_TYPE_ALIASES[type] || type) }
931
692
  condition do
932
- mime_types = types.map { |t| mime_type(t) }.compact
933
- url_format = params[:format].to_sym if params[:format]
934
- accepts = request.accept.map(&:to_str)
935
- accepts.clear if accepts == ["*/*"]
693
+ return provides_format?(types, params[:format].to_sym) if params[:format]
936
694
 
695
+ accepts = request.accept.map(&:to_str)
937
696
  # Per rfc2616-sec14:
938
697
  # Assume */* if no ACCEPT header is given.
939
- catch_all = (accepts.delete "*/*" || accepts.empty?)
940
- matching_types = accepts.empty? ? mime_types.slice(0,1) : (accepts & mime_types)
941
- if matching_types.empty? && types.include?(:any)
942
- matching_types = accepts
943
- end
698
+ catch_all = accepts.delete("*/*")
944
699
 
945
- if !url_format && matching_types.first
946
- type = ::Rack::Mime::MIME_TYPES.find { |k, v| v == matching_types.first }[0].sub(/\./,'').to_sym
947
- accept_format = CONTENT_TYPE_ALIASES[type] || type
948
- elsif catch_all && !types.include?(:any)
949
- type = types.first
950
- accept_format = CONTENT_TYPE_ALIASES[type] || type
951
- end
700
+ return provides_any?(accepts) if types.include?(:any)
952
701
 
953
- matched_format = types.include?(:any) ||
954
- types.include?(accept_format) ||
955
- types.include?(url_format) ||
956
- ((!url_format) && request.accept.empty? && types.include?(:html))
702
+ accepts = accepts.empty? ? mime_types.slice(0,1) : (accepts & mime_types)
957
703
 
958
- # Per rfc2616-sec14:
959
- # Answer with 406 if accept is given but types to not match any
960
- # provided type.
961
- halt 406 if
962
- (!url_format && !accepts.empty? && !matched_format) ||
963
- (settings.respond_to?(:treat_format_as_accept) && settings.treat_format_as_accept && url_format && !matched_format)
704
+ type = accepts.first && mime_symbol(accepts.first)
705
+ type ||= catch_all && types.first
964
706
 
965
- if matched_format
966
- @_content_type = url_format || accept_format || :html
967
-
968
- if @_content_type != :json
969
- content_type(@_content_type, :charset => 'utf-8')
970
- else
971
- content_type(@_content_type)
972
- end
707
+ accept_format = CONTENT_TYPE_ALIASES[type] || type
708
+ if types.include?(accept_format)
709
+ content_type(accept_format || :html, :charset => 'utf-8')
710
+ else
711
+ halt 406 unless catch_all
712
+ false
973
713
  end
974
-
975
- matched_format
976
714
  end
977
715
  end
978
716
 
@@ -986,14 +724,10 @@ module Padrino
986
724
  # # => GET /a CONTENT_TYPE application/xml => 406
987
725
  #
988
726
  def accepts(*types)
989
- mime_types = types.map { |type| mime_type(CONTENT_TYPE_ALIASES[type] || type) }.compact
727
+ mime_types = types.map{ |type| mime_type(CONTENT_TYPE_ALIASES[type] || type) }
990
728
  condition do
991
- halt 406 unless media_type = mime_types.detect{|mime_type| mime_type == request.media_type }
992
- if media_type != 'application/json'
993
- content_type(media_type, :charset => 'utf-8')
994
- else
995
- content_type(media_type)
996
- end
729
+ halt 406 unless mime_types.include?(request.media_type)
730
+ content_type(mime_symbol(request.media_type), :charset => 'utf-8')
997
731
  end
998
732
  end
999
733
 
@@ -1098,10 +832,10 @@ module Padrino
1098
832
  # serving files from the public directory.
1099
833
  #
1100
834
  def static_file?(path_info)
1101
- return if (public_dir = settings.public_folder).nil?
835
+ return unless public_dir = settings.public_folder
1102
836
  public_dir = File.expand_path(public_dir)
1103
837
  path = File.expand_path(public_dir + unescape(path_info))
1104
- return if path[0, public_dir.length] != public_dir
838
+ return unless path.start_with?(public_dir)
1105
839
  return unless File.file?(path)
1106
840
  return path
1107
841
  end
@@ -1135,15 +869,35 @@ module Padrino
1135
869
  # end
1136
870
  #
1137
871
  def content_type(type=nil, params={})
1138
- unless type.nil?
1139
- super(type, params)
1140
- @_content_type = type
1141
- end
1142
- @_content_type
872
+ return @_content_type unless type
873
+ params.delete(:charset) if type == :json
874
+ super(type, params)
875
+ @_content_type = type
1143
876
  end
1144
877
 
1145
878
  private
1146
879
 
880
+ def provides_any?(formats)
881
+ accepted_format = formats.first
882
+ type = accepted_format ? mime_symbol(accepted_format) : :html
883
+ content_type(CONTENT_TYPE_ALIASES[type] || type, :charset => 'utf-8')
884
+ end
885
+
886
+ def provides_format?(types, format)
887
+ if ([:any, format] & types).empty?
888
+ # Per rfc2616-sec14:
889
+ # Answer with 406 if accept is given but types to not match any provided type.
890
+ halt 406 if settings.respond_to?(:treat_format_as_accept) && settings.treat_format_as_accept
891
+ false
892
+ else
893
+ content_type(format || :html, :charset => 'utf-8')
894
+ end
895
+ end
896
+
897
+ def mime_symbol(media_type)
898
+ ::Rack::Mime::MIME_TYPES.key(media_type).sub(/\./,'').to_sym
899
+ end
900
+
1147
901
  def filter!(type, base=settings)
1148
902
  base.filters[type].each { |block| instance_eval(&block) }
1149
903
  end
@@ -1166,20 +920,19 @@ module Padrino
1166
920
 
1167
921
  def route!(base=settings, pass_block=nil)
1168
922
  Thread.current['padrino.instance'] = self
1169
- if base.compiled_router and match = base.compiled_router.call(@request.env)
1170
- if match.respond_to?(:each)
923
+
924
+ if base.compiled_router && result = base.compiled_router.call(@request.env)
925
+ if result.respond_to?(:each)
1171
926
  route_eval do
1172
- match[1].each { |k,v| response[k] = v }
1173
- status match[0]
1174
- route_missing if match[0] == 404
1175
- route_missing if allow = response['Allow'] and allow.include?(request.env['REQUEST_METHOD'])
927
+ response.headers.merge!(result[1])
928
+ route_missing if status(result[0]) == 404
929
+ route_missing if (allow = response['Allow']) && allow.include?(request.env['REQUEST_METHOD'])
1176
930
  end
1177
931
  end
1178
932
  else
1179
933
  filter! :before
1180
934
  end
1181
935
 
1182
- # Run routes defined in superclass.
1183
936
  if base.superclass.respond_to?(:router)
1184
937
  route!(base.superclass, pass_block)
1185
938
  return