August 17, 2021·4 min read·engineeringrubyrubygemsbundlertooling

RubyGems 3.2.26 narrows automatic bundle activation to executable stubs

RubyGems 3.2.26 improves its experimental Gemfile-aware executable mode and restores user-installed plugin loading. The changes make activation depend on the appropriate launch point and configured gem paths.

An executable name is not enough to identify the version a Ruby project intends to run. The project's lockfile supplies additional context, but users normally have to invoke commands through a bundle-aware entry point. RubyGems 3.2.26, released on August 17, improves an experimental mode that applies that context through executable stubs without requiring bundle exec at each invocation.

The announcement describes enabling RUBYGEMS_GEMDEPS with the value - for automatic discovery or with a specific Gemfile name. It explicitly calls the mode experimental and asks for feedback. That qualification matters because the change concerns how executable startup selects and activates dependencies, a behavior that can affect commands throughout a developer's environment.

I appreciate Ruby's concise command-line tooling when the version being run remains understandable. Removing repeated launch syntax is useful, but the startup mechanism needs a clear boundary. An automatic dependency mode should not turn every incidental load of RubyGems into an unrelated project activation.

Executable stubs provide the activation point

The change linked by the release moves the Gem.use_gemdeps call into generated executable stubs. The earlier behavior called it when RubyGems itself was loaded. That broader location could activate a bundle during startup paths that had not intentionally launched a project executable.

A generated stub is a more specific entry point. It is already responsible for selecting and loading executable code supplied by a gem. Asking it to apply dependency context connects automatic activation to the action that needs the selected executable. It also avoids making a general library require carry all the same startup effects.

This changes where the dependency lookup occurs without making the lookup unnecessary. The command still needs to discover the dependency file and activate the appropriate environment. Convenience comes from the launch spelling. The lockfile and installed dependencies continue to determine which executable version can actually run.

For a single command in an environment with a suitable Gemfile and installed dependencies, the documented mode can be enabled through an environment assignment. This example uses rake as an illustrative installed executable.

env RUBYGEMS_GEMDEPS=- rake --version

The result depends on the surrounding project and installed gems. The command is not a substitute for installing the bundle. It changes the executable startup's access to dependency context, which is why the distinction between loading RubyGems and launching a stub matters.

Failure handling stays near bundle setup

The same patch adjusts error handling around Bundler setup. It loads Bundler before handling setup errors through Bundler's error class, keeping failures to load Bundler itself distinct. The missing-dependency guidance recommends bundle install.

That separation gives failures a more appropriate explanation. A bundle setup error concerns the selected dependency environment. Failing to load the tool that performs setup is a different problem. Combining both under one generic missing-gem message can hide the stage that actually failed.

The regression tests launch generated executables and inspect activated specifications. They include invocation from a subdirectory where automatic discovery finds a dependency file above it. This tests the launch behavior itself rather than merely asserting that a helper method can read a Gemfile when called directly.

Directory context is therefore part of the experiment's semantics. An executable started below a project can obtain dependency requirements from that project through discovery. Giving the environment variable a specific filename instead supplies a more explicit input. The announcement documents both choices because automatically locating a conventional dependency file and naming a nonstandard one are distinct ways to establish the intended environment.

Plugin discovery must cover configured installations

A separate plugin-loading repair makes RubyGems inspect plugin directories across Gem.path. Previously, the method searched one plugin directory. That missed plugins installed in the user's gem location even when that location participated in the configured paths.

The patch iterates over each gem path and searches its plugin directory for matching plugin files. Its regression test installs a plugin as a user gem, includes both the system and user locations in the configured gem path, activates the gem and checks that plugin loading runs its code.

This is another case where the installation and activation models need to agree. Successfully installing a user gem does not establish that plugin discovery will search its location. The repair aligns discovery with the configured set of gem paths instead of assuming a single installation root.

I regard these as useful maintenance changes because they attach behavior to the relevant context. Bundle activation belongs at an executable launch that needs it. Plugin lookup belongs across the configured gem installations. The release changelog records both changes in 3.2.26, alongside improved handling of operating-system defaults loading. The experimental mode now has a narrower activation point, and user-installed plugins have a discovery path that matches their installation.