menu_commander 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +147 -0
- data/bin/menu +17 -0
- data/lib/menu_commander/cli.rb +13 -0
- data/lib/menu_commander/command.rb +43 -0
- data/lib/menu_commander/exceptions.rb +11 -0
- data/lib/menu_commander/menu.rb +74 -0
- data/lib/menu_commander/version.rb +3 -0
- data/lib/menu_commander.rb +6 -0
- metadata +93 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '09d63d573439372dd5e017940ded720734eef31f0eea6cc290ff0605328a0118'
|
4
|
+
data.tar.gz: 3b6e7e0a01a17463289c8390581cf899498281c98ccb1eb6fcd88535462db953
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b496ffd6d0b7734a906091ce1c90e685ba691f3415108bca93c6766caeaca7153c39251ebe4c9ca690b6b51d845242d42b4ce9794d0cd4d84b23d5d024c5a671
|
7
|
+
data.tar.gz: 47c792e570005e6e47746d7495ee138b80a5d8d9330f92d1a22399772cd1687d78f1a45ce2f92a628861b8064b2f97b0276bdad5495ed689a76752e0303e9ac0
|
data/README.md
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
Menu Commander
|
2
|
+
==================================================
|
3
|
+
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/menu_commander.svg)](https://badge.fury.io/rb/menu_commander)
|
5
|
+
[![Build Status](https://travis-ci.com/DannyBen/menu_commander.svg?branch=master)](https://travis-ci.com/DannyBen/menu_commander)
|
6
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/.../maintainability)](https://codeclimate.com/github/DannyBen/menu_commander/maintainability)
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
Easily create menus for any command line tool using simple YAML configuration.
|
11
|
+
|
12
|
+
---
|
13
|
+
|
14
|
+
Installation
|
15
|
+
--------------------------------------------------
|
16
|
+
|
17
|
+
$ gem install menu_commander
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
Usage
|
22
|
+
--------------------------------------------------
|
23
|
+
|
24
|
+
Menu Commander adds the `menu` command line tool to your path. When running
|
25
|
+
it without arguments, it will look for a `menu.yml` file in the current
|
26
|
+
directory, and will provide you with a menu to execute any shell command.
|
27
|
+
|
28
|
+
A basic menu configuration file looks like this:
|
29
|
+
|
30
|
+
```yaml
|
31
|
+
# menu.yml
|
32
|
+
|
33
|
+
# Using %{variables} in a command will prompt for an input when executed
|
34
|
+
menu:
|
35
|
+
hello: echo hello
|
36
|
+
hi: echo hi %{name}
|
37
|
+
|
38
|
+
# Define sub menus for any %{variable} that was defined in the command
|
39
|
+
args:
|
40
|
+
name:
|
41
|
+
- Harry
|
42
|
+
- Lloyd
|
43
|
+
```
|
44
|
+
|
45
|
+
Running it, looks like this:
|
46
|
+
|
47
|
+
![Demo](/demo/demo.gif)
|
48
|
+
|
49
|
+
|
50
|
+
Features
|
51
|
+
--------------------------------------------------
|
52
|
+
|
53
|
+
All features have an example configuration in the
|
54
|
+
[examples folder](examples). To run an example, simply execute
|
55
|
+
`menu EAXMPLE_NAME` form within the examples folder, where `EXAMPLE_NAME`
|
56
|
+
is the name of the YAML file without the extension.
|
57
|
+
|
58
|
+
### Minimal menu requirements
|
59
|
+
|
60
|
+
The only requirement for a minimal menu is to have a `menu` definition
|
61
|
+
with `key: command` to run.
|
62
|
+
|
63
|
+
```yaml
|
64
|
+
# examples/minimal.yml
|
65
|
+
menu:
|
66
|
+
hello: echo hello
|
67
|
+
whoami: whoami
|
68
|
+
```
|
69
|
+
|
70
|
+
### Argument sub-menus
|
71
|
+
|
72
|
+
Using `%{variables}` in a command will prompt for an input when executed. The
|
73
|
+
sub-menu for that input is specified in the `args` definition.
|
74
|
+
|
75
|
+
```yaml
|
76
|
+
# examples/args-array.yml
|
77
|
+
menu:
|
78
|
+
server: rails server --env %{environment}
|
79
|
+
test: RAILS_ENV=%{environment} rspec
|
80
|
+
|
81
|
+
args:
|
82
|
+
environment:
|
83
|
+
- staging
|
84
|
+
- production
|
85
|
+
```
|
86
|
+
|
87
|
+
Using `key: value` pairs in the `args` menu will create a sub-menu with
|
88
|
+
labels that are different from their substituted value:
|
89
|
+
|
90
|
+
```yaml
|
91
|
+
# examples/args-hash.yml
|
92
|
+
menu:
|
93
|
+
server: rails server --env %{environment}
|
94
|
+
test: RAILS_ENV=%{environment} rspec
|
95
|
+
|
96
|
+
args:
|
97
|
+
environment:
|
98
|
+
Staging Environment: staging
|
99
|
+
Production Environment: production
|
100
|
+
```
|
101
|
+
|
102
|
+
In order to obtain the sub-menu items from a shell command, simply provide
|
103
|
+
the command to run, instead of providing the menu options. The command is
|
104
|
+
expected to provide newline-delimited output.
|
105
|
+
|
106
|
+
```yaml
|
107
|
+
# examples/args-shell.yml
|
108
|
+
menu:
|
109
|
+
show: cat %{file}
|
110
|
+
edit: vi %{file}
|
111
|
+
|
112
|
+
args:
|
113
|
+
file: ls
|
114
|
+
```
|
115
|
+
|
116
|
+
### Free text input
|
117
|
+
|
118
|
+
When using a `%{variable}` that does not have a corresponding definition in
|
119
|
+
the `args` section, you will simply be prompted for a free text input:
|
120
|
+
|
121
|
+
```yaml
|
122
|
+
# examples/args-free-text.yml
|
123
|
+
menu:
|
124
|
+
release:
|
125
|
+
echo %{version} > version.txt &&
|
126
|
+
git tag v%{version}
|
127
|
+
```
|
128
|
+
|
129
|
+
### Nested menus
|
130
|
+
|
131
|
+
You can nest as many menu levels as you wish under the menu definition.
|
132
|
+
|
133
|
+
```yaml
|
134
|
+
# examples/nested.yml
|
135
|
+
menu:
|
136
|
+
docker:
|
137
|
+
images: docker images ls
|
138
|
+
containers: docker ps -a
|
139
|
+
stack:
|
140
|
+
deploy: docker stack deploy -c docker-compose.yml mystack
|
141
|
+
list: docker stack ls
|
142
|
+
|
143
|
+
git:
|
144
|
+
status: git status
|
145
|
+
branch: git branch
|
146
|
+
```
|
147
|
+
|
data/bin/menu
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'menu_commander'
|
3
|
+
require 'colsole'
|
4
|
+
include Colsole
|
5
|
+
|
6
|
+
router = MenuCommander::CLI.router
|
7
|
+
|
8
|
+
begin
|
9
|
+
exit router.run ARGV
|
10
|
+
rescue MenuCommander::MenuNotFound => e
|
11
|
+
say! "!txtred!#{e.message}"
|
12
|
+
exit 1
|
13
|
+
rescue => e
|
14
|
+
puts e.backtrace.reverse if ENV['DEBUG']
|
15
|
+
say! "!txtred!#{e.class}: #{e.message}"
|
16
|
+
exit 1
|
17
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'mister_bin'
|
2
|
+
require 'colsole'
|
3
|
+
|
4
|
+
module MenuCommander
|
5
|
+
class Command < MisterBin::Command
|
6
|
+
include Colsole
|
7
|
+
|
8
|
+
help "Execute the menu"
|
9
|
+
usage "menu [CONFIG --dry]"
|
10
|
+
usage "menu (-h|--help)"
|
11
|
+
option "-d --dry", "Dry run. Do not execute the command at the end, just show it."
|
12
|
+
param "CONFIG", "The name of the menu config file without the .yml extension [default: menu]"
|
13
|
+
|
14
|
+
def run
|
15
|
+
raise MenuNotFound unless File.exist? menu_file
|
16
|
+
|
17
|
+
if args['--dry']
|
18
|
+
say "$ !txtpur!#{command}"
|
19
|
+
else
|
20
|
+
exec command
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def menu
|
25
|
+
@menu ||= Menu.new menu_file
|
26
|
+
end
|
27
|
+
|
28
|
+
def command
|
29
|
+
@command ||= menu.call
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def menu_file
|
35
|
+
"#{config}.yml"
|
36
|
+
end
|
37
|
+
|
38
|
+
def config
|
39
|
+
config = args['CONFIG'] || 'menu'
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'tty/prompt'
|
3
|
+
|
4
|
+
module MenuCommander
|
5
|
+
class Menu
|
6
|
+
attr_reader :config
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
config = YAML.load_file config if config.is_a? String
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(menu = nil)
|
14
|
+
menu ||= config['menu']
|
15
|
+
response = select menu
|
16
|
+
if response.is_a? String
|
17
|
+
params = {}
|
18
|
+
placeholders(response).each do |key|
|
19
|
+
params[key.to_sym] = get_user_response key
|
20
|
+
end
|
21
|
+
|
22
|
+
response % params
|
23
|
+
else
|
24
|
+
call response
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def placeholders(template)
|
31
|
+
template.scan(/%{([^}]+)}/).flatten.uniq
|
32
|
+
end
|
33
|
+
|
34
|
+
def args
|
35
|
+
config['args']
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_user_response(key)
|
39
|
+
opts = args ? args[key] : nil
|
40
|
+
opts = opts.is_a?(String) ? `#{opts}`.split("\n") : opts
|
41
|
+
|
42
|
+
if opts
|
43
|
+
opts.size == 1 ? opts[0] : select(opts, key)
|
44
|
+
else
|
45
|
+
ask(key)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def prompt
|
50
|
+
@prompt ||= TTY::Prompt.new
|
51
|
+
end
|
52
|
+
|
53
|
+
def ask(title)
|
54
|
+
prompt.ask "> #{title}:"
|
55
|
+
rescue TTY::Reader::InputInterrupt
|
56
|
+
# :nocov:
|
57
|
+
puts "\nGoodbye"
|
58
|
+
exit
|
59
|
+
# :nocov:
|
60
|
+
end
|
61
|
+
|
62
|
+
def select(options, title = nil)
|
63
|
+
title = title ? "> #{title}:" : ">"
|
64
|
+
menu_config = { marker: '>', per_page: 10 }
|
65
|
+
menu_config['filter'] = true if options.size > 10
|
66
|
+
prompt.select title, options, menu_config
|
67
|
+
rescue TTY::Reader::InputInterrupt
|
68
|
+
# :nocov:
|
69
|
+
puts "\nGoodbye"
|
70
|
+
exit
|
71
|
+
# :nocov:
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: menu_commander
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Danny Ben Shitrit
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-04-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mister_bin
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: colsole
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.5'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: tty-prompt
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.18'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.18'
|
55
|
+
description: Easily create menus for any command line tool using simple YAML configuration
|
56
|
+
email: db@dannyben.com
|
57
|
+
executables:
|
58
|
+
- menu
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- README.md
|
63
|
+
- bin/menu
|
64
|
+
- lib/menu_commander.rb
|
65
|
+
- lib/menu_commander/cli.rb
|
66
|
+
- lib/menu_commander/command.rb
|
67
|
+
- lib/menu_commander/exceptions.rb
|
68
|
+
- lib/menu_commander/menu.rb
|
69
|
+
- lib/menu_commander/version.rb
|
70
|
+
homepage: https://github.com/dannyben/menu_commander
|
71
|
+
licenses:
|
72
|
+
- MIT
|
73
|
+
metadata: {}
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options: []
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.3.0
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubygems_version: 3.0.3
|
90
|
+
signing_key:
|
91
|
+
specification_version: 4
|
92
|
+
summary: Create menus for any CLI tool
|
93
|
+
test_files: []
|