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
-
.clear ⇒ Object
Clear the entire cache.
-
.invalidate(path) ⇒ Object
Invalidate all cached entries for a given path.
-
.parse(path) ⇒ Object
Parse a Ruby source file and cache the result.
-
.parse_string(source) ⇒ Object
Parse a Ruby source string (no caching).
-
.size ⇒ Object
Number of cached entries (for diagnostics).
Class Method Details
.clear ⇒ Object
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.
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 |
.size ⇒ Object
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 |