TTY::MenuTree
Interactive, hierarchical command-line menus built on tty-prompt.
You model each menu entry as a small action object. TTY::MenuTree::Menu
runs them in a loop: leaf actions are invoked, groups open a submenu (with
automatic "Back" navigation), and an exit action ends the loop. Banners and
goodbyes are injectable hooks, so the menu itself stays free of
application-specific content.
Installation
Add it to your Gemfile:
gem "tty-menu-tree"
Then run:
bundle install
Or install it directly:
gem install tty-menu-tree
Usage
An action is any object that responds to name, call, submenu, and
exit?. Subclass TTY::MenuTree::Action to get sensible defaults.
require "tty/menu_tree"
class SayHello < TTY::MenuTree::Action
def name = "Say hello"
def call = puts("Hello! 👋")
end
class ShowTime < TTY::MenuTree::Action
def name = "Show the time"
def call = puts(Time.now)
end
actions = [
TTY::MenuTree::Group.new(name: "Greetings", actions: [SayHello.new]),
ShowTime.new,
TTY::MenuTree::ExitAction.new,
]
TTY::MenuTree::Menu.new(
actions: actions,
title: "What would you like to do?",
on_start: -> { puts "Welcome!" },
on_exit: -> { puts "Goodbye!" },
).run
The action protocol
| Method | Returns | Meaning |
|---|---|---|
name |
String |
Label shown in the menu. |
call |
anything | Runs a leaf action (skipped when submenu is set). |
submenu |
Array<#name>/nil |
Child actions to descend into, or nil for leaves. |
exit? |
Boolean |
When true, ends the top-level loop. |
You do not have to subclass anything — any duck-typed object works. The provided building blocks are just conveniences:
TTY::MenuTree::Action— base class with defaults andNotImplementedErrorguards.TTY::MenuTree::Group— an action whosesubmenuis its child actions.TTY::MenuTree::ExitAction— an action whoseexit?istrue.
Customizing the prompt
Menu only needs an object responding to
select_action(title, actions, back:). The default TTY::MenuTree::Prompt
wraps tty-prompt and appends a "Back" entry (returning nil) when
back: true. Pass your own prompt to fully control rendering:
TTY::MenuTree::Menu.new(actions: actions, prompt: MyPrompt.new).run
You can also customize the default prompt's colors or Back label:
prompt = TTY::MenuTree::Prompt.new(
tty_prompt: TTY::Prompt.new(active_color: :magenta),
back_label: "⬅ Back",
)
Development
bin/setup # bundle install
bundle exec rspec
License
Released under the MIT License.