RubyGems 3.2.7 keeps staging paths out of plugin wrappers
RubyGems 3.2.7 changes generated plugin wrappers to require files relative to their installed location. The repair prevents a temporary build root from becoming a permanent runtime dependency.
A package can install its files in the correct place and still fail after deployment if generated code remembers the temporary directory used to build it. RubyGems 3.2.7, released on January 27, fixes that problem for plugin wrappers generated with --build-root. The release note calls the change relative requires, but the practical issue is the distinction between a staging location and an installed location.
David Rodríguez's fix explains that wrappers unexpectedly included the build-root parameter. The correction writes a relative load instruction based on the relationship between the wrapper directory and the plugin file. It preserves the path relationship the installation needs while discarding a prefix that belongs only to the build environment.
I find Ruby more consistent and approachable than Perl for larger object-oriented code. This kind of packaging defect is a reminder that readable application code still relies on generated code beneath it. A short wrapper deserves attention because it determines whether the application can reach the code that was installed.
A wrapper records how to find a plugin
The implementation in the release iterates over the plugins reported by a gem specification. For each one, it creates a wrapper under the selected plugin directory. The wrapper name includes the gem name and plugin extension, and its contents load the actual plugin file.
Previously, that generated line used require with the plugin path. When the path included a temporary build root, the wrapper retained that temporary location. Moving the staged installation into its final destination did not rewrite the string inside the generated Ruby file. The files could be present while the recorded absolute location was wrong.
The new implementation uses Pathname to compute the plugin's relative path from the wrapper directory. It emits that path with require_relative. The relationship is anchored to the generated wrapper's location, so relocating the containing installation preserves it when the internal directory layout stays the same.
This is a precise form of relocatability. It does not imply that an arbitrary installation can be rearranged internally without consequences. The relative route still depends on the wrapper and plugin keeping the relationship used during generation. The repair removes an irrelevant outer prefix while retaining the directory structure that actually connects the files.
Installation success alone misses the defect
The installer regression test constructs a gem containing a RubyGems plugin and installs it with a build root. It checks that the wrapper exists beneath that root and has not been written into the system plugin directory. Those assertions establish the destination of the generated file.
The patch adds another assertion that the generated wrapper does not contain the build-root string. This is necessary because file placement and file contents are separate properties. A wrapper in the correct staging directory can still contain a runtime reference to that staging directory. Checking only for its existence would accept the broken artifact.
That makes the regression interesting despite the small code change. The failure is a leak of build-time context into runtime behavior. Inspecting generated output directly provides evidence about that leak. A successful installer return value cannot establish that the generated loader refers to the intended final arrangement.
The test also keeps the earlier assertions about where installation may write. Fixing the embedded path must not redirect generation into the real system directory. Both properties matter to staged packaging. The build environment needs isolation from the live installation, and the resulting package needs paths that remain valid when staging ends.
Relative loading describes the dependency more accurately
An absolute path states where a file happened to exist during generation. A relative path states where it exists in relation to the loader. For this wrapper, the second statement captures the useful invariant. The implementation can compute that relationship from known paths without asking the package author to supply another setting.
The patch also returns early when the specification has no plugins, before loading Pathname. That keeps the extra work associated with installations that actually generate wrappers. The important behavior remains the content written for each plugin, rather than an alteration to the plugin's own implementation.
I prefer fixes that correct the generated artifact at its source. Asking every downstream packager to remove a staging prefix would duplicate RubyGems' knowledge of the wrapper layout. Computing the relative relationship while both paths are available puts the correction in the component responsible for writing the loader.
The release announcement provides the normal system-update command and checksums for its distribution artifacts. Its single listed fix targets plugin wrapper generation, so the expected benefit is specific. RubyGems 3.2.7 prevents a temporary build-root path from becoming a permanent requirement of those generated plugin loaders.