CrackedRuby logo

CrackedRuby

REPL Configuration

Overview

REPL Configuration in Ruby centers on customizing the Interactive Ruby (IRB) environment and alternative REPLs like Pry. Ruby's standard IRB provides extensive configuration options through initialization files, runtime settings, and programmatic configuration APIs. The configuration system controls prompt appearance, command history, auto-completion behavior, output formatting, and workspace context.

IRB reads configuration from .irbrc files located in the user's home directory or current working directory. The configuration system uses Ruby code directly, allowing complex customization logic and integration with external gems. Configuration affects the IRB::Context object that manages each REPL session's state, workspace, and behavior.

# Basic .irbrc configuration
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.conf[:SAVE_HISTORY] = 1000
IRB.conf[:AUTO_INDENT] = true

The configuration system operates through the IRB.conf hash, which stores all settings as key-value pairs. Changes to this hash immediately affect the current session and persist for future sessions when saved in configuration files. The system supports nested configuration objects for complex features like custom prompts and workspace isolation.

# Accessing configuration programmatically
current_config = IRB.conf
puts current_config[:PROMPT_MODE]
# => :DEFAULT

Ruby also supports per-directory configuration through .irbrc files in project directories, allowing project-specific REPL environments. The configuration loading order follows a hierarchy: system-wide settings, user home directory settings, then local directory settings, with later configurations overriding earlier ones.

Basic Usage

IRB configuration begins with the .irbrc file, which Ruby executes as normal Ruby code during IRB startup. The most common configurations involve prompt customization, history management, and basic feature toggles.

# ~/.irbrc - Basic configuration
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.conf[:SAVE_HISTORY] = 2000
IRB.conf[:HISTORY_FILE] = File.expand_path('~/.irb_history')
IRB.conf[:AUTO_INDENT] = true
IRB.conf[:USE_READLINE] = true

Prompt configuration accepts several predefined modes or custom prompt definitions. The :SIMPLE mode removes line numbers and reduces visual clutter, while :DEFAULT provides full context information including nesting level and continuation indicators.

# Custom prompt configuration
IRB.conf[:PROMPT][:CUSTOM] = {
  :PROMPT_I => "ruby> ",           # Normal prompt
  :PROMPT_S => "ruby* ",           # String continuation
  :PROMPT_C => "ruby? ",           # Expression continuation  
  :PROMPT_N => "ruby+ ",           # Nested level indicator
  :RETURN => "=> %s\n"             # Return value format
}
IRB.conf[:PROMPT_MODE] = :CUSTOM

History configuration controls command persistence between sessions. The SAVE_HISTORY setting determines how many commands to store, while HISTORY_FILE specifies the storage location. Setting SAVE_HISTORY to nil disables history persistence entirely.

# History configuration options
IRB.conf[:SAVE_HISTORY] = 5000
IRB.conf[:HISTORY_FILE] = '/tmp/irb_history'
IRB.conf[:EVAL_HISTORY] = 100  # Number of results to store

Auto-completion behavior controls how IRB responds to tab key presses. The system supports method name completion, constant completion, and filename completion depending on the context. Disabling readline removes completion functionality but improves compatibility with some terminal environments.

# Completion and editing configuration
IRB.conf[:USE_READLINE] = true
IRB.conf[:USE_TRACER] = false
IRB.conf[:IGNORE_SIGINT] = false
IRB.conf[:IGNORE_EOF] = false

IRB supports workspace isolation through context configuration. Each IRB session operates within a specific binding context, which determines variable accessibility and method resolution. The default context uses the main object, but custom contexts allow sandbox environments and isolated evaluation spaces.

Advanced Usage

Advanced REPL configuration involves custom command definition, startup hooks, output formatting customization, and integration with external tools. These configurations enable sophisticated development workflows and personalized debugging environments.

Custom commands extend IRB functionality beyond Ruby evaluation. Commands register through the IRB::ExtendCommandBundle module and appear as methods within the REPL session. Command definitions support parameters, help text, and complex logic integration.

# Custom command definition in .irbrc
module IRB::ExtendCommandBundle
  def time_eval(statement)
    start_time = Time.now
    result = eval(statement)
    elapsed = Time.now - start_time
    puts "Execution time: #{elapsed.round(4)}s"
    result
  end
end

# Usage: time_eval "sleep 1; 42"

Startup hooks execute arbitrary Ruby code during IRB initialization, enabling environment preparation, gem loading, and utility method definition. Hooks run after basic configuration but before the interactive prompt appears, providing a clean setup phase for complex environments.

# Startup hooks and environment setup
if defined?(IRB)
  # Load development gems automatically
  begin
    require 'awesome_print'
    IRB.conf[:USE_COLORIZE] = true
  rescue LoadError
    puts "awesome_print not available"
  end
  
  # Define utility methods
  def reload!
    load __FILE__ if __FILE__ && File.exist?(__FILE__)
  end
  
  def clear
    system 'clear'
  end
