Comparison of Ruby command-line parsers

Ruby offers several popular command-line parsers—which one is best for your project?

Whether you realize it or not, you’ve probably used all of the command-line libraries that Ruby has to offer. Rails uses Thor to power its command line interface, Rake is dropped into every Rails project for developers to customize with their own tasks, OptionsParser is included with Ruby itself and runs their CLIs, and Bake is an alternative to Rake that addresses some of its shortcomings.

For this article we’ll look at a simple example where we try to have a hello world CLI that accepts a “name” argument and a “greeting” flag so you can see how both of those work in their respective libraries. The idea is we get as close to something like this as possible:

./greet world -g "hello"

Let’s see how this works.

Rake

Rake is pervasive in the Ruby community since it was part of the Ruby standard libary for over a decade. If you build Rails apps, you’ve probably seen a Rakefile in the root of your directory that runs various Rails tasks like database migrations, clearing cache directories, and other developer tasks. In many projects, it’s often the “junk drawer” of utility scripts.

Let’s see what it looks like for our greet script goal above.

# Use ENV variables to pass in arguments
require "rake"

desc "Say hello"
task :greet do
  puts "#{ENV.fetch("GREETING", "Hi")} #{ENV.fetch("NAME", "Planet")}!"
end

Something to not about Rake–it’s not designed to be run directly. Instead you run rake and it looks for a Rakefile in the current directory. Another thing you’ll notice is Rake doesn’t have a great way of passing arguments into it.

NAME="World" GREETING="Hello" rake greet

Alternatively, if you’re OK with positional arguments, the following is possible:

desc "Say hello"
task :greet, [:name, :greeting] do |t, args|
  # Provide default values if needed
  args.with_defaults(name: "World", greeting: "Hello")

  puts "#{args[:greeting]}, #{args[:name]}!"
end

Want to run it?

rake greet[Hello,World]

It’s a bit awkward.

Built-in help

The desc methods describe what tasks do in Rake. If you want to see a list of tasks that are available to run you’d run the rake -T command.

rake -T
TODO

OptionsParser

A comparions of the most popular Ruby command line parsers wouldn’t be complete without the one that ships with Ruby itself. OptionsParser is a simple and easy to use command line parser that is included with Ruby. It’s not as feature rich as some of the other options, but it’s a great choice for simple command line parsing tasks.

#!/usr/bin/env ruby
require 'optparse'

options = {}
OptionParser.new do |opts|
  opts.banner = "Usage: hi [options]"

  opts.on("-n", "--name NAME", "Name to greet") do |name|
    options[:name] = name
  end

  opts.on("-g", "--greeting GREETING", "Greeting to use") do |greeting|
    options[:greeting] = greeting
  end
end.parse!

puts "#{options[:greeting]} #{options[:name]}!"

To call it you’d run:

./hi greet John -g "hello"

And if you run it with nothing, you get:

Usage: options_parser.rb [options]
    -n, --name NAME                  Name to greet
    -g, --greeting GREETING          Greeting to use

Thor

Thor is a Ruby command line parser that is used to build command line tools. It’s a great choice for building command line tools because it’s easy to use and it’s easy to extend. Thor is also a great choice for building command line tools because it’s easy to test.

#!/usr/bin/env ruby
require 'thor'

class MyCLI < Thor
  desc "greet NAME", "Say hello to NAME"
  option :greeting, type: :string, desc: "Greeting to use"
  def greet(name)
    puts "Hello, #{name}!"
  end
end

To call it you’d run:

./hi greet John -g "hello"

Bake

Bake is a Ruby command line parser that is used to build command line tools. It’s a great choice for building command line tools because it’s easy to use and it’s easy to extend. Bake is also a great choice for building command line tools because it’s easy to test.

Support this blog 🤗

If you like what you read and want to see more articles like this, please consider using Terminalwire for your web application’s command-line interface. In under 10 minutes you can build a command-line in your favorite language and web framework, deploy it to your server, then stream it to the Terminalwire thin-client that runs on your users desktops. Terminalwire manages the binaries, installation, and updates, so you can focus on building a great CLI experience.