
Using IRB to Explore Ruby
IRB (Interactive Ruby) is Ruby’s built-in REPL (Read-Eval-Print Loop) that lets you execute Ruby code interactively, test snippets, debug applications, and explore Ruby features in real-time. It’s an essential tool for Ruby developers who need to prototype code, investigate object behavior, or debug issues without writing full scripts. This guide will show you how to leverage IRB effectively for exploration, debugging, and rapid development, including advanced configuration options and real-world workflows that can significantly speed up your Ruby development process.
How IRB Works Under the Hood
IRB operates as a simple loop that reads your input, evaluates it as Ruby code, prints the result, and waits for the next command. Behind the scenes, it uses Ruby’s built-in parsing and evaluation mechanisms through methods like eval
and maintains context between commands, allowing you to build upon previous statements.
The magic happens through Ruby’s introspection capabilities. IRB can access and display information about any Ruby object, method, or constant in your current session. It maintains a workspace that preserves variables, method definitions, and loaded libraries across commands.
# IRB maintains state across commands
irb(main):001:0> x = "Hello World"
=> "Hello World"
irb(main):002:0> x.upcase
=> "HELLO WORLD"
irb(main):003:0> x.methods.grep(/up/)
=> [:upcase, :upcase!]
Getting Started and Basic Configuration
Launch IRB from your terminal by simply typing irb
. For more advanced usage, you’ll want to customize your IRB environment through a .irbrc
file in your home directory:
# ~/.irbrc
require 'irb/completion'
require 'irb/ext/save-history'
IRB.conf[:SAVE_HISTORY] = 1000
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb_history"
IRB.conf[:AUTO_INDENT] = true
IRB.conf[:USE_READLINE] = true
IRB.conf[:LOAD_MODULES] = []
# Custom prompt
IRB.conf[:PROMPT_MODE] = :SIMPLE
# Useful aliases and helper methods
def clear
system('clear')
end
def pbcopy(input)
str = input.to_s
IO.popen('pbcopy', 'w') { |f| f << str }
str
end
You can also load specific gems or files automatically:
# Load commonly used gems
begin
require 'awesome_print'
IRB.conf[:USE_COLORIZE] = true
rescue LoadError
puts "awesome_print not available"
end
# Load project-specific files
if File.exist?('./.irbrc_local')
load './.irbrc_local'
end
Essential IRB Commands and Navigation
IRB provides several built-in commands that aren't immediately obvious to new users:
Command | Purpose | Example |
---|---|---|
help |
Show available commands | help |
show_source |
Display method source code | show_source String#upcase |
show_doc |
Show method documentation | show_doc Array#map |
ls |
List methods and variables | ls String |
cd |
Change context to an object | cd "hello" |
whereami |
Show current context | whereami |
hist |
Show command history | hist -n 10 |
Here's how to use these effectively:
# Explore an object's methods
irb(main):001:0> arr = [1, 2, 3]
=> [1, 2, 3]
irb(main):002:0> ls arr
Enumerable#methods:
all? any? chain chunk chunk_while collect
count cycle detect drop drop_while each_cons
# ... many more methods listed
# Change context to work directly with an object
irb(main):003:0> cd arr
irb(#):004:0> length
=> 3
irb(#):005:0> first
=> 1
Advanced Exploration Techniques
IRB really shines when you need to understand how Ruby objects work or debug complex issues. Here are some advanced techniques:
Object Introspection
# Investigate object hierarchy
irb(main):001:0> "hello".class
=> String
irb(main):002:0> "hello".class.ancestors
=> [String, Comparable, Object, Kernel, BasicObject]
# Find methods by pattern
irb(main):003:0> "hello".methods.grep(/case/)
=> [:upcase, :downcase, :swapcase, :upcase!, :downcase!, :swapcase!]
# Check method arity and parameters
irb(main):004:0> method(:puts).parameters
=> [[:rest, :args]]
irb(main):005:0> String.instance_method(:gsub).parameters
=> [[:req, :pattern], [:opt, :replacement], [:block, :block]]
Runtime Debugging and Monkey Patching
# Debug by adding temporary methods
irb(main):001:0> class Array
irb(main):002:1> def debug_map
irb(main):003:2> puts "Mapping over #{self.inspect}"
irb(main):004:2> map { |x| puts "Processing: #{x}"; yield(x) }
irb(main):005:2> end
irb(main):006:1> end
=> :debug_map
irb(main):007:0> [1, 2, 3].debug_map { |x| x * 2 }
Mapping over [1, 2, 3]
Processing: 1
Processing: 2
Processing: 3
=> [2, 4, 6]
Memory and Performance Investigation
# Check object memory usage
irb(main):001:0> require 'objspace'
=> true
irb(main):002:0> arr = Array.new(1000) { |i| "string_#{i}" }
irb(main):003:0> ObjectSpace.memsize_of(arr)
=> 8024
irb(main):004:0> ObjectSpace.count_objects[:T_STRING]
=> 2847
# Benchmark code snippets
irb(main):005:0> require 'benchmark'
=> true
irb(main):006:0> Benchmark.measure { 10000.times { "hello".upcase } }
=> #
Real-World Use Cases and Workflows
API Testing and Web Scraping
# Quick API testing
irb(main):001:0> require 'net/http'
irb(main):002:0> require 'json'
irb(main):003:0> uri = URI('https://api.github.com/users/octocat')
irb(main):004:0> response = Net::HTTP.get_response(uri)
irb(main):005:0> data = JSON.parse(response.body)
irb(main):006:0> data['public_repos']
=> 8
Database Query Development
# Rails console-style database interaction
irb(main):001:0> require 'sqlite3'
irb(main):002:0> db = SQLite3::Database.new('test.db')
irb(main):003:0> db.execute('CREATE TABLE IF NOT EXISTS users (id INTEGER, name TEXT)')
irb(main):004:0> db.execute('INSERT INTO users VALUES (1, "Alice")')
irb(main):005:0> db.execute('SELECT * FROM users')
=> [[1, "Alice"]]
File Processing and Text Manipulation
# Process files interactively
irb(main):001:0> lines = File.readlines('log.txt')
irb(main):002:0> errors = lines.select { |line| line.include?('ERROR') }
irb(main):003:0> error_counts = errors.group_by { |line| line.split(' ')[2] }
irb(main):004:0> error_counts.transform_values(&:count)
=> {"AuthenticationError"=>5, "DatabaseError"=>3}
Comparison with Alternative Tools
Tool | Pros | Cons | Best For |
---|---|---|---|
IRB | Built-in, simple, reliable | Basic features, limited syntax highlighting | Quick exploration, basic debugging |
Pry | Advanced debugging, syntax highlighting, plugins | Additional dependency, steeper learning curve | Complex debugging, development workflows |
Rails Console | Full Rails environment, ActiveRecord access | Rails-specific, heavyweight | Rails development and debugging |
ripper-tags + editor | IDE-like features, persistent sessions | Setup complexity, not interactive | Large codebases, refactoring |
Best Practices and Common Pitfalls
Performance Considerations
- Avoid loading large datasets directly into IRB variables - use iterators and lazy evaluation instead
- Use
GC.start
periodically during long sessions to manage memory - Be cautious with infinite loops - always have an exit strategy
- Use
system('clear')
or custom clear methods to manage screen clutter
Security Best Practices
- Never paste untrusted code directly into IRB, especially in production environments
- Be careful with file operations - IRB runs with your user permissions
- Avoid storing sensitive data in IRB history files
- Use IRB subsessions for testing potentially destructive operations
Common Pitfalls
# Pitfall 1: Forgetting return values
irb(main):001:0> x = [1, 2, 3].each { |i| puts i }
1
2
3
=> [1, 2, 3] # each returns the original array, not what you printed
# Better approach:
irb(main):002:0> x = [1, 2, 3].map { |i| i * 2 }
=> [2, 4, 6]
# Pitfall 2: Modifying constants
irb(main):003:0> MY_CONSTANT = "hello"
=> "hello"
irb(main):004:0> MY_CONSTANT = "world" # This generates a warning
(irb):4: warning: already initialized constant MY_CONSTANT
# Pitfall 3: Infinite recursion in custom inspect methods
class BadExample
def inspect
"BadExample: #{self.inspect}" # This will cause stack overflow
end
end
Advanced Configuration and Customization
For power users, IRB can be extensively customized. Here's an advanced .irbrc
configuration:
# Advanced .irbrc configuration
require 'irb/completion'
require 'irb/ext/save-history'
# History configuration
IRB.conf[:SAVE_HISTORY] = 10000
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb_history"
# Enhanced prompt with git branch info
IRB.conf[:PROMPT][:CUSTOM] = {
:PROMPT_I => "%N(%m):%03n:%i> ",
:PROMPT_N => "%N(%m):%03n:%i> ",
:PROMPT_S => "%N(%m):%03n:%i%l ",
:PROMPT_C => "%N(%m):%03n:%i* ",
:RETURN => "=> %s\n"
}
IRB.conf[:PROMPT_MODE] = :CUSTOM
# Auto-indenting and readline
IRB.conf[:AUTO_INDENT] = true
IRB.conf[:USE_READLINE] = true
# Load project-specific gems
if defined?(Bundler)
begin
Bundler.require(:default, :development)
rescue Bundler::GemNotFound
# Handle missing gems gracefully
end
end
# Useful helper methods
def time(&block)
start = Time.now
result = yield
puts "Execution time: #{Time.now - start} seconds"
result
end
def reload!(print = true)
puts "Reloading ..." if print
# Reload logic here
true
end
# Method to quickly inspect SQL queries (Rails-specific)
def sql(query)
ActiveRecord::Base.connection.execute(query).to_a if defined?(ActiveRecord)
end
For more advanced IRB usage and configuration options, check out the official Ruby documentation at https://ruby-doc.org/stdlib-3.0.0/libdoc/irb/rdoc/IRB.html and the Ruby community's IRB tips at https://github.com/ruby/irb.
Integration with Development Workflows
IRB becomes most powerful when integrated into your regular development workflow. Here are some practical integration strategies:
Debugging Integration
# Add binding.irb calls for runtime debugging
def complex_calculation(data)
processed = data.map(&:to_i)
binding.irb if ENV['DEBUG'] # Drop into IRB when DEBUG=1
result = processed.sum / processed.length
result
end
Testing and Prototyping
# Use IRB to prototype before writing tests
irb(main):001:0> def fibonacci(n)
irb(main):002:1> return n if n <= 1
irb(main):003:1> fibonacci(n-1) + fibonacci(n-2)
irb(main):004:1> end
=> :fibonacci
irb(main):005:0> (0..10).map { |i| fibonacci(i) }
=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
# Once satisfied, convert to proper test
# Copy the working code to your test file
IRB remains one of the most underutilized yet powerful tools in the Ruby ecosystem. Whether you're debugging production issues, exploring new gems, or prototyping algorithms, mastering IRB will significantly enhance your Ruby development productivity. The key is to make it part of your daily workflow rather than just an occasional debugging tool.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.