Skip to content

Instantly share code, notes, and snippets.

@sporkmonger
Forked from technoweenie/gist:23630
Created November 10, 2008 22:15
Show Gist options
  • Save sporkmonger/23660 to your computer and use it in GitHub Desktop.
Save sporkmonger/23660 to your computer and use it in GitHub Desktop.
# Percent encodes a URI or component.
#
# @param [String, #to_str] uri The URI or component to encode.
#
# @option [String, Regexp] character_class
# The characters which are not percent encoded. If a <tt>String</tt>
# is passed, the <tt>String</tt> must be formatted as a regular
# expression character class. (Do not include the surrounding square
# brackets.) For example, <tt>"b-zB-Z0-9"</tt> would cause everything
# but the letters 'b' through 'z' and the numbers '0' through '9' to be
# percent encoded. If a <tt>Regexp</tt> is passed, the value
# <tt>/[^b-zB-Z0-9]/</tt> would have the same effect.
# A set of useful <tt>String</tt> values may be found in the
# <tt>Addressable::URI::CharacterClasses</tt> module. The default value
# is the reserved plus unreserved character classes specified in
# <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
#
# @return [String] The encoded component.
#
# @example
# Addressable::URI.encode(
# "simple/example", :character_class => "b-zB-Z0-9"
# )
# => "simple%2Fex%61mple"
# Addressable::URI.encode(
# "simple/example", :character_class => /[^b-zB-Z0-9]/
# )
# => "simple%2Fex%61mple"
# Addressable::URI.encode(
# "simple/example",
# :character_class => Addressable::URI::CharacterClasses::UNRESERVED
# )
# => "simple%2Fexample"
# Addressable::URI.encode(
# "simple/example",
# :character_class => Addressable::URI::CharacterClasses::UNRESERVED
# )
# => "simple%2Fexample"
def self.encode(uri, options={})
return nil if uri.nil?
if !uri.respond_to?(:to_str)
raise TypeError, "Can't convert #{uri.class} into String."
end
# Process optional parameters
if options.kind_of?(Regexp)
options = {:character_class => options}
elsif options.kind_of?(Class)
options = {:returning => options}
end
options = {
:character_class => nil,
:returning => String,
:component => nil
}.merge(options)
encode_all = !options[:character_class] && !options[:component]
if options[:character_class] == nil
case options[:component]
when :scheme
options[:character_class] =
Addressable::URI::CharacterClasses::SCHEME
when :user, :password, :host, :port, :userinfo, :authority
options[:character_class] =
Addressable::URI::CharacterClasses::AUTHORITY
when :path
options[:character_class] =
Addressable::URI::CharacterClasses::PATH
when :query
options[:character_class] =
Addressable::URI::CharacterClasses::QUERY
when :fragment
options[:character_class] =
Addressable::URI::CharacterClasses::FRAGMENT
else
options[:character_class] =
CharacterClasses::RESERVED + CharacterClasses::UNRESERVED
end
end
if ![String, ::Addressable::URI].include?(options[:returning])
raise TypeError,
"Expected String or Addressable::URI, " +
"got #{options[:returning].inspect}"
end
if ![String, Regexp].include?(options[:character_class])
raise TypeError,
"Expected String or Regexp, " +
"got #{options[:character_class].inspect}"
end
if encode_all
uri = uri.kind_of?(self) ? uri : self.parse(uri.to_str)
encoded_uri = Addressable::URI.new(
:scheme => self.encode(
uri.scheme, :component => :scheme
),
:authority => self.encode_component(
uri.authority, :component => :authority
),
:path => self.encode_component(
uri.path, :component => :path
),
:query => self.encode_component(
uri.query, :component => :query
),
:fragment => self.encode_component(
uri.fragment, :component => :fragment
)
)
if returning == String
return encoded_uri.to_s
elsif returning == ::Addressable::URI
return encoded_uri
end
else
component = uri.to_str
if options[:character_class].kind_of?(String)
options[:character_class] = /[^#{options[:character_class]}]/
end
return component.gsub(options[:character_class]) do |sequence|
(sequence.unpack('C*').map { |c| "%#{c.to_s(16).upcase}" }).join("")
end
end
end
class << self
alias_method :escape, :encode
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment