Class: GemContribute::Cache

Inherits:
Object
  • Object
show all
Defined in:
lib/gem_contribute/cache.rb

Overview

Disk cache at ~/.cache/gem-contribute/<namespace>/<key>.json.

Honors XDG_CACHE_HOME so tests (and users with non-default XDG layouts) don’t pollute each other.

Per docs/design.md the namespaces and TTLs are:

gems    — RubyGems metadata           — 7 days
issues  — GitHub issue lists          — 5 minutes
repos   — community profile responses — 1 day
files   — file contents (CONTRIBUTING) — 1 day

The cache stores ‘payload:` so the TTL check is local rather than dependent on filesystem mtime (which differs across platforms).

Constant Summary collapse

DEFAULT_NAMESPACE_TTL =
{
  "gems" => 7 * 24 * 60 * 60,
  "issues" => 5 * 60,
  "repos" => 24 * 60 * 60,
  "files" => 24 * 60 * 60
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root: Cache.default_root, ttl: DEFAULT_NAMESPACE_TTL, clock: -> { Time.now.to_i }) ⇒ Cache

Returns a new instance of Cache.



31
32
33
34
35
# File 'lib/gem_contribute/cache.rb', line 31

def initialize(root: Cache.default_root, ttl: DEFAULT_NAMESPACE_TTL, clock: -> { Time.now.to_i })
  @root = root
  @ttl = ttl
  @clock = clock
end

Instance Attribute Details

#rootObject (readonly)

Returns the value of attribute root.



29
30
31
# File 'lib/gem_contribute/cache.rb', line 29

def root
  @root
end

Class Method Details

.default_rootObject



67
68
69
70
# File 'lib/gem_contribute/cache.rb', line 67

def self.default_root
  base = ENV["XDG_CACHE_HOME"] || File.expand_path("~/.cache")
  File.join(base, "gem-contribute")
end

Instance Method Details

#clear!Object

Clear every namespace under the cache root. Powers ‘–refresh`.



63
64
65
# File 'lib/gem_contribute/cache.rb', line 63

def clear!
  FileUtils.rm_rf(@root) if File.directory?(@root)
end

#fetch(namespace, key) ⇒ Object

Look up a cached value. Returns the payload Hash or nil. Expired entries are treated as misses but left on disk; the next write overwrites them. (Aggressive deletion costs IO for no real gain.)



40
41
42
43
44
45
46
47
48
49
# File 'lib/gem_contribute/cache.rb', line 40

def fetch(namespace, key)
  path = path_for(namespace, key)
  return nil unless File.file?(path)

  data = read_json(path)
  return nil if data.nil?
  return nil if expired?(namespace, data)

  data["payload"]
end

#write(namespace, key, payload) ⇒ Object

Cache a payload. Returns the payload as given.



52
53
54
55
56
57
58
59
60
# File 'lib/gem_contribute/cache.rb', line 52

def write(namespace, key, payload)
  path = path_for(namespace, key)
  FileUtils.mkdir_p(File.dirname(path))

  tmp = "#{path}.tmp"
  File.write(tmp, JSON.generate("stored_at" => @clock.call, "payload" => payload), encoding: "UTF-8")
  File.rename(tmp, path)
  payload
end