Module: Mbeditor::RailsRelatedFilesService
- Defined in:
- app/services/mbeditor/rails_related_files_service.rb
Overview
Given a workspace-relative file path, finds related Rails files grouped by type: controller, model, views, helper, tests, and custom directories.
Only groups with at least one existing file are included in the result. All returned paths are workspace-relative strings.
Class Method Summary collapse
-
.find(workspace_root, relative_path, custom_paths: []) ⇒ Object
Returns a hash of groups.
Class Method Details
.find(workspace_root, relative_path, custom_paths: []) ⇒ Object
Returns a hash of groups. Example:
{
controller: [{path: "app/controllers/users_controller.rb", name: "users_controller.rb"}],
model: [{path: "app/models/user.rb", name: "user.rb"}],
views: [{path: "app/views/users/index.html.erb", name: "index.html.erb"}],
helper: [{path: "app/helpers/users_helper.rb", name: "users_helper.rb"}],
tests: [{path: "test/controllers/users_controller_test.rb", name: "users_controller_test.rb"}],
custom: {"app/assets/javascripts/app" => [{path: "...", name: "..."}]}
}
Returns {} when the path does not match any known Rails convention.
24 25 26 27 28 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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'app/services/mbeditor/rails_related_files_service.rb', line 24 def find(workspace_root, relative_path, custom_paths: []) plural, singular = extract_resource_names(relative_path, custom_paths: custom_paths) return {} unless plural && singular result = {} # ── controller ──────────────────────────────────────────────────────────── controller_path = "app/controllers/#{plural}_controller.rb" if file_exists?(workspace_root, controller_path) result[:controller] = [entry(controller_path, kind: 'Controller')] end # ── model ───────────────────────────────────────────────────────────────── model_path = "app/models/#{singular}.rb" if file_exists?(workspace_root, model_path) result[:model] = [entry(model_path, kind: 'Model')] end # ── views ───────────────────────────────────────────────────────────────── views_dir = File.join(workspace_root, "app", "views", plural) if File.directory?(views_dir) children = dir_children(workspace_root, "app/views/#{plural}", kind: 'View') result[:views] = children unless children.empty? end # ── helper ──────────────────────────────────────────────────────────────── helper_path = "app/helpers/#{plural}_helper.rb" if file_exists?(workspace_root, helper_path) result[:helper] = [entry(helper_path, kind: 'Helper')] end # ── tests ───────────────────────────────────────────────────────────────── test_candidates = [ "test/controllers/#{plural}_controller_test.rb", "test/models/#{singular}_test.rb", "spec/controllers/#{plural}_controller_spec.rb", "spec/models/#{singular}_spec.rb" ] tests = test_candidates.select { |p| file_exists?(workspace_root, p) }.map { |p| entry(p, kind: 'Test') } result[:tests] = tests unless tests.empty? # ── concerns ────────────────────────────────────────────────────────────── plain_plural = plural.split('/').last plain_singular = singular.split('/').last concern_dirs = ['app/models/concerns', 'app/controllers/concerns'] concern_files = [] concern_dirs.each do |dir| children = dir_children(workspace_root, dir, kind: 'Concern') matching = children.select { |c| base = File.basename(c[:path], '.*') base == plain_plural || base == plain_singular || base.start_with?("#{plain_plural}_") || base.start_with?("#{plain_singular}_") || base.end_with?("_#{plain_plural}") || base.end_with?("_#{plain_singular}") } concern_files.concat(matching) end result[:concerns] = concern_files.uniq { |c| c[:path] } unless concern_files.empty? # ── custom paths ────────────────────────────────────────────────────────── custom_result = {} Array(custom_paths).each do |base| base = base.to_s.strip next if base.empty? # Derive a human-readable kind from the last segment of the base path custom_kind = base.split('/').last.to_s.tr('_', ' ').split.map(&:capitalize).join(' ') [plural, singular].uniq.each do |name| rel_dir = "#{base}/#{name}" abs_dir = File.join(workspace_root, rel_dir) next unless File.directory?(abs_dir) begin real_ws = File.realpath(workspace_root) real_dir = File.realpath(abs_dir) next unless real_dir.start_with?("#{real_ws}/") || real_dir == real_ws rescue Errno::ENOENT, Errno::EACCES next end children = dir_children(workspace_root, rel_dir, kind: custom_kind) next if children.empty? custom_result[base] ||= [] custom_result[base].concat(children) end end result[:custom] = custom_result unless custom_result.empty? result end |