Class: Mbeditor::RubyDefinitionService
- Inherits:
-
Object
- Object
- Mbeditor::RubyDefinitionService
- Defined in:
- app/services/mbeditor/ruby_definition_service.rb
Overview
Searches .rb files in a workspace for definitions of a named Ruby method using Ripper’s AST parser (no subprocesses).
Returns an array of hashes, each describing one definition site:
{
file: String, # workspace-relative path
line: Integer, # 1-based line number of the `def` keyword
signature: String, # trimmed source text of the def line
comments: String # leading # comment lines immediately above the def (may be empty)
}
Usage:
results = RubyDefinitionService.call(workspace_root, "my_method",
excluded_dirnames: %w[tmp .git])
Constant Summary collapse
- MAX_RESULTS =
20- MAX_COMMENT_LOOKAHEAD =
15
Class Attribute Summary collapse
-
.cache_path ⇒ Object
Returns the value of attribute cache_path.
-
.file_cache ⇒ Object
readonly
Returns the value of attribute file_cache.
-
.mutex ⇒ Object
readonly
Returns the value of attribute mutex.
Class Method Summary collapse
- .call(workspace_root, symbol, excluded_dirnames: [], excluded_paths: []) ⇒ Object
-
.clear_cache! ⇒ Object
Exposed for tests.
-
.load_disk_cache_once ⇒ Object
Load the JSON cache from disk exactly once per process (double-checked under the mutex so concurrent first-calls don’t double-load).
-
.persist_cache ⇒ Object
Atomically write the in-memory cache to disk (tmp-file + rename).
Instance Method Summary collapse
- #call ⇒ Object
-
#initialize(workspace_root, symbol, excluded_dirnames: [], excluded_paths: []) ⇒ RubyDefinitionService
constructor
A new instance of RubyDefinitionService.
Constructor Details
#initialize(workspace_root, symbol, excluded_dirnames: [], excluded_paths: []) ⇒ RubyDefinitionService
Returns a new instance of RubyDefinitionService.
94 95 96 97 98 99 |
# File 'app/services/mbeditor/ruby_definition_service.rb', line 94 def initialize(workspace_root, symbol, excluded_dirnames: [], excluded_paths: []) @workspace_root = workspace_root.to_s.chomp("/") @symbol = symbol @excluded_dirnames = Array(excluded_dirnames) @excluded_paths = Array(excluded_paths) end |
Class Attribute Details
.cache_path ⇒ Object
Returns the value of attribute cache_path.
38 39 40 |
# File 'app/services/mbeditor/ruby_definition_service.rb', line 38 def cache_path @cache_path end |
.file_cache ⇒ Object (readonly)
Returns the value of attribute file_cache.
37 38 39 |
# File 'app/services/mbeditor/ruby_definition_service.rb', line 37 def file_cache @file_cache end |
.mutex ⇒ Object (readonly)
Returns the value of attribute mutex.
37 38 39 |
# File 'app/services/mbeditor/ruby_definition_service.rb', line 37 def mutex @mutex end |
Class Method Details
.call(workspace_root, symbol, excluded_dirnames: [], excluded_paths: []) ⇒ Object
40 41 42 43 44 |
# File 'app/services/mbeditor/ruby_definition_service.rb', line 40 def call(workspace_root, symbol, excluded_dirnames: [], excluded_paths: []) new(workspace_root, symbol, excluded_dirnames: excluded_dirnames, excluded_paths: excluded_paths).call end |
.clear_cache! ⇒ Object
Exposed for tests.
85 86 87 88 89 90 91 |
# File 'app/services/mbeditor/ruby_definition_service.rb', line 85 def clear_cache! @mutex.synchronize { @file_cache.clear; @cache_loaded = false } path = @cache_path.to_s File.delete(path) if !path.empty? && File.exist?(path) rescue StandardError nil end |
.load_disk_cache_once ⇒ Object
Load the JSON cache from disk exactly once per process (double-checked under the mutex so concurrent first-calls don’t double-load).
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'app/services/mbeditor/ruby_definition_service.rb', line 48 def load_disk_cache_once return if @cache_loaded @mutex.synchronize do return if @cache_loaded @cache_loaded = true path = @cache_path.to_s return if path.empty? || !File.exist?(path) raw = JSON.parse(File.read(path)) raw.each do |abs_path, entry| @file_cache[abs_path] = { mtime: entry["mtime"].to_f, lines: entry["lines"], all_defs: entry["all_defs"] } end rescue StandardError nil # corrupted or incompatible cache file — start fresh end end |
.persist_cache ⇒ Object
Atomically write the in-memory cache to disk (tmp-file + rename).
72 73 74 75 76 77 78 79 80 81 82 |
# File 'app/services/mbeditor/ruby_definition_service.rb', line 72 def persist_cache path = @cache_path.to_s return if path.empty? snapshot = @mutex.synchronize { @file_cache.dup } tmp_path = "#{path}.tmp" File.write(tmp_path, JSON.generate(snapshot)) File.rename(tmp_path, path) rescue StandardError nil end |
Instance Method Details
#call ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'app/services/mbeditor/ruby_definition_service.rb', line 101 def call self.class.load_disk_cache_once results = [] @new_entries = false Find.find(@workspace_root) do |path| # Prune excluded directories if File.directory?(path) dirname = File.basename(path) rel_dir = relative_path(path) if path != @workspace_root && excluded_dir?(dirname, rel_dir) Find.prune end next end next unless path.end_with?(".rb") rel = relative_path(path) next if excluded_rel_path?(rel, File.basename(path)) begin cached = cache_entry_for(path) next unless cached hit_lines = cached[:all_defs][@symbol] next unless hit_lines && hit_lines.any? hit_lines.each do |def_line| results << { file: rel, line: def_line, signature: (cached[:lines][def_line - 1] || "").strip, comments: extract_comments(cached[:lines], def_line) } return results if results.length >= MAX_RESULTS end rescue StandardError # Malformed file or unreadable; skip silently end end self.class.persist_cache if @new_entries results end |