require 'uri' #require 'cgi' require 'facets/kernel/blank' module URI module_function # Decode the uri components. # def decode(uri) ## gmosx: hmm is this needed? ## guard against invalid filenames for example pictures with ## spaces uploaded by users escaped_uri = uri.gsub(/ /, "+") if md = URI::REGEXP::REL_URI.match(escaped_uri) path = "#{md[5]}#{md[6]}" type = File.extname(path) query_string = md[7] ## real_path = "#{$root_dir}/#{path}" parameters = URI.query_to_hash(query_string) path.gsub!(/\+/, " ") return [path, type, parameters, query_string] end ## this is usefull for uncovering bugs! raise ArgumentError.new("the parameter '#{uri}' is not a valid uri") end # Extend the basic query string parser provided by the cgi module. # converts single valued params (the most common case) to # objects instead of arrays # # Returns hash of parameters, contains arrays for multivalued parameters # (multiselect, checkboxes , etc). # # If no query string is provided (nil or "") returns an empty hash. def query_to_hash(query_string) return {} unless query_string query_parameters = cgi_parse(query_string) query_parameters.each { |key, val| ## replace the array with an object query_parameters[key] = val[0] if 1 == val.length } ## set default value to nil! cgi sets this to [] query_parameters.default = nil return query_parameters end alias_method :query_string_to_hash, :query_to_hash # KEY_VALUE_SEPARATOR = ";" # "&" # Given a hash with parameter/value pairs construct a # standard query string. # # URI.hash_to_query(:a => 1, :b => 2) # #=> "a=1;b=2" # def hash_to_query(parameters) return '' unless parameters pairs = [] parameters.each do |param, value| pairs << "#{param}=#{cgi_escape(value.to_s)}" end return pairs.join(KEY_VALUE_SEPARATOR) end alias_method :hash_to_query_string, :hash_to_query # CGI escape # # TODO: How does this compare to URI.escape? def cgi_escape(string) string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do '%' + $1.unpack('H2' * $1.size).join('%').upcase end.tr(' ', '+') end # def cgi_unescape(string) string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do [$1.delete('%')].pack('H*') end end # def cgi_parse(query) params = Hash.new([].freeze) query.split(/[&;]/n).each do |pairs| key, value = pairs.split('=',2).collect{|v| cgi_unescape(v) } if params.has_key?(key) params[key].push(value) else params[key] = [value] end end params end # This method returns the query string of a uri # # Input: # the uri # # Output: # the query string. # returns nil if no query string def get_query_string(uri) return nil unless uri # gmosx: INVESTIGATE ruby's URI seems to differently handle # abs and rel uris. if md = URI::REGEXP::ABS_URI.match(uri) return md[8] elsif md = URI::REGEXP::REL_URI.match(uri) return md[7] end return nil end # Removes the query string from a +uri+. # # Returns the chomped uri. def chomp_query_string(uri) return nil unless uri query_string = self.get_query_string(uri) return uri.dup.chomp("?#{query_string}") end # Get a uri and a hash of parameters. Inject the hash values # as parameters in the query sting path. Returns the full uri. # # uri - the uri to filter (String) # parameter - hash of parameters to update # # Returns the full updated query string. # # TODO: optimize def update_query_string(uri, parameters) query_string = self.get_query_string(uri) rest = uri.dup.gsub(/\?#{query_string}/, "") hash = self.query_string_to_hash(query_string) hash.update(parameters) query_string = self.hash_to_query_string(hash) unless query_string.blank? return "#{rest}?#{query_string}" else return rest end end # Gets the request uri, injects extra parameters in the query string # and returns a new uri. The request object is not modified. # There is always a qs string so an extra test is skipped. # # TODO: find a better name? def update_request_uri(request, parameters) hash = request.parameters.dup() hash.update(parameters) ## use this in hash_to_querystring. query_string = hash.collect { |k, v| "#{k}=#{v}" }.join(";") ## return "#{request.translated_uri}?#{query_string}" return "#{request.path}?#{query_string}" end module Kernel # def uri(s, w=%r{[^a-zA-Z_0-9./-]}) URI.escape(s, w) end # def unuri(s) URI.unescape(s) end end module Hash # def to_uri URI.hash_to_query(self) end end end class Object #:nodoc: include URI::Kernel end class Hash #:nodoc: include URI::Hash end