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, 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:
- Add the gem to your app's Gemfile:
- Execute it with
- 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')
There are a few basic Prompt methods you're most likely to use in your CLI app:
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? 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
A nifty tool for when you require confidential information from your user, like a password, is using the
prompt.mask(‘Enter your password:') #=> Enter your password: ••••
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
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_selectallows the user to select more than one option:
enum_selectallows 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 : 2
TTY::Prompt gives you a lot of ways to personalize your prompts. Let's go over some of the more useful ones.
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:
prompt.ask(‘What industry do you work in?', default: ’Tech') # => # What industry do you work in? (Tech)
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 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 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.