end

Output formatting controls how IRB displays evaluation results and error messages. Custom formatting functions receive the result object and context information, enabling specialized display logic for different data types.

# Custom output formatting
IRB.conf[:USE_COLORIZE] = true
class << IRB.conf[:MAIN_CONTEXT].io
  alias_method :original_puts, :puts
  
  def puts(*args)
    args.each do |arg|
      case arg
      when Hash
        original_puts JSON.pretty_generate(arg)
      when Array
        original_puts arg.inspect
      else
        original_puts arg
      end
    end
  end
end

Workspace configuration enables multiple isolated REPL environments within a single session. Each workspace maintains separate variable bindings, method definitions, and context state. This isolation supports testing different code versions and managing complex debugging scenarios.

# Workspace isolation and context management
class CustomWorkspace < IRB::WorkSpace
  def initialize(binding = TOPLEVEL_BINDING, name = "custom")
    super(binding)
    @workspace_name = name
  end
  
  def code_around_binding
    if @binding && @binding.respond_to?(:source_location)
      location = @binding.source_location
      "#{@workspace_name}: #{location&.join(':') || 'unknown'}"
    else
      @workspace_name
    end
  end
end

# Switch to custom workspace
IRB.conf[:MAIN_CONTEXT].workspace = CustomWorkspace.new(binding, "debug")

Integration with external tools requires careful configuration management and gem compatibility considerations. Popular gems like Pry, awesome_print, and hirb provide enhanced REPL experiences but may conflict with custom configurations or modify default behavior unexpectedly.

# External tool integration
if defined?(Pry)
  # Pry configuration fallback
  Pry.config.editor = ENV['EDITOR'] || 'vim'
  Pry.config.history_file = File.expand_path('~/.pry_history')
elsif defined?(IRB)
  # IRB-specific enhancements
  IRB.conf[:USE_COLORIZE] = true
  IRB.conf[:COMPLETOR] = :type if IRB::VERSION >= "1.4.0"
end

Common Pitfalls

REPL configuration involves several subtle issues around initialization timing, file loading order, and feature compatibility. These problems often manifest as silent failures or unexpected behavior that can be difficult to diagnose.

Configuration file loading follows a specific order that can cause settings to be overwritten unexpectedly. IRB loads system-wide configuration first, then user home directory .irbrc, and finally local directory .irbrc files. Later configurations completely replace earlier settings rather than merging them, which can eliminate carefully crafted customizations.

# Problem: Local .irbrc overwrites all previous configuration
# Home ~/.irbrc
IRB.conf[:SAVE_HISTORY] = 5000
IRB.conf[:PROMPT_MODE] = :CUSTOM
IRB.conf[:AUTO_INDENT] = true

# Project .irbrc (overwrites everything above)
IRB.conf[:PROMPT_MODE] = :SIMPLE  # Only this setting remains active

# Solution: Preserve existing settings
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.conf[:SAVE_HISTORY] ||= 1000  # Preserve if already set

Prompt customization requires understanding IRB's internal state machine and continuation handling. Custom prompts that don't properly handle all prompt types cause display corruption or missing indicators for nested expressions and string continuations.

# Problematic prompt configuration
IRB.conf[:PROMPT][:BROKEN] = {
  :PROMPT_I => "> ",     # Missing other prompt types
  :RETURN => "=> %s\n"
}

# Complete prompt configuration
IRB.conf[:PROMPT][:COMPLETE] = {
  :PROMPT_I => "ruby> ",        # Normal input
  :PROMPT_S => "ruby* ",        # String continuation  
  :PROMPT_C => "ruby? ",        # Command continuation
  :PROMPT_N => "ruby+ ",        # Nested prompt
  :RETURN => "=> %s\n",         # Return value display
  :AUTO_INDENT => true          # Maintain indentation
}

History file permissions and location issues cause silent history loss. IRB attempts to write history files without error handling, leading to situations where commands appear to be saved during the session but disappear after restart due to write permission failures or invalid file paths.

# Problematic history configuration
IRB.conf[:HISTORY_FILE] = "/root/.irb_history"  # Permission denied
IRB.conf[:SAVE_HISTORY] = 1000

# Robust history configuration with error handling
history_dir = File.expand_path("~/.config/irb")
Dir.mkdir(history_dir) unless Dir.exist?(history_dir)
history_file = File.join(history_dir, "history")

if File.writable?(File.dirname(history_file))
  IRB.conf[:HISTORY_FILE] = history_file
  IRB.conf[:SAVE_HISTORY] = 1000
else
  warn "Cannot write to #{history_file}, history disabled"
  IRB.conf[:SAVE_HISTORY] = nil
