skip to content

How do you pass arguments to a Rake task, as in rake bump[1.4.0], and how does that differ from NAME=value on the rake command line?

level: middleimportance: should knowfreq 45%

answer

  1. task :bump, [:version] => :prereq
  2. block gets |t, args|
  3. values arrive as Strings or nil
  4. with_defaults and extras
  5. NAME=value goes into ENV

basics

~20 s

Declare argument names after the task name, task :bump, [:version] do |t, args|, and pass values as rake bump[1.4.0]; they arrive as Strings, missing ones as nil. rake bump VERSION=1.4.0 instead sets ENV["VERSION"] for the whole run.

solid answer

~40 s

`task :bump, [:version, :note] => :clean do |t, args|` names the arguments, and prerequisites move after them with `=>`. On the command line `rake bump[1.4.0]` fills them positionally; the whole `name[args]` must be one shell word, so write `rake "bump[1.4.0,security fix]"` for spaces, and quote brackets in shells such as zsh that treat them as a glob. Inside the block `args[:version]` or `args.version` return a **String**, or `nil` when omitted; `args.with_defaults(note: "maintenance")` fills gaps, `args.fetch(:version)` raises `KeyError` when missing, and `args.extras` holds surplus values. A prerequisite that declares an argument with the same name receives it too. By contrast `rake bump VERSION=1.4.0` is parsed by Rake as an environment assignment: it sets `ENV["VERSION"]` for every task and any subprocess.

code

ruby · 11 lines
ruby
desc "Write a new version number"
task :bump, [:version, :note] => :clean do |t, args|
  args.with_defaults(note: "maintenance release")
  version = args.fetch(:version) { abort "usage: rake bump[1.4.0]" }
  File.write("VERSION", version)
  puts "#{t.name}: #{version} (#{args.note})"
end

task :clean do
  rm_rf "pkg"
end

go deeper

for a junior

Declare a task with an argument array and call it as rake name[value].

for a middle

Explain String values, nil for missing arguments, with_defaults, fetch and extras, and the shell quoting rules.

for a senior

Choose between task arguments and ENV deliberately: per-task, self-documenting input versus global settings that leak into subprocesses.

for a principal

Standardise how release and maintenance tasks take input so they are scriptable in CI and hard to misuse by hand.

## Two ways to pass data to a task Rake tasks often need input — a version number, a target environment. Rake supports two mechanisms, and they behave differently. ## Task arguments Declare argument names in an array after the task name: - `task :bump, [:version] do |t, args| ... end` - with prerequisites: `task :bump, [:version, :note] => :clean do |t, args| ... end` The block's second parameter is a **`Rake::TaskArguments`** object: | Call | Returns | |---|---| | `args[:version]` / `args.version` | the value as a **String**, or `nil` if not given | | `args.fetch(:version)` | the value, or raises `KeyError` when absent | | `args.with_defaults(note: "maintenance")` | fills only the arguments that were not given | | `args.extras` | values beyond the declared names, as an Array | | `args.to_a` | all values in order | | `args.to_hash` | the named values as a Hash | Things that trip people up: - **Everything is a String.** `rake split[3]` gives `"3"`; convert with `Integer(args[:parts])`. - **Empty values count as missing.** `rake bump[,note]` leaves `version` unset rather than `""`. - **Old-style `:needs`** declarations are still supported for compatibility but not recommended by Rake's documentation; use the `=>` form. ## Command-line syntax Arguments are attached to the task name in square brackets, comma-separated: 1. `rake bump[1.4.0]` — one argument. 2. `rake "bump[1.4.0,security fix]"` — quotes, because the task name and its arguments must reach Rake as **one** shell word. 3. In zsh, unquoted brackets are a glob pattern and fail with a no-match error, so quoting is a good habit everywhere. 4. A comma inside a value is escaped with a backslash: `rake "note[a\,b]"`. Arguments also flow to prerequisites: when `bump` invokes `clean`, and `clean` declares an argument called `version`, it receives the same value. ## NAME=value: environment variables Rake scans its command line for words shaped like `NAME=value` and assigns them to **`ENV`** before running anything: - `rake bump VERSION=1.4.0` sets `ENV["VERSION"] = "1.4.0"`; - the value is visible to **every** task in the run and to any subprocess started with `sh`; - it works in any position on the line and needs no declaration. ## Which to use | Need | Better choice | |---|---| | Input that belongs to one task and should appear in `rake -T` (`rake bump[version,note]`) | task arguments | | A setting several tasks or child processes read (`CI=true`, `GEM_HOST=...`) | `NAME=value` / `ENV` | | A required value with a clear error | `args.fetch(:version)` or an explicit `abort` | Task arguments are self-documenting — `rake -T` prints `rake bump[version,note]` — while environment variables are global and invisible in the listing.

  • Why does args[:parts] + 1 raise TypeError in rake split[3]?
    Task arguments come from the command line and are always Strings, so `args[:parts]` is `"3"` and `"3" + 1` raises `TypeError` (no implicit conversion of Integer into String). Convert explicitly, for example `Integer(args[:parts])`, which also rejects non-numeric input.
  • In rake bump[1.4.0], can a prerequisite task see the version argument?
    Yes, if the prerequisite declares an argument with the same name. Rake builds a new argument scope for each prerequisite from its own argument names, looking values up in the caller's arguments, so `task :clean, [:version]` receives `"1.4.0"`. A prerequisite that declares no arguments gets none.

saying these in an interview costs you the question

  • rake bump[1.4.0] passes 1.4.0 as a Float or Integer.
  • A missing task argument raises an error instead of returning nil.
  • rake bump VERSION=1.4.0 fills the task's first declared argument.
  • Spaces inside brackets work without quoting the task name.
  • with_defaults overwrites values the user passed on the command line.