From 8eceea6ead61ead3404aa5cafe4f2dfaf9312acb Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 11 Nov 2025 15:59:06 -1000 Subject: [PATCH 1/5] Add rvm and nvm support to ci-switch-config script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the script only supported mise and asdf version managers. This adds support for rvm (Ruby) and nvm (Node.js) to make the script more flexible for developers using different version management tools. Key changes: - Detect rvm, nvm, or rvm+nvm combinations in addition to mise/asdf - Add set_ruby_version() helper to switch Ruby versions with rvm - Add set_node_version() helper to switch Node versions with nvm - Update both minimum and latest config functions to use new helpers - Add appropriate reload/verification instructions for each manager 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- bin/ci-switch-config | 164 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 134 insertions(+), 30 deletions(-) diff --git a/bin/ci-switch-config b/bin/ci-switch-config index 18a90d9851..94651bd3aa 100755 --- a/bin/ci-switch-config +++ b/bin/ci-switch-config @@ -39,14 +39,64 @@ check_version_manager() { echo "mise" elif command -v asdf &> /dev/null; then echo "asdf" + elif command -v rvm &> /dev/null && command -v nvm &> /dev/null; then + echo "rvm+nvm" + elif command -v rvm &> /dev/null; then + echo "rvm" + elif command -v nvm &> /dev/null; then + echo "nvm" else - print_error "No version manager found. Please install mise or asdf:" + print_error "No version manager found. Please install one of:" echo " mise (recommended): https://mise.jdx.dev/" - echo " asdf (legacy): https://asdf-vm.com/" + echo " asdf: https://asdf-vm.com/" + echo " rvm + nvm: https://rvm.io/ + https://github.com/nvm-sh/nvm" exit 1 fi } +set_ruby_version() { + local version="$1" + local version_manager="$2" + + case "$version_manager" in + mise|asdf) + # Handled via .tool-versions + ;; + rvm|rvm+nvm) + print_header "Setting Ruby $version with rvm" + if ! rvm list strings | grep -q "^ruby-${version}$"; then + print_warning "Ruby $version not installed. Installing..." + rvm install "$version" + fi + rvm use "$version" + ;; + esac +} + +set_node_version() { + local version="$1" + local version_manager="$2" + + case "$version_manager" in + mise|asdf) + # Handled via .tool-versions + ;; + nvm|rvm+nvm) + print_header "Setting Node $version with nvm" + # Source nvm if not already loaded + if [ -z "${NVM_DIR:-}" ]; then + export NVM_DIR="$HOME/.nvm" + [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + fi + if ! nvm list "$version" &> /dev/null; then + print_warning "Node $version not installed. Installing..." + nvm install "$version" + fi + nvm use "$version" + ;; + esac +} + show_status() { print_header "Current Configuration" echo "" @@ -121,12 +171,17 @@ switch_to_minimum() { fi # Set Ruby and Node versions - print_header "Setting runtime versions in .tool-versions" - cat > "$PROJECT_ROOT/.tool-versions" < "$PROJECT_ROOT/.tool-versions" < "$PROJECT_ROOT/.tool-versions" < "$PROJECT_ROOT/.tool-versions" < Date: Tue, 11 Nov 2025 16:06:14 -1000 Subject: [PATCH 2/5] Improve rvm/nvm support with robust error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhanced the ci-switch-config script based on code review feedback: **Error Handling & Validation:** - Add comprehensive error checking for rvm/nvm commands with helpful messages - Detect and fail early when only rvm or only nvm is installed - Guide users to source shell configs or install missing managers - Make rvm version check more flexible (handles with/without ruby- prefix) **nvm Installation Detection:** - Support multiple common nvm locations (standard, Homebrew, XDG config) - Try ~/.nvm, /opt/homebrew/opt/nvm, and ~/.config/nvm - Provide clear error messages showing which locations were tried **Documentation:** - Update SWITCHING_CI_CONFIGS.md with complete rvm+nvm installation guide - Add troubleshooting sections for each version manager - Include verification commands for all supported managers - Add note clarifying asdf sourcing only affects script's subshell 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- SWITCHING_CI_CONFIGS.md | 58 +++++++++++++++++++++++++++---- bin/ci-switch-config | 76 +++++++++++++++++++++++++++++++++++------ 2 files changed, 118 insertions(+), 16 deletions(-) diff --git a/SWITCHING_CI_CONFIGS.md b/SWITCHING_CI_CONFIGS.md index 6bd8f4293e..a61d61c49c 100644 --- a/SWITCHING_CI_CONFIGS.md +++ b/SWITCHING_CI_CONFIGS.md @@ -53,24 +53,50 @@ The project runs tests against two configurations: ## Prerequisites -You must have a version manager like [mise](https://mise.jdx.dev/) (recommended) or [asdf](https://asdf-vm.com/) installed to manage Ruby and Node versions. +You must have a version manager installed to manage Ruby and Node versions. The script supports: + +- **[mise](https://mise.jdx.dev/)** - Recommended, modern, manages both Ruby and Node +- **[asdf](https://asdf-vm.com/)** - Legacy option, manages both Ruby and Node +- **[rvm](https://rvm.io/) + [nvm](https://github.com/nvm-sh/nvm)** - Separate managers for Ruby and Node + +### Option 1: mise (Recommended) ```bash -# Install mise (recommended, modern alternative to asdf) +# Install mise brew install mise echo 'eval "$(mise activate zsh)"' >> ~/.zshrc source ~/.zshrc -# OR install asdf (legacy option) +# mise automatically reads from .tool-versions +``` + +### Option 2: asdf + +```bash +# Install asdf brew install asdf echo -e "\n. $(brew --prefix asdf)/libexec/asdf.sh" >> ~/.zshrc source ~/.zshrc -# Install plugins (only needed for asdf, mise reads from mise.toml) +# Install plugins asdf plugin add ruby asdf plugin add nodejs ``` +### Option 3: rvm + nvm + +```bash +# Install rvm for Ruby +\curl -sSL https://get.rvm.io | bash -s stable +source ~/.rvm/scripts/rvm + +# Install nvm for Node +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash +# Add to shell config (the installer usually does this automatically) +``` + +**Note:** If you only have rvm (no nvm) or only nvm (no rvm), the script will detect this and provide helpful error messages guiding you to install the missing manager or switch to mise/asdf. + ## Detailed Usage ### 1. Check Current Configuration @@ -107,7 +133,9 @@ This will: ```bash # Reload your shell to pick up new Ruby/Node versions cd -mise current # or: asdf current +mise current # For mise users +# asdf current # For asdf users +# rvm current && nvm current # For rvm+nvm users # Build and test rake node_package @@ -137,7 +165,9 @@ This will: ```bash # Reload your shell to pick up new Ruby/Node versions cd -mise current # or: asdf current +mise current # For mise users +# asdf current # For asdf users +# rvm current && nvm current # For rvm+nvm users # Build and test rake node_package @@ -243,6 +273,22 @@ asdf reshim ruby asdf reshim nodejs ``` +**For rvm + nvm:** + +```bash +# Install and use specific Ruby version +rvm install 3.2.8 # or 3.4.3 +rvm use 3.2.8 + +# Install and use specific Node version +nvm install 20.18.1 # or 22.12.0 +nvm use 20.18.1 + +# Verify versions +ruby --version +node --version +``` + ### Yarn install fails If you get package resolution errors: diff --git a/bin/ci-switch-config b/bin/ci-switch-config index 94651bd3aa..4d2b1a41a5 100755 --- a/bin/ci-switch-config +++ b/bin/ci-switch-config @@ -64,11 +64,29 @@ set_ruby_version() { ;; rvm|rvm+nvm) print_header "Setting Ruby $version with rvm" - if ! rvm list strings | grep -q "^ruby-${version}$"; then + # Check if version exists (with or without ruby- prefix) + if ! rvm list strings | grep -qE "^(ruby-)?${version}$"; then print_warning "Ruby $version not installed. Installing..." - rvm install "$version" + if ! rvm install "$version"; then + print_error "Failed to install Ruby $version with rvm" + print_warning "Make sure rvm is properly configured. Try running: source ~/.rvm/scripts/rvm" + exit 1 + fi fi - rvm use "$version" + if ! rvm use "$version"; then + print_error "Failed to switch to Ruby $version" + print_warning "Make sure rvm is properly configured. Try running: source ~/.rvm/scripts/rvm" + exit 1 + fi + print_success "Switched to Ruby $version" + ;; + nvm) + print_error "Cannot set Ruby version: nvm doesn't manage Ruby" + echo "Please install one of the following to manage Ruby versions:" + echo " - rvm: https://rvm.io/" + echo " - mise: https://mise.jdx.dev/ (recommended, manages both Ruby and Node)" + echo " - asdf: https://asdf-vm.com/ (manages both Ruby and Node)" + exit 1 ;; esac } @@ -83,16 +101,52 @@ set_node_version() { ;; nvm|rvm+nvm) print_header "Setting Node $version with nvm" - # Source nvm if not already loaded - if [ -z "${NVM_DIR:-}" ]; then - export NVM_DIR="$HOME/.nvm" - [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + + # Source nvm if not already loaded - try multiple common locations + if ! command -v nvm &> /dev/null; then + # Try standard nvm location + if [ -s "$HOME/.nvm/nvm.sh" ]; then + export NVM_DIR="$HOME/.nvm" + \. "$NVM_DIR/nvm.sh" + # Try Homebrew location (macOS) + elif [ -s "/opt/homebrew/opt/nvm/nvm.sh" ]; then + export NVM_DIR="/opt/homebrew/opt/nvm" + \. "/opt/homebrew/opt/nvm/nvm.sh" + # Try XDG config location + elif [ -s "${XDG_CONFIG_HOME:-$HOME/.config}/nvm/nvm.sh" ]; then + export NVM_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/nvm" + \. "$NVM_DIR/nvm.sh" + else + print_error "Could not find nvm installation" + print_warning "Tried locations: ~/.nvm, /opt/homebrew/opt/nvm, ~/.config/nvm" + echo "Please source nvm manually or install it from: https://github.com/nvm-sh/nvm" + exit 1 + fi fi - if ! nvm list "$version" &> /dev/null; then + + # Check if version is already installed + if ! nvm list | grep -q "v${version}"; then print_warning "Node $version not installed. Installing..." - nvm install "$version" + if ! nvm install "$version"; then + print_error "Failed to install Node $version with nvm" + exit 1 + fi fi - nvm use "$version" + + if ! nvm use "$version"; then + print_error "Failed to switch to Node $version" + print_warning "Make sure nvm is properly configured. Try running: nvm use $version" + exit 1 + fi + print_success "Switched to Node $version" + ;; + rvm) + print_error "Cannot set Node version: rvm doesn't manage Node" + echo "Please install one of the following to manage Node versions:" + echo " - nvm: https://github.com/nvm-sh/nvm" + echo " - mise: https://mise.jdx.dev/ (recommended, manages both Ruby and Node)" + echo " - asdf: https://asdf-vm.com/ (manages both Ruby and Node)" + exit 1 ;; esac } @@ -218,6 +272,7 @@ EOF # mise will auto-detect .tool-versions on next cd ;; asdf) + # Note: This only affects the script's subshell, not the user's current shell if [ -f "$HOME/.asdf/asdf.sh" ]; then source "$HOME/.asdf/asdf.sh" fi @@ -325,6 +380,7 @@ EOF # mise will auto-detect .tool-versions on next cd ;; asdf) + # Note: This only affects the script's subshell, not the user's current shell if [ -f "$HOME/.asdf/asdf.sh" ]; then source "$HOME/.asdf/asdf.sh" fi From e133a132d63c6c4cf3e081a0e7d03f8e9dee7bbb Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 11 Nov 2025 16:12:34 -1000 Subject: [PATCH 3/5] Fix edge cases in version manager detection and improve UX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on additional code review feedback: **Version Detection Improvements:** - Use `rvm list rubies` instead of `rvm list strings` for more consistent output across different rvm versions - Use `nvm version VERSION` instead of `nvm list | grep` for more reliable version checking across different nvm versions **User Experience:** - Add explicit warning that rvm/nvm version changes only affect the script's subshell - Inform users they may need to open a new terminal or source their shell config for changes to take effect - Clarify the persistent vs. temporary nature of version switches These changes make the script more robust across different version manager installations and set clearer expectations for users. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- bin/ci-switch-config | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/bin/ci-switch-config b/bin/ci-switch-config index 4d2b1a41a5..2623793930 100755 --- a/bin/ci-switch-config +++ b/bin/ci-switch-config @@ -64,8 +64,8 @@ set_ruby_version() { ;; rvm|rvm+nvm) print_header "Setting Ruby $version with rvm" - # Check if version exists (with or without ruby- prefix) - if ! rvm list strings | grep -qE "^(ruby-)?${version}$"; then + # Check if version exists using rvm list rubies for consistent output + if ! rvm list rubies | grep -qE "(ruby-)?${version}"; then print_warning "Ruby $version not installed. Installing..." if ! rvm install "$version"; then print_error "Failed to install Ruby $version with rvm" @@ -124,8 +124,8 @@ set_node_version() { fi fi - # Check if version is already installed - if ! nvm list | grep -q "v${version}"; then + # Check if version is already installed using nvm version for reliability + if ! nvm version "$version" &> /dev/null; then print_warning "Node $version not installed. Installing..." if ! nvm install "$version"; then print_error "Failed to install Node $version with nvm" @@ -287,6 +287,14 @@ EOF echo "" print_success "Switched to MINIMUM configuration" + + case "$VERSION_MANAGER" in + rvm+nvm|rvm|nvm) + print_warning "Note: Version changes only affect this script's subshell." + print_warning "You may need to open a new terminal or source your shell config." + ;; + esac + print_warning "Run these commands to reload your shell and verify:" echo " cd $PROJECT_ROOT" case "$VERSION_MANAGER" in @@ -395,6 +403,14 @@ EOF echo "" print_success "Restored to LATEST configuration" + + case "$VERSION_MANAGER" in + rvm+nvm|rvm|nvm) + print_warning "Note: Version changes only affect this script's subshell." + print_warning "You may need to open a new terminal or source your shell config." + ;; + esac + print_warning "Run these commands to reload your shell and verify:" echo " cd $PROJECT_ROOT" case "$VERSION_MANAGER" in From 06b7927868dfe64db35a41c81cbe3a44b937f6fb Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 11 Nov 2025 16:19:04 -1000 Subject: [PATCH 4/5] Add .ruby-version/.nvmrc support and enhance UX warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on final code review feedback: **Version File Management:** - Create .ruby-version for rvm users (enables auto-switching on cd) - Create .nvmrc for nvm users (enables auto-switching on cd) - Maintains .tool-versions for mise/asdf users - Allows users to leverage each manager's native auto-switching features **Improved Version Matching:** - Fix rvm version check to avoid partial matches (3.2.8 won't match 3.2.80) - Use word boundaries in grep pattern for exact version matching **Enhanced User Warnings:** - Make subshell limitation warnings more explicit and prominent - Explain WHY versions don't persist (subshell vs. parent shell) - Provide clear, actionable steps with two distinct options: 1. Open new terminal (recommended) 2. Source shell config files (with exact commands) - Show appropriate sourcing commands based on version manager **Documentation:** - Add warning about not mixing version managers (mise + rvm, etc.) - Explain version manager priority (mise > asdf > rvm+nvm) - Clarify potential confusion from using multiple managers These changes make the script more user-friendly by enabling native auto-switching features and setting much clearer expectations about how version changes work with rvm/nvm. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- SWITCHING_CI_CONFIGS.md | 5 ++- bin/ci-switch-config | 79 ++++++++++++++++++++++++++++++++--------- 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/SWITCHING_CI_CONFIGS.md b/SWITCHING_CI_CONFIGS.md index a61d61c49c..6eeb1d0ad5 100644 --- a/SWITCHING_CI_CONFIGS.md +++ b/SWITCHING_CI_CONFIGS.md @@ -95,7 +95,10 @@ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash # Add to shell config (the installer usually does this automatically) ``` -**Note:** If you only have rvm (no nvm) or only nvm (no rvm), the script will detect this and provide helpful error messages guiding you to install the missing manager or switch to mise/asdf. +**Important Notes:** + +- If you only have rvm (no nvm) or only nvm (no rvm), the script will detect this and provide helpful error messages guiding you to install the missing manager or switch to mise/asdf. +- **Do not mix version managers** (e.g., don't install both mise and rvm). The script prioritizes mise > asdf > rvm+nvm, so mise/asdf will always take precedence. Using multiple managers can cause confusion about which versions are active. ## Detailed Usage diff --git a/bin/ci-switch-config b/bin/ci-switch-config index 2623793930..286ba6caec 100755 --- a/bin/ci-switch-config +++ b/bin/ci-switch-config @@ -65,7 +65,8 @@ set_ruby_version() { rvm|rvm+nvm) print_header "Setting Ruby $version with rvm" # Check if version exists using rvm list rubies for consistent output - if ! rvm list rubies | grep -qE "(ruby-)?${version}"; then + # Use word boundaries to avoid matching partial versions (e.g., 3.2.8 shouldn't match 3.2.80) + if ! rvm list rubies | grep -qE "(ruby-)?${version}([[:space:]]|$)"; then print_warning "Ruby $version not installed. Installing..." if ! rvm install "$version"; then print_error "Failed to install Ruby $version with rvm" @@ -225,14 +226,29 @@ switch_to_minimum() { fi # Set Ruby and Node versions - if [[ "$VERSION_MANAGER" == "mise" ]] || [[ "$VERSION_MANAGER" == "asdf" ]]; then - print_header "Setting runtime versions in .tool-versions" - cat > "$PROJECT_ROOT/.tool-versions" < "$PROJECT_ROOT/.tool-versions" < "$PROJECT_ROOT/.ruby-version" + print_success "Created .ruby-version with Ruby 3.2.8" + ;; + esac + + case "$VERSION_MANAGER" in + nvm|rvm+nvm) + print_header "Creating .nvmrc for nvm" + echo "20.18.1" > "$PROJECT_ROOT/.nvmrc" + print_success "Created .nvmrc with Node 20.18.1" + ;; + esac set_ruby_version "3.2.8" "$VERSION_MANAGER" set_node_version "20.18.1" "$VERSION_MANAGER" @@ -290,12 +306,19 @@ EOF case "$VERSION_MANAGER" in rvm+nvm|rvm|nvm) - print_warning "Note: Version changes only affect this script's subshell." - print_warning "You may need to open a new terminal or source your shell config." + print_warning "IMPORTANT: Version changes in this script don't persist to your current shell." + print_warning "The rvm/nvm commands run in a subshell and cannot affect your terminal." + echo "" + print_warning "Choose one of these options to activate the new versions:" + echo " Option 1 (Recommended): Open a new terminal and cd into the project" + echo " Option 2: Source your shell config:" + [ "$VERSION_MANAGER" = "rvm" ] || [ "$VERSION_MANAGER" = "rvm+nvm" ] && echo " source ~/.rvm/scripts/rvm" + [ "$VERSION_MANAGER" = "nvm" ] || [ "$VERSION_MANAGER" = "rvm+nvm" ] && echo " source \$NVM_DIR/nvm.sh" + echo "" ;; esac - print_warning "Run these commands to reload your shell and verify:" + print_warning "After activating versions, verify with:" echo " cd $PROJECT_ROOT" case "$VERSION_MANAGER" in mise) @@ -341,14 +364,29 @@ restore_to_latest() { fi # Set Ruby and Node versions - if [[ "$VERSION_MANAGER" == "mise" ]] || [[ "$VERSION_MANAGER" == "asdf" ]]; then - print_header "Setting runtime versions in .tool-versions" - cat > "$PROJECT_ROOT/.tool-versions" < "$PROJECT_ROOT/.tool-versions" < "$PROJECT_ROOT/.ruby-version" + print_success "Created .ruby-version with Ruby 3.4.3" + ;; + esac + + case "$VERSION_MANAGER" in + nvm|rvm+nvm) + print_header "Creating .nvmrc for nvm" + echo "22.12.0" > "$PROJECT_ROOT/.nvmrc" + print_success "Created .nvmrc with Node 22.12.0" + ;; + esac set_ruby_version "3.4.3" "$VERSION_MANAGER" set_node_version "22.12.0" "$VERSION_MANAGER" @@ -406,12 +444,19 @@ EOF case "$VERSION_MANAGER" in rvm+nvm|rvm|nvm) - print_warning "Note: Version changes only affect this script's subshell." - print_warning "You may need to open a new terminal or source your shell config." + print_warning "IMPORTANT: Version changes in this script don't persist to your current shell." + print_warning "The rvm/nvm commands run in a subshell and cannot affect your terminal." + echo "" + print_warning "Choose one of these options to activate the new versions:" + echo " Option 1 (Recommended): Open a new terminal and cd into the project" + echo " Option 2: Source your shell config:" + [ "$VERSION_MANAGER" = "rvm" ] || [ "$VERSION_MANAGER" = "rvm+nvm" ] && echo " source ~/.rvm/scripts/rvm" + [ "$VERSION_MANAGER" = "nvm" ] || [ "$VERSION_MANAGER" = "rvm+nvm" ] && echo " source \$NVM_DIR/nvm.sh" + echo "" ;; esac - print_warning "Run these commands to reload your shell and verify:" + print_warning "After activating versions, verify with:" echo " cd $PROJECT_ROOT" case "$VERSION_MANAGER" in mise) From 5d3ef2fbe77d840cd89733f556635517353f05c8 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Tue, 11 Nov 2025 16:29:23 -1000 Subject: [PATCH 5/5] Fix regex anchoring to prevent false version matches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix critical regex bug where version detection could match unintended versions. For example, searching for "3.2.8" could incorrectly match "13.2.8" because the pattern wasn't anchored to the start of the line. Changes: - Add line-start anchor (^) to prevent matching partial strings - Allow optional leading whitespace: ^[[:space:]]* - Keep optional ruby- prefix: (ruby-)? - Remove end anchor to allow patch suffixes (3.2.8-p123) New pattern: ^[[:space:]]*(ruby-)?${version} This ensures exact version matching at the start of each line while still being flexible enough to match versions with or without the ruby- prefix and with any patch suffix. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- bin/ci-switch-config | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/ci-switch-config b/bin/ci-switch-config index 286ba6caec..3c969ffc73 100755 --- a/bin/ci-switch-config +++ b/bin/ci-switch-config @@ -65,8 +65,9 @@ set_ruby_version() { rvm|rvm+nvm) print_header "Setting Ruby $version with rvm" # Check if version exists using rvm list rubies for consistent output - # Use word boundaries to avoid matching partial versions (e.g., 3.2.8 shouldn't match 3.2.80) - if ! rvm list rubies | grep -qE "(ruby-)?${version}([[:space:]]|$)"; then + # Anchor to start of line to avoid false matches (e.g., 3.2.8 shouldn't match 13.2.8) + # Allow optional leading whitespace and ruby- prefix, no end anchor to allow patch suffixes + if ! rvm list rubies | grep -qE "^[[:space:]]*(ruby-)?${version}"; then print_warning "Ruby $version not installed. Installing..." if ! rvm install "$version"; then print_error "Failed to install Ruby $version with rvm"