command_tree 0.1.1 → 0.2.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 +4 -4
- data/Gemfile.lock +7 -8
- data/README.md +14 -1
- data/command_tree.gemspec +3 -4
- data/lib/command_tree/command.rb +33 -0
- data/lib/command_tree/group.rb +31 -0
- data/lib/command_tree/text_menu.rb +55 -0
- data/lib/command_tree/tree.rb +55 -37
- data/lib/command_tree/version.rb +1 -1
- metadata +21 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8aed81a9c05e2f2e5610157af9f29faa54e699caddd21f4c5bc6bdf021b9b56a
|
4
|
+
data.tar.gz: 54245dba9ee4085224117ca3891bfcd4f1eda142deae333844fa74787a91ad9f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa3f0b10340221ed303c805529652ea0ce40d2e4a58b26eaeaea14afc03c372c271fe217eb56cc55507bfc44183265a984f237a212bf8f36520b3eb3279840a0
|
7
|
+
data.tar.gz: f48773a682ce667a3a285eade3cd75b10112acf6922016aa4cc8c0a05261be56c4006d0ea942962bfdcb4856ca87f27fbac5e84fcef98ee55b9cafcacc56bb79
|
data/Gemfile.lock
CHANGED
@@ -1,24 +1,23 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
command_tree (0.
|
5
|
-
colorize
|
4
|
+
command_tree (0.2.0)
|
5
|
+
colorize
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
10
|
colorize (0.8.1)
|
11
|
-
minitest (5.
|
12
|
-
rake (
|
11
|
+
minitest (5.14.1)
|
12
|
+
rake (13.0.1)
|
13
13
|
|
14
14
|
PLATFORMS
|
15
15
|
ruby
|
16
16
|
|
17
17
|
DEPENDENCIES
|
18
|
-
bundler (~> 1.16)
|
19
18
|
command_tree!
|
20
|
-
minitest
|
21
|
-
rake
|
19
|
+
minitest
|
20
|
+
rake
|
22
21
|
|
23
22
|
BUNDLED WITH
|
24
|
-
1.
|
23
|
+
2.1.4
|
data/README.md
CHANGED
@@ -29,7 +29,7 @@ You start by creating a new tree
|
|
29
29
|
t = CommandTree::Tree.new
|
30
30
|
```
|
31
31
|
|
32
|
-
Then you
|
32
|
+
Then you register a command category (a node that contains a group of commands)
|
33
33
|
|
34
34
|
```ruby
|
35
35
|
t.register 'a', 'Applications' # associate the character 'a' to a category called 'applications'
|
@@ -52,6 +52,19 @@ it will print the toplevel categories and commands and wait for you to press a c
|
|
52
52
|
|
53
53
|
when the tree reachs a leaf it'll exit, if a command is the leaf it will execute it and exit the tree giving your code the control again.
|
54
54
|
|
55
|
+
|
56
|
+
There is another way to define a group of commands in a nested way using `Tree#group` method as follows
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
t = CommandTree::Tree.new
|
60
|
+
t.group 'a', 'Applications' do |g|
|
61
|
+
g.register 'g','Google Chrome' do
|
62
|
+
system 'google-chrome-stable'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
t.show
|
66
|
+
```
|
67
|
+
|
55
68
|
## Development
|
56
69
|
|
57
70
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/command_tree.gemspec
CHANGED
@@ -21,9 +21,8 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
-
spec.add_dependency "colorize"
|
24
|
+
spec.add_dependency "colorize"
|
25
25
|
|
26
|
-
spec.add_development_dependency "
|
27
|
-
spec.add_development_dependency "
|
28
|
-
spec.add_development_dependency "minitest", "~> 5.0"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "minitest"
|
29
28
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module CommandTree
|
2
|
+
# A command class
|
3
|
+
class Command
|
4
|
+
attr_reader :name, :desc, :prefix, :block
|
5
|
+
|
6
|
+
def initialize(prefix, name, options = {}, &block)
|
7
|
+
@prefix = prefix
|
8
|
+
@name = name
|
9
|
+
@desc = options[:desc]
|
10
|
+
@block = block
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute
|
14
|
+
print_banner
|
15
|
+
block.call
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def print_banner
|
21
|
+
puts pretty_name if name
|
22
|
+
puts pretty_description if desc
|
23
|
+
end
|
24
|
+
|
25
|
+
def pretty_name
|
26
|
+
name.light_magenta.bold if name
|
27
|
+
end
|
28
|
+
|
29
|
+
def pretty_description
|
30
|
+
desc.to_s.light_black if desc
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module CommandTree
|
2
|
+
# A group of commands
|
3
|
+
class Group
|
4
|
+
attr_reader :name, :desc, :prefix
|
5
|
+
|
6
|
+
def initialize(prefix, name, options = {})
|
7
|
+
@prefix = prefix
|
8
|
+
@name = name
|
9
|
+
@desc = options[:desc]
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute
|
13
|
+
print_banner
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def print_banner
|
19
|
+
puts pretty_name if name
|
20
|
+
puts pretty_description if desc
|
21
|
+
end
|
22
|
+
|
23
|
+
def pretty_name
|
24
|
+
name.light_magenta.bold if name
|
25
|
+
end
|
26
|
+
|
27
|
+
def pretty_description
|
28
|
+
desc.to_s.light_black if desc
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'colorize'
|
2
|
+
require 'colorized_string'
|
3
|
+
|
4
|
+
module CommandTree
|
5
|
+
# responsible for showing the menu in terminal
|
6
|
+
class TextMenu
|
7
|
+
def initialize(item_width)
|
8
|
+
@item_width = item_width
|
9
|
+
@items = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def render
|
13
|
+
_, screen_width = IO.console.winsize
|
14
|
+
items_per_row = screen_width / item_width
|
15
|
+
|
16
|
+
names = items.dup.map! { |item| item_name(item) }
|
17
|
+
descs = items.dup.map! { |item| item_desc(item) }
|
18
|
+
|
19
|
+
until names.empty?
|
20
|
+
puts names.shift(items_per_row).join
|
21
|
+
row_descs = descs.shift(items_per_row).join
|
22
|
+
puts row_descs unless row_descs.strip.empty?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def add(item)
|
27
|
+
items << item
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :items, :item_width
|
33
|
+
|
34
|
+
def item_name(item)
|
35
|
+
prefix = item.prefix
|
36
|
+
arrow = ' → '
|
37
|
+
|
38
|
+
name_width = item_width - prefix.length - arrow.length
|
39
|
+
name = (item.is_a?(Group) ? '+' : '') + item.name
|
40
|
+
name = name.ljust(name_width)
|
41
|
+
|
42
|
+
colored_name = item.is_a?(Group) ? name.light_magenta.bold : name.cyan
|
43
|
+
|
44
|
+
(prefix.green + arrow.light_black + colored_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def item_desc(item)
|
48
|
+
desc = item.desc.to_s
|
49
|
+
return desc.ljust(item_width) if desc.strip.empty?
|
50
|
+
|
51
|
+
return (desc[0...item_width - 3] + '...').light_black if desc.length >= item_width
|
52
|
+
return desc.ljust(item_width).light_black
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/command_tree/tree.rb
CHANGED
@@ -1,47 +1,78 @@
|
|
1
1
|
require 'io/console'
|
2
|
-
|
3
|
-
|
2
|
+
|
3
|
+
require_relative 'group'
|
4
|
+
require_relative 'command'
|
5
|
+
require_relative 'text_menu'
|
4
6
|
|
5
7
|
module CommandTree
|
8
|
+
# A tree of commands and associated keys for every node
|
6
9
|
class Tree
|
7
10
|
def initialize
|
8
|
-
@calls = { '' =>
|
11
|
+
@calls = { '' => nil }
|
9
12
|
end
|
10
13
|
|
14
|
+
# register a `path` to a `name` with a block of code if
|
15
|
+
# you wish it to be a command, the following `options` are
|
16
|
+
# supported:
|
17
|
+
# desc: a description of the item, as a help text for the user
|
11
18
|
def register(path, name, options = {}, &block)
|
19
|
+
path = path.to_s
|
20
|
+
name = name.to_s
|
21
|
+
prefix = path[-1]
|
22
|
+
|
12
23
|
insure_path(path, name, options)
|
13
|
-
|
24
|
+
return unless block_given?
|
25
|
+
|
26
|
+
calls[path] = Command.new(prefix, name, options, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
# define a group of commands (subtree)
|
30
|
+
# the method will create a subtree and pass it to
|
31
|
+
# the given block of code if you passed a block
|
32
|
+
# otherwise it works in a similar way to register
|
33
|
+
def group(prefix, name, options = {})
|
34
|
+
subtree = self.class.new
|
35
|
+
yield(subtree) if block_given?
|
36
|
+
|
37
|
+
merge(subtree, prefix, name, options)
|
14
38
|
end
|
15
39
|
|
40
|
+
# Start the tree, prints the first level and walk
|
41
|
+
# the user through the tree with keystroks
|
16
42
|
def show
|
17
43
|
execute_path('')
|
18
44
|
end
|
19
45
|
|
20
|
-
|
46
|
+
# merge a subtree with a prefix and a name
|
47
|
+
def merge(subtree, prefix, name, options = {})
|
48
|
+
register(prefix, name, options)
|
49
|
+
subtree.calls.each do |key, command|
|
50
|
+
next unless command
|
51
|
+
|
52
|
+
calls["#{prefix}#{key}"] = command
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
21
57
|
|
22
58
|
attr_accessor :calls
|
23
59
|
|
60
|
+
private
|
61
|
+
|
24
62
|
def insure_path(path, name, options = {})
|
25
63
|
return if path.empty?
|
26
64
|
|
27
65
|
insure_path(path[0...-1], name, options)
|
28
|
-
calls[path] =
|
66
|
+
calls[path] = Group.new(path[-1], name, options) unless calls[path]
|
29
67
|
end
|
30
68
|
|
31
69
|
def execute_path(path)
|
32
70
|
return puts "#{path} couldn't be found..." unless calls.key?(path)
|
33
71
|
|
34
72
|
node = calls[path]
|
35
|
-
|
36
|
-
children.sort!
|
37
|
-
|
38
|
-
puts "#{node[:name]}:".light_magenta.bold if node.key?(:name)
|
39
|
-
|
40
|
-
description = node.dig(:options, :desc)
|
41
|
-
puts description.to_s.light_black if description
|
42
|
-
|
43
|
-
node[:block].call if node.key?(:block)
|
73
|
+
node.execute if node
|
44
74
|
|
75
|
+
children = get_children(path)
|
45
76
|
return if children.empty?
|
46
77
|
|
47
78
|
print_children(children)
|
@@ -49,34 +80,21 @@ module CommandTree
|
|
49
80
|
execute_path(path + choice)
|
50
81
|
end
|
51
82
|
|
83
|
+
def get_children(path)
|
84
|
+
calls.keys.select do |key|
|
85
|
+
key.start_with?(path) && key.length == (path.length + 1)
|
86
|
+
end.sort
|
87
|
+
end
|
88
|
+
|
52
89
|
def print_children(children)
|
53
|
-
|
90
|
+
menu = TextMenu.new(40)
|
54
91
|
|
55
92
|
children.each do |child|
|
56
|
-
|
57
|
-
|
58
|
-
output = child[-1].green
|
59
|
-
output << ' → '.light_black
|
60
|
-
|
61
|
-
output << if child_node.key?(:block)
|
62
|
-
" #{child_node[:name].ljust(40)}".cyan
|
63
|
-
else
|
64
|
-
"+#{child_node[:name].ljust(40)}".light_magenta.bold
|
65
|
-
end
|
66
|
-
|
67
|
-
table_content << output
|
93
|
+
menu.add calls[child]
|
68
94
|
end
|
69
95
|
|
70
|
-
|
96
|
+
menu.render
|
71
97
|
print "\n"
|
72
98
|
end
|
73
|
-
|
74
|
-
def table(items, item_width)
|
75
|
-
_, screen_width = IO.console.winsize
|
76
|
-
items_per_row = screen_width / item_width
|
77
|
-
items_dup = items.dup
|
78
|
-
|
79
|
-
puts items_dup.shift(items_per_row).join until items_dup.empty?
|
80
|
-
end
|
81
99
|
end
|
82
100
|
end
|
data/lib/command_tree/version.rb
CHANGED
metadata
CHANGED
@@ -1,71 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: command_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Emad Elsaid
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-08-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0
|
19
|
+
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: bundler
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '1.16'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '1.16'
|
26
|
+
version: '0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: rake
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
44
30
|
requirements:
|
45
|
-
- - "
|
31
|
+
- - ">="
|
46
32
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
33
|
+
version: '0'
|
48
34
|
type: :development
|
49
35
|
prerelease: false
|
50
36
|
version_requirements: !ruby/object:Gem::Requirement
|
51
37
|
requirements:
|
52
|
-
- - "
|
38
|
+
- - ">="
|
53
39
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
40
|
+
version: '0'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: minitest
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
58
44
|
requirements:
|
59
|
-
- - "
|
45
|
+
- - ">="
|
60
46
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
47
|
+
version: '0'
|
62
48
|
type: :development
|
63
49
|
prerelease: false
|
64
50
|
version_requirements: !ruby/object:Gem::Requirement
|
65
51
|
requirements:
|
66
|
-
- - "
|
52
|
+
- - ">="
|
67
53
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
54
|
+
version: '0'
|
69
55
|
description: Builds trees of commands for the terminal, each node is either a group
|
70
56
|
of commands or the command itself, every node is associated with a character to
|
71
57
|
access it.
|
@@ -86,13 +72,16 @@ files:
|
|
86
72
|
- bin/setup
|
87
73
|
- command_tree.gemspec
|
88
74
|
- lib/command_tree.rb
|
75
|
+
- lib/command_tree/command.rb
|
76
|
+
- lib/command_tree/group.rb
|
77
|
+
- lib/command_tree/text_menu.rb
|
89
78
|
- lib/command_tree/tree.rb
|
90
79
|
- lib/command_tree/version.rb
|
91
80
|
homepage: https://www.github.com/emad-elsaid/command_tree
|
92
81
|
licenses:
|
93
82
|
- MIT
|
94
83
|
metadata: {}
|
95
|
-
post_install_message:
|
84
|
+
post_install_message:
|
96
85
|
rdoc_options: []
|
97
86
|
require_paths:
|
98
87
|
- lib
|
@@ -107,9 +96,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
96
|
- !ruby/object:Gem::Version
|
108
97
|
version: '0'
|
109
98
|
requirements: []
|
110
|
-
|
111
|
-
|
112
|
-
signing_key:
|
99
|
+
rubygems_version: 3.1.2
|
100
|
+
signing_key:
|
113
101
|
specification_version: 4
|
114
102
|
summary: Command trees for the terminal
|
115
103
|
test_files: []
|