clio 0.0.1
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/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
|
+
|