Class: RubynCode::Tools::FileCache

Inherits:
Object
  • Object
show all
Defined in:
lib/rubyn_code/tools/file_cache.rb

Overview

Session-scoped file cache that serves previously-read file contents when the file has not been modified since the last read. Invalidates automatically when Rubyn writes or edits a file, or when mtime changes.

Defined Under Namespace

Classes: Entry

Constant Summary collapse

CHARS_PER_TOKEN =
4

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize ⇒ FileCache



15
16
17
# File 'lib/rubyn_code/tools/file_cache.rb', line 15

def initialize
  @cache = {}
end

Instance Attribute Details

#cache ⇒ Object (readonly)

Returns the value of attribute cache.



13
14
15
# File 'lib/rubyn_code/tools/file_cache.rb', line 13

def cache
  @cache
end

Instance Method Details

#cached?(path) ⇒ Boolean

Returns true if the given path is currently cached and fresh.



53
54
55
56
57
58
59
60
# File 'lib/rubyn_code/tools/file_cache.rb', line 53

def cached?(path)
  return false unless @cache.key?(path)

  @cache[path].mtime == File.mtime(path)
rescue Errno::ENOENT
  @cache.delete(path)
  false
end

#clear! ⇒ Object

Clears the entire cache.



63
64
65
# File 'lib/rubyn_code/tools/file_cache.rb', line 63

def clear!
  @cache.clear
end

#invalidate(path) ⇒ Object

Removes a path from the cache. Called when Rubyn writes/edits the file.



43
44
45
# File 'lib/rubyn_code/tools/file_cache.rb', line 43

def invalidate(path)
  @cache.delete(path)
end

#on_write(path) ⇒ Object

Alias for use as a write hook.



48
49
50
# File 'lib/rubyn_code/tools/file_cache.rb', line 48

def on_write(path)
  invalidate(path)
end

#read(path) ⇒ Hash

Returns cached content if the file hasn't changed, otherwise reads from disk and caches the result.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/rubyn_code/tools/file_cache.rb', line 24

def read(path)
  current_mtime = File.mtime(path)
  cached = @cache[path]

  if cached && cached.mtime == current_mtime
    bump_hits(path)
    { content: cached.content, source: :cache, tokens_saved: cached.token_count }
  else
    content = File.read(path)
    token_count = estimate_tokens(content)
    @cache[path] = Entry.new(
      content: content, mtime: current_mtime,
      token_count: token_count, read_count: 1, cache_hits: 0
    )
    { content: content, source: :disk, tokens_saved: 0 }
  end
end

#stats ⇒ Object

Returns aggregate statistics about cache performance.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rubyn_code/tools/file_cache.rb', line 68

def stats
  total_reads = @cache.values.sum(&:read_count)
  total_hits = @cache.values.sum(&:cache_hits)
  tokens_saved = @cache.values.sum { |e| e.cache_hits * e.token_count }
  hit_rate = total_reads.positive? ? total_hits.to_f / (total_reads + total_hits) : 0.0

  {
    entries: @cache.size,
    total_reads: total_reads,
    cache_hits: total_hits,
    hit_rate: hit_rate.round(3),
    tokens_saved: tokens_saved
  }
end