class Furi::Uri

Public Class Methods

new(argument) click to toggle source
# File lib/furi/uri.rb, line 18
def initialize(argument)
  @query_tokens = []
  case argument
  when String
    parse_uri_string(argument)
  when Hash
    replace(argument)
  when ::URI::Generic
    parse_uri_string(argument.to_s)
  else
    raise ParseError, "wrong Uri argument"
  end
end

Public Instance Methods

==(other) click to toggle source
# File lib/furi/uri.rb, line 446
def ==(other)
  to_s == other.to_s
end
[](part) click to toggle source
# File lib/furi/uri.rb, line 459
def [](part)
  send(part)
end
[]=(part, value) click to toggle source
# File lib/furi/uri.rb, line 463
def []=(part, value)
  send(:"#{part}=", value)
end
abstract_protocol?() click to toggle source
# File lib/furi/uri.rb, line 417
def abstract_protocol?
  protocol == ""
end
anchor=(string) click to toggle source
# File lib/furi/uri.rb, line 454
def anchor=(string)
  string = string.to_s
  @anchor = string.empty? ? nil : string
end
authority() click to toggle source
# File lib/furi/uri.rb, line 158
def authority
  return hostinfo unless userinfo
  [userinfo, hostinfo].join("@")
end
authority=(string) click to toggle source
# File lib/furi/uri.rb, line 163
def authority=(string)
  if string.include?("@")
    userinfo, string = string.split("@", 2)
    self.userinfo = userinfo
  else
    self.userinfo = nil
  end
  self.hostinfo = string
end
custom_port?() click to toggle source
# File lib/furi/uri.rb, line 486
def custom_port?
  port && port != default_port
end
default_port() click to toggle source
# File lib/furi/uri.rb, line 382
def default_port
  Furi::PROTOCOLS.fetch(protocol, {})[:port]
end
default_web_port?() click to toggle source
# File lib/furi/uri.rb, line 407
def default_web_port?
  Furi::WEB_PROTOCOL.any? do |web_protocol|
    Furi::PROTOCOLS[web_protocol][:port] == port!
  end
end
defaults(parts) click to toggle source
# File lib/furi/uri.rb, line 54
def defaults(parts)
  parts.each do |part, value|
    case part.to_sym
    when :query, :query_tokens
      Furi.parse_query(value).each do |key, default_value|
        unless query.key?(key)
          query[key] = default_value
        end
      end
    else
      unless self[part]
        self[part] = value
      end
    end
  end
  self
end
directory() click to toggle source
# File lib/furi/uri.rb, line 309
def directory
  path_tokens[0..-2].join("/")
end
directory=(string) click to toggle source
# File lib/furi/uri.rb, line 313
def directory=(string)
  string ||= "/"
  if file && string !~ %r{/\z}
    string += '/'
  end
  self.path = string + file.to_s
end
domain() click to toggle source
# File lib/furi/uri.rb, line 121
def domain
  join_domain(parsed_host[1..2].flatten)
end
domain=(new_domain) click to toggle source
# File lib/furi/uri.rb, line 125
def domain=(new_domain)
  self.host= [subdomain, new_domain]
end
domainname() click to toggle source
# File lib/furi/uri.rb, line 113
def domainname
  parsed_host[1]
end
domainname=(new_domainname) click to toggle source
# File lib/furi/uri.rb, line 117
def domainname=(new_domainname)
  self.domain = join_domain([subdomain, new_domainname, domainzone])
end
domainzone() click to toggle source
# File lib/furi/uri.rb, line 105
def domainzone
  parsed_host.last
end
domainzone=(new_zone) click to toggle source
# File lib/furi/uri.rb, line 109
def domainzone=(new_zone)
  self.host = [subdomain, domainname, new_zone]
end
email() click to toggle source
# File lib/furi/uri.rb, line 482
def email
  authority
end
email=(email) click to toggle source
# File lib/furi/uri.rb, line 477
def email=(email)
  self.protocol ||= "mailto"
  self.authority = email
end
extension() click to toggle source
# File lib/furi/uri.rb, line 321
def extension
  return nil unless file
  file_tokens.size > 1 ? file_tokens.last : nil
end
extension=(string) click to toggle source
# File lib/furi/uri.rb, line 326
def extension=(string)
  tokens = file_tokens
  case tokens.size
  when 0
    raise Furi::FormattingError, "can not assign extension when there is no file"
  when 1
    tokens.push(string)
  else
    if string
      tokens[-1] = string
    else
      tokens.pop
    end
  end
  self.file = tokens.join(".")
