Few days ago I’ve created a script for the project I’m working on. It was an ugly script with hardcoded values, but it did ther job - create tokens on request. But I’ve decided to improve it a bit, because sometimes I needed to change params and I’ve added ability to submit params from the command line. Of course, there are a lot of awesome libraries such as dry-cli, TTY Toolkit or cli-kit from Shopify, but in most cases you can use standard ruby libraries like OptionParser or GetoptLong. Lets see how you can create a CLI utils with those libraries just in few minutes.
We will create simple app, which will ask for your name for the time of the day. If there’s no input - script will show you a help screen with list of required and optional arguments.
GetoptLong
We will start with GetoptLong library.
#!/usr/bin/env ruby
require "getoptlong"
opts = GetoptLong.new(
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
[ '--name', '-n', GetoptLong::REQUIRED_ARGUMENT ],
[ '--time', GetoptLong::OPTIONAL_ARGUMENT ]
)
options = {}
help_message = <<-EOF
Usage: greeting.rb [options]
-h, --help:
show help
--name yourname, -n yourname:
your name
--time time_of_the_day:
time of the day
EOF
opts.each do |opt, arg|
case opt
when "--help"
puts help_message
when "--name"
options[:name] = arg
when "--time"
options[:time] = arg
end
end
if options.empty?
puts help_message
else
puts "Good #{options[:time]}, #{options[:name]}"
end
Our code is simple - we create an instance of GetoptLong
class with list of available params, then in case of match with param name we do execute some code.
OptionParser
Next stop - OptionParser. Similar with GetoptLong
we create an instance of OptionParser
class with list of available params. There are an opts.banner
option which allow us to add some text before list of available params.
#!/usr/bin/env ruby
require 'optparse'
option_parser = OptionParser.new do |opts|
opts.banner = 'Usage: greeting.rb [options]'
opts.on '-n', '--name=NAME', 'Set name'
opts.on '-t', '--time=TIME', 'Set time'
end
options = {}
option_parser.parse!(into: options)
if options.empty?
puts option_parser
else
puts "Good #{options[:time]}, #{options[:name]}"
end
Every solution is simple and easy to implement without any additional library, but OptionParser
code looks more compact and readable, isn’t it?