Command Line Subcommands in Crystal
Here’s the translation of the Go code to Crystal, with explanations in Markdown format suitable for Hugo:
Our first program demonstrates how to create command-line subcommands with their own set of flags. This is similar to how tools like git
have subcommands like git commit
and git push
, each with their own options.
require "option_parser"
# We declare a subcommand using a separate OptionParser
# and proceed to define new flags specific for this subcommand.
foo_cmd = OptionParser.new do |parser|
parser.banner = "Usage: foo [options]"
foo_enable = false
foo_name = ""
parser.on("-e", "--enable", "Enable") { foo_enable = true }
parser.on("-n NAME", "--name=NAME", "Name") { |name| foo_name = name }
parser.on("-h", "--help", "Show this help") do
puts parser
exit
end
parser.unknown_args do |args|
puts "subcommand 'foo'"
puts " enable: #{foo_enable}"
puts " name: #{foo_name}"
puts " tail: #{args}"
end
end
# For a different subcommand we can define different
# supported flags.
bar_cmd = OptionParser.new do |parser|
parser.banner = "Usage: bar [options]"
bar_level = 0
parser.on("-l LEVEL", "--level=LEVEL", "Level") { |level| bar_level = level.to_i }
parser.on("-h", "--help", "Show this help") do
puts parser
exit
end
parser.unknown_args do |args|
puts "subcommand 'bar'"
puts " level: #{bar_level}"
puts " tail: #{args}"
end
end
# The subcommand is expected as the first argument
# to the program.
if ARGV.empty?
puts "expected 'foo' or 'bar' subcommands"
exit(1)
end
# Check which subcommand is invoked.
case ARGV[0]
# For every subcommand, we parse its own flags and
# have access to trailing positional arguments.
when "foo"
foo_cmd.parse(ARGV[1..-1])
when "bar"
bar_cmd.parse(ARGV[1..-1])
else
puts "expected 'foo' or 'bar' subcommands"
exit(1)
end
To run the program, save it as command_line_subcommands.cr
and use the Crystal compiler:
$ crystal build command_line_subcommands.cr
First invoke the foo subcommand:
$ ./command_line_subcommands foo --enable --name=joe a1 a2
subcommand 'foo'
enable: true
name: joe
tail: ["a1", "a2"]
Now try bar:
$ ./command_line_subcommands bar --level 8 a1
subcommand 'bar'
level: 8
tail: ["a1"]
But bar won’t accept foo’s flags:
$ ./command_line_subcommands bar --enable a1
Error: Unknown option '--enable'
This example demonstrates how to create a command-line application with subcommands in Crystal. It uses the OptionParser
class to define and parse command-line options for each subcommand. The structure is similar to the original, but it uses Crystal’s idiomatic ways of handling command-line arguments and subcommands.
Next, we’ll look at environment variables, another common way to parameterize programs.