class Redis::Client

def _parse_options(options)

def _parse_options(options)
  return options if options[:_parsed]
  defaults = DEFAULTS.dup
  options = options.dup
  defaults.keys.each do |key|
    # Fill in defaults if needed
    if defaults[key].respond_to?(:call)
      defaults[key] = defaults[key].call
    end
    # Symbolize only keys that are needed
    options[key] = options[key.to_s] if options.has_key?(key.to_s)
  end
  url = options[:url] || defaults[:url]
  # Override defaults from URL if given
  if url
    require "uri"
    uri = URI(url)
    if uri.scheme == "unix"
      defaults[:path]   = uri.path
    elsif uri.scheme == "redis" || uri.scheme == "rediss"
      defaults[:scheme]   = uri.scheme
      defaults[:host]     = uri.host if uri.host
      defaults[:port]     = uri.port if uri.port
      defaults[:password] = CGI.unescape(uri.password) if uri.password
      defaults[:db]       = uri.path[1..-1].to_i if uri.path
      defaults[:role] = :master
    else
      raise ArgumentError, "invalid uri scheme '#{uri.scheme}'"
    end
    defaults[:ssl] = true if uri.scheme == "rediss"
  end
  # Use default when option is not specified or nil
  defaults.keys.each do |key|
    options[key] = defaults[key] if options[key].nil?
  end
  if options[:path]
    # Unix socket
    options[:scheme] = "unix"
    options.delete(:host)
    options.delete(:port)
  else
    # TCP socket
    options[:host] = options[:host].to_s
    options[:port] = options[:port].to_i
  end
  if options.has_key?(:timeout)
    options[:connect_timeout] ||= options[:timeout]
    options[:read_timeout]    ||= options[:timeout]
    options[:write_timeout]   ||= options[:timeout]
  end
  options[:connect_timeout] = Float(options[:connect_timeout])
  options[:read_timeout]    = Float(options[:read_timeout])
  options[:write_timeout]   = Float(options[:write_timeout])
  options[:reconnect_attempts] = options[:reconnect_attempts].to_i
  options[:db] = options[:db].to_i
  options[:driver] = _parse_driver(options[:driver]) || Connection.drivers.last
  case options[:tcp_keepalive]
  when Hash
    [:time, :intvl, :probes].each do |key|
      unless options[:tcp_keepalive][key].is_a?(Integer)
        raise "Expected the #{key.inspect} key in :tcp_keepalive to be an Integer"
      end
    end
  when Integer
    if options[:tcp_keepalive] >= 60
      options[:tcp_keepalive] = {:time => options[:tcp_keepalive] - 20, :intvl => 10, :probes => 2}
    elsif options[:tcp_keepalive] >= 30
      options[:tcp_keepalive] = {:time => options[:tcp_keepalive] - 10, :intvl => 5, :probes => 2}
    elsif options[:tcp_keepalive] >= 5
      options[:tcp_keepalive] = {:time => options[:tcp_keepalive] - 2, :intvl => 2, :probes => 1}
    end
  end
  options[:_parsed] = true
  options
end