Skip to content

Commit 3700f1f

Browse files
committed
fix: locate the maps registry yaml under rubygems 4
rubygems 4 removed StubSpecification#files, which Gem.find_latest_files relies on - on rubygems-4 installs every Interscript.transliterate call raised from map_gems before any map could load. The fast path is kept for rubygems 3 and wrapped: when it raises (or comes back empty), the fallback globs the interscript-maps gems directly (one or two gems, cheap). Verified on a rubygems-4.0.23 install where the gem index is in stub-only state: map resolution and transliteration work without any workaround; rubygems-3 behavior unchanged (fast path intact).
1 parent 34bd882 commit 3700f1f

2 files changed

Lines changed: 58 additions & 1 deletion

File tree

‎lib/interscript.rb‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,28 @@ def detect(source, destination, **kwargs)
8282
detector.call(source, destination)
8383
end
8484

85+
# Locate the interscript-maps registry yaml(s) across installed gems.
86+
#
87+
# rubygems 4 removed StubSpecification#files, which
88+
# Gem.find_latest_files relies on, so the fast path can raise there;
89+
# the fallback globs the interscript-maps gems directly (there are
90+
# only ever one or two of them, so this stays cheap).
91+
def locate_map_gems_yaml
92+
found = begin
93+
Gem.find_latest_files("interscript-maps.yaml")
94+
rescue StandardError, NameError
95+
nil
96+
end
97+
return found if found.is_a?(Array) && found.any?
98+
99+
Gem::Specification.latest_specs
100+
.select { |spec| spec.name == "interscript-maps" }
101+
.flat_map { |spec| Dir.glob(File.join(spec.full_gem_path, "**", "interscript-maps.yaml")) }
102+
.uniq
103+
end
104+
85105
def map_gems
86-
@map_gems ||= Gem.find_latest_files("interscript-maps.yaml").map do |i|
106+
@map_gems ||= locate_map_gems_yaml.map do |i|
87107
[i, YAML.load_file(i)]
88108
end.to_h
89109
end

‎spec/interscript/map_gems_spec.rb‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# frozen_string_literal: true
2+
3+
require "interscript"
4+
require "tmpdir"
5+
require "fileutils"
6+
require "yaml"
7+
8+
RSpec.describe Interscript do
9+
describe ".locate_map_gems_yaml" do
10+
it "finds the registry yaml via Gem.find_latest_files when available" do
11+
Dir.mktmpdir do |dir|
12+
gem_dir = File.join(dir, "gems", "interscript-maps-9.9.9")
13+
FileUtils.mkdir_p(gem_dir)
14+
yaml_path = File.join(gem_dir, "interscript-maps.yaml")
15+
File.write(yaml_path, { "paths" => ["maps"] }.to_yaml)
16+
spec = Struct.new(:name, :full_gem_path).new("interscript-maps", gem_dir)
17+
allow(Gem::Specification).to receive(:latest_specs).and_return([spec])
18+
allow(Gem).to receive(:find_latest_files).with("interscript-maps.yaml").and_return([yaml_path])
19+
expect(Interscript.locate_map_gems_yaml).to include(yaml_path)
20+
end
21+
end
22+
23+
it "falls back to a direct gem-dir glob when Gem.find_latest_files is unavailable (rubygems 4)" do
24+
Dir.mktmpdir do |dir|
25+
gem_dir = File.join(dir, "gems", "interscript-maps-9.9.9")
26+
FileUtils.mkdir_p(File.join(gem_dir, "maps"))
27+
yaml_path = File.join(gem_dir, "interscript-maps.yaml")
28+
File.write(yaml_path, { "paths" => ["maps"] }.to_yaml)
29+
spec = Struct.new(:name, :full_gem_path).new("interscript-maps", gem_dir)
30+
allow(Gem::Specification).to receive(:latest_specs).and_return([spec])
31+
allow(Gem).to receive(:find_latest_files).with("interscript-maps.yaml")
32+
.and_raise(RuntimeError, "undefined method 'files' for Gem::StubSpecification")
33+
expect(Interscript.locate_map_gems_yaml).to include(yaml_path)
34+
end
35+
end
36+
end
37+
end

0 commit comments

Comments
 (0)