end
file() click to toggle source
# File lib/furi/uri.rb, line 398
def file
  result = path_tokens.last
  result == "" ? nil : result
end
file!() click to toggle source
# File lib/furi/uri.rb, line 403
def file!
  file || ''
end
file=(name) click to toggle source
# File lib/furi/uri.rb, line 343
def file=(name)
  unless name
    return unless path
  else
    name = name.gsub(%r{\A/}, "")
  end

  self.path = path_tokens.tap do |p|
    filename_index = [p.size-1, 0].max
    p[filename_index] = name
  end.join("/")
end
home_page?() click to toggle source
# File lib/furi/uri.rb, line 224
def home_page?
  path! == Furi::ROOT || path! == "/index.html"
end
host!() click to toggle source
# File lib/furi/uri.rb, line 442
def host!
  host || ""
end
host=(host) click to toggle source
# File lib/furi/uri.rb, line 94
def host=(host)
  @host = case host
          when Array
            join_domain(host)
          when "", nil
            nil
          else
            host.to_s.downcase
          end
end
hostinfo() click to toggle source
# File lib/furi/uri.rb, line 137
def hostinfo
  return host unless custom_port?
  if port && !host
    raise Furi::FormattingError, "can not build URI with port but without host"
  end
  [host, port].join(":")
end
hostinfo=(string) click to toggle source
# File lib/furi/uri.rb, line 145
def hostinfo=(string)
  if string.match(%r{\A\[.+\]\z}) #ipv6 host
    self.host = string
  else
    if match = string.match(/\A(.+):(.*)\z/)
      self.host, self.port = match.captures
    else
      self.host = string
      self.port = nil
    end
  end
end
inspect() click to toggle source
# File lib/furi/uri.rb, line 450
def inspect
  "#<#{self.class} #{to_s.inspect}>"
end
location() click to toggle source
# File lib/furi/uri.rb, line 186
def location
  if protocol
    if !host && !mailto?
      raise Furi::FormattingError, "can not build URI with protocol but without host"
    end
    [
      protocol.empty? ? "" : "#{protocol}:", authority
    ].join(mailto? ? "" : "//")
  else
    authority
  end
end
location=(string) click to toggle source
# File lib/furi/uri.rb, line 199
def location=(string)
  string ||= ""
  string  = string.gsub(%r(/\Z), '')
  self.protocol = nil
  string = parse_protocol(string)
  self.authority = string
end
mailto?() click to toggle source
# File lib/furi/uri.rb, line 490
def mailto?
  protocol == "mailto"
end
merge_query(query) click to toggle source
# File lib/furi/uri.rb, line 72
def merge_query(query)
  case query
  when Hash
    self.query = self.query.merge(Furi::Utils.stringify_keys(query))
  when String, Array
    self.query_tokens += Furi.query_tokens(query)
  when nil
  else
    raise QueryParseError, "#{query.inspect} can not be merged"
  end
end
password=(password) click to toggle source
# File lib/furi/uri.rb, line 284
def password=(password)
  @password = password.nil? ? nil : password.to_s
end
path!() click to toggle source
# File lib/furi/uri.rb, line 434
def path!
  path || Furi::ROOT
end
path=(path) click to toggle source
# File lib/furi/uri.rb, line 294
def path=(path)
  @path = path.to_s
  if !@path.empty? && !@path.start_with?("/")
    @path = "/" + @path
  end
end
path_tokens() click to toggle source
# File lib/furi/uri.rb, line 356
def path_tokens
  return [] unless path
  path.split("/", -1)
end
port!() click to toggle source
# File lib/furi/uri.rb, line 378
def port!
  port || default_port
end
port=(port) click to toggle source
# File lib/furi/uri.rb, line 251
def port=(port)
  @port = case port
          when String
            if port.empty?
              nil
            else
              unless port =~ /\A\s*\d+\s*\z/
                raise ArgumentError, "port should be an Integer >= 0"
              end
              port.to_i
            end
          when Integer
            if port < 0
              raise ArgumentError, "port should be an Integer >= 0"
            end
            port
          when nil
            nil
          else
            raise ArgumentError, "can not parse port: #{port.inspect}"
          end
  @port
