The command_line_boss
gem
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.
Installation
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
Usage
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.
Getting started
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 your command line
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 ...]
Start your command line parser class
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 options
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 additional validations
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
Process any remaining non-option arguments
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
Optional: define help output
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!
Use the parser
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(', ')}"
Run the command line
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 $
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake
to run the tests. You can also run
specbin/console
for an interactive prompt that
will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
.
Contributing
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.
Commit message guidelines
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.
Pull request guidelines
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.
License
The gem is available as open source under the terms of the MIT
License.
Code of Conduct
Everyone interacting in the CommandLineBoss project’s codebases, issue trackers, chat
rooms and mailing lists is expected to follow the code of
conduct.