From 65e67be4b9ff48624c71323ed7e501a6e105387f Mon Sep 17 00:00:00 2001 From: Leo Arnold Date: Tue, 26 May 2026 00:19:41 +0200 Subject: [PATCH] Share gems between Ruby minor versions ASDF itself treats every install as a separate entity and does not have a concept of sharing data between installs. Luckily, Rubygems already provides such a concept through [`Gem.user_dir`](https://github.com/ruby/rubygems/blob/v4.0.12/lib/rubygems/defaults.rb#L103-L109) which holds a value like ```text /home/johndoe/.gem/4.0.0 ``` There are two features to note here: - Since ASDF will usually install everything into the user's home directory (i.e. `~/.asdf/`), we can do the same with the Ruby gems (by using `~/.gem`) without loss of generality. - While `RUBY_VERSION` changes with every Ruby release, the built-in value `RbConfig::CONFIG["ruby_version"]` stays the same for all versions of Ruby which are binary compatible. For example, all Ruby releases in the `3.4.X` series will have `3.4.0` as the value of `RbConfig::CONFIG["ruby_version"]`. So, in order to have communal gem homes for binary compatible releases of Ruby, all we need to do is to use `Gem.user_dir` as `GEM_HOME`. We set this value at runtime using `bin/exec-env` Fixes #119 --- bin/exec-env | 6 ++++++ bin/list-bin-paths | 6 ++++-- lib/utils.sh | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/bin/exec-env b/bin/exec-env index 986bf4d..f2c2d07 100755 --- a/bin/exec-env +++ b/bin/exec-env @@ -3,9 +3,15 @@ current_script_path="${BASH_SOURCE[0]}" ruby_plugin_dir="$(dirname "$(dirname "$current_script_path")")" +source "$ruby_plugin_dir/lib/utils.sh" + RUBYLIB=${RUBYLIB:-} if [ "$RUBYLIB" = "" ]; then export RUBYLIB="$ruby_plugin_dir/rubygems-plugin" else export RUBYLIB="$ruby_plugin_dir/rubygems-plugin:$RUBYLIB" fi + +if output=$(gem_user_dir); then + export GEM_HOME="$output" +fi diff --git a/bin/list-bin-paths b/bin/list-bin-paths index e24bb72..66a7d0c 100755 --- a/bin/list-bin-paths +++ b/bin/list-bin-paths @@ -1,4 +1,6 @@ #!/usr/bin/env bash -gem_version="${ASDF_INSTALL_VERSION%.*}.0" -echo "bin lib/ruby/gems/$gem_version/bin" +# shellcheck source=/dev/null +source "$(dirname "$0")/../lib/utils.sh" + +echo "bin lib/ruby/gems/$(ruby_minor_version)/bin" diff --git a/lib/utils.sh b/lib/utils.sh index 6e863bf..2608856 100644 --- a/lib/utils.sh +++ b/lib/utils.sh @@ -76,3 +76,18 @@ ruby_build_source_dir() { ruby_build_path() { echo "$(ruby_build_dir)/bin/ruby-build" } + +# Prevent ASDF from repeatedly invoking itself (e.g. via bin/exec-env) +# until the host machine runs out of memory +ruby_bypassing_asdf_callbacks() { + "$ASDF_INSTALL_PATH/bin/ruby" "$@" +} + +ruby_minor_version() { + ruby_bypassing_asdf_callbacks -e 'puts RbConfig::CONFIG["ruby_version"]' +} + +gem_user_dir() { + ruby_bypassing_asdf_callbacks -rrubygems -e 'puts Gem.user_dir' +} +