Question
I have a Rakefile that builds a project in two different ways based on the global variable $build_type, which can be either :debug or :release. Each build writes its output to a separate directory.
task :build => [:some_other_tasks] do
# build logic here
end
I want to create another task that builds the project in both configurations, one after the other, something like this:
task :build_all do
[:debug, :release].each do |t|
$build_type = t
# run :build together with all of its prerequisite tasks
end
end
Is there a way to call a Rake task from inside another task as if it were a method? If not, how can I achieve similar behavior correctly in Rake?
Short Answer
By the end of this page, you will understand how Rake tasks can call other tasks, how invoke works, why tasks usually run only once, and how reenable lets you run the same task multiple times in a loop. You will also see cleaner alternatives, such as extracting shared build logic into plain Ruby methods or using task arguments instead of global variables.
Concept
Rake tasks are not ordinary Ruby methods, but they can be triggered programmatically from inside other tasks.
The key idea is that a Rake task is an object managed by Rake's task system. You usually run tasks from the command line:
rake build
But inside a Rakefile, you can also look up a task and execute it:
Rake::Task["build"].invoke
Important behavior: tasks run only once by default
This is the part that surprises many beginners.
When you call:
Rake::Task["build"].invoke
Rake remembers that build has already run. If you call invoke again later in the same process, it will not run a second time unless you reset it with:
Rake::Task["build"].reenable
This matters a lot in your case because you want to run the same build task twice:
Mental Model
Think of a Rake task like a checklist item in a build system.
- A Ruby method is like a function you can call whenever you want.
- A Rake task is more like a named job on a project board.
When Rake completes a job, it marks it as done. If you ask for it again, Rake says, “That one already ran.”
If you really want to run it again, you must explicitly clear that done-state with reenable.
So the flow is:
- Set the build mode
- Tell Rake to run the
buildjob - Reset the
buildjob - Set the next build mode
- Run it again
That is why Rake tasks are similar to methods in some ways, but not identical.
Syntax and Examples
The core API for running tasks from other tasks is:
Rake::Task["task_name"].invoke
If you want to run the same task again in the same process:
Rake::Task["task_name"].reenable
Rake::Task["task_name"].invoke
Basic example
task :hello do
puts "Hello from :hello"
end
task :greet do
Rake::Task["hello"].invoke
end
Running:
rake greet
will print:
Hello from :hello
Running a task multiple times
task
puts
task
[, ].each ||
= type
[].reenable
[].invoke
Step by Step Execution
Consider this example:
task :prepare do
puts "Preparing files"
end
task :build => [:prepare] do
puts "Building #{$build_type}"
end
task :build_all do
[:debug, :release].each do |type|
$build_type = type
Rake::Task["build"].reenable
Rake::Task["build"].invoke
end
end
If you run:
rake build_all
here is what happens.
First iteration: :debug
$build_type = :debug
Now the global variable holds :debug.
Real World Use Cases
Running tasks from other tasks is common in automation and build systems.
Building multiple variants
For example:
- debug and release builds
- staging and production assets
- desktop and mobile bundles
Database workflows
A task may orchestrate several smaller tasks:
- create database
- load schema
- seed sample data
- run checks
CI/CD pipelines
A top-level task might run:
- lint
- test
- package
- deploy
Data processing
A batch task may process several input modes:
task :process_all do
[:csv, :json, :xml].each do |format|
# run processing task for each format
end
end
Project setup scripts
A setup task might trigger tasks for:
- installing dependencies
- generating config files
- compiling assets
- preparing local data
These are all examples of Rake acting as a task orchestrator.
Real Codebase Usage
In real projects, developers often use Rake tasks as thin wrappers around reusable Ruby code.
Common pattern: orchestration in Rake, logic in methods/classes
def compile_project(type)
puts "Compiling #{type} build"
# real build steps
end
task :build_debug do
compile_project(:debug)
end
task :build_release do
compile_project(:release)
end
task :build_all do
compile_project(:debug)
compile_project(:release)
end
This is easier to test and avoids hidden global state.
Guard clauses and validation
Developers often validate inputs before running work:
def compile_project(type)
unless [:debug, :release].include?(type)
raise ArgumentError, "Unknown build type: #{type}"
end
puts
Common Mistakes
1. Assuming invoke behaves like a normal method call
Beginners often expect this to run every time:
Rake::Task["build"].invoke
Rake::Task["build"].invoke
But the second call usually does nothing.
Fix
Use reenable before invoking again:
Rake::Task["build"].reenable
Rake::Task["build"].invoke
2. Forgetting that prerequisites may also need re-enabling
Broken expectation:
task :prepare do
puts "Preparing"
end
task :build => [:prepare] do
puts "Building"
end
If build is reenabled and invoked again, may still not rerun.
Comparisons
| Approach | How it works | Good for | Drawbacks |
|---|---|---|---|
Rake::Task["build"].invoke | Runs a named task and its prerequisites | Triggering one task from another | Runs only once unless reenabled |
reenable + invoke | Resets the task, then runs it again | Repeating the same task in a loop | Easy to forget prerequisites may also need reset |
| Plain Ruby method | Extract logic into def build_project(type) | Reusable logic, easy testing | Not automatically part of Rake dependency graph |
| Separate tasks | build:debug, build:release, build:all | Clear build targets |
Cheat Sheet
# Run another task
Rake::Task["build"].invoke
# Allow a task to run again
Rake::Task["build"].reenable
# Run it again after re-enabling
Rake::Task["build"].invoke
Rules to remember
- A Rake task is not the same as a Ruby method.
- Use
Rake::Task["name"].invoketo run a task from another task. invokeruns prerequisites too.- A task normally runs only once per process.
- Use
reenableif you need to run it again. - If prerequisites must rerun too, reenable them as well.
Common pattern
task :build_all do
[:debug, :release].each do |type|
$build_type = type
Rake::Task["build"].reenable
Rake[].invoke
FAQ
Can one Rake task call another?
Yes. Use:
Rake::Task["task_name"].invoke
Why does my Rake task only run once inside a loop?
Because invoke marks the task as already executed. Later calls in the same process do nothing unless you call reenable first.
How do I run the same Rake task twice?
Use:
Rake::Task["build"].reenable
Rake::Task["build"].invoke
Does invoke also run prerequisite tasks?
Yes. That is one reason it is usually preferred over execute.
Should I use a global variable like $build_type?
You can, but it is often better to use task arguments, environment variables, or a plain Ruby method with parameters.
What is the difference between a Rake task and a Ruby method?
A Ruby method is normal executable code you can call directly. A Rake task is a named automation unit managed by Rake, with prerequisite handling and run-once behavior.
Mini Project
Description
Create a small Rake-based build script that generates two output files: one for a debug build and one for a release build. This project demonstrates how to run one task from another, how prerequisites work, and why reenable is needed when the same task must run more than once.
Goal
Build both debug and release outputs from a single build_all task using proper Rake task invocation.
Requirements
- Create a
preparetask that ensures an output directory exists. - Create a
buildtask that writes a file based on the current build type. - Create a
build_alltask that runs the build twice: once for:debugand once for:release. - Ensure the build task can run multiple times in one execution.
- Make the generated files easy to verify after running the task.
Keep learning
Related questions
Calling a Class Method from an Instance in Ruby
Learn how to call a class method from an instance in Ruby using self.class, with examples, pitfalls, and practical usage patterns.
Calling an Overridden Monkey-Patched Method in Ruby
Learn how to call the original method when monkey patching in Ruby, including alias_method patterns, examples, pitfalls, and practical usage.
Convert a Unix Timestamp to Ruby DateTime
Learn how to convert Unix timestamps to Ruby DateTime and Time objects, with examples, differences, pitfalls, and practical Ruby usage.