In Ruby, what does the RUBYOPT environment variable do, which switches may it carry, and when would you run ruby --disable=rubyopt?
answer
- options every child ruby inherits
- short switches EIdvwWrKU only
- -n or -e raise RuntimeError
- -w sets $VERBOSE to true
- --disable=gems,rubyopt
basics
~20 sRUBYOPT adds command-line options to every ruby process that inherits the environment. Only a safe subset is allowed (-d, -E, -I, -K, -r, -U, -v, -w, -W and some long options); -e, -n or -p raise RuntimeError. --disable=rubyopt ignores it.
solid answer
~40 s`RUBYOPT` is read after the command line and applied as extra switches to every Ruby process started with that environment, including children, which makes it both powerful and easy to forget. The short switches accepted there are `-E`, `-I`, `-d`, `-v`, `-w`, `-W`, `-r`, `-K` and `-U`, plus long options such as `--enable`, `--disable` and `--debug`; anything that changes what program runs, like `-e`, `-n`, `-p` or `-c`, raises `RuntimeError: invalid switch in RUBYOPT`. `bundle exec` itself prepends a `-r` of `bundler/setup` to `RUBYOPT`, so child Ruby processes inherit the bundle. When a process behaves differently from a clean shell (unexpected warnings, libraries preloaded), `ruby --disable=rubyopt` ignores the variable so you can compare.
code
bash · 8 lines$ ruby -e 'p $VERBOSE'
false
$ RUBYOPT=-w ruby -e 'p $VERBOSE'
true
$ RUBYOPT=-w ruby --disable=rubyopt -e 'p $VERBOSE'
false
$ RUBYOPT=-n ruby -e 'p 1'
# fails: invalid switch in RUBYOPT: -n (RuntimeError)go deeper
Recall that RUBYOPT passes extra options to every ruby started with that environment, and that -w turns on verbose warnings.
Explain which switches RUBYOPT accepts and why -e, -n or -p are refused, and what --enable and --disable toggle.
Diagnose environment-dependent behaviour: inspect RUBYOPT, compare with --disable=rubyopt, and account for bundle exec injecting a require into child processes.
Keep interpreter behaviour in the repository, not in shells: agree where warning levels and preloads are configured so CI, containers and laptops match.
## What `RUBYOPT` is `RUBYOPT` is an environment variable holding extra interpreter switches, separated by whitespace. After Ruby has parsed its own command line, it reads `RUBYOPT` (unless told not to) and applies those switches as well. Because environment variables are inherited, every Ruby process started from that shell, CI job or container, including processes spawned by other Ruby processes, receives the same options. Typical legitimate uses: - `RUBYOPT=-w` in a CI job so every test process runs with verbose warnings; - `RUBYOPT=-Ilib` while hacking on a library without installing it; - `RUBYOPT=-rsome/preload` to load instrumentation before the program; - `bundle exec`, which prepends `-r` followed by the path of `bundler/setup` so that child Ruby processes it launches resolve gems from the same bundle. ## What it may contain The interpreter deliberately refuses switches that would change which program runs or how its input is read. | Allowed in `RUBYOPT` | Refused in `RUBYOPT` | |---|---| | `-I dir`, `-r lib` | `-e`, `-n`, `-p`, `-a`, `-l` | | `-w`, `-W[level]`, `-W:category` | `-c`, `-s`, `-S`, `-x`, `-C`, `-i`, `-0`, `-F` | | `-d`, `--debug`, `-v` | `-h`, `--help`, `--version`, `--copyright` | | `-E`, `-K`, `-U` | | | `--enable=…`, `--disable=…` | | A refused switch fails fast: `RUBYOPT=-n ruby app.rb` stops with `RuntimeError` and the message `invalid switch in RUBYOPT: -n`. The `ruby(1)` man page still lists `-T` among the allowed switches, but the interpreter no longer has a `-T` switch at all. ## Warning switches you will meet there 1. With no flag, `$VERBOSE` is `false`: ordinary warnings print, verbose-only ones do not. 2. `-w` sets `$VERBOSE` to `true` and turns on the deprecated and experimental warning categories. 3. `-W0` sets `$VERBOSE` to `nil`, which silences `Kernel#warn` entirely; `-W1` is the default level and `-W2` (or bare `-W`) equals `-w`'s verbosity. 4. `-v` prints the version and also sets `$VERBOSE` to `true`. ## `--enable` and `--disable` These switches take a comma-separated list of features: - `gems`: loading RubyGems at startup (enabled by default; disabling it is meant for debugging, and gems installed outside the standard library directories then cannot be required); - `did_you_mean`, `error_highlight`, `syntax_suggest`: the helpers that improve error messages (enabled by default); - `rubyopt`: whether `RUBYOPT` is read at all (enabled by default). `ruby --disable=rubyopt script.rb` is therefore the quickest way to prove that a surprising behaviour comes from the environment rather than the code. It works only on the command line, since `RUBYOPT` is read after the command-line switches that could disable it. ## Diagnosing a polluted environment 1. Print it: `echo "$RUBYOPT"` in the failing shell, CI step or container. 2. Compare `ruby -e 'p $VERBOSE, $LOADED_FEATURES.size'` with and without `--disable=rubyopt`. 3. Look for tools that set it for you: `bundle exec`, wrapper scripts, CI images, or a shell profile. 4. Prefer explicit switches or configuration in the project over a global `RUBYOPT`, so behaviour does not depend on which shell started the process. ## Seeing what the interpreter actually received A quick probe prints the settings that `RUBYOPT` most often changes: ```bash ruby -e 'p verbose: $VERBOSE, debug: $DEBUG, first: $LOAD_PATH.first' ruby --disable=rubyopt -e 'p verbose: $VERBOSE, debug: $DEBUG, first: $LOAD_PATH.first' ``` If the two lines differ, the environment is responsible. Printing the variable itself inside `bundle exec` shows the extra `-r` entry pointing at `bundler/setup`. ## Why some switches are refused The accepted set adjusts how a program runs: warnings, debugging, encodings, extra load-path directories, preloaded libraries and feature toggles. The refused set would change which program runs or how its input is read (`-e`, `-n`, `-p`, `-x`), or would print something and stop (`-h`, `--version`). Accepting those from an inherited variable would let one stray export alter every Ruby program started afterwards, so the interpreter fails fast instead.
- Why does a Ruby process started from inside `bundle exec` still see the bundle's gems?`bundle exec` prepends a `-r` of `bundler/setup` to `RUBYOPT` before launching the command. Any Ruby child process inherits that variable, so it also requires `bundler/setup` at startup and resolves gems from the same Gemfile.lock.
- What is the difference between `-W0` and leaving warnings at the default?By default `$VERBOSE` is `false`: ordinary warnings, including explicit `Kernel#warn` calls, still print. `-W0` sets `$VERBOSE` to `nil`, and then `Kernel#warn` and most interpreter warnings print nothing, which can hide real problems in CI.
saying these in an interview costs you the question
- RUBYOPT affects only the first ruby process, not its children
- Any command-line switch, including -e, can go in RUBYOPT
- -w is the same as the default warning level
- --disable=gems only hides gem warnings
- Putting --disable=rubyopt inside RUBYOPT turns it off