dencli 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|