I recently became a software engineering student at Flatiron School, a coding school originally based in New York that's branched out across the country.
In our third week, we were charged with creating our first robust project: a CLI (Command Lind Interface) app. A project we'd then have to present. In front of all our classmates. It was awful. But, in all seriousness, a CLI app is a great project for beginners and something I highly recommend as a great challenge to step up your learning.
And for those who want to take their CLI app to the next level, I present to you an awesome gem that's simple to use and makes your app look a step above without extra fuss:
TTY::Prompt
TTY::Prompt, created by Piotr Murach, is an open-source gem that provides "a beautiful and powerful interactive command line prompt."* It's pretty great. If your CLI app ever needs input from a user (which it should because, why not?), this is the gem for you. It gives you great options to display prompts or menus with choices that your user can fill in or pick from and makes the styling neat and handsome. Like so:
How to use it
It's simple!
- Add the gem to your app's Gemfile:
gem 'tty-prompt'
- Execute it with
bundle
- Or install it manually in your bash with
gem install tty-prompt
When you're using it in your application, all you need is to create a variable prompt
and create a new instance of the TTY::Prompt class.
prompt = TTY::Prompt.new
This way, you can call on any of the methods the gem provides on this new prompt variable.
prompt.ask(‘Your question here')
Methods
There are a few basic Prompt methods you're most likely to use in your CLI app:
ask
To ask a question that the user would respond with simple input, use the ask
method. As with any time you want to use TTY::Prompt, you first need to create a prompt, then call the method on that prompt variable you have created.
prompt = TTY::Prompt.new
prompt.ask('What is your name?')
# => What is your name? doge
# => "doge"
The return value is a string of your user's input. So say your user types in "doge," when they hit the return key, not only will your return value be equal to "doge," but your user also probably looks something like this:
yes?/no?
The yes?
method is similarly built, but will only return true or false when the user presses 'y' or 'n' respectively.
prompt.yes?(‘Are you a dog?’)
#=> Are you a dog? yes
#=> true
You can also change the defaulted (Y/n) option to say something like (Agree/Disagree) instead, with the .suffix
option.
mask
A nifty tool for when you require confidential information from your user, like a password, is using the mask
method.
prompt.mask(‘Enter your password:')
#=> Enter your password: ••••
Menu methods
Prompt gives you a few different ways to create menus where your user selects one or more from a list of options to choose from. The most basic way to create a menu would be with a select
method.
select
Whenever you need your user to choose one of a list of options, the select
method is your friend. Your user will use the up/down keys to choose from a list of options you provide, which will then return a string of the option chosen:
prompt.select("What's your favorite kind of taco shell?", %w(Soft_taco Hard_taco
Porque_no_los_dos?))
#What's your favorite kind of taco shell?
# Soft_taco
# Hard_taco
#‣ Porque_no_los_dos?
#=> "Porque_no_los_dos?"
There are two other variations on the select method:
multi_select
allows the user to select more than one option:enum_select
allows users to select an option by entering the numbered key corresponding to its option:
prompt.multi_select("What's your favorite pet?", %w(cats dogs fish
birds reptiles plants))
#What's your favorite pet? cats, dogs, plants
# ⬢ cats
# ⬢ dogs
# ⬡ fish
# ⬡ birds
# ⬡ reptiles
#‣ ⬢ plants
prompt.enum_select("What's your favorite pet?", %w(cats
dogs fish birds reptiles plants))
#What's your favorite pet?
# 1) cats
# 2) dogs
# 3) fish
# 4) birds
# 5) reptiles
# 6) plants
# Choose 1-6 [1]: 2
Cool Features
TTY::Prompt gives you a lot of ways to personalize your prompts. Let's go over some of the more useful ones.
Default
Many of the methods have the option of defining a default value to your prompts. It's a neat feature to have when options are given in cases of exceptions to the norm. Or maybe you foresee users being particularly lazy or paranoid about using their name; you can have a default:
value set to "Anonymous".
prompt.ask(‘What's your name?', default: 'Anonymous')
# =>
# What is your name? (Anonymous)
TTY::Prompt is smart enough to have the default option available for quite a few methods:
-
ask
prompt.ask(‘What industry do you work in?', default: ’Tech')
# =>
# What industry do you work in? (Tech)
-
yes?
prompt.yes?(‘Is GrumpyCat grumpy?', default: true)
#=> Is GrumpyCat grumpy? yes
#=> true
-
And any menu method with
menu.default <default value(s)>
inside the menu iteration
prompt.select('Choose your fruit of choice') do |menu|
menu.default 3
menu.choice 'Papaya', 1
menu.choice 'Mango', 2
menu.choice 'Watermelon', 3
end
prompt.multi_select("Select tea?") do |menu|
menu.default 2, 5
menu.choice :green
menu.choice :black
menu.choice :white
menu.choice :earl_grey
menu.choice :sweet
end
Require
The :require
option allows a prompt to be (you guessed it) required before a user can move on. Like default:
, it can be added to essentially any prompt method, which makes them both extremely useful features.
prompt.mask('Enter a password:', required: true)
#Enter a password:
#>> Value must be provided
prompt.ask('What is your name?', required: true)
#What is your name?
#>> Value must be provided
Admittedly, with methods like the menu methods, the user would have to input a response before they can move on regardless of whether or not it is required, so pinning it onto the end of a menu prompt would be redundant.
Return values
Return values are defaulted to be a string of whichever option the user chooses, like in the first doge example. But return values can also be customized by adding the return value you'd like for that choice right after choice itself like you see in the fruit example above: menu.choice 'Papaya', 1
Though I've claimed these methods here to be the most useful, there are many more features available with TTY::Prompt and I encourage you to fully explore their documentation page and give yourself a chance to play around with them. Happy Coding!
*- Edited June 21st to credit the creator.
Top comments (5)
Thanks for the article and glad to hear tty-prompt helped you write your CLI app.
Thanks, Piotr! I really did love using it and recommended it to fellow students. I know at least one student definitely used it for their CLI project this past week. It's a great gem, good work!
I'd love to have your testimonial on tty website to ensure different experiences are represented. Would you be willing to write one? If so, please can you send it to my email.
A very cool explanation of a very handy gem!
Thanks! Hope it helps.