OptionParser

Part of Ruby's standard library, making it a readily available and simple choice for basic argument parsing tasks.

rubyclicommand-linestdlib

Framework

OptionParser

Overview

OptionParser is part of Ruby's standard library, making it a readily available and simple choice for basic command-line argument parsing tasks. As a standard library, it continues to be used in simple scripts as it can be used without additional dependencies. It has a low learning curve and is suitable for basic Ruby CLI tool development.

Details

OptionParser is a command-line argument parsing library included with Ruby by default. It can be used without adding external gems and provides basic option parsing functionality. With its simple API and lightweight implementation, it's suitable for developing small CLI tools.

Key Features

  • Standard Library: No additional gem installation required
  • Lightweight: Minimal overhead
  • Basic Functionality: Sufficient option parsing features
  • Automatic Help Generation: Automatic help message generation
  • Type Conversion: Automatic conversion to strings, numbers, arrays
  • Validation: Basic value validation
  • Short/Long Form: Supports both -v and --verbose

Pros and Cons

Pros

  • No Dependencies: No additional installation required as standard library
  • Low Learning Curve: Simple and easy-to-understand API
  • Lightweight: Low memory usage and performance overhead
  • Stability: Long-term support as Ruby standard library
  • Sufficient Features: Adequate for basic CLI tools

Cons

  • Feature Limitations: Advanced features are inferior to other libraries
  • No Subcommand Support: Not suitable for complex CLI structures
  • Limited Extensibility: Limited customization capabilities
  • Not Modern: Doesn't support latest CLI design patterns

Key Links

Usage Examples

Basic Usage

#!/usr/bin/env ruby

require 'optparse'

# Hash to store options
options = {}

# Create OptionParser instance
opt_parser = OptionParser.new do |opts|
  opts.banner = "Usage: #{$0} [options] file"

  # String option
  opts.on('-n', '--name NAME', 'Specify name') do |name|
    options[:name] = name
  end

  # Numeric option
  opts.on('-c', '--count COUNT', Integer, 'Repeat count') do |count|
    options[:count] = count
  end

  # Flag option
  opts.on('-v', '--verbose', 'Verbose output') do
    options[:verbose] = true
  end

  # Help option
  opts.on('-h', '--help', 'Show help') do
    puts opts
    exit
  end
end

# Parse arguments
begin
  opt_parser.parse!(ARGV)
rescue OptionParser::InvalidOption => e
  puts "Error: #{e.message}"
  puts opt_parser
  exit 1
end

# Remaining arguments (like filenames)
files = ARGV

# Use options
name = options[:name] || 'World'
count = options[:count] || 1
verbose = options[:verbose]

# Execute
count.times do |i|
  puts "Hello, #{name}!"
  puts "Execution count: #{i + 1}" if verbose
end

if files.any?
  puts "Processing files: #{files.join(', ')}"
end

Advanced Example

#!/usr/bin/env ruby

require 'optparse'
require 'ostruct'

# Object to store options
options = OpenStruct.new
options.verbose = false
options.format = 'txt'
options.output = nil
options.force = false

opt_parser = OptionParser.new do |opts|
  opts.banner = "File Processing Tool v1.0\nUsage: #{$0} [options] input_files..."

  opts.separator ""
  opts.separator "Basic options:"

  # Required option (checked later)
  opts.on('-o', '--output FILE', 'Output filename') do |output|
    options.output = output
  end

  # Choice selection
  opts.on('-f', '--format FORMAT', %w[txt csv json xml], 
          'Output format (txt, csv, json, xml)') do |format|
    options.format = format
  end

  # Numeric range
  opts.on('-l', '--limit LIMIT', Integer, 'Processing limit (1-1000)') do |limit|
    if limit < 1 || limit > 1000
      raise OptionParser::InvalidArgument, "Limit must be in range 1-1000"
    end
    options.limit = limit
  end

  # Array option
  opts.on('-t', '--tags TAG1,TAG2,TAG3', Array, 'Tag list (comma-separated)') do |tags|
    options.tags = tags
  end

  # Regex option
  opts.on('-p', '--pattern REGEX', Regexp, 'Filter pattern (regex)') do |pattern|
    options.pattern = pattern
  end

  opts.separator ""
  opts.separator "Flag options:"

  opts.on('-v', '--verbose', 'Verbose output') do
    options.verbose = true
  end

  opts.on('-q', '--quiet', 'Quiet mode') do
    options.quiet = true
  end

  opts.on('--force', 'Force execution') do
    options.force = true
  end

  opts.on('--dry-run', 'Don\'t actually execute') do
    options.dry_run = true
  end

  opts.separator ""
  opts.separator "Other:"

  opts.on_tail('-h', '--help', 'Show this help') do
    puts opts
    exit
  end

  opts.on_tail('--version', 'Show version') do
    puts "File Processing Tool v1.0"
    exit
  end
end

# Parse arguments and handle errors
begin
  opt_parser.parse!(ARGV)
rescue OptionParser::InvalidOption => e
  STDERR.puts "Error: #{e.message}"
  STDERR.puts opt_parser
  exit 1
rescue OptionParser::InvalidArgument => e
  STDERR.puts "Error: #{e.message}"
  exit 1
end

# Check required parameters
if ARGV.empty?
  STDERR.puts "Error: No input files specified"
  STDERR.puts opt_parser
  exit 1
end

# Check mutually exclusive options
if options.verbose && options.quiet
  STDERR.puts "Error: --verbose and --quiet cannot be specified together"
  exit 1
end

# Display configuration
unless options.quiet
  puts "Processing configuration:"
  puts "  Input files: #{ARGV.join(', ')}"
  puts "  Output file: #{options.output || 'stdout'}"
  puts "  Output format: #{options.format}"
  puts "  Limit: #{options.limit || 'unlimited'}"
  puts "  Tags: #{options.tags&.join(', ') || 'none'}"
  puts "  Pattern: #{options.pattern || 'none'}"
  puts "  Verbose output: #{options.verbose ? 'yes' : 'no'}"
  puts "  Dry run: #{options.dry_run ? 'yes' : 'no'}"
  puts
end

# Execute file processing
ARGV.each do |input_file|
  unless File.exist?(input_file)
    STDERR.puts "Warning: File not found: #{input_file}"
    next
  end

  puts "Processing: #{input_file}" if options.verbose

  # File processing simulation
  unless options.dry_run
    lines = File.readlines(input_file)
    
    # Pattern filtering
    if options.pattern
      lines = lines.select { |line| line.match?(options.pattern) }
    end

    # Apply limit
    if options.limit
      lines = lines.first(options.limit)
    end

    # Output processing
    output_content = case options.format
                     when 'csv'
                       lines.map { |line| "\"#{line.chomp}\"" }.join(",\n")
                     when 'json'
                       require 'json'
                       lines.map(&:chomp).to_json
                     when 'xml'
                       "<lines>\n" + lines.map { |line| "  <line>#{line.chomp}</line>" }.join("\n") + "\n</lines>"
                     else
                       lines.join
                     end

    # Output
    if options.output
      File.write(options.output, output_content)
      puts "Output complete: #{options.output}" unless options.quiet
    else
      puts output_content
    end
  end
end

puts "Processing complete" unless options.quiet

Execution Examples

# Basic usage
ruby script.rb --name "Ruby" --count 3 --verbose file1.txt file2.txt

# With configuration file
ruby configurable_app.rb --config config.yml --port 9000

# Validation example
ruby validated_app.rb --email test@example.com --url https://example.com --number 50