DEV Community

Aidi Rivera
Aidi Rivera

Posted on • Edited on

Using TTY::Prompt for your CLI app

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!

  1. Add the gem to your app's Gemfile: gem 'tty-prompt'
  2. Execute it with bundle
  3. 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
Enter fullscreen mode Exit fullscreen mode

This way, you can call on any of the methods the gem provides on this new prompt variable.

prompt.ask(Your question here')
Enter fullscreen mode Exit fullscreen mode



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"
Enter fullscreen mode Exit fullscreen mode

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: doge dog


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
Enter fullscreen mode Exit fullscreen mode

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: ••••
Enter fullscreen mode Exit fullscreen mode

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?))
Enter fullscreen mode Exit fullscreen mode
#What's your favorite kind of taco shell? 
#  Soft_taco
#  Hard_taco
#‣ Porque_no_los_dos?
#=> "Porque_no_los_dos?"
Enter fullscreen mode Exit fullscreen mode

porque no los dos girl

There are two other variations on the select method:

  1. multi_select allows the user to select more than one option:

  2. 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
Enter fullscreen mode Exit fullscreen mode
      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
Enter fullscreen mode Exit fullscreen mode



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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode
  • yes?
prompt.yes?(Is GrumpyCat grumpy?', default: true)
#=> Is GrumpyCat grumpy? yes
#=> true
Enter fullscreen mode Exit fullscreen mode

grumpy cat

  • 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
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
prompt.ask('What is your name?', required: true)
#What is your name? 
#>> Value must be provided
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
piotrmurach profile image
Piotr Murach

Thanks for the article and glad to hear tty-prompt helped you write your CLI app.

Collapse
 
aidiri profile image
Aidi Rivera

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!

Collapse
 
piotrmurach profile image
Piotr Murach

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.

Collapse
 
lbonanomi profile image
lbonanomi

A very cool explanation of a very handy gem!

Collapse
 
aidiri profile image
Aidi Rivera

Thanks! Hope it helps.