clio 0.0.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.
- data/CHANGES +66 -0
- data/MANIFEST +48 -169
- data/README +13 -17
- data/RELEASE +8 -0
- data/VERSION +1 -0
- data/lib/clio/buffer.rb +93 -0
- data/lib/clio/commandable.rb +71 -69
- data/lib/clio/commandline.rb +429 -230
- data/lib/clio/consoleutils.rb +0 -16
- data/lib/clio/facets/kernel.rb +13 -0
- data/lib/clio/facets/string.rb +25 -0
- data/lib/clio/layout.rb +14 -0
- data/lib/clio/layout/flow.rb +1 -0
- data/lib/clio/layout/line.rb +23 -0
- data/lib/clio/layout/list.rb +33 -0
- data/lib/clio/layout/split.rb +122 -0
- data/lib/clio/layout/stack.rb +17 -0
- data/lib/clio/layout/table.rb +46 -0
- data/lib/clio/progressbar.rb +189 -210
- data/lib/clio/string.rb +116 -109
- data/lib/clio/usage.rb +184 -0
- data/lib/clio/usage/argument.rb +84 -0
- data/lib/clio/usage/command.rb +440 -0
- data/lib/clio/usage/interface.rb +122 -0
- data/lib/clio/usage/main.rb +165 -0
- data/lib/clio/usage/option.rb +251 -0
- data/lib/clio/usage/parser.rb +191 -0
- data/lib/clio/usage/signature.rb +55 -0
- data/meta/abstract +3 -0
- data/meta/authors +1 -0
- data/meta/created +1 -0
- data/meta/homepage +1 -0
- data/meta/license +1 -0
- data/meta/repository +1 -0
- data/meta/summary +1 -0
- data/spec/commandline/autousage.rd +56 -0
- data/spec/commandline/bracket.rd +64 -0
- data/spec/commandline/completion.rd +38 -0
- data/spec/commandline/define.rd +44 -0
- data/spec/commandline/method.rd +60 -0
- data/spec/commandline/parse.rd +72 -0
- data/spec/commandline/scenario.rd +81 -0
- data/spec/commandline/subclass.rd +54 -0
- data/spec/string/unit.rd +58 -0
- data/spec/usage/define.rd +44 -0
- data/spec/usage/parse.rd +47 -0
- metadata +65 -196
- data/HISTORY +0 -11
- data/METADATA +0 -18
- data/NEWS +0 -10
- data/admin/config/reap.yaml +0 -30
- data/admin/depot/commandline.rb +0 -219
- data/admin/depot/multicommand.rb +0 -403
- data/admin/depot/test_multicommand.rb +0 -40
- data/admin/log/notes.xml +0 -28
- data/admin/log/stats.html +0 -25
- data/admin/log/syntax.log +0 -0
- data/admin/log/testunit.log +0 -16
- data/admin/pack/clio-0.0.1.gem +0 -0
- data/admin/share/reap/example.rb +0 -7
- data/admin/temps/lib/clio/about.rb.erb +0 -4
- data/lib/clio/command.rb +0 -296
- data/lib/clio/option.rb +0 -36
- data/lib/clio/runmode.rb +0 -126
- data/test/test_command.rb +0 -42
- data/test/test_commandline.rb +0 -83
- data/vendor/Console/Console.cpp +0 -1203
- data/vendor/Console/Console.rdoc +0 -690
- data/vendor/Console/Console_ANSI.rdoc +0 -302
- data/vendor/Console/HISTORY.txt +0 -7
- data/vendor/Console/INSTALL.txt +0 -18
- data/vendor/Console/Makefile +0 -162
- data/vendor/Console/README.txt +0 -26
- data/vendor/Console/doc/classes/Win32.html +0 -115
- data/vendor/Console/doc/classes/Win32/Console.html +0 -650
- data/vendor/Console/doc/classes/Win32/Console.src/M000001.html +0 -31
- data/vendor/Console/doc/classes/Win32/Console.src/M000002.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000003.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000004.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console.src/M000005.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000006.html +0 -28
- data/vendor/Console/doc/classes/Win32/Console.src/M000007.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000008.html +0 -24
- data/vendor/Console/doc/classes/Win32/Console.src/M000009.html +0 -44
- data/vendor/Console/doc/classes/Win32/Console.src/M000010.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000011.html +0 -33
- data/vendor/Console/doc/classes/Win32/Console.src/M000012.html +0 -26
- data/vendor/Console/doc/classes/Win32/Console.src/M000013.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console.src/M000014.html +0 -28
- data/vendor/Console/doc/classes/Win32/Console.src/M000015.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000016.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000017.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000018.html +0 -29
- data/vendor/Console/doc/classes/Win32/Console.src/M000019.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000020.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000021.html +0 -28
- data/vendor/Console/doc/classes/Win32/Console.src/M000022.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000023.html +0 -28
- data/vendor/Console/doc/classes/Win32/Console.src/M000024.html +0 -35
- data/vendor/Console/doc/classes/Win32/Console.src/M000025.html +0 -28
- data/vendor/Console/doc/classes/Win32/Console.src/M000026.html +0 -28
- data/vendor/Console/doc/classes/Win32/Console.src/M000027.html +0 -28
- data/vendor/Console/doc/classes/Win32/Console.src/M000028.html +0 -31
- data/vendor/Console/doc/classes/Win32/Console.src/M000029.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000030.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000031.html +0 -23
- data/vendor/Console/doc/classes/Win32/Console.src/M000032.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console.src/M000033.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console.src/M000034.html +0 -25
- data/vendor/Console/doc/classes/Win32/Console/ANSI.html +0 -103
- data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.html +0 -220
- data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000035.html +0 -32
- data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000036.html +0 -205
- data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000037.html +0 -40
- data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000038.html +0 -25
- data/vendor/Console/doc/classes/Win32/Console/API.html +0 -758
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000039.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000040.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000041.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000042.html +0 -32
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000043.html +0 -32
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000044.html +0 -28
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000045.html +0 -26
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000046.html +0 -26
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000047.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000048.html +0 -30
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000049.html +0 -29
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000050.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000051.html +0 -28
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000052.html +0 -30
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000053.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000054.html +0 -29
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000055.html +0 -29
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000056.html +0 -28
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000057.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000058.html +0 -47
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000059.html +0 -32
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000060.html +0 -47
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000061.html +0 -34
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000062.html +0 -32
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000063.html +0 -32
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000064.html +0 -35
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000065.html +0 -26
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000066.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000067.html +0 -29
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000068.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000069.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000070.html +0 -28
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000071.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000072.html +0 -26
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000073.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000074.html +0 -31
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000075.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000076.html +0 -32
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000077.html +0 -27
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000078.html +0 -32
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000079.html +0 -32
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000080.html +0 -32
- data/vendor/Console/doc/classes/Win32/Console/Constants.html +0 -360
- data/vendor/Console/doc/created.rid +0 -1
- data/vendor/Console/doc/files/Console_ANSI_rdoc.html +0 -407
- data/vendor/Console/doc/files/Console_cpp.html +0 -104
- data/vendor/Console/doc/files/Console_rdoc.html +0 -964
- data/vendor/Console/doc/files/lib/Win32/Console/ANSI_rb.html +0 -123
- data/vendor/Console/doc/files/lib/Win32/Console_rb.html +0 -297
- data/vendor/Console/doc/fr_class_index.html +0 -32
- data/vendor/Console/doc/fr_file_index.html +0 -31
- data/vendor/Console/doc/fr_method_index.html +0 -106
- data/vendor/Console/doc/index.html +0 -24
- data/vendor/Console/doc/rdoc-style.css +0 -172
- data/vendor/Console/extconf.rb +0 -18
- data/vendor/Console/lib/Term/ansicolor.rb +0 -76
- data/vendor/Console/lib/Win32/Console.rb +0 -970
- data/vendor/Console/lib/Win32/Console/ANSI.rb +0 -305
- data/vendor/Console/test/test_cursor.rb +0 -9
- data/vendor/Console/test/test_mouse.rb +0 -6
- data/vendor/Console/test/test_readinput.rb +0 -62
- data/vendor/Console/test/test_readoutput.rb +0 -52
- data/vendor/Console/test/test_sendevent.rb +0 -17
- data/vendor/Console/test/test_title.rb +0 -14
- data/vendor/Console/test/test_write.rb +0 -36
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
require 'clio/usage/command'
|
|
2
|
+
|
|
3
|
+
module Clio
|
|
4
|
+
|
|
5
|
+
module Usage #:nodoc:
|
|
6
|
+
|
|
7
|
+
# = Main
|
|
8
|
+
#
|
|
9
|
+
# Main specifies the toplevel "Command".
|
|
10
|
+
#
|
|
11
|
+
class Main < Command
|
|
12
|
+
|
|
13
|
+
# New Usage.
|
|
14
|
+
#
|
|
15
|
+
def initialize(name=nil, &block)
|
|
16
|
+
name ||= File.basename($0)
|
|
17
|
+
super(name, &block)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Define a command.
|
|
21
|
+
#
|
|
22
|
+
# command('remote')
|
|
23
|
+
# command('remote','add')
|
|
24
|
+
#
|
|
25
|
+
#def command(name, &block)
|
|
26
|
+
# raise "Command cannot have both arguments and subcommands (eg. #{name})." unless arguments.empty?
|
|
27
|
+
# key = name.to_s.strip
|
|
28
|
+
# if cmd = @commands.find{|c| c === key}
|
|
29
|
+
# else
|
|
30
|
+
# cmd = Command.new(key, self)
|
|
31
|
+
# @commands << cmd
|
|
32
|
+
# end
|
|
33
|
+
# cmd.instance_eval(&block) if block
|
|
34
|
+
# cmd
|
|
35
|
+
#end
|
|
36
|
+
|
|
37
|
+
=begin
|
|
38
|
+
#alias_method :[], :command
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# ARRAY NOTATION
|
|
42
|
+
#-------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
#
|
|
45
|
+
def [](*args)
|
|
46
|
+
res = nil
|
|
47
|
+
head, *tail = *args
|
|
48
|
+
case head.to_s
|
|
49
|
+
when /^-/
|
|
50
|
+
x = []
|
|
51
|
+
opts = args.map do |o|
|
|
52
|
+
o = o.to_s
|
|
53
|
+
if i = o.index('=')
|
|
54
|
+
x << o[i+1..-1]
|
|
55
|
+
o[0...i]
|
|
56
|
+
else
|
|
57
|
+
o
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
x = x.uniq
|
|
61
|
+
|
|
62
|
+
res = opt(*opts)
|
|
63
|
+
else
|
|
64
|
+
args.each do |name|
|
|
65
|
+
res = command(name)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
return res
|
|
69
|
+
end
|
|
70
|
+
=end
|
|
71
|
+
|
|
72
|
+
=begin
|
|
73
|
+
# Usage text.
|
|
74
|
+
#
|
|
75
|
+
def to_s
|
|
76
|
+
#s = [full_name]
|
|
77
|
+
s = [name]
|
|
78
|
+
|
|
79
|
+
case options.size
|
|
80
|
+
when 0
|
|
81
|
+
when 1, 2, 3
|
|
82
|
+
s.concat(options.collect{ |o| "[#{o.to_s.strip}]" })
|
|
83
|
+
else
|
|
84
|
+
s << "[switches]"
|
|
85
|
+
end
|
|
86
|
+
# switches? vs. options
|
|
87
|
+
s << arguments.join(' ') unless arguments.empty?
|
|
88
|
+
|
|
89
|
+
case commands.size
|
|
90
|
+
when 0
|
|
91
|
+
when 1
|
|
92
|
+
s << commands.join('')
|
|
93
|
+
when 2, 3
|
|
94
|
+
s << '[' + commands.join(' | ') + ']'
|
|
95
|
+
else
|
|
96
|
+
s << 'command'
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
s.flatten.join(' ')
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Help text.
|
|
103
|
+
#
|
|
104
|
+
def to_s_help
|
|
105
|
+
s = []
|
|
106
|
+
unless help.empty?
|
|
107
|
+
s << help
|
|
108
|
+
s << ''
|
|
109
|
+
end
|
|
110
|
+
s << "Usage:"
|
|
111
|
+
s << " " + to_s
|
|
112
|
+
unless commands.empty?
|
|
113
|
+
s << ''
|
|
114
|
+
s << 'Commands:'
|
|
115
|
+
s.concat(commands.collect{ |x| " %-20s %s" % [x.key, x.help] }.sort)
|
|
116
|
+
end
|
|
117
|
+
unless arguments.empty?
|
|
118
|
+
s << ''
|
|
119
|
+
s << "Arguments:"
|
|
120
|
+
s.concat(arguments.collect{ |x| " %-20s %s" % [x, x.help] })
|
|
121
|
+
end
|
|
122
|
+
unless options.empty?
|
|
123
|
+
s << ''
|
|
124
|
+
s << 'Switches:'
|
|
125
|
+
s.concat(options.collect{ |x| " %-20s %s" % [x, x.help] })
|
|
126
|
+
end
|
|
127
|
+
s.flatten.join("\n")
|
|
128
|
+
end
|
|
129
|
+
=end
|
|
130
|
+
|
|
131
|
+
def parse(argv)
|
|
132
|
+
Parser.new(self, argv).parse #(argv)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Cache usage into a per-user cache file for reuse.
|
|
136
|
+
# This can be used to greatly speed up tab completion.
|
|
137
|
+
#
|
|
138
|
+
def cache
|
|
139
|
+
File.open(cache_file, 'w'){ |f| f << to_yaml }
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
private
|
|
143
|
+
|
|
144
|
+
# TODO: Use XDG
|
|
145
|
+
|
|
146
|
+
def cache_file
|
|
147
|
+
File.join(File.expand_path('~'), '.cache', 'clio', "#{name}.yaml")
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def self.cache_file
|
|
151
|
+
File.join(File.expand_path('~'), '.cache', 'clio', "#{name}.yaml")
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def self.load_cache
|
|
155
|
+
if File.file?(cache_file)
|
|
156
|
+
YAML.load(File.new(cache_file))
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
end#class Main
|
|
161
|
+
|
|
162
|
+
end#module Usage
|
|
163
|
+
|
|
164
|
+
end#module Clio
|
|
165
|
+
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
module Clio
|
|
2
|
+
|
|
3
|
+
module Usage #:nodoc:
|
|
4
|
+
|
|
5
|
+
# = Commandline Option
|
|
6
|
+
#
|
|
7
|
+
class Option
|
|
8
|
+
|
|
9
|
+
# Parent command.
|
|
10
|
+
#attr :parent
|
|
11
|
+
|
|
12
|
+
# Option name.
|
|
13
|
+
attr :name
|
|
14
|
+
|
|
15
|
+
# Alternate names for this option.
|
|
16
|
+
attr :aliases
|
|
17
|
+
|
|
18
|
+
# Option arguments.
|
|
19
|
+
attr :arguments
|
|
20
|
+
|
|
21
|
+
# Option can be used more that once.
|
|
22
|
+
attr :multiple
|
|
23
|
+
|
|
24
|
+
# Option (names) that are mutually exlusive
|
|
25
|
+
# to this option.
|
|
26
|
+
attr :excludes
|
|
27
|
+
|
|
28
|
+
# Is the option greedy (true/false)? A greedy
|
|
29
|
+
# option is one that is parsed from the
|
|
30
|
+
# commandline no matter where it appears.
|
|
31
|
+
#attr_accessor :greedy
|
|
32
|
+
|
|
33
|
+
# Help text for this option.
|
|
34
|
+
attr :help
|
|
35
|
+
|
|
36
|
+
# New Option.
|
|
37
|
+
#def initialize(name, parent=nil, &block)
|
|
38
|
+
def initialize(name, &block)
|
|
39
|
+
@name = clean_name(name)
|
|
40
|
+
#@parent = parent
|
|
41
|
+
@aliases = []
|
|
42
|
+
@arguments = []
|
|
43
|
+
@multiple = false
|
|
44
|
+
#@greedy = false
|
|
45
|
+
@exclude = []
|
|
46
|
+
@help = ''
|
|
47
|
+
instance_eval(&block) if block
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
#
|
|
51
|
+
def initialize_copy(o)
|
|
52
|
+
@name = o.name.dup
|
|
53
|
+
@aliases = o.aliases.dup
|
|
54
|
+
#@multiple = o.multiple
|
|
55
|
+
@exclude = o.exclude.dup
|
|
56
|
+
@help = o.help.dup
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Same as +name+ but given as a symbol.
|
|
60
|
+
def key
|
|
61
|
+
name.to_sym
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Can this option occur multiple times in the
|
|
65
|
+
# command line?
|
|
66
|
+
def multiple? ; @multiple ; end
|
|
67
|
+
|
|
68
|
+
# Is this option greedy?
|
|
69
|
+
#def greedy? ; @greedy ; end
|
|
70
|
+
|
|
71
|
+
#
|
|
72
|
+
def inspect
|
|
73
|
+
to_s
|
|
74
|
+
#s = "[--#{key}"
|
|
75
|
+
#s << "*" if multiple
|
|
76
|
+
#s << "=" + arguments.join(',') unless arguments.empty?
|
|
77
|
+
#s << " " + aliases.collect{ |a| "-#{a}" } unless aliases.empty?
|
|
78
|
+
##s << " @excludes=#{@excludes.inspect}" unless @excludes.empty?
|
|
79
|
+
#s << "]"
|
|
80
|
+
#s
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Is this option a boolean flag?
|
|
84
|
+
def flag?; @arguments.empty?; end
|
|
85
|
+
|
|
86
|
+
# Assign an argument to the option.
|
|
87
|
+
def argument(name, &block)
|
|
88
|
+
arg = Argument.new(name) #, self)
|
|
89
|
+
arg.instance_eval(&block) if block
|
|
90
|
+
@arguments << arg
|
|
91
|
+
arg
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Specify aliases for the option.
|
|
95
|
+
def aliases(*names)
|
|
96
|
+
return @aliases if names.empty?
|
|
97
|
+
names.each do |name|
|
|
98
|
+
@aliases << clean_key(name)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Specify if the option be used multiple times.
|
|
103
|
+
def multiple(bool=nil)
|
|
104
|
+
return @multiple if bool.nil?
|
|
105
|
+
@multiple = bool
|
|
106
|
+
self
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Specify mutually exclusive options.
|
|
110
|
+
def xor(*opts)
|
|
111
|
+
@exclusive.concat(opts)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
#
|
|
115
|
+
#def |(other)
|
|
116
|
+
# xor(other)
|
|
117
|
+
#end
|
|
118
|
+
|
|
119
|
+
#
|
|
120
|
+
def help(string=nil)
|
|
121
|
+
@help.replace(string.to_s) if string
|
|
122
|
+
@help
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Tab completion.
|
|
126
|
+
def completion
|
|
127
|
+
arguments.collect{|c| c.key}
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# SHORTHAND NOTATION
|
|
131
|
+
#-------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
# Argument shorthand.
|
|
134
|
+
#
|
|
135
|
+
# arg('PIN', 'pin number')
|
|
136
|
+
#
|
|
137
|
+
def arg(slot, help=nil)
|
|
138
|
+
argument(slot).help(help)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
#
|
|
142
|
+
def to_s
|
|
143
|
+
tiny = aliases.select do |a|
|
|
144
|
+
a.to_s.size == 1
|
|
145
|
+
end
|
|
146
|
+
tiny.unshift(name) if name.size == 1
|
|
147
|
+
|
|
148
|
+
long = aliases.select do |a|
|
|
149
|
+
a.to_s.size > 1
|
|
150
|
+
end
|
|
151
|
+
long.unshift(name) if name.size > 1
|
|
152
|
+
|
|
153
|
+
tiny = tiny.collect{ |l| "-#{l}" }
|
|
154
|
+
long = long.collect{ |w| "--#{w}" }
|
|
155
|
+
|
|
156
|
+
if tiny.empty?
|
|
157
|
+
opts = [ ' ', *long ]
|
|
158
|
+
else
|
|
159
|
+
opts = tiny + long
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
unless arguments.empty?
|
|
163
|
+
args = arguments.collect{ |a| a.to_s.sub(/^[<]/,'').sub(/[>]$/,'') }
|
|
164
|
+
opts.last << "=" + args.join(',')
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
opts.join(' ')
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
#
|
|
171
|
+
def ===(other)
|
|
172
|
+
other = clean_key(other)
|
|
173
|
+
return true if clean_key(key) == other
|
|
174
|
+
return true if aliases.include?(other)
|
|
175
|
+
return false
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Breaks down an option at index of argv.
|
|
179
|
+
#def parse(argv, index)
|
|
180
|
+
#end
|
|
181
|
+
|
|
182
|
+
private
|
|
183
|
+
|
|
184
|
+
#
|
|
185
|
+
def clean_key(key)
|
|
186
|
+
clean_name(key).to_sym
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
#
|
|
190
|
+
def clean_name(name)
|
|
191
|
+
name = name.to_s
|
|
192
|
+
name = name.gsub(/^[-]+/, '')
|
|
193
|
+
name.chomp('?')
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
#
|
|
197
|
+
def flag_key?(key)
|
|
198
|
+
name = key.to_s
|
|
199
|
+
return key[-1,1] == '?'
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
#
|
|
203
|
+
def option_key(key)
|
|
204
|
+
k = clean_key(key).to_s
|
|
205
|
+
if k.size == 1
|
|
206
|
+
"-#{k}".to_sym
|
|
207
|
+
else
|
|
208
|
+
"--#{k}".to_sym
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
end # class Commandline
|
|
215
|
+
|
|
216
|
+
end # module Clio
|
|
217
|
+
|
|
218
|
+
=begin
|
|
219
|
+
# Option class. This is used by some command
|
|
220
|
+
# of the command line parser class to store
|
|
221
|
+
# option information.
|
|
222
|
+
class Option
|
|
223
|
+
attr_reader :name
|
|
224
|
+
attr_accessor :type
|
|
225
|
+
attr_accessor :init
|
|
226
|
+
attr_accessor :desc
|
|
227
|
+
|
|
228
|
+
alias_method :default, :init
|
|
229
|
+
alias_method :description, :desc
|
|
230
|
+
|
|
231
|
+
def initialize(name, desc, opts)
|
|
232
|
+
@name = name
|
|
233
|
+
@desc = desc
|
|
234
|
+
@type = opts[:type] || 'value'
|
|
235
|
+
@init = opts[:default] || opts[:init]
|
|
236
|
+
end
|
|
237
|
+
def usage
|
|
238
|
+
"--#{name}=#{type.to_s.upcase}"
|
|
239
|
+
end
|
|
240
|
+
def assert_valid(value)
|
|
241
|
+
raise "invalid" unless valid?(value)
|
|
242
|
+
end
|
|
243
|
+
def valid?(value)
|
|
244
|
+
validation ? validation.call(value) : true
|
|
245
|
+
end
|
|
246
|
+
def validation(&block)
|
|
247
|
+
@validation = block if block
|
|
248
|
+
@validation
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
=end
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
require 'shellwords'
|
|
2
|
+
require 'clio/usage/signature'
|
|
3
|
+
require 'clio/usage/interface'
|
|
4
|
+
|
|
5
|
+
module Clio
|
|
6
|
+
|
|
7
|
+
module Usage #:nodoc:
|
|
8
|
+
|
|
9
|
+
# = Parser
|
|
10
|
+
#
|
|
11
|
+
# Parse commandline arguments according to given Usage.
|
|
12
|
+
#
|
|
13
|
+
class Parser
|
|
14
|
+
attr :usage
|
|
15
|
+
attr :argv
|
|
16
|
+
|
|
17
|
+
attr :signatures
|
|
18
|
+
|
|
19
|
+
#
|
|
20
|
+
def initialize(usage, argv) #, index=0)
|
|
21
|
+
# convert to array if argv string
|
|
22
|
+
if ::String===argv
|
|
23
|
+
argv = Shellwords.shellwords(argv)
|
|
24
|
+
else
|
|
25
|
+
argv = argv.dup
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
@usage = usage
|
|
29
|
+
@argv = argv
|
|
30
|
+
|
|
31
|
+
@parsed = false
|
|
32
|
+
@signatures = []
|
|
33
|
+
@errors = []
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
#
|
|
37
|
+
def name ; usage.name ; end
|
|
38
|
+
def key ; usage.key ; end
|
|
39
|
+
|
|
40
|
+
#
|
|
41
|
+
def inspect
|
|
42
|
+
s = "<" + signatures.inspect + ">"
|
|
43
|
+
s
|
|
44
|
+
#s = "#<#{self.class}"
|
|
45
|
+
#s << " @options=#{@options.inspect}" unless @options.empty?
|
|
46
|
+
#s << " @arguments=#{@arguments.inspect}" unless @arguments.empty?
|
|
47
|
+
#s << " @subcommand=#{@subcommand}>" if @subcommand
|
|
48
|
+
#s << ">"
|
|
49
|
+
#s
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
#
|
|
53
|
+
def parse
|
|
54
|
+
@parsed = false
|
|
55
|
+
@signatures = []
|
|
56
|
+
@errors = []
|
|
57
|
+
|
|
58
|
+
parse_command(usage, argv.dup)
|
|
59
|
+
|
|
60
|
+
@parsed = true
|
|
61
|
+
|
|
62
|
+
return Interface.new(@signatures, @errors)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Has the commandline been parsed?
|
|
66
|
+
def parsed? ; @parsed ; end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
# TODO: clean-up parsing
|
|
71
|
+
def parse_command(usage, argv)
|
|
72
|
+
options = {}
|
|
73
|
+
arguments = []
|
|
74
|
+
command = nil
|
|
75
|
+
|
|
76
|
+
#greedy = parse_greedy(usage, argv)
|
|
77
|
+
|
|
78
|
+
#options.update(greedy)
|
|
79
|
+
|
|
80
|
+
until argv.empty?
|
|
81
|
+
use, val = parse_option(usage, argv)
|
|
82
|
+
if use
|
|
83
|
+
#p "use: #{use.key}, #{val}"
|
|
84
|
+
if val == "\t"
|
|
85
|
+
parse_errors << [val, use]
|
|
86
|
+
elsif use.multiple?
|
|
87
|
+
options[use.key] ||= []
|
|
88
|
+
options[use.key] << val
|
|
89
|
+
else
|
|
90
|
+
options[use.key] = val
|
|
91
|
+
end
|
|
92
|
+
elsif !usage.arguments.empty?
|
|
93
|
+
usage.arguments.each do |a|
|
|
94
|
+
if a.splat
|
|
95
|
+
while argv.first && argv.first !~ /^[-]/
|
|
96
|
+
arguments << argv.shift
|
|
97
|
+
end
|
|
98
|
+
break if argv.empty?
|
|
99
|
+
else
|
|
100
|
+
arguments << argv.shift
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
else
|
|
104
|
+
break if argv.empty?
|
|
105
|
+
arg = argv.shift
|
|
106
|
+
use = usage.commands.find{|c| c === arg}
|
|
107
|
+
if use
|
|
108
|
+
parse_command(use, argv)
|
|
109
|
+
break
|
|
110
|
+
else
|
|
111
|
+
parse_errors << [arg, usage]
|
|
112
|
+
#raise ParseError, "unknown command or argument #{a} for #{usage.key} command"
|
|
113
|
+
break
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
@signatures.unshift(Signature.new(usage.name, arguments, options))
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
=begin
|
|
121
|
+
# Parse greedy options. This function loops thru ARGV and
|
|
122
|
+
# removes any matching greedy options.
|
|
123
|
+
def parse_greedy(usage, argv)
|
|
124
|
+
options = {}
|
|
125
|
+
d, i = [], 0
|
|
126
|
+
while i < argv.size
|
|
127
|
+
case a = argv[i]
|
|
128
|
+
when /^[-].+/
|
|
129
|
+
#res = parse_option(a, i)
|
|
130
|
+
name, val = *a.split('=')
|
|
131
|
+
use = usage.greedy_option?(name)
|
|
132
|
+
if use && use.greedy?
|
|
133
|
+
d << i
|
|
134
|
+
if use.flag?
|
|
135
|
+
val = val || true
|
|
136
|
+
else
|
|
137
|
+
val = argv[i+1] unless val
|
|
138
|
+
i += 1
|
|
139
|
+
d << i
|
|
140
|
+
end
|
|
141
|
+
options[use.key] = val
|
|
142
|
+
end
|
|
143
|
+
res = val
|
|
144
|
+
end
|
|
145
|
+
i += 1
|
|
146
|
+
end
|
|
147
|
+
d.each{ |i| argv[i] = nil }
|
|
148
|
+
argv.compact!
|
|
149
|
+
return options
|
|
150
|
+
end
|
|
151
|
+
=end
|
|
152
|
+
|
|
153
|
+
#
|
|
154
|
+
def parse_option(usage, argv)
|
|
155
|
+
return if argv.first =~ /^[-]+$/
|
|
156
|
+
return if argv.first !~ /(^-.+|=)/
|
|
157
|
+
arg = argv.shift
|
|
158
|
+
name, val = *arg.split('=')
|
|
159
|
+
if use = usage.option?(name)
|
|
160
|
+
if use.flag?
|
|
161
|
+
val = true unless val
|
|
162
|
+
else
|
|
163
|
+
val = argv.shift unless val
|
|
164
|
+
end
|
|
165
|
+
#options[use.name] = val
|
|
166
|
+
else
|
|
167
|
+
parse_errors << [arg, usage.key]
|
|
168
|
+
end
|
|
169
|
+
return use, val
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
public
|
|
173
|
+
|
|
174
|
+
#
|
|
175
|
+
def errors
|
|
176
|
+
@errors
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
alias_method :parse_errors, :errors
|
|
180
|
+
|
|
181
|
+
end #class Parser
|
|
182
|
+
|
|
183
|
+
#
|
|
184
|
+
class ParseError < StandardError
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
end #class Usage
|
|
188
|
+
|
|
189
|
+
end #module Clio
|
|
190
|
+
|
|
191
|
+
|