class HTTP::CookieJar::HashStore

to be expired individually.
they differ in the ‘for_domain` flag value, which means they need
two cookies with the same name, domain and path coexist as long as
affects in storing cookies. On the other hand, in MozillaStore
RFC 6265 5.3 where there is no mention of how the host-only-flag
value. This store is built after the storage model described in
will overwrite each other regardless of the `for_domain` flag
In this store, cookies that share the same name, domain and path
A store class that uses a hash-based cookie store.

def add(cookie)

def add(cookie)
  path_cookies = ((@jar[cookie.domain] ||= {})[cookie.path] ||= {})
  path_cookies[cookie.name] = cookie
  cleanup if (@gc_index += 1) >= @gc_threshold
  self
end

def cleanup(session = false)

def cleanup(session = false)
  now = Time.now
  all_cookies = []
  synchronize {
    break if @gc_index == 0
    @jar.each { |domain, paths|
      domain_cookies = []
      paths.each { |path, hash|
        hash.delete_if { |name, cookie|
          if cookie.expired?(now) || (session && cookie.session?)
            true
          else
            domain_cookies << cookie
            false
          end
        }
      }
      if (debt = domain_cookies.size - HTTP::Cookie::MAX_COOKIES_PER_DOMAIN) > 0
        domain_cookies.sort_by!(&:created_at)
        domain_cookies.slice!(0, debt).each { |cookie|
          delete(cookie)
        }
      end
      all_cookies.concat(domain_cookies)
    }
    if (debt = all_cookies.size - HTTP::Cookie::MAX_COOKIES_TOTAL) > 0
      all_cookies.sort_by!(&:created_at)
      all_cookies.slice!(0, debt).each { |cookie|
        delete(cookie)
      }
    end
    @jar.delete_if { |domain, paths|
      paths.delete_if { |path, hash|
        hash.empty?
      }
      paths.empty?
    }
    @gc_index = 0
  }
  self
end

def clear

def clear
  @jar.clear
  self
end

def default_options

def default_options
  {
    :gc_threshold => HTTP::Cookie::MAX_COOKIES_TOTAL / 20
  }
end

def delete(cookie)

def delete(cookie)
  path_cookies = ((@jar[cookie.domain] ||= {})[cookie.path] ||= {})
  path_cookies.delete(cookie.name)
  self
end

def each(uri = nil) # :yield: cookie

:yield: cookie
def each(uri = nil) # :yield: cookie
  now = Time.now
  if uri
    tpath = uri.path
    @jar.each { |domain, paths|
      paths.each { |path, hash|
        next unless HTTP::Cookie.path_match?(path, tpath)
        hash.delete_if { |name, cookie|
          if cookie.expired?(now)
            true
          else
            if cookie.valid_for_uri?(uri)
              cookie.accessed_at = now
              yield cookie
            end
            false
          end
        }
      }
    }
  else
    synchronize {
      @jar.each { |domain, paths|
        paths.each { |path, hash|
          hash.delete_if { |name, cookie|
            if cookie.expired?(now)
              true
            else
              yield cookie
              false
            end
          }
        }
      }
    }
  end
  self
end

def initialize(options = nil)

been stored (default: `HTTP::Cookie::MAX_COOKIES_TOTAL / 20`)
: GC threshold; A GC happens when this many times cookies have
:gc_threshold

Available option keywords are as below:

Generates a hash based cookie store.

new(**options)
:call-seq:
def initialize(options = nil)
  super
  @jar = {
  # hostname => {
  #   path => {
  #     name => cookie,
  #     ...
  #   },
  #   ...
  # },
  # ...
  }
  @gc_index = 0
end

def initialize_copy(other)

The copy constructor. This store class supports cloning.
def initialize_copy(other)
  @jar = Marshal.load(Marshal.dump(other.instance_variable_get(:@jar)))
end