end

Gem integration conflicts arise when multiple gems attempt to modify the same IRB configuration settings or when gems make assumptions about default configuration values. These conflicts often result in features being disabled or error messages during startup.

# Conflict between gems modifying the same setting
# Gem A sets:
IRB.conf[:USE_READLINE] = false

# Gem B expects:
if IRB.conf[:USE_READLINE]
  # This code never executes due to Gem A
  setup_completion_features
end

# Defensive configuration approach
original_readline = IRB.conf[:USE_READLINE]
require 'problematic_gem'
IRB.conf[:USE_READLINE] = original_readline if original_readline

Custom command definition scope issues occur when commands reference variables or methods that aren't available in the IRB evaluation context. Commands defined in the configuration file context may not have access to the current session's variables or workspace methods.

# Problem: Command references unavailable variable
my_config = { debug: true }
module IRB::ExtendCommandBundle
  def debug_info
    puts my_config[:debug]  # my_config not available here
  end
end

# Solution: Use instance variables or configuration storage
module IRB::ExtendCommandBundle
  def debug_info
    config = IRB.conf[:CUSTOM_CONFIG] ||= { debug: true }
    puts config[:debug]
  end
end
IRB.conf[:CUSTOM_CONFIG] = { debug: true }

Reference

Core Configuration Keys

Setting Type Default Description
:PROMPT_MODE Symbol :DEFAULT Active prompt style identifier
:SAVE_HISTORY Integer/nil 1000 Number of commands to persist
:HISTORY_FILE String ~/.irb_history History storage file path
:AUTO_INDENT Boolean true Enable automatic indentation
:USE_READLINE Boolean true Enable readline library features
:USE_COLORIZE Boolean true Enable syntax highlighting
:EVAL_HISTORY Integer nil Number of results to remember
:IGNORE_SIGINT Boolean true Handle Ctrl+C gracefully
:IGNORE_EOF Boolean false Handle Ctrl+D behavior
:ECHO Boolean true Display evaluation results

Prompt Configuration Structure

Key Purpose Example
:PROMPT_I Normal input prompt "irb> "
:PROMPT_S String continuation "irb* "
:PROMPT_C Command continuation "irb? "
:PROMPT_N Nested level indicator "irb+ "
:RETURN Result display format "=> %s\n"
:AUTO_INDENT Indentation behavior true

Predefined Prompt Modes

Mode Characteristics Use Case
:DEFAULT Full context with line numbers Development debugging
:SIMPLE Clean minimal prompts Production console work
:CLASSIC Traditional IRB appearance Legacy compatibility
:NULL No prompts displayed Automated scripting
:XMP Example mode formatting Documentation generation

Configuration File Locations

Priority Location Usage
1 /etc/irbrc System-wide defaults
2 ~/.irbrc User personal settings
3 ./.irbrc Project-specific configuration
4 $IRBRC Environment variable path

Context Configuration Methods

Method Parameters Returns Description
IRB.conf[:MAIN_CONTEXT].workspace WorkSpace object WorkSpace Current evaluation binding
IRB.conf[:MAIN_CONTEXT].io IO object IO Input/output stream handler
IRB.conf[:MAIN_CONTEXT].echo? None Boolean Result display status
IRB.conf[:MAIN_CONTEXT].inspect? None Boolean Object inspection mode

Custom Command Definition

# Command registration pattern
module IRB::ExtendCommandBundle
  def command_name(parameters = nil)
    # Command implementation
    result
  end
end

# Required method signature for help system
def help_message_for_command_name
  "Description of command functionality"
end

Error Handling Constants

Constant Value Usage
IRB::Abort Exception class Graceful session termination
IRB::CantChangeBinding Exception class Workspace modification errors
IRB::CantShiftToMultiIrbMode Exception class Multi-session failures

Environment Variables

Variable Effect Default
IRBRC Configuration file path ~/.irbrc
IRB_USE_READLINE Force readline usage Auto-detect
IRB_LANG Locale for messages System locale

Version Compatibility Matrix

Feature IRB 1.0+ IRB 1.3+ IRB 1.4+
Type completion
Multi-line editing
Syntax highlighting
Custom completor

Configuration Validation

# Validate configuration integrity
def validate_irb_config
  required_keys = [:PROMPT_MODE, :SAVE_HISTORY, :AUTO_INDENT]
  missing = required_keys.reject { |key| IRB.conf.key?(key) }
  warn "Missing configuration: #{missing}" unless missing.empty?
  
  # Validate file permissions
  if IRB.conf[:HISTORY_FILE] && !File.writable?(File.dirname(IRB.conf[:HISTORY_FILE]))
    warn "History file not writable: #{IRB.conf[:HISTORY_FILE]}"
  end
end