In Ruby with Bundler, what is the difference between `require "bundler/setup"` and `Bundler.require`, and how do group arguments change each?
answer
- load path versus actually loading
- setup: all groups minus without
- require: :default when called bare
- Bundler.setup(:test) omits :default
- require: option picks the file
basics
~20 srequire "bundler/setup" calls Bundler.setup, which puts the locked gems of all installed groups on the load path but loads none. Bundler.require runs setup and then requires every gem of the named groups, :default when called without arguments.
solid answer
~40 s`Bundler.setup`, which `require "bundler/setup"` calls, makes the bundle *available*: it checks the Gemfile against Gemfile.lock and the running Ruby, activates the locked version of each gem, adds their `lib` directories to `$LOAD_PATH` and blocks gems outside the bundle. It requires no gem; your code still writes `require "sinatra"`. Without arguments it sets up every group except those skipped by `without`; `Bundler.setup(:default, :test)` restricts it, and `Bundler.setup(:test)` alone omits `:default`. `Bundler.require(*groups)` calls setup for those groups and then **requires** each gem in them, using the gem's `require:` option or its name. Without arguments it requires only `:default`, so frameworks pass groups explicitly, as in `Bundler.require(:default, ENV.fetch("RACK_ENV", "development").to_sym)`. Setup gives explicit control over load order; require trades that for convenience and boot cost.
code
ruby · 6 lines# config.ru of a small Rack app
require "bundler/setup" # locked gems on the load path, none loaded
require "sinatra/base" # explicit, in the order you choose
require_relative "app"
run Appgo deeper
Recall that bundler/setup makes the locked gems available and that Bundler.require also loads them, the default group when called without arguments.
Explain which groups each call covers by default, why Bundler.setup(:test) leaves out :default, and how the require option decides what Bundler.require loads.
Choose explicit requires or Bundler.require per application, controlling boot time and load-order side effects, and debug LoadErrors caused by missing group setup.
Decide whether the organisation's services autoload their bundles or require explicitly, weighing boot time, memory per process and how clearly dependencies read in code.
## Two steps: make available, then load Running Ruby code under **Bundler** involves two separate steps: 1. **Setup** - decide which gem versions this process may use and make their files findable. 2. **Require** - actually load a gem's code into the process. `require "bundler/setup"` (or calling `Bundler.setup`) performs only step 1. `Bundler.require` performs step 1 for the requested groups and then step 2 for every gem in them. ## What `Bundler.setup` does When `Bundler.setup` runs, it: - validates the running Ruby and platform against the Gemfile's `ruby` directive and the lockfile, raising `RubyVersionMismatch` on a wrong Ruby; - compares the Gemfile with Gemfile.lock: in frozen mode a mismatch raises, otherwise Bundler re-resolves and writes the updated lockfile; - removes gem paths that were already on the load path from other activations; - activates the **exact locked version** of each gem in the requested groups and adds its `lib` directories to `$LOAD_PATH`; - patches RubyGems so `Kernel#gem` and gem activation cannot reach gems outside the bundle. After that, `require "sinatra"` finds Sinatra's locked version, and `require "some_gem_not_in_the_gemfile"` fails with `LoadError` even if that gem is installed on the machine. Groups decide which gems are set up: ```ruby Bundler.setup # all groups, except those in the without setting Bundler.setup(:default) # only the default group Bundler.setup(:default, :test) # default and test Bundler.setup(:test) # test only - NOT default ``` The call is cached: once a no-argument `Bundler.setup` has run in a process, later calls return immediately. ## What `Bundler.require` does `Bundler.require(*groups)` is `Bundler.setup(*groups)` followed by requiring each dependency whose group matches (and whose platform matches the running Ruby). For every gem it requires: - the paths given by the Gemfile's `require:` option, when present; - nothing, when the option is `require: false`; - otherwise the gem's name, retrying with dashes turned into slashes on a `LoadError` for that path. With **no arguments it requires only `:default`**. That is the most common surprise: gems in a `:test` group are set up by a bare `Bundler.setup`, but a bare `Bundler.require` does not load them. Applications therefore pass the environment's group, as in `Bundler.require(:default, :test)` or a computed list. ## Side by side | | `require "bundler/setup"` | `Bundler.require` | |---|---|---| | Locked versions enforced | yes | yes (runs setup first) | | Default groups | all, minus `without` | `:default` only | | Gems loaded | none | every gem in the named groups | | Load order | yours, explicit | Gemfile order | | Boot cost | only what you require | everything in the groups | ## How the `without` setting interacts A group skipped at install time by the `without` setting is not installed, so a bare `Bundler.setup` leaves it out rather than failing on missing gems. Asking for it explicitly is different: - `Bundler.setup` with no arguments covers the requested groups: all groups, minus `without`, minus optional groups not named in `with`. Skipped groups are simply left out. - Naming a skipped group explicitly, as in `Bundler.setup(:test)` or `Bundler.require(:test)`, asks for gems that were never installed, and setup fails with Bundler reporting them as missing. - Code that never asks for the group and never requires its gems is unaffected. This is why production images that skip `development` and `test` boot fine with a bare setup and fail only if code asks for a test-only group or gem. ## Choosing between them - **Libraries, scripts and small Rack or Sinatra apps** usually call `require "bundler/setup"` and then require what they use. Load order is visible, and gems with load-time side effects are loaded only where intended. - **Frameworks that autoload the whole bundle** call `Bundler.require` with the current environment's groups, and use `require: false` in the Gemfile for gems that must not be loaded eagerly. - **Neither replaces** `require_relative` for your own files; Bundler handles gems only. ## Traps - Calling `Bundler.require(:test)` in a spec helper without an earlier setup of `:default`: only the test group is on the load path. - Expecting `require "bundler/setup"` to load gems; it never does. - Forgetting that `require: false` gems are still set up: an explicit `require` of them works.
- A spec helper calls `Bundler.require(:test)` first. Why does `require "sinatra"` then fail?Because `Bundler.require(:test)` runs `Bundler.setup(:test)`, which sets up only the test group, not `:default`. Sinatra's lib directory never reached the load path. Call `require "bundler/setup"` (all groups) first, or pass both groups: `Bundler.require(:default, :test)`.
- Can code call `Bundler.require` more than once?Yes. Once a no-argument `Bundler.setup` has run, later setup calls return the cached runtime, so `Bundler.require(:default)` at boot and `Bundler.require(:test)` later each just require their group's gems. Bundler's own documentation shows exactly that pattern.
saying these in an interview costs you the question
- require "bundler/setup" loads every gem in the Gemfile
- A bare Bundler.require loads the test and development groups too
- Bundler.setup(:test) also sets up the default group
- After Bundler.setup, gems outside the Gemfile can still be required if installed
- Bundler.require skips version checks because it only loads files