Module: RailsAiContext::AstCache

Defined in:
lib/rails_ai_context/ast_cache.rb

Overview

Thread-safe AST parse cache backed by Concurrent::Map. Keyed by path + content hash + mtime — automatically invalidates when file content changes. Used by all Prism-based introspectors.

Bounded: evicts oldest entries when MAX_SIZE is exceeded.

Constant Summary collapse

STORE =
Concurrent::Map.new
MAX_SIZE =
500
EVICTION_MUTEX =
Mutex.new
MAX_PARSE_SIZE =

Max file size for parsing (default: matches config.max_file_size). Public API — callers don’t need to pre-check size.

5_000_000

Class Method Summary collapse

Class Method Details

.clearObject

Clear the entire cache.



59
60
61
# File 'lib/rails_ai_context/ast_cache.rb', line 59

def self.clear
  STORE.clear
end

.invalidate(path) ⇒ Object

Invalidate all cached entries for a given path.



51
52
53
54
55
56
# File 'lib/rails_ai_context/ast_cache.rb', line 51

def self.invalidate(path)
  prefix = "#{path}:"
  STORE.each_key do |k|
    STORE.delete(k) if k.start_with?(prefix)
  end
end

.parse(path) ⇒ Object

Parse a Ruby source file and cache the result. Returns a Prism::ParseResult. Rejects files exceeding MAX_PARSE_SIZE.

Reads content first, then checks size — avoids TOCTOU race where the file could change between File.size and File.read.

Raises:

  • (ArgumentError)


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/rails_ai_context/ast_cache.rb', line 27

def self.parse(path)
  content = File.read(path)
  size = content.bytesize
  raise ArgumentError, "File too large for AST parsing: #{path} (#{size} bytes, max #{MAX_PARSE_SIZE})" if size > MAX_PARSE_SIZE

  mtime = File.mtime(path).to_i
  key   = "#{path}:#{Digest::SHA256.hexdigest(content)}:#{mtime}"

  cached = STORE[key]
  return cached if cached

  # Evict BEFORE inserting to avoid running inside compute_if_absent
  evict_if_full

  STORE.compute_if_absent(key) { Prism.parse(content) }
end

.parse_string(source) ⇒ Object

Parse a Ruby source string (no caching). Returns a Prism::ParseResult.



46
47
48
# File 'lib/rails_ai_context/ast_cache.rb', line 46

def self.parse_string(source)
  Prism.parse(source)
end

.sizeObject

Number of cached entries (for diagnostics).



64
65
66
# File 'lib/rails_ai_context/ast_cache.rb', line 64

def self.size
  STORE.size
end