end
protocol!() click to toggle source
# File lib/furi/uri.rb, line 305
def protocol!
  protocol || default_protocol_for_port || 'http' # Web Rules Them All!
end
protocol=(protocol) click to toggle source
# File lib/furi/uri.rb, line 301
def protocol=(protocol)
  @protocol = protocol ? protocol.gsub(%r{:?/?/?\Z}, "").downcase : nil
end
query() click to toggle source
# File lib/furi/uri.rb, line 228
def query
  return @query if query_level?
  @query = Furi.parse_query(query_tokens)
end
query=(value) click to toggle source
# File lib/furi/uri.rb, line 234
def query=(value)
  case value
  when true
    # Assuming that current query needs to be parsed to Hash
    query
  when String, Array
    self.query_tokens = value
    @query = nil
  when Hash
    self.query_tokens = value
    @query = value
  when nil
  else
    raise QueryParseError, 'Query can only be Hash or String'
  end
end
query_string() click to toggle source
# File lib/furi/uri.rb, line 362
def query_string
  if query_level?
    Furi.serialize(query)
  else
    query_tokens.any? ? query_tokens.join("&") : nil
  end
end
query_string!() click to toggle source
# File lib/furi/uri.rb, line 370
def query_string!
  query_string || ""
end
query_string=(string) click to toggle source
# File lib/furi/uri.rb, line 374
def query_string=(string)
  self.query_tokens = string.to_s
end
query_tokens=(tokens) click to toggle source
# File lib/furi/uri.rb, line 275
def query_tokens=(tokens)
  @query = nil
  @query_tokens = Furi.query_tokens(tokens)
end
replace(parts) click to toggle source
# File lib/furi/uri.rb, line 32
def replace(parts)
  if parts
    parts.each do |part, value|
      self[part] = value
    end
  end
  self
end
request() click to toggle source
# File lib/furi/uri.rb, line 207
def request
  return nil if !path && query_tokens.empty?
  result = []
  result << path!
  result << "?" << query_string if query_tokens.any?
  result.join
end
request!() click to toggle source
# File lib/furi/uri.rb, line 215
def request!
  request || path!
end
request=(string) click to toggle source
# File lib/furi/uri.rb, line 219
def request=(string)
  string = parse_anchor_and_query(string)
  self.path = string
end
resource() click to toggle source
# File lib/furi/uri.rb, line 421
def resource
  return nil unless request
  request + encoded_anchor
end
resource!() click to toggle source
# File lib/furi/uri.rb, line 438
def resource!
  resource || request!
end
resource=(value) click to toggle source
# File lib/furi/uri.rb, line 426
def resource=(value)
  self.anchor = nil
  self.query_tokens = []
  self.path = nil
  value = parse_anchor_and_query(value)
  self.path = value
end
rfc3986?() click to toggle source
# File lib/furi/uri.rb, line 471
def rfc3986?
  uri = to_s
  !!(uri.match(URI::RFC3986_Parser::RFC3986_URI) ||
     uri.match(URI::RFC3986_Parser::RFC3986_relative_ref))
end
rfc?() click to toggle source
# File lib/furi/uri.rb, line 467
def rfc?
  rfc3986?
end
ssl() click to toggle source
# File lib/furi/uri.rb, line 390
def ssl
  ssl?
end
ssl=(ssl) click to toggle source
# File lib/furi/uri.rb, line 394
def ssl=(ssl)
  self.protocol = find_protocol_for_ssl(ssl)
end
ssl?() click to toggle source
# File lib/furi/uri.rb, line 386
def ssl?
  !!(Furi::PROTOCOLS.fetch(protocol, {})[:ssl])
end
subdomain() click to toggle source
# File lib/furi/uri.rb, line 129
def subdomain
  parsed_host.first
end
subdomain=(new_subdomain) click to toggle source
# File lib/furi/uri.rb, line 133
def subdomain=(new_subdomain)
  self.host = [new_subdomain, domain]
end
to_s() click to toggle source
# File lib/furi/uri.rb, line 173
def to_s
  result = []
  result << location
  result << (host || mailto? ? path : path!)
  if query_tokens.any?
    result << "?" << query_string
  end
  if anchor
    result << encoded_anchor
  end
  result.join
