Ruby OptionParser

Vinicius Negrisolo Vinicius Negrisolo Ruby

In order to parse user inputs passed to CLI Scripts we can use the Ruby class OptionParser. With that it’s possible to define an argument specification like required/optional, or restrict values or even convert into a specified class. Find out how to configure OptionParser and use it.

User Inputs

It’s quite common for CLI Scripts to receive arguments like:

flag and value description
-f short style without any value
-f bar value separated by whitespace
-f=bar value separated by =
--foo bar long style with value
--foo bar,baz multiple values (list)

This is so common that this become implemented by OptionParser class. Let’s see how to configure all that.

OptionParser class

The Ruby standard library has a class called OptionParser that handle user inputs in a very easy way. The main idea is to define a parser and parse it, simple as: do |parser|
  # define your parser here

The parse! method has a default of ARGV and so you can receive ruby script arguments.

Another nice catch is to use a Struct class to hold the configuration variables parsed by OptionParser, and possibly with default values, something like this:

Config =*%i[color drink lang fun point sports time user]) do
  def initialize    = false
    self.point  = 0
    self.sports = []

Finally it’s important to memoize the Config instance, so we are going to have just one parser and call parse! method just once.

class OptparseExample
  class << self
    def config
      @config ||= do |config|

Complete example

Maybe the easiest way to explain how to configure and use OptionParser is providing a full example with a Ruby script file and call it with some arguments. Check this out:

Config =*%i[color drink lang fun point sports time user]) do
  DRINKS = %i[water tea beer]
  LANGS  = {
    de: 'Deutsch',
    en: 'English',
    fr: 'Français',

  def self.drinks

  def self.langs

  def initialize
    self.drink  = DRINKS.first
    self.lang   = LANGS.values.first    = false
    self.point  = 0
    self.sports = []

The User class just represents a simple model, and this class is being used for Custom Converters. In this case I want to receive a user by id, fetch him in the database and provide as a configuration the found User, not just the id. This is just to show how powerful can be a Custom Converter.

User = do
  def self.find(id)
    all[id - 1]

  def self.all

Finally the full Ruby script file:

#!/usr/bin/env ruby

require 'optparse'
require 'optparse/time'

class OptparseExample
  class << self
    def config
      @config ||= do |config|


    def build_parser(config) do |parser|
        parser.banner = 'Help: ./my-script --help'

        parser.separator "\nCommon options:"
        define_common_config(parser, config)

        parser.separator "\nSpecific options:"
        define_specific_config(parser, config)

    def define_custom_converters(parser)
      parser.accept(User) { |id| User.find(id.to_i) }

    def define_common_config(parser, config)
      parser.on('-h', '--help',    'Show help')    { quit_script(parser) }
      parser.on('-v', '--version', 'Show version') { quit_script('Version => 1.0.0') }

    def define_specific_config(parser, config)
      parser.on('-c', '--color=COLOR', 'Favorite Color')           { |v| config.color  = v }
      parser.on('-d', '--drink=DRINK', drinks, "Drink: #{drinks}") { |v| config.drink  = v }
      parser.on('-l', '--lang=LANG', langs, "Lang: #{langs}")      { |v| config.lang   = v }
      parser.on('-f', '--[no-]fun', 'Run with Fun Mode')           { |v|    = v }
      parser.on('-p', '--point=POINT', Float, 'Points')            { |v| config.point  = v }
      parser.on('-s', '--sports=X,Y,Z', Array, 'Favorite Sports')  { |v| config.sports = v }
      parser.on('-t', '--time=TIME', Time, 'Starting time')        { |v| config.time   = v }
      parser.on('-u', '--user=USER_ID', User, 'User ID')           { |v| config.user   = v }

    def quit_script(message = nil)
      puts message if message

    def drinks

    def langs

puts OptparseExample.config

If we run this script with the --help flag:

./my-ruby-script --help
#=> Usage: ./my-script [options]
#=> Common options:
#=>     -v, --version                    Show version
#=>     -h, --help                       Show help
#=> Specific options:
#=>     -c, --color=COLOR                Favorite Color
#=>     -d, --drink=DRINK                Drink: [:water, :tea, :beer]
#=>     -l, --lang=LANG                  Lang: {:de=>"Deutsch", :en=>"English", :fr=>"Français"}
#=>     -f, --[no-]fun                   Run with Fun Mode
#=>     -p, --point=POINT                Points
#=>     -s, --sports=X,Y,Z               Favorite Sports
#=>     -t, --time=TIME                  Starting time
#=>     -u, --user=USER_ID               User ID

Now running the same script setting a lot of different flags:

./my-ruby-script -c blue \
                 -d tea \
                 -l en \
                 -f \
                 -p 5 \
                 -s hockey,soccer,rugby \
                 -t 14/07/2016-08:53:20 \
                 -u 1;

#=> #<struct Config
#=>   color="blue",
#=>   drink=:tea,
#=>   lang="English",
#=>   fun=true,
#=>   point=5.0,
#=>   sports=["hockey", "soccer", "rugby"],
#=>   time=2016-07-14 08:53:20 -0300,
#=>   user=#<struct User name="John">
#=> >

Try yourself with this code and verify what happens if you change the flags configuration or values when calling the script.


OptionParser class is a simplifier class when we are dealing with Ruby Script files. It helps us to define and parse an user input and with this definition we can use it to print a help message in the same script. Let’s use it to get user inputs, restrict to a list of possible values, make them required, convert to specific classes and so on.

Read also:

Struct Factory for Elixir Elixir

How easy is to build a Factory solution for Elixir applications? In this post I share a simple 20ish lines-of-code solution and its testing ✅. Check this out and start using factories for building data for tests and seed.

Ruby CLI Script Ruby

To create CLI script that runs Ruby code is super fast and straightforward. With that you can run any Ruby code directly from terminal, including your own gem. Let’s take a look what’s need to be done in order to get a nice maintainable CLI script written in Ruby.