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