tty-menu-tree 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +25 -0
- data/LICENSE.txt +21 -0
- data/README.md +110 -0
- data/lib/tty/menu_tree/action.rb +46 -0
- data/lib/tty/menu_tree/exit_action.rb +33 -0
- data/lib/tty/menu_tree/group.rb +29 -0
- data/lib/tty/menu_tree/menu.rb +70 -0
- data/lib/tty/menu_tree/prompt.rb +38 -0
- data/lib/tty/menu_tree/version.rb +7 -0
- data/lib/tty/menu_tree.rb +17 -0
- metadata +85 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 401abaaf372d1d2c9cf1302166e8f10b59806e6fc5e12107119c9ad242b0ce38
|
|
4
|
+
data.tar.gz: b5dd398022905ea05cb357b4e92fd6894f3ce3669a2737a720c9f3cd00e68f4c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: d76b274a7e3f4ad52c9cb3835712315bac5bf2ebdf3c65ba45b7f5d025445b443ac989cc9faff734d09e62889feb719f4b679cfede4fbc8bf13541868bcb8971
|
|
7
|
+
data.tar.gz: 617e6ece447e68f1b7096c5f2d599e762fa2f2de25a4a7b12afa5ca261fb6c496a2ba981871bd1444b5c5d009c6e636f73bac713bfb7aaa21562e760a3fdb329
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0]
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `TTY::MenuTree::Menu` — runs a tree of actions as an interactive menu with
|
|
15
|
+
submenu descent, back navigation, and an exit action.
|
|
16
|
+
- `TTY::MenuTree::Action` — base class defining the `name`/`call`/`submenu`/`exit?`
|
|
17
|
+
protocol.
|
|
18
|
+
- `TTY::MenuTree::Group` — an action that opens a submenu of child actions.
|
|
19
|
+
- `TTY::MenuTree::ExitAction` — a ready-made action that ends the loop.
|
|
20
|
+
- `TTY::MenuTree::Prompt` — a `tty-prompt` wrapper providing `select_action`
|
|
21
|
+
with optional "Back" handling.
|
|
22
|
+
- `on_start` / `on_exit` hooks so banners and goodbyes stay out of the library.
|
|
23
|
+
|
|
24
|
+
[Unreleased]: https://github.com/xef5000/tty-menu-tree/compare/v0.1.0...HEAD
|
|
25
|
+
[0.1.0]: https://github.com/xef5000/tty-menu-tree/releases/tag/v0.1.0
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Romain Deshaies
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# TTY::MenuTree
|
|
2
|
+
|
|
3
|
+
Interactive, hierarchical command-line menus built on
|
|
4
|
+
[tty-prompt](https://github.com/piotrmurach/tty-prompt).
|
|
5
|
+
|
|
6
|
+
You model each menu entry as a small **action** object. `TTY::MenuTree::Menu`
|
|
7
|
+
runs them in a loop: leaf actions are invoked, groups open a submenu (with
|
|
8
|
+
automatic "Back" navigation), and an exit action ends the loop. Banners and
|
|
9
|
+
goodbyes are injectable hooks, so the menu itself stays free of
|
|
10
|
+
application-specific content.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
Add it to your Gemfile:
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
gem "tty-menu-tree"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Then run:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
bundle install
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or install it directly:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
gem install tty-menu-tree
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
An action is any object that responds to `name`, `call`, `submenu`, and
|
|
35
|
+
`exit?`. Subclass `TTY::MenuTree::Action` to get sensible defaults.
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
require "tty/menu_tree"
|
|
39
|
+
|
|
40
|
+
class SayHello < TTY::MenuTree::Action
|
|
41
|
+
def name = "Say hello"
|
|
42
|
+
def call = puts("Hello! 👋")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class ShowTime < TTY::MenuTree::Action
|
|
46
|
+
def name = "Show the time"
|
|
47
|
+
def call = puts(Time.now)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
actions = [
|
|
51
|
+
TTY::MenuTree::Group.new(name: "Greetings", actions: [SayHello.new]),
|
|
52
|
+
ShowTime.new,
|
|
53
|
+
TTY::MenuTree::ExitAction.new,
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
TTY::MenuTree::Menu.new(
|
|
57
|
+
actions: actions,
|
|
58
|
+
title: "What would you like to do?",
|
|
59
|
+
on_start: -> { puts "Welcome!" },
|
|
60
|
+
on_exit: -> { puts "Goodbye!" },
|
|
61
|
+
).run
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### The action protocol
|
|
65
|
+
|
|
66
|
+
| Method | Returns | Meaning |
|
|
67
|
+
| ---------- | -------------------- | -------------------------------------------------- |
|
|
68
|
+
| `name` | `String` | Label shown in the menu. |
|
|
69
|
+
| `call` | anything | Runs a leaf action (skipped when `submenu` is set).|
|
|
70
|
+
| `submenu` | `Array<#name>`/`nil` | Child actions to descend into, or `nil` for leaves.|
|
|
71
|
+
| `exit?` | `Boolean` | When `true`, ends the top-level loop. |
|
|
72
|
+
|
|
73
|
+
You do not have to subclass anything — any duck-typed object works. The
|
|
74
|
+
provided building blocks are just conveniences:
|
|
75
|
+
|
|
76
|
+
- `TTY::MenuTree::Action` — base class with defaults and `NotImplementedError`
|
|
77
|
+
guards.
|
|
78
|
+
- `TTY::MenuTree::Group` — an action whose `submenu` is its child actions.
|
|
79
|
+
- `TTY::MenuTree::ExitAction` — an action whose `exit?` is `true`.
|
|
80
|
+
|
|
81
|
+
### Customizing the prompt
|
|
82
|
+
|
|
83
|
+
`Menu` only needs an object responding to
|
|
84
|
+
`select_action(title, actions, back:)`. The default `TTY::MenuTree::Prompt`
|
|
85
|
+
wraps `tty-prompt` and appends a "Back" entry (returning `nil`) when
|
|
86
|
+
`back: true`. Pass your own prompt to fully control rendering:
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
TTY::MenuTree::Menu.new(actions: actions, prompt: MyPrompt.new).run
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
You can also customize the default prompt's colors or Back label:
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
prompt = TTY::MenuTree::Prompt.new(
|
|
96
|
+
tty_prompt: TTY::Prompt.new(active_color: :magenta),
|
|
97
|
+
back_label: "⬅ Back",
|
|
98
|
+
)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Development
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
bin/setup # bundle install
|
|
105
|
+
bundle exec rspec
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
Released under the [MIT License](LICENSE.txt).
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TTY
|
|
4
|
+
module MenuTree
|
|
5
|
+
# Base class for anything that can appear in a menu.
|
|
6
|
+
#
|
|
7
|
+
# An action is any object that responds to the four methods below. You do
|
|
8
|
+
# not have to subclass +Action+; duck typing is enough. Subclassing simply
|
|
9
|
+
# gives you sensible defaults ({#submenu} => +nil+, {#exit?} => +false+) and
|
|
10
|
+
# +NotImplementedError+ guards for the parts you must define.
|
|
11
|
+
#
|
|
12
|
+
# @example A leaf action
|
|
13
|
+
# class SayHello < TTY::MenuTree::Action
|
|
14
|
+
# def name = "Say hello"
|
|
15
|
+
# def call = puts("Hello!")
|
|
16
|
+
# end
|
|
17
|
+
class Action
|
|
18
|
+
# @return [String] the label shown for this action in a menu.
|
|
19
|
+
def name
|
|
20
|
+
raise NotImplementedError, "#{self.class}#name must be implemented"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Invoked when a leaf action is selected.
|
|
24
|
+
#
|
|
25
|
+
# Not called for actions that return a {#submenu}; those are descended
|
|
26
|
+
# into instead.
|
|
27
|
+
#
|
|
28
|
+
# @return [void]
|
|
29
|
+
def call
|
|
30
|
+
raise NotImplementedError, "#{self.class}#call must be implemented"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [Array<#name>, nil] child actions to descend into, or +nil+ for
|
|
34
|
+
# a leaf action.
|
|
35
|
+
def submenu
|
|
36
|
+
nil
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @return [Boolean] when +true+, selecting this action ends the top-level
|
|
40
|
+
# menu loop.
|
|
41
|
+
def exit?
|
|
42
|
+
false
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "action"
|
|
4
|
+
|
|
5
|
+
module TTY
|
|
6
|
+
module MenuTree
|
|
7
|
+
# A ready-made action that ends the top-level menu loop when selected.
|
|
8
|
+
#
|
|
9
|
+
# @example Custom label
|
|
10
|
+
# TTY::MenuTree::ExitAction.new(name: "Quit")
|
|
11
|
+
class ExitAction < Action
|
|
12
|
+
DEFAULT_NAME = "Exit"
|
|
13
|
+
|
|
14
|
+
# @return [String] the label shown for this action.
|
|
15
|
+
attr_reader :name
|
|
16
|
+
|
|
17
|
+
# @param name [String] label shown in the menu.
|
|
18
|
+
def initialize(name: DEFAULT_NAME)
|
|
19
|
+
super()
|
|
20
|
+
@name = name
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# No-op; selecting this action ends the loop rather than doing work.
|
|
24
|
+
# @return [void]
|
|
25
|
+
def call; end
|
|
26
|
+
|
|
27
|
+
# @return [true]
|
|
28
|
+
def exit?
|
|
29
|
+
true
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "action"
|
|
4
|
+
|
|
5
|
+
module TTY
|
|
6
|
+
module MenuTree
|
|
7
|
+
# An action that, when selected, opens a submenu of child actions rather
|
|
8
|
+
# than performing work itself.
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
# TTY::MenuTree::Group.new(name: "Settings", actions: [ChangeTheme.new, Reset.new])
|
|
12
|
+
class Group < Action
|
|
13
|
+
# @return [String] the label shown for this group.
|
|
14
|
+
attr_reader :name
|
|
15
|
+
|
|
16
|
+
# @return [Array<#name>] the child actions.
|
|
17
|
+
attr_reader :submenu
|
|
18
|
+
|
|
19
|
+
# @param name [String] label shown in the parent menu.
|
|
20
|
+
# @param actions [Array<#name>] child actions to show when this group is
|
|
21
|
+
# selected.
|
|
22
|
+
def initialize(name:, actions:)
|
|
23
|
+
super()
|
|
24
|
+
@name = name
|
|
25
|
+
@submenu = actions
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "prompt"
|
|
4
|
+
|
|
5
|
+
module TTY
|
|
6
|
+
module MenuTree
|
|
7
|
+
# Runs a tree of actions as an interactive, hierarchical menu.
|
|
8
|
+
#
|
|
9
|
+
# The loop repeatedly asks the user to pick an action. Leaf actions are
|
|
10
|
+
# invoked via +#call+; actions that expose a +#submenu+ are descended into
|
|
11
|
+
# (with a "Back" entry); and an action whose +#exit?+ returns +true+ ends
|
|
12
|
+
# the loop.
|
|
13
|
+
#
|
|
14
|
+
# @example
|
|
15
|
+
# menu = TTY::MenuTree::Menu.new(
|
|
16
|
+
# actions: [group, TTY::MenuTree::ExitAction.new],
|
|
17
|
+
# title: "What would you like to do?",
|
|
18
|
+
# on_start: -> { puts "Welcome!" },
|
|
19
|
+
# on_exit: -> { puts "Goodbye!" },
|
|
20
|
+
# )
|
|
21
|
+
# menu.run
|
|
22
|
+
class Menu
|
|
23
|
+
# @param actions [Array<#name>] top-level actions.
|
|
24
|
+
# @param prompt [#select_action] object used to render menus. Defaults to
|
|
25
|
+
# a {Prompt}.
|
|
26
|
+
# @param title [String] heading shown for the top-level menu each loop.
|
|
27
|
+
# @param on_start [#call, nil] callable run once before the loop starts.
|
|
28
|
+
# @param on_exit [#call, nil] callable run once after an exit action is
|
|
29
|
+
# chosen.
|
|
30
|
+
def initialize(actions:, prompt: Prompt.new, title: "What would you like to do?",
|
|
31
|
+
on_start: nil, on_exit: nil)
|
|
32
|
+
@actions = actions
|
|
33
|
+
@prompt = prompt
|
|
34
|
+
@title = title
|
|
35
|
+
@on_start = on_start
|
|
36
|
+
@on_exit = on_exit
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Run the interactive loop until an exit action is chosen.
|
|
40
|
+
# @return [void]
|
|
41
|
+
def run
|
|
42
|
+
@on_start&.call
|
|
43
|
+
|
|
44
|
+
loop do
|
|
45
|
+
action = @prompt.select_action(@title, @actions)
|
|
46
|
+
|
|
47
|
+
if action.exit?
|
|
48
|
+
@on_exit&.call
|
|
49
|
+
break
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
run_action(action)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def run_action(action)
|
|
59
|
+
return action.call unless action.submenu
|
|
60
|
+
|
|
61
|
+
loop do
|
|
62
|
+
child = @prompt.select_action(action.name, action.submenu, back: true)
|
|
63
|
+
return if child.nil?
|
|
64
|
+
|
|
65
|
+
run_action(child)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tty-prompt"
|
|
4
|
+
|
|
5
|
+
module TTY
|
|
6
|
+
module MenuTree
|
|
7
|
+
# Thin wrapper around +TTY::Prompt+ that knows how to render a list of
|
|
8
|
+
# actions and, optionally, a "Back" entry.
|
|
9
|
+
#
|
|
10
|
+
# {Menu} only depends on the {#select_action} method, so you may pass any
|
|
11
|
+
# object that implements it if you want fully custom rendering.
|
|
12
|
+
class Prompt
|
|
13
|
+
DEFAULT_BACK_LABEL = "\u21A9\uFE0F Back"
|
|
14
|
+
|
|
15
|
+
# @param tty_prompt [TTY::Prompt] the underlying prompt to drive.
|
|
16
|
+
# @param back_label [String] label used for the "Back" entry.
|
|
17
|
+
def initialize(tty_prompt: TTY::Prompt.new(active_color: :cyan, help_color: :bright_black),
|
|
18
|
+
back_label: DEFAULT_BACK_LABEL)
|
|
19
|
+
@tty_prompt = tty_prompt
|
|
20
|
+
@back_label = back_label
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Present +actions+ and return the one the user picked.
|
|
24
|
+
#
|
|
25
|
+
# @param title [String] heading shown above the choices.
|
|
26
|
+
# @param actions [Array<#name>] selectable actions.
|
|
27
|
+
# @param back [Boolean] when +true+, append a "Back" entry that returns
|
|
28
|
+
# +nil+ when chosen.
|
|
29
|
+
# @return [Object, nil] the selected action, or +nil+ when "Back" was
|
|
30
|
+
# chosen.
|
|
31
|
+
def select_action(title, actions, back: false)
|
|
32
|
+
choices = actions.to_h { |action| [action.name, action] }
|
|
33
|
+
choices[@back_label] = nil if back
|
|
34
|
+
@tty_prompt.select("\n#{title}", choices, per_page: choices.size)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "menu_tree/version"
|
|
4
|
+
require_relative "menu_tree/action"
|
|
5
|
+
require_relative "menu_tree/group"
|
|
6
|
+
require_relative "menu_tree/exit_action"
|
|
7
|
+
require_relative "menu_tree/prompt"
|
|
8
|
+
require_relative "menu_tree/menu"
|
|
9
|
+
|
|
10
|
+
module TTY
|
|
11
|
+
# A small toolkit for building interactive, hierarchical command-line menus
|
|
12
|
+
# on top of +tty-prompt+.
|
|
13
|
+
#
|
|
14
|
+
# See {TTY::MenuTree::Menu} for the entry point.
|
|
15
|
+
module MenuTree
|
|
16
|
+
end
|
|
17
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: tty-menu-tree
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Romain Deshaies
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: tty-prompt
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.23'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.23'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: rspec
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '3.0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '3.0'
|
|
40
|
+
description: |-
|
|
41
|
+
TTY::MenuTree runs a tree of polymorphic "action" objects as an interactive
|
|
42
|
+
command-line menu, with support for nested submenus, back navigation, and an
|
|
43
|
+
exit action. Content such as banners and goodbyes are injectable hooks so the
|
|
44
|
+
menu itself stays free of application-specific concerns.
|
|
45
|
+
email:
|
|
46
|
+
- romain.deshaies@shopify.com
|
|
47
|
+
executables: []
|
|
48
|
+
extensions: []
|
|
49
|
+
extra_rdoc_files: []
|
|
50
|
+
files:
|
|
51
|
+
- CHANGELOG.md
|
|
52
|
+
- LICENSE.txt
|
|
53
|
+
- README.md
|
|
54
|
+
- lib/tty/menu_tree.rb
|
|
55
|
+
- lib/tty/menu_tree/action.rb
|
|
56
|
+
- lib/tty/menu_tree/exit_action.rb
|
|
57
|
+
- lib/tty/menu_tree/group.rb
|
|
58
|
+
- lib/tty/menu_tree/menu.rb
|
|
59
|
+
- lib/tty/menu_tree/prompt.rb
|
|
60
|
+
- lib/tty/menu_tree/version.rb
|
|
61
|
+
homepage: https://github.com/xef5000/tty-menu-tree
|
|
62
|
+
licenses:
|
|
63
|
+
- MIT
|
|
64
|
+
metadata:
|
|
65
|
+
source_code_uri: https://github.com/xef5000/tty-menu-tree
|
|
66
|
+
changelog_uri: https://github.com/xef5000/tty-menu-tree/blob/main/CHANGELOG.md
|
|
67
|
+
rubygems_mfa_required: 'true'
|
|
68
|
+
rdoc_options: []
|
|
69
|
+
require_paths:
|
|
70
|
+
- lib
|
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '3.0'
|
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
|
+
requirements:
|
|
78
|
+
- - ">="
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: '0'
|
|
81
|
+
requirements: []
|
|
82
|
+
rubygems_version: 4.0.16
|
|
83
|
+
specification_version: 4
|
|
84
|
+
summary: Interactive, hierarchical command-line menus built on tty-prompt.
|
|
85
|
+
test_files: []
|