dencli 0.1.0 → 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/.gitignore +1 -0
- data/lib/dencli.rb +10 -101
- data/lib/dencli/cmd.rb +31 -0
- data/lib/dencli/interactive.rb +133 -0
- data/lib/dencli/sub.rb +74 -0
- data/lib/dencli/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81af9b5ecb0bfa6a5c5d0546bef0424ab3301e5306222a9a0db5050039f20049
|
4
|
+
data.tar.gz: cdb5ce86ac9ba4e8c574c5c3b688b3e82874c35a9b6873cf9f294800925c9d31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b82a4b1d8f179b3b12d481f6bd63b891d70f695987d9b0efc81eb0c40f34d984b14b8714c25b0a1b6ef090b6be97055040e5cc0d967624e1c821112a1e0b8bd5
|
7
|
+
data.tar.gz: 64eb45044b043717ad869b3cab606e5b2283c2666fa82df2ffc3b5f13e30de3d3b9672ab72ab64424688fda8c5535542217511b72d13da509cc88dd91f546869
|
data/.gitignore
CHANGED
data/lib/dencli.rb
CHANGED
@@ -4,6 +4,11 @@ class DenCli
|
|
4
4
|
class UnknownCommand < UsageError
|
5
5
|
end
|
6
6
|
|
7
|
+
require_relative 'dencli/cmd'
|
8
|
+
require_relative 'dencli/sub'
|
9
|
+
require_relative 'dencli/interactive'
|
10
|
+
require_relative 'dencli/version'
|
11
|
+
|
7
12
|
class <<self
|
8
13
|
# Helper Function for generate Regular Expressions of string,
|
9
14
|
# which matches all strings which has parts fron beginning of the given string.
|
@@ -47,107 +52,7 @@ class DenCli
|
|
47
52
|
alias g gen_aliases
|
48
53
|
end
|
49
54
|
|
50
|
-
|
51
|
-
attr_reader :parent, :name, :desc, :exe
|
52
|
-
def initialize parent, name, desc, exe
|
53
|
-
raise "Proc expected, instead of: #{exe.inspect}" unless Proc === exe
|
54
|
-
@parent, @name, @desc, @exe = parent, name, desc, exe
|
55
|
-
end
|
56
|
-
|
57
|
-
def _full_cmd post
|
58
|
-
parent._full_cmd [@name]+post
|
59
|
-
end
|
60
|
-
|
61
|
-
def full_cmd
|
62
|
-
_full_cmd []
|
63
|
-
end
|
64
|
-
|
65
|
-
def call *a
|
66
|
-
@exe.call *a
|
67
|
-
end
|
68
|
-
|
69
|
-
def help
|
70
|
-
"#{parent.full_cmd.join ' '} #{name}\n#{ desc}"
|
71
|
-
end
|
72
|
-
|
73
|
-
def inspect
|
74
|
-
"#<%s:0x%x %s @name=%p @desc=%p @parent=<%s:0x%x %s> @exe=<arity=%d>>" % [
|
75
|
-
self.class.name, self.object_id, self.full_cmd,
|
76
|
-
@name, @desc, @parent.class.name, @parent.class.object_id, @parent.full_cmd,
|
77
|
-
@exe.arity
|
78
|
-
]
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
class Sub
|
83
|
-
attr_reader :parent, :name, :desc, :subs
|
84
|
-
def initialize parent, name, desc
|
85
|
-
@parent, @name, @desc, @subs, @aliases = parent, name, desc, {}, {}
|
86
|
-
end
|
87
|
-
|
88
|
-
def _full_cmd post
|
89
|
-
parent._full_cmd [@name]+post
|
90
|
-
end
|
91
|
-
|
92
|
-
def full_cmd
|
93
|
-
_full_cmd []
|
94
|
-
end
|
95
|
-
|
96
|
-
def [] k
|
97
|
-
@aliases[k]
|
98
|
-
end
|
99
|
-
|
100
|
-
def help n = nil, *a
|
101
|
-
if n.nil?
|
102
|
-
r = "#{full_cmd.join ' '}: #{desc}\n\n"
|
103
|
-
m = @subs.map {|k,_| k.length }.max
|
104
|
-
@subs.each do |k, c|
|
105
|
-
r += " % -#{m}s %s\n" % [k, c.desc] unless k.nil?
|
106
|
-
end
|
107
|
-
r
|
108
|
-
elsif @aliases.has_key? n
|
109
|
-
@aliases[n].help *a
|
110
|
-
else
|
111
|
-
raise UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.inspect}"
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def call *a
|
116
|
-
n, *a = *a
|
117
|
-
if @aliases.has_key? n
|
118
|
-
@aliases[n].call *a
|
119
|
-
else
|
120
|
-
raise UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.inspect}"
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def _add name, min, obj, aliases
|
125
|
-
name = name.to_s unless name.nil?
|
126
|
-
@subs[name] = obj
|
127
|
-
DenCli.gen_aliases( name, min) {|a| @aliases[a] = obj }
|
128
|
-
if aliases
|
129
|
-
[*aliases].each {|a| @aliases[a] = obj }
|
130
|
-
end
|
131
|
-
obj
|
132
|
-
end
|
133
|
-
private :_add
|
134
|
-
|
135
|
-
def sub name, desc, min: nil, aliases: nil, &exe
|
136
|
-
r = _add name, min, Sub.new( self, name, desc), aliases
|
137
|
-
block_given? ? yield( r) : r
|
138
|
-
end
|
139
|
-
|
140
|
-
def cmd name, desc, min: nil, aliases: nil, &exe
|
141
|
-
_add name, min, CMD.new( self, name, desc, exe), aliases
|
142
|
-
end
|
143
|
-
|
144
|
-
def inspect
|
145
|
-
"#<%s:0x%x %s @name=%p @desc=%p @subs={%s} @aliases={%s} @parent=<%s:0x%x %s>>" % [
|
146
|
-
self.class.name, self.object_id, self.full_cmd,
|
147
|
-
@name, @desc, @subs.keys.join(', '), @aliases.keys.join(', '), @parent.class.name, @parent.class.object_id, @parent.full_cmd
|
148
|
-
]
|
149
|
-
end
|
150
|
-
end
|
55
|
+
attr_reader :subs
|
151
56
|
|
152
57
|
def initialize progname, desc
|
153
58
|
@subs = Sub.new self, progname, desc
|
@@ -180,4 +85,8 @@ class DenCli
|
|
180
85
|
def [] k
|
181
86
|
@subs[k]
|
182
87
|
end
|
88
|
+
|
89
|
+
def interactive *args, **opts
|
90
|
+
Interactive.new self, *args, **opts
|
91
|
+
end
|
183
92
|
end
|
data/lib/dencli/cmd.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative '../dencli'
|
2
|
+
|
3
|
+
class DenCli::CMD
|
4
|
+
attr_reader :parent, :name, :desc, :exe, :completion
|
5
|
+
|
6
|
+
def initialize parent, name, desc, exe
|
7
|
+
raise "Proc expected, instead of: #{exe.inspect}" unless Proc === exe
|
8
|
+
@parent, @name, @desc, @exe = parent, name, desc, exe
|
9
|
+
completion {|*a| [] }
|
10
|
+
end
|
11
|
+
|
12
|
+
def _full_cmd( post) parent._full_cmd [@name]+post end
|
13
|
+
def full_cmd() _full_cmd [] end
|
14
|
+
def call( *a) @exe.call *a end
|
15
|
+
def help() "#{parent.full_cmd.join ' '} #{name}\n#{ desc}" end
|
16
|
+
|
17
|
+
def complete( *pre, str) @completion.call *pre, str end
|
18
|
+
|
19
|
+
def completion &exe
|
20
|
+
@completion = exe
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def inspect
|
25
|
+
"#<%s:0x%x %s @name=%p @desc=%p @parent=<%s:0x%x %s> @exe=<arity=%d>>" % [
|
26
|
+
self.class.name, self.object_id, self.full_cmd,
|
27
|
+
@name, @desc, @parent.class.name, @parent.class.object_id, @parent.full_cmd,
|
28
|
+
@exe.arity
|
29
|
+
]
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require_relative '../dencli'
|
2
|
+
|
3
|
+
class DenCli::Interactive
|
4
|
+
attr_reader :cl, :prompt, :cur, :histfile
|
5
|
+
|
6
|
+
def initialize cl, prompt, histfile: nil
|
7
|
+
require 'readline'
|
8
|
+
@cl, self.prompt = cl, prompt
|
9
|
+
@cur = cl.subs
|
10
|
+
cur.instance_variable_set :@name, ''
|
11
|
+
|
12
|
+
@histfile =
|
13
|
+
case histfile
|
14
|
+
when nil then nil
|
15
|
+
when Pathname then histfile
|
16
|
+
else Pathname.new histfile.to_s
|
17
|
+
end
|
18
|
+
read_history if @histfile
|
19
|
+
|
20
|
+
Readline.vi_editing_mode rescue NotImplementedError
|
21
|
+
Readline.completion_append_character = " "
|
22
|
+
Readline.completion_proc = method :complete
|
23
|
+
|
24
|
+
prepare_sub cl.subs
|
25
|
+
cl.cmd :exit, "exit", min: 2 do
|
26
|
+
exit 0
|
27
|
+
end
|
28
|
+
cl.subs.aliases['?'] = cl.subs.subs['help']
|
29
|
+
cl.subs.subs.delete 'cli'
|
30
|
+
|
31
|
+
stty_save = %x`stty -g`.chomp
|
32
|
+
trap "INT" do
|
33
|
+
system "stty", stty_save
|
34
|
+
Readline.refresh_line
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def history_file file = nil
|
39
|
+
file =
|
40
|
+
case file
|
41
|
+
when Pathname then file
|
42
|
+
when nil then @histfile
|
43
|
+
else Pathname.new file.to_s
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def read_history file = nil
|
48
|
+
file = history_file file
|
49
|
+
return unless file and file.exist?
|
50
|
+
file.each_line do |line|
|
51
|
+
Readline::HISTORY.push line.chomp
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def write_history file = nil
|
56
|
+
file = history_file file
|
57
|
+
return unless file
|
58
|
+
file.open 'w+' do |f|
|
59
|
+
Readline::HISTORY.each do |line|
|
60
|
+
f.puts line
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def prompt= s
|
66
|
+
@prompt = s.to_s
|
67
|
+
end
|
68
|
+
|
69
|
+
def complete s
|
70
|
+
ws = words Readline.line_buffer
|
71
|
+
@cur.complete *ws[0...-1], s
|
72
|
+
end
|
73
|
+
|
74
|
+
def sub *args, cur: nil
|
75
|
+
args.inject( cur || @cur) do |r, a|
|
76
|
+
return nil unless r.is_a? DenCli::Sub
|
77
|
+
r[a]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
private :sub
|
81
|
+
|
82
|
+
def words line = nil
|
83
|
+
r = line.split " "
|
84
|
+
r.push '' if ' ' == line[-1]
|
85
|
+
r
|
86
|
+
end
|
87
|
+
private :words
|
88
|
+
|
89
|
+
def prepare_sub c
|
90
|
+
c.subs.values.each do |n|
|
91
|
+
case n
|
92
|
+
when DenCli::Sub
|
93
|
+
n.cmd :exit, "<- #{n.parent.full_cmd.join ' '} - #{n.parent.desc[3..-1]}", min: 2 do
|
94
|
+
@cur = n.parent
|
95
|
+
end
|
96
|
+
n.cmd '', "", min: 2, aliases: [nil] do
|
97
|
+
@cur = n
|
98
|
+
end
|
99
|
+
n.subs.delete ''
|
100
|
+
n.aliases['?'] = n.subs['help']
|
101
|
+
prepare_sub n
|
102
|
+
when DenCli::CMD
|
103
|
+
else raise "Unsupported sub-type: #{x}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def read
|
109
|
+
line = Readline.readline( "#{prompt}#{cur.full_cmd.join ' '}> ", true)
|
110
|
+
return nil if line.nil?
|
111
|
+
Readline::HISTORY.pop if /^\s*$/ =~ line
|
112
|
+
if 0 < Readline::HISTORY.length-2 and Readline::HISTORY[Readline::HISTORY.length-2] == line
|
113
|
+
Readline::HISTORY.pop
|
114
|
+
end
|
115
|
+
line.split " "
|
116
|
+
end
|
117
|
+
|
118
|
+
def step
|
119
|
+
line = read
|
120
|
+
return nil if line.nil?
|
121
|
+
begin
|
122
|
+
cur.call *line
|
123
|
+
rescue ::UsageError
|
124
|
+
STDERR.puts "! #$!"
|
125
|
+
end
|
126
|
+
true
|
127
|
+
end
|
128
|
+
|
129
|
+
def run
|
130
|
+
while step
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
data/lib/dencli/sub.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative '../dencli'
|
2
|
+
|
3
|
+
class DenCli::Sub
|
4
|
+
attr_reader :parent, :name, :desc, :subs, :aliases
|
5
|
+
|
6
|
+
def initialize parent, name, desc
|
7
|
+
@parent, @name, @desc, @subs, @aliases = parent, name, "-> #{desc}", {}, {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def _full_cmd( post) parent._full_cmd [@name]+post end
|
11
|
+
def full_cmd() _full_cmd [] end
|
12
|
+
def []( k) @aliases[k] end
|
13
|
+
|
14
|
+
def help n = nil, *a
|
15
|
+
if n.nil?
|
16
|
+
r = "#{full_cmd.join ' '}: #{desc}\n\n"
|
17
|
+
m = @subs.map {|k,_| k.length }.max
|
18
|
+
@subs.each do |k, c|
|
19
|
+
r += " % -#{m}s %s\n" % [k, c.desc] unless k.nil?
|
20
|
+
end
|
21
|
+
r
|
22
|
+
elsif @aliases.has_key? n
|
23
|
+
@aliases[n].help *a
|
24
|
+
else
|
25
|
+
raise UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.join ' '}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def call *a
|
30
|
+
n, *a = *a
|
31
|
+
if @aliases.has_key? n
|
32
|
+
@aliases[n].call *a
|
33
|
+
else
|
34
|
+
raise UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.join ' '}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def _add name, min, obj, aliases
|
39
|
+
name = name.to_s unless name.nil?
|
40
|
+
@subs[name] = obj
|
41
|
+
DenCli.gen_aliases( name, min) {|a| @aliases[a] = obj }
|
42
|
+
if aliases
|
43
|
+
[*aliases].each {|a| @aliases[a] = obj }
|
44
|
+
end
|
45
|
+
obj
|
46
|
+
end
|
47
|
+
private :_add
|
48
|
+
|
49
|
+
def sub name, desc, min: nil, aliases: nil, &exe
|
50
|
+
r = _add name, min, DenCli::Sub.new( self, name, desc), aliases
|
51
|
+
block_given? ? yield( r) : r
|
52
|
+
end
|
53
|
+
|
54
|
+
def cmd name, desc, min: nil, aliases: nil, &exe
|
55
|
+
_add name, min, DenCli::CMD.new( self, name, desc, exe), aliases
|
56
|
+
end
|
57
|
+
|
58
|
+
def complete *pre, str
|
59
|
+
if pre.empty?
|
60
|
+
@subs.keys.grep /\A#{Regexp.escape str}/
|
61
|
+
elsif sub = @subs[pre[0]]
|
62
|
+
sub.complete *pre[1..-1], str
|
63
|
+
else
|
64
|
+
STDOUT.print "\a"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def inspect
|
69
|
+
"#<%s:0x%x %s @name=%p @desc=%p @subs={%s} @aliases={%s} @parent=<%s:0x%x %s>>" % [
|
70
|
+
self.class.name, self.object_id, self.full_cmd,
|
71
|
+
@name, @desc, @subs.keys.join(', '), @aliases.keys.join(', '), @parent.class.name, @parent.class.object_id, @parent.full_cmd
|
72
|
+
]
|
73
|
+
end
|
74
|
+
end
|
data/lib/dencli/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dencli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Knauf
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-12-
|
11
|
+
date: 2020-12-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -41,6 +41,9 @@ files:
|
|
41
41
|
- bin/example.rb
|
42
42
|
- dencli.gemspec
|
43
43
|
- lib/dencli.rb
|
44
|
+
- lib/dencli/cmd.rb
|
45
|
+
- lib/dencli/interactive.rb
|
46
|
+
- lib/dencli/sub.rb
|
44
47
|
- lib/dencli/version.rb
|
45
48
|
homepage: https://git.denkn.at/deac/dencli
|
46
49
|
licenses:
|