command_line_boss
makes it easy to build, test, and maintain complex command line
interfaces. It is built on top of Ruby's OptionParser
class and works best for
traditional options-based command-line interfaces that you would build with
OptionParser
.
To use command_line_boss
you are expected to already know how to define options
with OptionParser
.
For defining command-line interfaces with multiple commands and subcommands (aka a git-like interface), we recommend using a gem like thor. Other good alternatives also exist.
To install this gem, add to the following line to your application's gemspec OR Gemfile:
gemspec:
spec.add_development_dependency "command_line_boss", '~> 0.1'
Gemfile:
gem "command_line_boss", "~> 0.1", groups: [:development, :test]
and then run bundle install
.
If bundler is not being used to manage dependencies, install the gem by executing:
gem install command_line_boss
More detailed examples are given in the examples
directory.
examples/readme_example
- a super-simple example of using this gem. The remainder of this section is a walkthrough of this example was constructed.examples/create_spreadsheet
- a more complicated example complete with tests.
This section provides a step-by-step guide to building a super simple command line
using this gem. A parser this simple would probably be easier to implement with
OptionParser
directly without this gem. This example is meant to show how you
can get started.
This gem really starts to shine as your command-line interface grows beyond something this simple.
The end result of this guide can be found in this project in the file
examples/readme_example/create-spreadsheet
.
Find a suitable directory to create your code in. For this example, all the code
will live in ONE script file that you create and set its executable permission bit
via chmod
.
Make sure you have the command_line_boss
gem installed.
Design the command line following the Google developer documentation style guide for command line syntax.
Here is what a simple example might look like that creates a spreadsheet with named sheets:
Usage:
create_spreadsheet SPREADSHEET_NAME --sheet=SHEET_NAME [--sheet=SHEET_NAME ...]
The first step will be to create your own command line parsing class. This class
must inherit from CommandLineBoss
.
Add the attributess representing the items you want to capture from the command
line. Set default values for these attributes in a method called set_defaults
.
#!/usr/bin/env ruby
require 'command_line_boss'
class CreateSpreadsheetCli < CommandLineBoss
attr_reader :spreadsheet_name, :sheet_names
private
def set_defaults
@spreadsheet_name = nil
@sheet_names = []
end
end
Define private methods whose names follow the pattern define_*_option
. Methods
MUST be private or they won't be called.
Report any errors by calling add_error_message
with the text of the error
message.
The return value of these methods is ignored.
Continuing the example, add the following code to the CreateSpreadsheetCli
class:
class CreateSpreadsheetCli < CommandLineBoss
# ...
private
def define_sheet_option
parser.on('--sheet=SHEET_NAME', 'Name of a sheet to create') do |name|
add_error_message('Sheet names must be unique!') if sheet_names.include?(name)
sheet_names << name
end
end
end
Define private methods whose names follow the pattern validate_*
. Methods MUST
be private or they won't be called.
Report any errors by calling add_error_message
with the text of the error
message.
The return value of these methods is ignored.
Continuing the example, add the following code to the CreateSpreadsheetCli
class:
class CreateSpreadsheetCli < CommandLineBoss
# ...
private
def validate_spreadsheet_name_given
add_error_message('A spreadsheet name is required') if spreadsheet_name.nil?
end
def validate_at_least_one_sheet_name_given
add_error_message('At least one sheet name is required') if sheet_names.empty?
end
end
Implement parse_arguments
to deal the remaining non-option arguments from the
command line. Within this method, the args
method returns the remaining
non-option arguments.
For example, in the command line create-spreadsheet "Yearly Sales" --sheet Summary
,
args
would return an array ['Yearly Sales']
.
Remove any values from args
that will be used. By default, if args
is not
empty after parse_arguments
returns, an error will result.
Report any errors by calling add_error_message
with the text of the error
message.
The return value of this method is ignored.
Continuing the example, add the following code to the CreateSpreadsheetCli
class:
class CreateSpreadsheetCli < CommandLineBoss
# ...
private
def parse_arguments
@spreadsheet_name = args.shift
end
end
Include the CommandLineBoss::HelpOption
module add a help option (-h
and
--help
) and structure the help output.
Help output is divided into sections that is output as follows:
BANNER
HEADER
OPTIONS
FOOTER
The OPTIONS section is generated by OptionsParser
.
You may provide the content for the other sections by implementing any or all of the
methods: banner
, header
, and footer
. These methods are expected to return a
string with the content.
If you do not provide content for the banner
section, it is generated by
OptionsParser
. The default banner looks something like this:
Usage: create-spreadsheet [options]
If you do not provide content for the header
or footer
sections, they are
omitted from the help output.
Continuing the example, add the following code to the CreateSpreadsheetCli
class:
class CreateSpreadsheetCli < CommandLineBoss
include CommandLineBoss::HelpOption
# ...
private
include CommandLineBoss::HelpOption
def banner = <<~BANNER
Create a spreadsheet
Usage:
create_spreadsheet SPREADSHEET_NAME --sheet=SHEET_NAME [--sheet=SHEET_NAME ...]
BANNER
end
The CreateSpreadsheetCli
class is complete!
Now that the command line parser is fully defined, you just need to use it, report errors, and (if successful) do something with the parsed values.
Place the following code at the end of your script file, after the
CreateSpreadsheetCli
class:
# Parse the command line arguments
options = CreateSpreadsheetCli.new.parse(ARGV)
# Report errors
if options.failed?
warn options.error_messages.join("\n")
exit 1
end
# Do something with the result
# In this case just output the command line values
require 'pp'
puts \
"Creating spreadsheet #{options.spreadsheet_name.pretty_inspect.chomp} " \
"with sheets #{options.sheet_names.map(&:pretty_inspect).map(&:chomp).join(', ')}"
Should you have a problem running your script, you can compare your script against
the expected result which can be found in this project in the file
examples/readme_example/create-spreadsheet
.
Test your script by running it from the command line. Here are some examples:
Show help output:
$ ./create-spreadsheet --help
Create a spreadsheetasdf
Usage:
create_spreadsheet SPREADSHEET_NAME --sheet=SHEET_NAME [--sheet=SHEET_NAME ...]
Options:
--sheet=SHEET_NAME Name of a sheet to create
-h, --help Show this message
$
A happy-path example:
$ ./create-spreadsheet 'Yearly Sales' --sheet=Summary --sheet=Details
Creating spreadsheet "Yearly Sales" with sheets "Summary", "Details"
$
An example with errors:
$ ./create-spreadsheet
ERROR: A spreadsheet name is required
ERROR: At least one sheet name is required
$
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that
will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
.
Bug reports and pull requests are welcome on GitHub at https://github.com/main_branch/command_line_boss. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
All commit messages must follow the Conventional Commits standard. This helps us maintain a clear and structured commit history, automate versioning, and generate changelogs effectively.
To ensure compliance, this project includes:
-
A git commit-msg hook that validates your commit messages before they are accepted.
To activate the hook, you must have node installed and run
npm install
. -
A GitHub Actions workflow that will enforce the Conventional Commit standard as part of the continuous integration pipeline.
Any commit message that does not conform to the Conventional Commits standard will cause the workflow to fail and not allow the PR to be merged.
All pull requests must be merged using rebase merges. This ensures that commit messages from the feature branch are preserved in the release branch, keeping the history clean and meaningful.
The gem is available as open source under the terms of the MIT License.
Everyone interacting in the CommandLineBoss project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.