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
    defaults[key] = defaults[key].call if defaults[key].respond_to?(:call)
    # Symbolize only keys that are needed
    options[key] = options[key.to_s] if options.key?(key.to_s)
  end
  url = options[:url]
  url = defaults[:url] if url.nil?
  # 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[:username] = CGI.unescape(uri.user) if uri.user && !uri.user.empty?
      defaults[:password] = CGI.unescape(uri.password) if uri.password && !uri.password.empty?
      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.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[:reconnect_delay] = options[:reconnect_delay].to_f
  options[:reconnect_delay_max] = options[:reconnect_delay_max].to_f
  options[:db] = options[:db].to_i
  options[:driver] = _parse_driver(options[:driver]) || Connection.drivers.last
  case options[:tcp_keepalive]
  when Hash
    %i[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