end
update(parts) click to toggle source
# File lib/furi/uri.rb, line 41
def update(parts)
  return self unless parts
  parts.each do |part, value|
    case part.to_sym
    when :query, :query_tokens, :query_string
      merge_query(value)
    else
      self[part] = value
    end
  end
  self
end
userinfo() click to toggle source
# File lib/furi/uri.rb, line 84
def userinfo
  if username
    [username, password].compact.join(":")
  elsif password
    raise Furi::FormattingError, "can not build URI with password but without username"
  else
    nil
  end
end
userinfo=(userinfo) click to toggle source
# File lib/furi/uri.rb, line 288
def userinfo=(userinfo)
  username, password = (userinfo || "").split(":", 2)
  self.username = username
  self.password = password
end
username=(username) click to toggle source
# File lib/furi/uri.rb, line 280
def username=(username)
  @username = username.nil? ? nil : username.to_s
end
web_protocol?() click to toggle source
# File lib/furi/uri.rb, line 413
def web_protocol?
  Furi::WEB_PROTOCOL.include?(protocol)
end

Protected Instance Methods

default_protocol_for_port() click to toggle source
# File lib/furi/uri.rb, line 581
def default_protocol_for_port
  return nil unless port
  PROTOCOLS.each do |protocol, data|
    if data[:port] == port
      return protocol
    end
  end
end
encoded_anchor() click to toggle source
# File lib/furi/uri.rb, line 590
def encoded_anchor
  return "" unless anchor
  "#" + ::URI::DEFAULT_PARSER.escape(anchor)
end
file_tokens() click to toggle source
# File lib/furi/uri.rb, line 496
def file_tokens
  file ? file.split('.') : []
end
find_protocol_for_ssl(ssl) click to toggle source
# File lib/furi/uri.rb, line 520
def find_protocol_for_ssl(ssl)
  if Furi::SSL_MAPPING.key?(protocol)
    ssl ? Furi::SSL_MAPPING[protocol] : protocol
  elsif Furi::SSL_MAPPING.values.include?(protocol)
    ssl ? protocol : Furi::SSL_MAPPING.invert[protocol]
  else
    raise ArgumentError, "Can not specify SSL for #{protocol.inspect} protocol"
  end
end
host_tokens() click to toggle source
# File lib/furi/uri.rb, line 577
def host_tokens
  host.split(".")
end
join(uri) click to toggle source
# File lib/furi/uri.rb, line 546
def join(uri)
  Uri.new(::URI.join(to_s, uri.to_s))
end
join_domain(tokens) click to toggle source
# File lib/furi/uri.rb, line 530
def join_domain(tokens)
  tokens = tokens.compact
  tokens.any? ? tokens.join(".") : nil
end
parse_anchor_and_query(string) click to toggle source
# File lib/furi/uri.rb, line 535
def parse_anchor_and_query(string)
  string ||= ''
  string, *anchor = string.split("#")
  self.anchor = ::URI::DEFAULT_PARSER.unescape(anchor.join("#"))
  if string && string.include?("?")
    string, query_string = string.split("?", 2)
    self.query_tokens = query_string
  end
  string
end
parse_protocol(string) click to toggle source
# File lib/furi/uri.rb, line 550
def parse_protocol(string)
  if string.include?("://") || string.start_with?("mailto:")
    protocol, string = string.split(":", 2)
    self.protocol = protocol
  end
  if string.start_with?("//")
    self.protocol ||= ''
    string = string[2..-1]
  end
  string
end
parse_uri_string(string) click to toggle source
# File lib/furi/uri.rb, line 504
def parse_uri_string(string)
  if string.empty?
    raise Furi::FormattingError, "can not be an empty string"
  end
  string = parse_anchor_and_query(string)

  string = parse_protocol(string)

  if string.include?("/")
    string, path = string.split("/", 2)
    self.path = "/" + path
  end

  self.authority = string
end
parsed_host() click to toggle source
# File lib/furi/uri.rb, line 562
def parsed_host
  return @parsed_host if @parsed_host
  tokens = host_tokens
  zone = []
  subdomain = []
  while tokens.any? && tokens.last.size <= 3 && tokens.size >= 2
    zone.unshift tokens.pop
  end
  while tokens.size > 1
    subdomain << tokens.shift
  end
  domainname = tokens.first
  @parsed_host = [join_domain(subdomain), domainname, join_domain(zone)]
end
query_level?() click to toggle source
# File lib/furi/uri.rb, line 500
def query_level?
  !!@query
end