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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c630a25a72718f5826c05cef883db24a1c86fb15e2a6b5cc7ff8dfaf2ddd4097
4
- data.tar.gz: 7de6920626c61aa2982680fd0df38d7f1ff229913d816adcccf3446b7243a7e3
3
+ metadata.gz: 81af9b5ecb0bfa6a5c5d0546bef0424ab3301e5306222a9a0db5050039f20049
4
+ data.tar.gz: cdb5ce86ac9ba4e8c574c5c3b688b3e82874c35a9b6873cf9f294800925c9d31
5
5
  SHA512:
6
- metadata.gz: df74bf563daf0e6c6ddb1863ce364225f05d5a8814857da4370dd002851d67f9d9cab422061d9e4a7bb7df6c4b2c3956a74f76c9be20ff3ad661ff3d234b5dea
7
- data.tar.gz: 99e2f4dc73b837f71a4c167e837b3ca88c6176d85e603bdf0cdd5cd1b21551b8e6c37f8ecf2bd7edfd1345cc65581789caded4a8a3e43d1670ef44f79c12e630
6
+ metadata.gz: b82a4b1d8f179b3b12d481f6bd63b891d70f695987d9b0efc81eb0c40f34d984b14b8714c25b0a1b6ef090b6be97055040e5cc0d967624e1c821112a1e0b8bd5
7
+ data.tar.gz: 64eb45044b043717ad869b3cab606e5b2283c2666fa82df2ffc3b5f13e30de3d3b9672ab72ab64424688fda8c5535542217511b72d13da509cc88dd91f546869
data/.gitignore CHANGED
@@ -6,3 +6,4 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ *.sw[o-t]
@@ -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
- class CMD
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
@@ -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
@@ -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
@@ -1,3 +1,3 @@
1
1
  class DenCli
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
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.1.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-13 00:00:00.000000000 Z
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: