command_tree 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 669d97d138e5a9b26b34f51561538f6a40e306f3f22682c854f74d8d1a6e76a6
4
- data.tar.gz: bdf8eea29094e6ec232bd32b9ed2b5f0b619b851c48b6e1049325c91dd6610a4
3
+ metadata.gz: 8aed81a9c05e2f2e5610157af9f29faa54e699caddd21f4c5bc6bdf021b9b56a
4
+ data.tar.gz: 54245dba9ee4085224117ca3891bfcd4f1eda142deae333844fa74787a91ad9f
5
5
  SHA512:
6
- metadata.gz: b169b9c1795f6d82cf335292a53c624b0ecf8cda0c99582753ef8beee229b43833a569bb4698d6d6c3e05aadf83152ffa25b8bb0727843777d19383dee22e4fb
7
- data.tar.gz: b2cc19380bff9655d04e0847624f042781a4359fd548bea49eced3d6e898a485b0313c0f0971630a5e310380b16c391404c7216209b016627ab110d3c6b55513
6
+ metadata.gz: fa3f0b10340221ed303c805529652ea0ce40d2e4a58b26eaeaea14afc03c372c271fe217eb56cc55507bfc44183265a984f237a212bf8f36520b3eb3279840a0
7
+ data.tar.gz: f48773a682ce667a3a285eade3cd75b10112acf6922016aa4cc8c0a05261be56c4006d0ea942962bfdcb4856ca87f27fbac5e84fcef98ee55b9cafcacc56bb79
@@ -1,24 +1,23 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- command_tree (0.1.1)
5
- colorize (~> 0.8)
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.11.3)
12
- rake (10.5.0)
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 (~> 5.0)
21
- rake (~> 10.0)
19
+ minitest
20
+ rake
22
21
 
23
22
  BUNDLED WITH
24
- 1.16.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 can register a command category (a node that contains commands)
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.
@@ -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", "~> 0.8"
24
+ spec.add_dependency "colorize"
25
25
 
26
- spec.add_development_dependency "bundler", "~> 1.16"
27
- spec.add_development_dependency "rake", "~> 10.0"
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
@@ -1,47 +1,78 @@
1
1
  require 'io/console'
2
- require 'colorize'
3
- require 'colorized_string'
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
- calls[path] = { name: name, options: options, block: block } if block_given?
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
- private
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] = { name: name, options: options } unless 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
- children = calls.keys.select { |key| key.start_with?(path) && key.length == (path.length + 1) }
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
- table_content = []
90
+ menu = TextMenu.new(40)
54
91
 
55
92
  children.each do |child|
56
- child_node = calls[child]
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
- table(table_content, 40)
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
@@ -1,3 +1,3 @@
1
1
  module CommandTree
2
- VERSION = "0.1.1"
2
+ VERSION = '0.2.0'
3
3
  end
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.1.1
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: 2018-09-28 00:00:00.000000000 Z
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.8'
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.8'
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: '10.0'
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: '10.0'
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: '5.0'
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: '5.0'
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
- rubyforge_project:
111
- rubygems_version: 2.7.3
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: []