ArgumentParser
OptionParser's missing sibling.
Parse command line arguments with like you parse options with OptionParser.
Installation
Add this line to your application's Gemfile:
gem 'argument_parser'And then execute:
$ bundle install
Or install it yourself as:
$ gem install argument_parser
Usage
ArgumentParser provides two ways to define argument schemas:
Method Chaining API
# Define a parser with required arguments
parser = ArgumentParser.schema
.required(:command)
.required(:target)
.build
args = parser.parse!(["deploy", "production"])
# => { command: "deploy", target: "production" }Builder Block API
# Define a parser using a builder block
parser = ArgumentParser.build do
required :command
required :target
end
args = parser.parse!(["deploy", "production"])
# => { command: "deploy", target: "production" }Argument Types
ArgumentParser supports three types of arguments that must be defined in a
specific order:
- Required - Must be present, consumed in order. Can't appear after optional or rest arguments.
- Optional - May be present. Only one allowed. Can't appear after rest arguments.
- Rest - Captures remaining arguments as an array. Can only appear once, at the end.
Order Requirements
Arguments must be defined in this exact order: required → optional → rest
# ✅ Valid: required followed by optional
ArgumentParser.schema.required(:cmd).optional(:env).build
# ✅ Valid: required followed by rest
ArgumentParser.schema.required(:cmd).rest(:files).build
# ✅ Valid: required, optional, then rest
ArgumentParser.schema.required(:cmd).optional(:env).rest(:files).build
# ✅ Valid: optional, then rest
ArgumentParser.schema.optional(:env).rest(:files).build
# ❌ Invalid: optional before required
ArgumentParser.schema.optional(:env).required(:cmd) # raises SchemaError
# ❌ Invalid: multiple optional arguments
ArgumentParser.schema.optional(:env).optional(:other) # raises SchemaError
# ❌ Invalid: optional after rest
ArgumentParser.schema.rest(:files).optional(:cmd) # raises SchemaError
# ❌ Invalid: required after rest
ArgumentParser.schema.rest(:files).required(:cmd) # raises SchemaError
# ❌ Invalid: multiple rest arguments
ArgumentParser.schema.rest(:files).rest(:others) # raises SchemaErrorOptions
Global Options
These options apply to all argument types.
Type Coercion
Coerce arguments to specific types:
parser = ArgumentParser.build do
required :count, type: Integer
required :ratio, type: Float
required :name, type: String
end
args = parser.parse!(["42", "3.14", "hello"])
# => { count: 42, ratio: 3.14, name: "hello" }Supported types: Integer, Float, String (default).
Pattern Validation
You can validate arguments against specific patterns.
Inclusion
Checks inclusion using #include?.
# Using arrays (checks inclusion)
parser = ArgumentParser.build do
required :env, pattern: %w[dev staging prod]
endMapping
If the object responds to #key? and #[], it will be used to map input values
to output values.
parser = ArgumentParser.build do
required :env, pattern: { "d" => "dev", "s" => "staging", "p" => "prod" }
end
args = parser.parse!(["d"])
# => { env: "dev" }Case Equality
Any object that responds to === can be used as a pattern (e.g., regexes,
ranges, procs):
parser = ArgumentParser.build do
required :command, pattern: /^(show|list|open)$/
required :port, type: Integer, pattern: (1..65535)
required :level, pattern: ->(v) { %w[debug info warn error].include?(v) }
endOptions for optional Arguments
Default Values
Provide default values for optional arguments:
parser = ArgumentParser.build do
required :command
optional :env, default: "development"
end
args = parser.parse!(["server"])
# => { command: "server", env: "development" }
args = parser.parse!(["server", "production"])
# => { command: "server", env: "production" }Options for rest Arguments
Size Constraints
Control the number of rest arguments:
parser = ArgumentParser.build do
rest :files, min: 1, max: 3
end
# Too few arguments
parser.parse!([]) # raises InvalidArgument: "expected at least 1 argument(s)"
# Too many arguments
parser.parse!(["f1", "f2", "f3", "f4"]) # raises InvalidArgument: "expected at most 3 argument(s)"
# Just right
args = parser.parse!(["file1", "file2"])
# => { files: ["file1", "file2"] }Example: CLI Tool
ArgumentParser works great alongside OptionParser. Use ArgumentParser for
positional arguments and OptionParser for options:
require 'optparse'
require 'argument_parser'
# Define the argument parser first
arg_parser = ArgumentParser.build do
required :command, pattern: %w[start stop restart status]
optional :service, default: "web"
end
# Parse options with OptionParser
options = {}
option_parser = OptionParser.new do |opts|
# Use ArgumentParser to generate the usage string
opts.banner = "Usage: #{arg_parser.usage("my-cli")} [OPTIONS]"
opts.on("-v", "--verbose", "Run verbosely") do |v|
options[:verbose] = v
end
opts.on("-p", "--port PORT", Integer, "Port number") do |port|
options[:port] = port
end
opts.on("-h", "--help", "Show this help message") do
puts opts
exit
end
end
# Handle help flag or parse errors
begin
option_parser.parse!(ARGV)
args = arg_parser.parse!(ARGV)
# Now you have both:
# options => { verbose: true, port: 3000 }
# args => { command: "start", service: "api" }
puts "#{options[:verbose] ? 'Verbosely' : 'Quietly'} #{args[:command]}ing #{args[:service]} on port #{options[:port] || 8080}"
rescue OptionParser::ParseError, ArgumentParser::ParseError => e
puts "Error: #{e.message}"
# The help output would look like:
# Usage: my-cli <COMMAND> [SERVICE] [OPTIONS]
# -v, --verbose Run verbosely
# -p, --port PORT Port number
# -h, --help Show this help message
puts option_parser
exit 1
endUsage Strings
ArgumentParser can generate standard CLI usage strings that show the expected syntax:
parser = ArgumentParser.build do
required :source
required :dest
optional :format
rest :files, min: 1
end
puts parser.usage("cp")
# => "cp <SOURCE> <DEST> [FORMAT] <FILES...>"
# Different argument combinations:
parser = ArgumentParser.build do
required :command
optional :env
end
puts parser.usage("deploy")
# => "deploy <COMMAND> [ENV]"
# Optional rest arguments (no minimum):
parser = ArgumentParser.build do
required :action
rest :targets # no min: specified
end
puts parser.usage("docker")
# => "docker <ACTION> [TARGETS...]"The usage string follows standard CLI conventions:
- Required arguments:
<ARG> - Optional arguments:
[ARG] - Required rest arguments:
<ARG...>(whenmin:is > 0) - Optional rest arguments:
[ARG...](when nomin:ormin: 0)
Error Handling
ArgumentParser raises specific exceptions for different error conditions. Both
MissingArgument and InvalidArgument inherit from ParseError:
begin
args = parser.parse!(argv)
rescue ArgumentParser::MissingArgument => e
puts "Missing required argument: #{e.message}"
rescue ArgumentParser::InvalidArgument => e
puts "Invalid argument: #{e.message}"
rescue ArgumentParser::ParseError => e
puts "Parse error: #{e.message}"
rescue ArgumentParser::SchemaError => e
puts "Schema definition error: #{e.message}"
endContributing
Bug reports and pull requests are welcome on GitHub at https://github.com/thoughtbot/argument_parser.
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
About thoughtbot
This repo is maintained and funded by thoughtbot, inc. The names and logos for thoughtbot are trademarks of thoughtbot, inc.
We love open source software! See our other projects. We are available for hire.
License
The gem is available as open source under the terms of the MIT License.