padrino-core 0.12.2 → 0.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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