Class: Mbeditor::UnusedMethodsService
- Inherits:
-
Object
- Object
- Mbeditor::UnusedMethodsService
- Defined in:
- app/services/mbeditor/unused_methods_service.rb
Overview
Finds method definitions in a file that have no call-sites anywhere in the workspace. Uses a single ripgrep (or grep) subprocess with an alternation pattern so cost is O(1) subprocesses regardless of how many methods the file contains.
Results are cached per-file; entries are invalidated when the file’s mtime changes OR when the entry is older than CACHE_TTL_SECONDS (handles edits to other files that may add or remove call-sites).
Usage:
UnusedMethodsService.call(workspace_root, abs_path,
excluded_dirnames: [], excluded_paths: [])
→ [{ name: "my_method", line: 42 }, ...]
Constant Summary collapse
- CACHE_TTL_SECONDS =
30- RG_TIMEOUT =
10- GREP_TIMEOUT =
30
Class Method Summary collapse
- .call(workspace_root, file_path, excluded_dirnames: [], excluded_paths: []) ⇒ Object
-
.clear_cache! ⇒ Object
Exposed for tests.
Class Method Details
.call(workspace_root, file_path, excluded_dirnames: [], excluded_paths: []) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'app/services/mbeditor/unused_methods_service.rb', line 29 def call(workspace_root, file_path, excluded_dirnames: [], excluded_paths: []) file_path = file_path.to_s begin mtime = File.mtime(file_path).to_f rescue StandardError return [] end # Return cached result if file mtime matches and the entry is fresh. cached = @cache_mutex.synchronize { @cache[file_path] } if cached && cached[:mtime] == mtime && (Process.clock_gettime(Process::CLOCK_MONOTONIC) - cached[:ts]) < CACHE_TTL_SECONDS return cached[:result] end # Ensure the file is indexed (populates module_names / include_calls too). defs = RubyDefinitionService.defs_in_file(file_path) if defs.empty? # File not yet in cache; trigger a parse of just this one file by # calling the definition service with a dummy symbol. RubyDefinitionService.call(workspace_root, "__mbeditor_warmup__", excluded_dirnames: excluded_dirnames, excluded_paths: excluded_paths) defs = RubyDefinitionService.defs_in_file(file_path) end return [] if defs.empty? method_names = defs.keys counts = count_occurrences(method_names, workspace_root.to_s, excluded_dirnames: excluded_dirnames, excluded_paths: excluded_paths) # A method with ≤1 total occurrence has only its own `def` line; no call-sites. unused = method_names.select { |n| counts.fetch(n, 0) <= 1 } result = unused.filter_map do |name| entries = defs[name] next unless entries&.any? { name: name, line: entries.first[:line] } end ts = Process.clock_gettime(Process::CLOCK_MONOTONIC) @cache_mutex.synchronize do @cache[file_path] = { mtime: mtime, ts: ts, result: result } end result rescue StandardError [] end |
.clear_cache! ⇒ Object
Exposed for tests.
81 82 83 |
# File 'app/services/mbeditor/unused_methods_service.rb', line 81 def clear_cache! @cache_mutex.synchronize { @cache.clear } end |