In a Gemfile, what does the `ruby` directive enforce, and how does the `platforms:` option on a gem differ from it?
answer
- a check, not an installer
- RubyVersionMismatch at install and setup
- ruby file: ".ruby-version"
- platforms means Ruby implementation
- :windows replaces :mingw and :mswin
basics
~20 sThe ruby directive declares which Ruby the app needs; Bundler raises RubyVersionMismatch at install or setup when the running Ruby differs, without installing one. platforms: limits one gem to certain Ruby implementations, and other platforms quietly skip it.
solid answer
~40 s`ruby "4.0.7"`, a requirement such as `ruby "~> 4.0.0"`, or `ruby file: ".ruby-version"` declares the Ruby the whole bundle needs. It is a guard: `bundle install`, `bundle exec` and `Bundler.setup` compare it with the running interpreter and raise `RubyVersionMismatch` ("Your Ruby version is 3.4.7, but your Gemfile specified 4.0.7") instead of switching or installing Ruby, which is a version manager's job. `engine:` and `engine_version:` cover JRuby or TruffleRuby. `platforms:` works per gem: `gem "tzinfo-data", platforms: %i[windows jruby]` makes the gem exist only on those Ruby implementations, and elsewhere it is treated like an excluded group, not installed or loaded, with no error. Values include `ruby`, `mri`, `windows`, `jruby` and `truffleruby`, optionally versioned like `mri_40`; `:mingw`, `:x64_mingw`, `:mswin` and `:mswin64` are deprecated in favour of `:windows`.
code
ruby · 10 linessource "https://rubygems.org"
ruby file: ".ruby-version" # .ruby-version holds 4.0.7
gem "sinatra", "~> 4.2"
gem "tzinfo-data", platforms: %i[windows jruby]
platforms :mri do
gem "stackprof"
endgo deeper
Recall that the ruby line checks the running Ruby version and that platforms: limits a gem to certain Ruby implementations such as Windows or JRuby.
Explain when Bundler validates the ruby directive, what RubyVersionMismatch looks like, how ruby file: reads .ruby-version, and why a platform-filtered gem is skipped silently.
Keep one Ruby source of truth across the version manager, the Gemfile and CI images, and separate implementation filters in the Gemfile from OS and CPU platforms in the lockfile.
Decide how strictly to pin the Ruby version, exact patch or a pessimistic requirement, balancing reproducible builds against how quickly security patch releases can roll out.
## Two different questions A **Gemfile** can answer two questions that sound alike: - **"Which Ruby does this application need?"** - the `ruby` directive, one per Gemfile, applying to the whole bundle. - **"On which Ruby implementations should this one gem be used?"** - the `platforms:` option (or a `platforms` block), applying to individual gems. The first is a **check that can fail**; the second is a **filter that silently includes or skips**. ## The `ruby` directive ```ruby source "https://rubygems.org" ruby "4.0.7" # or: ruby "~> 4.0.0" # or: ruby file: ".ruby-version" ``` The argument is a version or a RubyGems-style requirement. `ruby file:` reads the version from a file relative to the Gemfile's directory; it understands the plain `4.0.7` of a `.ruby-version` file, a `ruby-4.0.7` prefix, and the `ruby 4.0.7` line of a `.tool-versions` file. Passing both a version and `file:` raises `GemfileError` ("Do not pass version argument when using :file option"). Alternative implementations add `engine:` and `engine_version:`, which must be given together: ```ruby ruby "2.6.8", engine: "jruby", engine_version: "9.3.8.0" # the man page's example ``` The old `patchlevel:` option is still accepted, but the man page notes it has been meaningless since Ruby 2.1. **What it does**: Bundler validates the running interpreter whenever it builds the runtime - on `bundle install`, `bundle update`, `bundle exec` and in `Bundler.setup` (which `require "bundler/setup"` calls). On a mismatch it raises `RubyVersionMismatch`, for example "Your Ruby version is 3.4.7, but your Gemfile specified 4.0.7". A wrong engine produces "Your Ruby engine is ...". **What it does not do**: Bundler never downloads, installs or switches Ruby. Getting the right interpreter onto the machine is the job of a version manager such as rbenv, which reads `.ruby-version`; `ruby file: ".ruby-version"` simply lets the Gemfile and the version manager share one source of truth. The locked Ruby version is recorded in Gemfile.lock. ## The `platforms:` option ```ruby gem "tzinfo-data", platforms: %i[windows jruby] gem "ffi", force_ruby_platform: true platforms :mri do gem "stackprof" end ``` The gemfile(5) man page describes platforms as "essentially identical to groups", except that you never have to exclude them by hand: on a non-matching Ruby, `bundle install`, `Bundler.setup` and `Bundler.require` behave as if the gem's group had been excluded. The gem is not installed, not put on the load path and not required, and nothing raises. | Value | Matches | |---|---| | `ruby` | CRuby, Rubinius or TruffleRuby, but not Windows | | `mri` | CRuby only, not Windows | | `windows` | CRuby on Windows | | `jruby` | JRuby | | `truffleruby` | TruffleRuby | For `ruby`, `mri` and `windows` you can append a version without a dot: `mri_40` means CRuby 4.0. An unknown value raises `GemfileError` listing the valid ones. `:mingw`, `:x64_mingw`, `:mswin` and `:mswin64` are deprecated in favour of `:windows`; Bundler flags them with a deprecation message unless deprecations are silenced. `force_ruby_platform: true` is a related per-gem switch: it tells Bundler to prefer the gem's pure-Ruby variant, compiling any native extension, over a precompiled platform-specific build. ## Exact or pessimistic Ruby requirement Both forms are common, and each has a cost: - **`ruby "4.0.7"`** makes every machine run the same patch release, so a missing security release on a laptop or CI image shows up as an immediate `RubyVersionMismatch`. Every patch upgrade is an edit. - **`ruby "~> 4.0.0"`** accepts any 4.0.x, so patch releases roll out without touching the Gemfile, at the price of machines drifting across patches. - **`ruby file: ".ruby-version"`** inherits whatever the version file says; with a full version in that file it behaves like the exact form. Whichever you choose, the CI image and the production image must satisfy it, because `bundle install` and every `bundle exec` run the check. ## Not the lockfile's PLATFORMS The same word means something else in Gemfile.lock. There, **platforms** are operating-system and CPU pairs such as `x86_64-linux` or `arm64-darwin`, managed with `bundle lock --add-platform`. The man page warns that the Gemfile values are closer to "Ruby implementation", and the two sets are not interchangeable. ## Traps 1. Expecting the `ruby` directive to install Ruby, then being surprised by `RubyVersionMismatch` in CI. 2. Writing `platforms: :ruby` and expecting it to include Windows. 3. Putting an OS-and-CPU string like `x86_64-linux` in `platforms:`; that belongs to the lockfile.
- Why use `ruby file: ".ruby-version"` instead of repeating the version string in the Gemfile?It keeps one source of truth. The version manager reads `.ruby-version` to pick the interpreter, and Bundler reads the same file to validate it, so an upgrade edits one file. Bundler resolves the path relative to the Gemfile and also accepts a `.tool-versions` style `ruby 4.0.7` line.
- What is the difference between `platforms: :windows` in the Gemfile and `bundle lock --add-platform x64-mingw-ucrt`?The Gemfile option filters a gem by Ruby implementation at install and load time. `bundle lock --add-platform` adds an operating-system and CPU platform to Gemfile.lock so the bundle resolves platform-specific gem builds for that machine type. One says who uses a gem; the other says which binaries the lockfile covers.
The ruby directive is the height sign at a ride entrance: it measures whoever steps up and turns away anyone who does not fit, but it never makes anyone taller. Getting the right Ruby onto the machine is someone else's job.
saying these in an interview costs you the question
- The ruby directive makes Bundler install or switch to that Ruby
- A mismatched ruby directive only prints a warning
- platforms: :ruby includes CRuby on Windows
- A gem limited by platforms: raises an error on other platforms
- Gemfile platforms: takes the same values as bundle lock --add-platform