clio 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +170 -0
- data/HISTORY +11 -0
- data/MANIFEST +181 -0
- data/METADATA +18 -0
- data/NEWS +10 -0
- data/README +52 -0
- data/admin/config/reap.yaml +30 -0
- data/admin/depot/commandline.rb +219 -0
- data/admin/depot/multicommand.rb +403 -0
- data/admin/depot/test_multicommand.rb +40 -0
- data/admin/log/notes.xml +28 -0
- data/admin/log/stats.html +25 -0
- data/admin/log/syntax.log +0 -0
- data/admin/log/testunit.log +16 -0
- data/admin/pack/clio-0.0.1.gem +0 -0
- data/admin/share/reap/example.rb +7 -0
- data/admin/temps/lib/clio/about.rb.erb +4 -0
- data/lib/clio/ansicode.rb +319 -0
- data/lib/clio/command.rb +296 -0
- data/lib/clio/commandable.rb +195 -0
- data/lib/clio/commandline.rb +275 -0
- data/lib/clio/consoleutils.rb +117 -0
- data/lib/clio/errors.rb +16 -0
- data/lib/clio/option.rb +36 -0
- data/lib/clio/progressbar.rb +253 -0
- data/lib/clio/runmode.rb +126 -0
- data/lib/clio/string.rb +147 -0
- data/test/test_command.rb +42 -0
- data/test/test_commandline.rb +83 -0
- data/vendor/Console/Console.cpp +1203 -0
- data/vendor/Console/Console.rdoc +690 -0
- data/vendor/Console/Console_ANSI.rdoc +302 -0
- data/vendor/Console/HISTORY.txt +7 -0
- data/vendor/Console/INSTALL.txt +18 -0
- data/vendor/Console/Makefile +162 -0
- data/vendor/Console/README.txt +26 -0
- data/vendor/Console/doc/classes/Win32.html +115 -0
- data/vendor/Console/doc/classes/Win32/Console.html +650 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000001.html +31 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000002.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000003.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000004.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000005.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000006.html +28 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000007.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000008.html +24 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000009.html +44 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000010.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000011.html +33 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000012.html +26 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000013.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000014.html +28 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000015.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000016.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000017.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000018.html +29 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000019.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000020.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000021.html +28 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000022.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000023.html +28 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000024.html +35 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000025.html +28 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000026.html +28 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000027.html +28 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000028.html +31 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000029.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000030.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000031.html +23 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000032.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000033.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console.src/M000034.html +25 -0
- data/vendor/Console/doc/classes/Win32/Console/ANSI.html +103 -0
- data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.html +220 -0
- data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000035.html +32 -0
- data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000036.html +205 -0
- data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000037.html +40 -0
- data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000038.html +25 -0
- data/vendor/Console/doc/classes/Win32/Console/API.html +758 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000039.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000040.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000041.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000042.html +32 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000043.html +32 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000044.html +28 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000045.html +26 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000046.html +26 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000047.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000048.html +30 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000049.html +29 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000050.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000051.html +28 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000052.html +30 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000053.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000054.html +29 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000055.html +29 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000056.html +28 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000057.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000058.html +47 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000059.html +32 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000060.html +47 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000061.html +34 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000062.html +32 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000063.html +32 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000064.html +35 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000065.html +26 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000066.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000067.html +29 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000068.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000069.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000070.html +28 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000071.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000072.html +26 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000073.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000074.html +31 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000075.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000076.html +32 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000077.html +27 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000078.html +32 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000079.html +32 -0
- data/vendor/Console/doc/classes/Win32/Console/API.src/M000080.html +32 -0
- data/vendor/Console/doc/classes/Win32/Console/Constants.html +360 -0
- data/vendor/Console/doc/created.rid +1 -0
- data/vendor/Console/doc/files/Console_ANSI_rdoc.html +407 -0
- data/vendor/Console/doc/files/Console_cpp.html +104 -0
- data/vendor/Console/doc/files/Console_rdoc.html +964 -0
- data/vendor/Console/doc/files/lib/Win32/Console/ANSI_rb.html +123 -0
- data/vendor/Console/doc/files/lib/Win32/Console_rb.html +297 -0
- data/vendor/Console/doc/fr_class_index.html +32 -0
- data/vendor/Console/doc/fr_file_index.html +31 -0
- data/vendor/Console/doc/fr_method_index.html +106 -0
- data/vendor/Console/doc/index.html +24 -0
- data/vendor/Console/doc/rdoc-style.css +172 -0
- data/vendor/Console/extconf.rb +18 -0
- data/vendor/Console/lib/Term/ansicolor.rb +76 -0
- data/vendor/Console/lib/Win32/Console.rb +970 -0
- data/vendor/Console/lib/Win32/Console/ANSI.rb +305 -0
- data/vendor/Console/test/test_cursor.rb +9 -0
- data/vendor/Console/test/test_mouse.rb +6 -0
- data/vendor/Console/test/test_readinput.rb +62 -0
- data/vendor/Console/test/test_readoutput.rb +52 -0
- data/vendor/Console/test/test_sendevent.rb +17 -0
- data/vendor/Console/test/test_title.rb +14 -0
- data/vendor/Console/test/test_write.rb +36 -0
- metadata +253 -0
@@ -0,0 +1,275 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
require 'facets/kernel/object_class'
|
3
|
+
require 'facets/array/indexable'
|
4
|
+
|
5
|
+
module Clio
|
6
|
+
### = Commandline
|
7
|
+
###
|
8
|
+
### What a strange thing is the Clio Commandline.
|
9
|
+
### An entity unknown until put upon.
|
10
|
+
###
|
11
|
+
### cmd = Clio::Commandline.new("--force copy --file try.rb")
|
12
|
+
### cmd.option_alias(:f?, :force?)
|
13
|
+
### cmd.option_alias(:o, :file)
|
14
|
+
###
|
15
|
+
### cmd.file #=> 'try.rb'
|
16
|
+
### cmd.force? #=> true
|
17
|
+
### cmd.o #=> 'try.rb'
|
18
|
+
### cmd.f? #=> true
|
19
|
+
###
|
20
|
+
### TODO: Allow option setter methods (?)
|
21
|
+
### TODO: Allow a hash as argument to initialize (?)
|
22
|
+
class Commandline
|
23
|
+
instance_methods.each{ |m| private m if m !~ /^(__|instance_|object_|send$|inspect$)/ }
|
24
|
+
|
25
|
+
### Splits a raw command line into two smaller
|
26
|
+
### ones. The first including only options
|
27
|
+
### upto the first non-option argument. This
|
28
|
+
### makes quick work of separating a subcommand
|
29
|
+
### from the options for a main command.
|
30
|
+
# TODO: Rename this method.
|
31
|
+
def self.gerrymander(argv=ARGV)
|
32
|
+
if String===argv
|
33
|
+
argv = Shellwords.shellwords(argv)
|
34
|
+
end
|
35
|
+
sub = argv.find{ |x| x !~ /^[-]/ }
|
36
|
+
idx = argv.index(sub)
|
37
|
+
opts = argv[0...idx]
|
38
|
+
scmd = argv[idx..-1]
|
39
|
+
return opts, scmd
|
40
|
+
end
|
41
|
+
|
42
|
+
### Define an option attibute.
|
43
|
+
### While commandline can be used without
|
44
|
+
### pre-declartion of support options
|
45
|
+
### doding so allows for creating option
|
46
|
+
### aliases. Eg. --quiet and -q.
|
47
|
+
def self.attr(name, *aliases)
|
48
|
+
(@predefined_options ||= []) << [name, *aliases]
|
49
|
+
|
50
|
+
name = name.to_s
|
51
|
+
if name =~ /\?$/
|
52
|
+
key = name.chomp('?')
|
53
|
+
#attr_writer name
|
54
|
+
module_eval "def #{key}?; @#{key} ; end"
|
55
|
+
aliases.each do |alt|
|
56
|
+
alt = alt.to_s.chomp('?')
|
57
|
+
alias_method("#{alt}?", "#{key}?")
|
58
|
+
#alias_method("#{alt}=", "#{name}=")
|
59
|
+
end
|
60
|
+
else
|
61
|
+
attr_reader name
|
62
|
+
#module_eval "def #{name}; self[:#{name}] ; end"
|
63
|
+
aliases.each do |alt|
|
64
|
+
#alt = alt.to_s.chomp('?') # TODO: raise error ?
|
65
|
+
alias_method("#{alt}" , "#{name}")
|
66
|
+
#alias_method("#{alt}=", "#{name}=")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
### Returns a list of all pre-defined options.
|
72
|
+
### It does this by seaching class ancestry
|
73
|
+
### for instance_methods until it reaches the
|
74
|
+
### Commandline base class.
|
75
|
+
### TODO: Rename #runmodes method.
|
76
|
+
### TODO: Robust enough? Use an Inheritor instead?
|
77
|
+
def self.predefined_options
|
78
|
+
@predefined_options ||= []
|
79
|
+
ancestor = ancestors[1]
|
80
|
+
if ancestor > ::Clio::Commandline
|
81
|
+
@predefined_options
|
82
|
+
else
|
83
|
+
@predefined_options | ancestor.predefined_options
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
public
|
88
|
+
|
89
|
+
### This method provides the centralized means
|
90
|
+
### of accessing the options and arguments on
|
91
|
+
### the commandline.
|
92
|
+
def [](index)
|
93
|
+
case index
|
94
|
+
when Integer
|
95
|
+
@arguments[index] ||= (
|
96
|
+
args = @argv.select{ |e| e !~ /^-/ }
|
97
|
+
val = args[index]
|
98
|
+
@argv.delete(args[index])
|
99
|
+
val
|
100
|
+
)
|
101
|
+
else
|
102
|
+
return send(index) if respond_to?(index)
|
103
|
+
key = index.to_s.chomp('?')
|
104
|
+
val = option_parse(index)
|
105
|
+
instance_variable_set("@#{key}", val)
|
106
|
+
(class << self; self; end).class_eval %{
|
107
|
+
def #{index}; @#{key}; end
|
108
|
+
}
|
109
|
+
return val
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def shift!
|
114
|
+
args = @argv.select{ |e| e !~ /^-/ }
|
115
|
+
val = args.first
|
116
|
+
@argv.delete(val)
|
117
|
+
val
|
118
|
+
end
|
119
|
+
|
120
|
+
### Define an option alias. This adds en entry to
|
121
|
+
### the aliases hash, pointing new to a list of
|
122
|
+
### all aliases and the first entry on th list
|
123
|
+
### being the master key.
|
124
|
+
def option_alias(new, old)
|
125
|
+
self[old]
|
126
|
+
key = old.to_s.chomp('?')
|
127
|
+
val = option_parse(new)
|
128
|
+
instance_variable_set("@#{key}", val) if val
|
129
|
+
(class << self; self; end).class_eval do
|
130
|
+
alias_method new, old
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
### Access to the underlying commandline "ARGV".
|
135
|
+
### This will show what is yet to be processed.
|
136
|
+
def instance_delegate ; @argv ; end
|
137
|
+
|
138
|
+
### Returns a hash of all options parsed.
|
139
|
+
def instance_options
|
140
|
+
h = {}
|
141
|
+
ivs = instance_variables - ['@arguments','@argv']
|
142
|
+
ivs.each do |iv|
|
143
|
+
val = instance_variable_get(iv)
|
144
|
+
h[iv.sub('@','').to_sym] = val if val
|
145
|
+
end
|
146
|
+
h
|
147
|
+
end
|
148
|
+
|
149
|
+
### Returns a list of all arguments parsed.
|
150
|
+
def instance_arguments
|
151
|
+
@arguments
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
### New Commandline. Takse a single argument
|
157
|
+
### which can be a "shell" string, or an array
|
158
|
+
### of shell arguments, like ARGV. If none
|
159
|
+
### is given it defaults to ARGV.
|
160
|
+
def initialize(argv=ARGV)
|
161
|
+
case argv
|
162
|
+
when String
|
163
|
+
@argv = Shellwords.shellwords(argv)
|
164
|
+
#when Hash
|
165
|
+
# argv.each{ |k,v| send("#{k}=", v) }
|
166
|
+
else
|
167
|
+
@argv = argv.dup
|
168
|
+
end
|
169
|
+
@arguments = []
|
170
|
+
|
171
|
+
# parse predefined options attributes.
|
172
|
+
object_class.predefined_options.each do |modes|
|
173
|
+
key = modes.first.to_s.chomp('?')
|
174
|
+
modes.reverse.each do |i|
|
175
|
+
val = option_parse(i)
|
176
|
+
instance_variable_set("@#{key}", val) if val
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
### Routes to #[].
|
182
|
+
def method_missing(name, *args)
|
183
|
+
super unless args.empty?
|
184
|
+
case name.to_s
|
185
|
+
when /\=$/
|
186
|
+
super
|
187
|
+
else
|
188
|
+
self[name]
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def option_parse(index)
|
193
|
+
index = index.to_s
|
194
|
+
name = index.chomp('?')
|
195
|
+
key = name.to_sym
|
196
|
+
|
197
|
+
kind = name.size == 1 ? 'letter' : 'word'
|
198
|
+
flag = index =~ /\?$/ ? 'flag' : 'value'
|
199
|
+
|
200
|
+
send("option_#{kind}_#{flag}", key)
|
201
|
+
end
|
202
|
+
|
203
|
+
### Parse a flag option.
|
204
|
+
def option_word_flag(name)
|
205
|
+
o = "--#{name}"
|
206
|
+
i = @argv.index_of{ |e| e =~ /^#{o}[=]?/ }
|
207
|
+
return false unless i
|
208
|
+
raise ArgumentError if @argv[i] =~ /=/
|
209
|
+
@argv.delete_at(i)
|
210
|
+
return true
|
211
|
+
end
|
212
|
+
|
213
|
+
### Parse a value option.
|
214
|
+
def option_word_value(name)
|
215
|
+
o = "--#{name}"
|
216
|
+
i = @argv.index_of{ |e| e =~ /^#{o}[=]?/ }
|
217
|
+
return false unless i
|
218
|
+
|
219
|
+
if @argv[i] =~ /=/
|
220
|
+
key, val = *@argv[i].split('=')
|
221
|
+
argv[i] = nil
|
222
|
+
else
|
223
|
+
case @argv[i+1]
|
224
|
+
when nil, /^-/
|
225
|
+
raise ArgumentError
|
226
|
+
else
|
227
|
+
key = @argv[i]
|
228
|
+
val = @argv[i+1]
|
229
|
+
@argv.delete_at(i) # do it twice
|
230
|
+
@argv.delete_at(i)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
return val
|
234
|
+
end
|
235
|
+
|
236
|
+
### Parse a single letter flag option.
|
237
|
+
def option_letter_flag(letter)
|
238
|
+
o = letter
|
239
|
+
i = @argv.index_of{ |e| e =~ /[-][^-]\w*(#{o})\w*$/ }
|
240
|
+
if i
|
241
|
+
@argv[i] = @argv[i].gsub(o.to_s,'')
|
242
|
+
true
|
243
|
+
end
|
244
|
+
false
|
245
|
+
end
|
246
|
+
|
247
|
+
### Parse a single letter value option.
|
248
|
+
def option_letter_value(letter)
|
249
|
+
o = letter
|
250
|
+
i = @argv.index_of{ |e| e =~ /[-]\w*#{o}(\=|$)/ }
|
251
|
+
return nil unless i
|
252
|
+
if @argv[i] =~ /=/
|
253
|
+
rest, val = argv[i].split('=')
|
254
|
+
@argv[i] = rest
|
255
|
+
else
|
256
|
+
case @argv[i+1]
|
257
|
+
when nil, /^-/
|
258
|
+
raise ArgumentError
|
259
|
+
else
|
260
|
+
val = @argv[i+1]
|
261
|
+
new = @argv[i].gsub(o.to_s,'')
|
262
|
+
if new == '-'
|
263
|
+
@argv.delete_at(i)
|
264
|
+
else
|
265
|
+
@argv[i] = new
|
266
|
+
end
|
267
|
+
@argv.delete_at(i+1)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
return val
|
271
|
+
end
|
272
|
+
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# = Console Utilities
|
2
|
+
#
|
3
|
+
# ConsoleUtils provides methods that are
|
4
|
+
# generally useful in the context of
|
5
|
+
# creating console output.
|
6
|
+
#
|
7
|
+
# = Authors
|
8
|
+
#
|
9
|
+
# * Thomas Sawyer
|
10
|
+
#
|
11
|
+
# == Copying
|
12
|
+
#
|
13
|
+
# Copyright (c) 2006,2007 Thomas Sawyer
|
14
|
+
# Ruby/GPL
|
15
|
+
|
16
|
+
|
17
|
+
module Clio
|
18
|
+
|
19
|
+
# = Termninal
|
20
|
+
#
|
21
|
+
# ConsoleUtils provides methods that are
|
22
|
+
# generally useful in the context of
|
23
|
+
# creating console output.
|
24
|
+
#
|
25
|
+
module Terminal
|
26
|
+
|
27
|
+
module_function
|
28
|
+
|
29
|
+
# Convenient method to get simple console reply.
|
30
|
+
|
31
|
+
def ask(question, answers=nil)
|
32
|
+
print "#{question}"
|
33
|
+
print " [#{answers}] " if answers
|
34
|
+
until inp = $stdin.gets ; sleep 1 ; end
|
35
|
+
inp
|
36
|
+
end
|
37
|
+
|
38
|
+
# Convenience method for puts. Use this instead of
|
39
|
+
# puts when the output should be supressed if the
|
40
|
+
# global $QUIET option is set.
|
41
|
+
|
42
|
+
#def say(statement)
|
43
|
+
# puts statement #unless quiet? $QUIET
|
44
|
+
#end
|
45
|
+
|
46
|
+
# Ask for a password. (FIXME: only for unix so far)
|
47
|
+
|
48
|
+
def password(msg=nil)
|
49
|
+
msg ||= "Enter Password: "
|
50
|
+
inp = ''
|
51
|
+
|
52
|
+
$stdout << msg
|
53
|
+
|
54
|
+
begin
|
55
|
+
system "stty -echo"
|
56
|
+
inp = gets.chomp
|
57
|
+
ensure
|
58
|
+
system "stty echo"
|
59
|
+
end
|
60
|
+
|
61
|
+
return inp
|
62
|
+
end
|
63
|
+
|
64
|
+
# Console screen width (taken from progress bar)
|
65
|
+
#
|
66
|
+
# TODO: Don't know how portable #screen_width is.
|
67
|
+
|
68
|
+
def screen_width(out=STDERR)
|
69
|
+
default_width = ENV['COLUMNS'] || 80
|
70
|
+
begin
|
71
|
+
tiocgwinsz = 0x5413
|
72
|
+
data = [0, 0, 0, 0].pack("SSSS")
|
73
|
+
if out.ioctl(tiocgwinsz, data) >= 0 then
|
74
|
+
rows, cols, xpixels, ypixels = data.unpack("SSSS")
|
75
|
+
if cols >= 0 then cols else default_width end
|
76
|
+
else
|
77
|
+
default_width
|
78
|
+
end
|
79
|
+
rescue Exception
|
80
|
+
default_width
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Print a justified line with left and right entries.
|
85
|
+
#
|
86
|
+
# A fill option can be given to fill in any empty space
|
87
|
+
# between the two. And a ratio option can be given which defaults
|
88
|
+
# to 0.8 (eg. 80/20)
|
89
|
+
|
90
|
+
def print_justified(left, right, options={})
|
91
|
+
fill = options[:fill] || '.'
|
92
|
+
fill = ' ' if fill == ''
|
93
|
+
fill = fill[0,1]
|
94
|
+
|
95
|
+
ratio = options[:ratio] || 0.8
|
96
|
+
ratio = 1 + ratio if ratio < 0
|
97
|
+
|
98
|
+
width = (@screen_width ||= screen_width) - 1
|
99
|
+
|
100
|
+
#l = (width * ratio).to_i
|
101
|
+
r = (width * (1 - ratio)).to_i
|
102
|
+
l = width - r
|
103
|
+
|
104
|
+
left = left[0,l]
|
105
|
+
right = right[0,r]
|
106
|
+
|
107
|
+
str = fill * width
|
108
|
+
str[0,left.size] = left
|
109
|
+
str[width-right.size,right.size] = right
|
110
|
+
|
111
|
+
print str
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
data/lib/clio/errors.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Clio
|
2
|
+
|
3
|
+
class NoOptionError < ::NoMethodError # ArgumentError ?
|
4
|
+
def initialize(name, *arg)
|
5
|
+
super("unknown option -- #{name}", name, *args)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class NoCommandError < ::NoMethodError
|
10
|
+
def initialize(name, *arg)
|
11
|
+
super("unknown subcommand -- #{name}", name, *args)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
data/lib/clio/option.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Clio
|
2
|
+
|
3
|
+
# Option class. This is used by some command
|
4
|
+
# of the command line parser class to store
|
5
|
+
# option information.
|
6
|
+
class Option
|
7
|
+
attr_reader :name
|
8
|
+
attr_accessor :type
|
9
|
+
attr_accessor :init
|
10
|
+
attr_accessor :desc
|
11
|
+
|
12
|
+
alias_method :default, :init
|
13
|
+
alias_method :description, :desc
|
14
|
+
|
15
|
+
def initialize(name, desc, opts)
|
16
|
+
@name = name
|
17
|
+
@desc = desc
|
18
|
+
@type = opts[:type] || 'value'
|
19
|
+
@init = opts[:default] || opts[:init]
|
20
|
+
end
|
21
|
+
def usage
|
22
|
+
"--#{name}=#{type.to_s.upcase}"
|
23
|
+
end
|
24
|
+
def assert_valid(value)
|
25
|
+
raise "invalid" unless valid?(value)
|
26
|
+
end
|
27
|
+
def valid?(value)
|
28
|
+
validation ? validation.call(value) : true
|
29
|
+
end
|
30
|
+
def validation(&block)
|
31
|
+
@validation = block if block
|
32
|
+
@validation
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,253 @@
|
|
1
|
+
# = Progressbar
|
2
|
+
#
|
3
|
+
# ProgressBar is a text-based progressbar library.
|
4
|
+
#
|
5
|
+
# == Usage
|
6
|
+
#
|
7
|
+
# pbar = ProgressBar.new( "Demo", 100 )
|
8
|
+
# 100.times { pbar.inc }
|
9
|
+
# pbar.finish
|
10
|
+
#
|
11
|
+
# == Copying
|
12
|
+
#
|
13
|
+
# Copyright (C) 2001 Satoru Takabayashi
|
14
|
+
#
|
15
|
+
# Ruby License
|
16
|
+
#
|
17
|
+
# This module is free software. You may use, modify, and/or redistribute this
|
18
|
+
# software under the same terms as Ruby.
|
19
|
+
#
|
20
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
21
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
22
|
+
# FOR A PARTICULAR PURPOSE.
|
23
|
+
#
|
24
|
+
# == Author
|
25
|
+
#
|
26
|
+
# * Satoru Takabayashi
|
27
|
+
|
28
|
+
# = ProgressBar
|
29
|
+
#
|
30
|
+
# ProgressBar is a text-based progressbar library.
|
31
|
+
#
|
32
|
+
# pbar = ProgressBar.new( "Demo", 100 )
|
33
|
+
# 100.times { pbar.inc }
|
34
|
+
# pbar.finish
|
35
|
+
#
|
36
|
+
class ProgressBar
|
37
|
+
|
38
|
+
def initialize(title, total, out = STDERR)
|
39
|
+
@title = title
|
40
|
+
@total = total
|
41
|
+
@out = out
|
42
|
+
@bar_length = 80
|
43
|
+
@bar_mark = "o"
|
44
|
+
@total_overflow = true
|
45
|
+
@current = 0
|
46
|
+
@previous = 0
|
47
|
+
@is_finished = false
|
48
|
+
@start_time = Time.now
|
49
|
+
@format = "%-14s %3d%% %s %s"
|
50
|
+
@format_arguments = [:title, :percentage, :bar, :stat]
|
51
|
+
show_progress
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def convert_bytes (bytes)
|
56
|
+
if bytes < 1024
|
57
|
+
sprintf("%6dB", bytes)
|
58
|
+
elsif bytes < 1024 * 1000 # 1000kb
|
59
|
+
sprintf("%5.1fKB", bytes.to_f / 1024)
|
60
|
+
elsif bytes < 1024 * 1024 * 1000 # 1000mb
|
61
|
+
sprintf("%5.1fMB", bytes.to_f / 1024 / 1024)
|
62
|
+
else
|
63
|
+
sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def transfer_rate
|
68
|
+
bytes_per_second = @current.to_f / (Time.now - @start_time)
|
69
|
+
sprintf("%s/s", convert_bytes(bytes_per_second))
|
70
|
+
end
|
71
|
+
|
72
|
+
def bytes
|
73
|
+
convert_bytes(@current)
|
74
|
+
end
|
75
|
+
|
76
|
+
def format_time(t)
|
77
|
+
t = t.to_i
|
78
|
+
sec = t % 60
|
79
|
+
min = (t / 60) % 60
|
80
|
+
hour = t / 3600
|
81
|
+
sprintf("%02d:%02d:%02d", hour, min, sec);
|
82
|
+
end
|
83
|
+
|
84
|
+
# ETA stands for Estimated Time of Arrival.
|
85
|
+
def eta
|
86
|
+
if @current == 0
|
87
|
+
"ETA: --:--:--"
|
88
|
+
else
|
89
|
+
elapsed = Time.now - @start_time
|
90
|
+
eta = elapsed * @total / @current - elapsed;
|
91
|
+
sprintf("ETA: %s", format_time(eta))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def elapsed
|
96
|
+
elapsed = Time.now - @start_time
|
97
|
+
sprintf("Time: %s", format_time(elapsed))
|
98
|
+
end
|
99
|
+
|
100
|
+
def stat
|
101
|
+
if @is_finished then elapsed else eta end
|
102
|
+
end
|
103
|
+
|
104
|
+
def stat_for_file_transfer
|
105
|
+
if @is_finished then
|
106
|
+
sprintf("%s %s %s", bytes, transfer_rate, elapsed)
|
107
|
+
else
|
108
|
+
sprintf("%s %s %s", bytes, transfer_rate, eta)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def eol
|
113
|
+
if @is_finished then "\n" else "\r" end
|
114
|
+
end
|
115
|
+
|
116
|
+
def bar
|
117
|
+
len = percentage * @bar_length / 100
|
118
|
+
sprintf("|%s%s|", @bar_mark * len, " " * (@bar_length - len))
|
119
|
+
end
|
120
|
+
|
121
|
+
def percentage
|
122
|
+
if @total.zero?
|
123
|
+
100
|
124
|
+
else
|
125
|
+
@current * 100 / @total
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def title
|
130
|
+
@title[0,13] + ":"
|
131
|
+
end
|
132
|
+
|
133
|
+
def get_width
|
134
|
+
# FIXME: I don't know how portable it is.
|
135
|
+
default_width = 80
|
136
|
+
begin
|
137
|
+
tiocgwinsz = 0x5413
|
138
|
+
data = [0, 0, 0, 0].pack("SSSS")
|
139
|
+
if @out.ioctl(tiocgwinsz, data) >= 0 then
|
140
|
+
rows, cols, xpixels, ypixels = data.unpack("SSSS")
|
141
|
+
if cols >= 0 then cols else default_width end
|
142
|
+
else
|
143
|
+
default_width
|
144
|
+
end
|
145
|
+
rescue Exception
|
146
|
+
default_width
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def show
|
151
|
+
arguments = @format_arguments.map{|method| send(method)}
|
152
|
+
line = sprintf(@format, *arguments)
|
153
|
+
|
154
|
+
width = get_width
|
155
|
+
if line.length == width - 1
|
156
|
+
@out.print(line + eol)
|
157
|
+
elsif line.length >= width
|
158
|
+
@bar_length = [@bar_length - (line.length - width + 1), 0].max
|
159
|
+
if @bar_length == 0 then @out.print(line + eol) else show end
|
160
|
+
else #line.length < width - 1
|
161
|
+
@bar_length += width - line.length + 1
|
162
|
+
show
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def show_progress
|
167
|
+
if @total.zero?
|
168
|
+
cur_percentage = 100
|
169
|
+
prev_percentage = 0
|
170
|
+
else
|
171
|
+
cur_percentage = (@current * 100 / @total).to_i
|
172
|
+
prev_percentage = (@previous * 100 / @total).to_i
|
173
|
+
end
|
174
|
+
|
175
|
+
if cur_percentage > prev_percentage || @is_finished
|
176
|
+
show
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
public
|
181
|
+
def file_transfer_mode
|
182
|
+
@format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer]
|
183
|
+
end
|
184
|
+
|
185
|
+
def title=(str)
|
186
|
+
@title = str
|
187
|
+
end
|
188
|
+
|
189
|
+
def bar_mark=(mark)
|
190
|
+
@bar_mark = String(mark)[0..0]
|
191
|
+
end
|
192
|
+
|
193
|
+
def total_overflow=(boolv)
|
194
|
+
@total_overflow = boolv ? true : false
|
195
|
+
end
|
196
|
+
|
197
|
+
def format=(format)
|
198
|
+
@format = format
|
199
|
+
end
|
200
|
+
|
201
|
+
def format_arguments=(arguments)
|
202
|
+
@format_arguments = arguments
|
203
|
+
end
|
204
|
+
|
205
|
+
def finish
|
206
|
+
@current = @total
|
207
|
+
@is_finished = true
|
208
|
+
show_progress
|
209
|
+
end
|
210
|
+
|
211
|
+
def flush
|
212
|
+
@out.flush
|
213
|
+
end
|
214
|
+
|
215
|
+
def halt
|
216
|
+
@is_finished = true
|
217
|
+
show_progress
|
218
|
+
end
|
219
|
+
|
220
|
+
def set(count)
|
221
|
+
if count < 0
|
222
|
+
raise "invalid count less than zero: #{count}"
|
223
|
+
elsif count > @total
|
224
|
+
if @total_overflow
|
225
|
+
@total = count + 1
|
226
|
+
else
|
227
|
+
raise "invalid count greater than total: #{count}"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
@current = count
|
231
|
+
show_progress
|
232
|
+
@previous = @current
|
233
|
+
end
|
234
|
+
|
235
|
+
def inc(step = 1)
|
236
|
+
@current += step
|
237
|
+
@current = @total if @current > @total
|
238
|
+
show_progress
|
239
|
+
@previous = @current
|
240
|
+
end
|
241
|
+
|
242
|
+
def inspect
|
243
|
+
"(ProgressBar: #{@current}/#{@total})"
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
|
249
|
+
module Console #:nodoc:
|
250
|
+
# For backward compatibility
|
251
|
+
ProgressBar = ::ProgressBar
|
252
|
+
end
|
253
|
+
|