The context for this issue is a discussion here between Harriet, Jenny and Kou about the suitability of the naming of the --ruby-abi build flag.
Update 22nd Sept.
We will offer two separate build flags:
--ruby-abi <version> explicitly sets the Ruby ABI for the build.
--content-addressable requests that RubyGems build a content-addressable gem.
The existing --ruby-abi option must also remain available to gem push and gem yank, where it selects a particular ABI-specific artifact.
Desired Outcome
Before:
The --ruby-abi option both selects the Ruby ABI and enables content-addressable behaviour.
After:
gem build --content-addressable
This builds a content-addressable gem using the required_ruby_version and platform declared in the gemspec.
When the Ruby ABI needs to be supplied explicitly, the flags can be combined:
gem build --ruby-abi 3.4 --content-addressable
The --ruby-abi option sets required_ruby_version for the build, while --content-addressable enables and validates the content-addressable build.
Following on from this, in separate PRs, we will update the PackageTask work so that the final argument passed to Gem::Package.build is a boolean indicating whether to build a content-addressable gem, rather than a Ruby ABI value.
Breakdown of Changes
A skinny gem needs required_ruby_version, required_rubygems_version, and a platform. Currently, --ruby-abi sets or validates all of them even though its name refers only to the Ruby ABI. Separating the options makes the requested behaviour explicit.
1. Preserve --ruby-abi
Preserve --ruby-abi as an option that explicitly sets the Ruby ABI for the build.
Passing:
sets required_ruby_version to:
RubyGems should not overwrite required_ruby_version when this option has not been passed.
Passing --ruby-abi alone should not enable content-addressable naming. Without --content-addressable, the build should continue to produce a traditionally named gem.
2. Add --content-addressable
Add a new boolean --content-addressable option to gem build.
When this flag is passed, the build flow should:
- Validate
required_ruby_version and platform using Gem::ContentAddress.eligible?.
- Provide a useful error when the platform or Ruby requirement makes the specification ineligible.
- Raise the minimum
required_rubygems_version when necessary because older RubyGems versions cannot install content-addressable gems.
- Raise an error if the existing
required_rubygems_version excludes every compatible RubyGems version.
- Derive the Ruby ABI from
required_ruby_version.
- Build the gem using its content-addressable filename.
- Not change
required_ruby_version or platform.
- Remain incompatible with an explicitly supplied
--output filename because the generated filename must contain the content address.
The gemspec remains the source of truth unless an explicit option, such as --ruby-abi, has been passed to override a value for that build.
3. Preserve existing required_rubygems_version behaviour
The handling of required_rubygems_version should remain the same as the current --ruby-abi content-addressable build behaviour.
For a content-addressable build:
- Build from a duplicate of the supplied specification.
- Raise the duplicate’s
required_rubygems_version to the required minimum when necessary.
- Preserve the existing warning when the requirement is raised.
- Include the raised requirement in the built gem.
- After a successful build, copy the resulting
required_rubygems_version back onto the original in-memory spec.
- If validation or the build fails, leave the original
spec unchanged.
- If the existing requirement conflicts with the minimum, raise an error and leave the original
spec unchanged.
Traditional builds should continue to leave required_rubygems_version unchanged.
This changes only the in-memory Gem::Specification; it does not rewrite the .gemspec file on disk.
4. Preserve --ruby-abi for push and yank
Preserve the existing use of --ruby-abi in gem push and gem yank.
For these commands, the option selects a particular Ruby ABI variant; it does not enable content-addressable building.
5. Documentation update
Update command-reference.md to document both --ruby-abi and --content-addressable.
This could be added as an extra commit to this PR if it has not already been merged.
Suggested Implementation
build_command.rb
- Add the new boolean
--content-addressable option.
- Keep the existing
--ruby-abi option.
- When
--ruby-abi is passed, set the loaded spec’s required_ruby_version before calling Gem::Package.build.
- Pass the
content_addressable boolean to Gem::Package.build.
- Update the command description and examples.
version_option.rb
- Preserve
add_ruby_abi_option because it is shared with gem push and gem yank.
- Add a separate content-addressable option helper only if it is useful outside
BuildCommand; otherwise, define the option directly in BuildCommand.
Gem::Package.build
- Change the final argument from
ruby_abi to a content_addressable boolean.
- Default the argument to
false.
- Use the boolean to choose between the traditional and content-addressable build paths.
- Preserve the current duplicate-spec behaviour for content-addressable builds.
- After a successful content-addressable build, copy only the resulting
required_rubygems_version back to the original spec. Copying back required_ruby_version is no longer necessary because this method should not change it.
- Update the
--output conflict error so that it refers to content-addressable building rather than a Ruby ABI.
Gem::Package#build_content_addressable_file
- Remove the
ruby_abi argument.
- Remove
validate_ruby_abi.
- Validate the spec using
Gem::ContentAddress.eligible?.
- Do not overwrite
required_ruby_version or platform.
- Derive the ABI from
required_ruby_version for console output.
- Preserve the existing
required_rubygems_version normalization, warning, conflict detection, and copy-back behaviour.
Other callsites
Update internal five-argument Gem::Package.build callsites because the final argument changes from an ABI string to a boolean. These include:
test/rubygems/helper.rb
spec/support/builders.rb
- Content-addressable calls in
test/rubygems/test_gem_package.rb
Ordinary callers using between one and four arguments should remain unchanged.
Gem::PackageTask will be updated to pass the boolean in its separate follow-up PR.
Testing
Update tests in test_gem_commands_build_command.rb, test_gem_package.rb, and the affected helper callsites.
Tests should cover:
--ruby-abi alone sets required_ruby_version but produces a traditionally named gem.
--content-addressable alone uses the gemspec’s existing Ruby ABI and platform.
- Both flags can be used together.
- Neither flag preserves traditional build behaviour.
content_addressable = false produces a traditional gem even when the specification is otherwise eligible.
- Invalid platforms and Ruby requirements are rejected for content-addressable builds.
required_ruby_version and platform are preserved during a content-addressable build.
- A default or weak
required_rubygems_version is raised in the built gem and copied back to the original spec after success.
- The original
required_rubygems_version remains unchanged after a failed build.
- Conflicting
required_rubygems_version requirements are rejected.
--content-addressable and --output cannot be used together.
gem push and gem yank retain their existing --ruby-abi behaviour.
The context for this issue is a discussion here between Harriet, Jenny and Kou about the suitability of the naming of the
--ruby-abibuild flag.Update 22nd Sept.
We will offer two separate build flags:
--ruby-abi <version>explicitly sets the Ruby ABI for the build.--content-addressablerequests that RubyGems build a content-addressable gem.The existing
--ruby-abioption must also remain available togem pushandgem yank, where it selects a particular ABI-specific artifact.Desired Outcome
Before:
The
--ruby-abioption both selects the Ruby ABI and enables content-addressable behaviour.After:
This builds a content-addressable gem using the
required_ruby_versionandplatformdeclared in the gemspec.When the Ruby ABI needs to be supplied explicitly, the flags can be combined:
The
--ruby-abioption setsrequired_ruby_versionfor the build, while--content-addressableenables and validates the content-addressable build.Following on from this, in separate PRs, we will update the
PackageTaskwork so that the final argument passed toGem::Package.buildis a boolean indicating whether to build a content-addressable gem, rather than a Ruby ABI value.Breakdown of Changes
A skinny gem needs
required_ruby_version,required_rubygems_version, and a platform. Currently,--ruby-abisets or validates all of them even though its name refers only to the Ruby ABI. Separating the options makes the requested behaviour explicit.1. Preserve
--ruby-abiPreserve
--ruby-abias an option that explicitly sets the Ruby ABI for the build.Passing:
sets
required_ruby_versionto:"~> 3.4.0"RubyGems should not overwrite
required_ruby_versionwhen this option has not been passed.Passing
--ruby-abialone should not enable content-addressable naming. Without--content-addressable, the build should continue to produce a traditionally named gem.2. Add
--content-addressableAdd a new boolean
--content-addressableoption togem build.When this flag is passed, the build flow should:
required_ruby_versionandplatformusingGem::ContentAddress.eligible?.required_rubygems_versionwhen necessary because older RubyGems versions cannot install content-addressable gems.required_rubygems_versionexcludes every compatible RubyGems version.required_ruby_version.required_ruby_versionorplatform.--outputfilename because the generated filename must contain the content address.The gemspec remains the source of truth unless an explicit option, such as
--ruby-abi, has been passed to override a value for that build.3. Preserve existing
required_rubygems_versionbehaviourThe handling of
required_rubygems_versionshould remain the same as the current--ruby-abicontent-addressable build behaviour.For a content-addressable build:
required_rubygems_versionto the required minimum when necessary.required_rubygems_versionback onto the original in-memoryspec.specunchanged.specunchanged.Traditional builds should continue to leave
required_rubygems_versionunchanged.This changes only the in-memory
Gem::Specification; it does not rewrite the.gemspecfile on disk.4. Preserve
--ruby-abifor push and yankPreserve the existing use of
--ruby-abiingem pushandgem yank.For these commands, the option selects a particular Ruby ABI variant; it does not enable content-addressable building.
5. Documentation update
Update
command-reference.mdto document both--ruby-abiand--content-addressable.This could be added as an extra commit to this PR if it has not already been merged.
Suggested Implementation
build_command.rb--content-addressableoption.--ruby-abioption.--ruby-abiis passed, set the loaded spec’srequired_ruby_versionbefore callingGem::Package.build.content_addressableboolean toGem::Package.build.version_option.rbadd_ruby_abi_optionbecause it is shared withgem pushandgem yank.BuildCommand; otherwise, define the option directly inBuildCommand.Gem::Package.buildruby_abito acontent_addressableboolean.false.required_rubygems_versionback to the original spec. Copying backrequired_ruby_versionis no longer necessary because this method should not change it.--outputconflict error so that it refers to content-addressable building rather than a Ruby ABI.Gem::Package#build_content_addressable_fileruby_abiargument.validate_ruby_abi.Gem::ContentAddress.eligible?.required_ruby_versionorplatform.required_ruby_versionfor console output.required_rubygems_versionnormalization, warning, conflict detection, and copy-back behaviour.Other callsites
Update internal five-argument
Gem::Package.buildcallsites because the final argument changes from an ABI string to a boolean. These include:test/rubygems/helper.rbspec/support/builders.rbtest/rubygems/test_gem_package.rbOrdinary callers using between one and four arguments should remain unchanged.
Gem::PackageTaskwill be updated to pass the boolean in its separate follow-up PR.Testing
Update tests in
test_gem_commands_build_command.rb,test_gem_package.rb, and the affected helper callsites.Tests should cover:
--ruby-abialone setsrequired_ruby_versionbut produces a traditionally named gem.--content-addressablealone uses the gemspec’s existing Ruby ABI and platform.content_addressable = falseproduces a traditional gem even when the specification is otherwise eligible.required_ruby_versionandplatformare preserved during a content-addressable build.required_rubygems_versionis raised in the built gem and copied back to the original spec after success.required_rubygems_versionremains unchanged after a failed build.required_rubygems_versionrequirements are rejected.--content-addressableand--outputcannot be used together.gem pushandgem yankretain their existing--ruby-abibehaviour.