Crafting Your First Ruby CLI

Using gem or Bundler?

A CLI application is gem package. We have multiple ways to craft a gem package, directly using gem or creating by Bundler.
The majority of people select using the Bundler to build a gem package because it can easily manage dependencies and has a scaffold to create the gemspec, license, test, tec. files for our automatically.

Creating a gem project by Bundler

1. Installing Bundler

1
2
gem install bundler
bundle -v # check version

If necessary, you can update to the latest version of Bundler.

1
gem update bundler

2. Generating a gem project

1
bundle gem wand # app name

3. Writing unit tests [optional]

  • Installing rspec
    We use rspec to test our project. It’s a development dependency, so we add this line inside the Gem::Specification in the file wand.gemspec.
1
spec.add_development_dependency "rspec", "~> 3.2"
  • Creating the test directory
    Running bundle install to install all gem dependencies.
    Creating a spec folder in the project directory as our test directory.
    Writing a wand_spec.rb file in the spec directory.
    Look up the documentation of spec to write unit tests.
1
2
3
4
5
describe Wand::Echo do
it "echo messages" do
expect(Wand::Echo.echo("Hello")).to eql("Hello")
end
end
  • Creating a Ruby class
    Defining a class in lib/wand/echo like this:
1
2
3
4
5
6
7
module Wand
class Echo
def self.echo(msg)
puts msg
end
end
end

To load this file, we’ll need to add a require line to lib/wand.rb for it:

1
require 'wand/echo'

We will also need to require the lib/wand.rb at the top of spec/wand_spec.rb:

1
require `wand`

Then, we run bundle exec rspec spec to test our codes.

4. Crafting a CLI

There are many gems can help us to craft a CLI. We select the Thor to cover this.

  • Install Thor
    Adding the dependency to our gemspec file.
1
spec.add_dependency "thor"

Running bundle install to install the dependencies.

  • Writing our first CLI
    First, we need to create a cli file in lib/wand/cli.rb.
    Creating a CLI class into the file like this:
1
2
3
4
5
6
7
8
9
10
11
require `thor`
require `wand`

module Wand
class CLI < Thor
desc "echo message", "prints whatever you inputted"
def echo(msg)
Wand::Echo.echo(msg)
end
end
end
  • Test our CLI code
    The easiest approach to test our code directly is to create a cli.rb file in our project directory and run ruby ./cli.rb to test it.
    The content of the cli.rb file:
1
2
3
require `wand/cli`

Wand::CLI.start

If you run bundle exec ruby cli.rb echo Hello, the terminal will output the text Hello equaling to your input.

5. Testing a CLI

The test way above is just for our development convenience, not unit tests. We need a tool to execute unit tests for our CLI. The prevalent tools for CLI unit test are cucumber and aruba.

  • Adding dependencies
1
2
spec.add_development_dependency "cucumber"
spec.add_development_dependency "aruba"

Running bundle install to install them.

  • Creating a features folder and a file features/wand.feature in it
    Filling the file with this code:
1
2
3
4
5
6
Feature: Wand
Doing something

Scenario: Echo message
When I run `wand echo hello`
Then the output should contain "hello"
  • Setting up the cucumber
    You need to create a setup file features/support/setup.rb and fill it with this code:
1
require `aruba/cucumber`
  • Creating the executable file for unit tests.
    Creating a file exe/wand without any file extension.
    Running chmod +x exe/wand to give the file executable permission.
    Copying our cli.rb file’s code to the executable file. The file’s content:
1
2
3
require `wand/cli`

Wand::CLI.start

Executing bundle exec cucumber features to run CLI unit tests.

6. Releasing our CLI

  1. Committing our code
    First, we need to commit our code because the wand.gemspec file uses git ls-files to detect which files should be added to the gem when we release it.
1
2
git add .
git commit -m 'Initializing wand'
  1. Building gem files
    Before releasing our gem, we need to compile our code to a gem file.
1
rake build

The command finished and then you will find a wand-0.1.0.gem file was generated in the pkg folder.
We can run gem install pkg/wand-0.1.0.gem to install the gem directly. Then you can run wand echo hello in the terminal to use your first CLI.

  1. Releasing to gems
    If you want to share you CLI to others, you need to publish it to the http://rubygems.org. Next time you want to use your CLI in other devices, you can use gem install wand install it directly.
    Using rake to release a gem is easy.
1
rake release
  1. Simplifying your releasing process
    Every time you want to update your CLI, you need to update the VERSION in the file version.rb, commit the modification and then run rake release again.
    There is a tool gem-release can easily your work.
1
gem install gem-release

The common usages of the gem-release

1
2
3
$ gem bump --version minor # bumps to the next minor version
$ gem bump --version major # bumps to the next major version
$ gem bump --version 1.1.1 # bumps to the specified version
  1. Installing a gem from github directly
    Sometimes we don’t want releasing a public gem. Maybe the gem contains some personal privacy or the company’s code we cannot leak.
    The gem provides an approach to install a gem from our private git repository.
1
gem 'wand', git: 'https://github.com/ssbun/wand.git', branch: 'master', glob: 'tool/ruby/*.gemspec'

We can specify the branch or use the default branch. If your repository’s root directory doesn’t have the .gemspec file, you need to specify the file’s path via the glob argument.

Reference document
https://guides.rubygems.org/make-your-own-gem/
https://bundler.io/v2.0/guides/creating_gem.html