Module: RailsAiContext::PortablePath

Defined in:
lib/rails_ai_context/portable_path.rb

Overview

Rewrites a path so it means the same thing on another machine. What is generated here ends up in .ai-context.json, which the app commits: an absolute path is wrong on every other checkout, wrong again after a Ruby or gem upgrade, and it carries the generating developer's home directory into the repository. App paths go app-relative; gem paths keep the gem and version and drop the install prefix.

Distinct from PathResolver, which answers where a kind of app code lives.

Class Method Summary collapse

Class Method Details

.gem_checkoutsObject

A gem the Gemfile takes from path: or git: is never unpacked under a gem root, so its own checkout is the only prefix that names it. Longest first, because one checkout can sit inside another.



44
45
46
47
48
49
50
51
52
53
# File 'lib/rails_ai_context/portable_path.rb', line 44

def gem_checkouts
  @gem_checkouts ||= Gem.loaded_specs.each_value.filter_map { |spec|
    dir = spec.full_gem_path.to_s
    next if dir.empty? || gem_roots.any? { |gem_root| dir.start_with?(gem_root) }
    [ dir + File::SEPARATOR, spec.full_name ]
  }.sort_by { |dir, _name| -dir.length }
rescue => e
  $stderr.puts "[rails-ai-context] PortablePath.gem_checkouts failed: #{e.message}" if ENV["DEBUG"]
  []
end

.gem_rootsObject

Every prefix a gem can be unpacked under, trailing separator included so a prefix cannot match a sibling directory that merely starts the same.



36
37
38
39
# File 'lib/rails_ai_context/portable_path.rb', line 36

def gem_roots
  @gem_roots ||= (Gem.path + [ Gem.default_dir ]).compact.uniq
    .map { |dir| File.join(dir, "gems") + File::SEPARATOR }
end

.relativize(path, root) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/rails_ai_context/portable_path.rb', line 15

def relativize(path, root)
  path = path.to_s
  root = root.to_s
  return path.delete_prefix("#{root}/") if !root.empty? && path.start_with?("#{root}/")

  gem_roots.each do |gem_root|
    return path.delete_prefix(gem_root) if path.start_with?(gem_root)
  end

  gem_checkouts.each do |dir, name|
    return File.join(name, path.delete_prefix(dir)) if path.start_with?(dir)
  end
  path
end

.relativize_all(paths, root) ⇒ Object



30
31
32
# File 'lib/rails_ai_context/portable_path.rb', line 30

def relativize_all(paths, root)
  Array(paths).map { |path| relativize(path, root) }.uniq
end