CLIUtils
CLIUtils is a library of functionality designed to alleviate common tasks and headaches when developing command-line (CLI) apps in Ruby.
Why?
It's fairly simple:
-
I love developing Ruby-based CLI apps.
-
I found myself copy/pasting common code from one to another.
-
I decided to do something about it.
Installation
Add this line to your application's Gemfile:
$ gem 'cliutils'
And then execute:
$ bundle
Or install it yourself:
$ gem install cliutils
Usage
require 'cliutils'
If you want to mix in everything that CLIUtils has to offer:
include CLIUtils
Alternatively, as described below, mix in only the libraries that you want.
Note that although this README.md is extensive, it may not cover all methods. Check out the tests to see more examples.
Libraries
CLIUtils offers:
-
PrettyIO: nicer-looking CLI messages
-
Messenging: a full-featured Logger
-
Configuration: a app configuration manager
-
Prefs: a preferences prompter and manager
PrettyIO
First stop on our journey is better client IO. To activate, simply mix into your project:
include CLIUtils::PrettyIO
PrettyIO affords you colorized strings:
puts 'A sample string'.red
PrettyIO gives you utility methods for the common ANSI color codes:
String.blue
String.cyan
String.green
String.purple
String.red
String.white
String.yellow
You also get the colorize
method, which allows you to define
more complex color combinations. For example, to get some nice purple text
on a gnarly green background:
puts 'A sample string'.colorize('35;42')
Naturally, memorizing the ANSI color scheme is a pain, so PrettyIO gives you a convenient method to look up these color combinations:
color_chart
Messenging
Throughout the life of your application, you will most likely want to send several messages to your user (warnings, errors, info, etc.). Messenging makes this a snap. It, too, is a mixin:
include CLIUtils::Messenging
Once mixed in, you get access to messenger
, a type of Logger
that uses PrettyIO to send nicely-formatted messages to your user. For
example, if you'd like to warn your user:
messenger.warn('Hey pal, you need to be careful.')
Messenging Methods
messenger
gives you access to several basic methods:
-
messenger.error
: used to show a formatted-red error message. -
messenger.info
: used to show a formatted-blue infomational message. -
messenger.section
: used to show a formatted-purple sectional message. -
messenger.success
: used to show a formatted-green success message. -
messenger.yellow
: used to show a formatted-yellow warning message.
Let's see an example that uses them all:
messenger.section('STARTING ATTACK RUN...')
messenger.info('Beginning strafing run...')
messenger.warn('WARNING: Tie Fighters approaching!')
messenger.error('Porkins died :(')
messenger.success('But Luke still blew up the Death Star!')
messenger
also includes two “block” methods that allow you to
wrap program execution in messages that are “longer-term”.
messenger.info_block('Starting up...', 'Done!', multiline = false) { # do stuff here }
messenger
outputs 'Starting up…', runs the code in
# do stuff here
, and once complete, outputs 'Done!' on
the same line. Note that section_block
is the same exact
signature (except for the method name, of course!).
Message Wrapping
PrettyIO also gives messenger
the ability to wrap your
messages so that they don't span off into infinity. You can even
control what the wrap limit (in characters) is:
CLIUtils::PrettyIO::wrap_at(50)
messenger.info('This is a really long message, okay? It should wrap at some point. Seriously. Wrapping is nice.')
puts ''
CLIUtils::PrettyIO::wrap_at(20)
messenger.info('This is a really long message, okay? It should wrap at some point. Seriously. Wrapping is nice.')
puts ''
CLIUtils::PrettyIO::wrap(false)
messenger.info('This is a really long message, okay? It should wrap at some point. Seriously. Wrapping is nice.')
Prompting
messenger
also carries a convenient method to prompt your
users to give input (including an optional default). It makes use of
readline
, so you can do cool things like text expansion of
paths.
p = messenger.prompt('Are you a fan of Battlestar Galactica?', default = 'Y')
messenger.info("You answered: #{ p }")
Logging
Often, it's desirable to log messages as they appear to your user.
messenging
makes this a breeze by allowing you to attach and
detach Logger instances at will.
For instance, let's say you wanted to log a few messages to both your
user's STDOUT and to file.txt
:
file_logger = Logger.new('file.txt')
messenger.info('This should only appear in STDOUT.')
messenger.attach(file_logger)
messenger.warn('This warning should appear in STDOUT and file.txt')
messenger.error('This error should appear in STDOUT and file.txt')
messenger.debug('This debug message should only appear in file.txt')
messenger.detach(file_logger)
messenger.section('This section message should appear only in STDOUT')
In STDOUT:
…and in file.txt
:
W, [2014-03-29T15:14:34.844406 #4497] WARN -- : This warning should appear in STDOUT and file.txt
E, [2014-03-29T15:14:34.844553 #4497] ERROR -- : This error should appear in STDOUT and file.txt
D, [2014-03-29T15:14:34.844609 #4497] DEBUG -- : This debug message should only appear in file.txt
Since you can attach Logger objects, each can have it's own format and severity level. Cool!
Configuration
CLIUtils offers two “things” – a Configurator
class and a
Configuration
module that provides access to a shared instance
of Configurator
– that make managing a user's
configuration parameters easy. Mix it in!
include CLIUtils::Configuration
Loading a Configuration File
load_configuration('~/.my-app-config')
If there's data in there, it will be consumed into
configuration
's data
property.
Adding/Removing Sections
Sections are top levels of the configuration file and are managed via the
configuration
object:
configuration.add_section(:user_data)
configuration.add_section(:program_data)
configuration.delete_section(:program_data)
Adding Data to Sections
There are two ways data can be managed in configuration
: via
its @data
property or via some magic methods; your call:
configuration.data[:user_data].merge!(username: 'bob')
# OR
configuration.user_data.merge!(username: 'bob')
Saving to a File
When you're ready to save your configuration data to a YAML file:
configuration.save
Note that all your keys are converted to strings before saving (and,
likewise, are converted to symbols, when loading). Assuming we used the
commands above, we could expect this to be the contents of
~/.my-app-config
:
---
user_data:
username: bob
Known Issues
-
LoggerDelegator doesn't currently know what to do with
messenger.prompt
, so you'll have to manually log adebug
message if you want that information logged.
Bugs and Feature Requests
To report bugs with or suggest features/changes for CLIUtils, please use the Issues Page.
Contributing
Contributions are welcome and encouraged. To contribute:
-
Fork it ( github.com/bachya/cliutils/fork )
-
Create your feature branch (
git checkout -b my-new-feature
) -
Commit your changes (
git commit -am 'Add some feature'
) -
Push to the branch (
git push origin my-new-feature
) -
Create new Pull Request
License
(The MIT License)
Copyright © 2014 Aaron Bach bachya1208@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.