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.
Files changed (145) hide show
  1. data/COPYING +170 -0
  2. data/HISTORY +11 -0
  3. data/MANIFEST +181 -0
  4. data/METADATA +18 -0
  5. data/NEWS +10 -0
  6. data/README +52 -0
  7. data/admin/config/reap.yaml +30 -0
  8. data/admin/depot/commandline.rb +219 -0
  9. data/admin/depot/multicommand.rb +403 -0
  10. data/admin/depot/test_multicommand.rb +40 -0
  11. data/admin/log/notes.xml +28 -0
  12. data/admin/log/stats.html +25 -0
  13. data/admin/log/syntax.log +0 -0
  14. data/admin/log/testunit.log +16 -0
  15. data/admin/pack/clio-0.0.1.gem +0 -0
  16. data/admin/share/reap/example.rb +7 -0
  17. data/admin/temps/lib/clio/about.rb.erb +4 -0
  18. data/lib/clio/ansicode.rb +319 -0
  19. data/lib/clio/command.rb +296 -0
  20. data/lib/clio/commandable.rb +195 -0
  21. data/lib/clio/commandline.rb +275 -0
  22. data/lib/clio/consoleutils.rb +117 -0
  23. data/lib/clio/errors.rb +16 -0
  24. data/lib/clio/option.rb +36 -0
  25. data/lib/clio/progressbar.rb +253 -0
  26. data/lib/clio/runmode.rb +126 -0
  27. data/lib/clio/string.rb +147 -0
  28. data/test/test_command.rb +42 -0
  29. data/test/test_commandline.rb +83 -0
  30. data/vendor/Console/Console.cpp +1203 -0
  31. data/vendor/Console/Console.rdoc +690 -0
  32. data/vendor/Console/Console_ANSI.rdoc +302 -0
  33. data/vendor/Console/HISTORY.txt +7 -0
  34. data/vendor/Console/INSTALL.txt +18 -0
  35. data/vendor/Console/Makefile +162 -0
  36. data/vendor/Console/README.txt +26 -0
  37. data/vendor/Console/doc/classes/Win32.html +115 -0
  38. data/vendor/Console/doc/classes/Win32/Console.html +650 -0
  39. data/vendor/Console/doc/classes/Win32/Console.src/M000001.html +31 -0
  40. data/vendor/Console/doc/classes/Win32/Console.src/M000002.html +23 -0
  41. data/vendor/Console/doc/classes/Win32/Console.src/M000003.html +23 -0
  42. data/vendor/Console/doc/classes/Win32/Console.src/M000004.html +27 -0
  43. data/vendor/Console/doc/classes/Win32/Console.src/M000005.html +23 -0
  44. data/vendor/Console/doc/classes/Win32/Console.src/M000006.html +28 -0
  45. data/vendor/Console/doc/classes/Win32/Console.src/M000007.html +23 -0
  46. data/vendor/Console/doc/classes/Win32/Console.src/M000008.html +24 -0
  47. data/vendor/Console/doc/classes/Win32/Console.src/M000009.html +44 -0
  48. data/vendor/Console/doc/classes/Win32/Console.src/M000010.html +23 -0
  49. data/vendor/Console/doc/classes/Win32/Console.src/M000011.html +33 -0
  50. data/vendor/Console/doc/classes/Win32/Console.src/M000012.html +26 -0
  51. data/vendor/Console/doc/classes/Win32/Console.src/M000013.html +27 -0
  52. data/vendor/Console/doc/classes/Win32/Console.src/M000014.html +28 -0
  53. data/vendor/Console/doc/classes/Win32/Console.src/M000015.html +23 -0
  54. data/vendor/Console/doc/classes/Win32/Console.src/M000016.html +23 -0
  55. data/vendor/Console/doc/classes/Win32/Console.src/M000017.html +23 -0
  56. data/vendor/Console/doc/classes/Win32/Console.src/M000018.html +29 -0
  57. data/vendor/Console/doc/classes/Win32/Console.src/M000019.html +23 -0
  58. data/vendor/Console/doc/classes/Win32/Console.src/M000020.html +23 -0
  59. data/vendor/Console/doc/classes/Win32/Console.src/M000021.html +28 -0
  60. data/vendor/Console/doc/classes/Win32/Console.src/M000022.html +23 -0
  61. data/vendor/Console/doc/classes/Win32/Console.src/M000023.html +28 -0
  62. data/vendor/Console/doc/classes/Win32/Console.src/M000024.html +35 -0
  63. data/vendor/Console/doc/classes/Win32/Console.src/M000025.html +28 -0
  64. data/vendor/Console/doc/classes/Win32/Console.src/M000026.html +28 -0
  65. data/vendor/Console/doc/classes/Win32/Console.src/M000027.html +28 -0
  66. data/vendor/Console/doc/classes/Win32/Console.src/M000028.html +31 -0
  67. data/vendor/Console/doc/classes/Win32/Console.src/M000029.html +23 -0
  68. data/vendor/Console/doc/classes/Win32/Console.src/M000030.html +23 -0
  69. data/vendor/Console/doc/classes/Win32/Console.src/M000031.html +23 -0
  70. data/vendor/Console/doc/classes/Win32/Console.src/M000032.html +27 -0
  71. data/vendor/Console/doc/classes/Win32/Console.src/M000033.html +27 -0
  72. data/vendor/Console/doc/classes/Win32/Console.src/M000034.html +25 -0
  73. data/vendor/Console/doc/classes/Win32/Console/ANSI.html +103 -0
  74. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.html +220 -0
  75. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000035.html +32 -0
  76. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000036.html +205 -0
  77. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000037.html +40 -0
  78. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000038.html +25 -0
  79. data/vendor/Console/doc/classes/Win32/Console/API.html +758 -0
  80. data/vendor/Console/doc/classes/Win32/Console/API.src/M000039.html +27 -0
  81. data/vendor/Console/doc/classes/Win32/Console/API.src/M000040.html +27 -0
  82. data/vendor/Console/doc/classes/Win32/Console/API.src/M000041.html +27 -0
  83. data/vendor/Console/doc/classes/Win32/Console/API.src/M000042.html +32 -0
  84. data/vendor/Console/doc/classes/Win32/Console/API.src/M000043.html +32 -0
  85. data/vendor/Console/doc/classes/Win32/Console/API.src/M000044.html +28 -0
  86. data/vendor/Console/doc/classes/Win32/Console/API.src/M000045.html +26 -0
  87. data/vendor/Console/doc/classes/Win32/Console/API.src/M000046.html +26 -0
  88. data/vendor/Console/doc/classes/Win32/Console/API.src/M000047.html +27 -0
  89. data/vendor/Console/doc/classes/Win32/Console/API.src/M000048.html +30 -0
  90. data/vendor/Console/doc/classes/Win32/Console/API.src/M000049.html +29 -0
  91. data/vendor/Console/doc/classes/Win32/Console/API.src/M000050.html +27 -0
  92. data/vendor/Console/doc/classes/Win32/Console/API.src/M000051.html +28 -0
  93. data/vendor/Console/doc/classes/Win32/Console/API.src/M000052.html +30 -0
  94. data/vendor/Console/doc/classes/Win32/Console/API.src/M000053.html +27 -0
  95. data/vendor/Console/doc/classes/Win32/Console/API.src/M000054.html +29 -0
  96. data/vendor/Console/doc/classes/Win32/Console/API.src/M000055.html +29 -0
  97. data/vendor/Console/doc/classes/Win32/Console/API.src/M000056.html +28 -0
  98. data/vendor/Console/doc/classes/Win32/Console/API.src/M000057.html +27 -0
  99. data/vendor/Console/doc/classes/Win32/Console/API.src/M000058.html +47 -0
  100. data/vendor/Console/doc/classes/Win32/Console/API.src/M000059.html +32 -0
  101. data/vendor/Console/doc/classes/Win32/Console/API.src/M000060.html +47 -0
  102. data/vendor/Console/doc/classes/Win32/Console/API.src/M000061.html +34 -0
  103. data/vendor/Console/doc/classes/Win32/Console/API.src/M000062.html +32 -0
  104. data/vendor/Console/doc/classes/Win32/Console/API.src/M000063.html +32 -0
  105. data/vendor/Console/doc/classes/Win32/Console/API.src/M000064.html +35 -0
  106. data/vendor/Console/doc/classes/Win32/Console/API.src/M000065.html +26 -0
  107. data/vendor/Console/doc/classes/Win32/Console/API.src/M000066.html +27 -0
  108. data/vendor/Console/doc/classes/Win32/Console/API.src/M000067.html +29 -0
  109. data/vendor/Console/doc/classes/Win32/Console/API.src/M000068.html +27 -0
  110. data/vendor/Console/doc/classes/Win32/Console/API.src/M000069.html +27 -0
  111. data/vendor/Console/doc/classes/Win32/Console/API.src/M000070.html +28 -0
  112. data/vendor/Console/doc/classes/Win32/Console/API.src/M000071.html +27 -0
  113. data/vendor/Console/doc/classes/Win32/Console/API.src/M000072.html +26 -0
  114. data/vendor/Console/doc/classes/Win32/Console/API.src/M000073.html +27 -0
  115. data/vendor/Console/doc/classes/Win32/Console/API.src/M000074.html +31 -0
  116. data/vendor/Console/doc/classes/Win32/Console/API.src/M000075.html +27 -0
  117. data/vendor/Console/doc/classes/Win32/Console/API.src/M000076.html +32 -0
  118. data/vendor/Console/doc/classes/Win32/Console/API.src/M000077.html +27 -0
  119. data/vendor/Console/doc/classes/Win32/Console/API.src/M000078.html +32 -0
  120. data/vendor/Console/doc/classes/Win32/Console/API.src/M000079.html +32 -0
  121. data/vendor/Console/doc/classes/Win32/Console/API.src/M000080.html +32 -0
  122. data/vendor/Console/doc/classes/Win32/Console/Constants.html +360 -0
  123. data/vendor/Console/doc/created.rid +1 -0
  124. data/vendor/Console/doc/files/Console_ANSI_rdoc.html +407 -0
  125. data/vendor/Console/doc/files/Console_cpp.html +104 -0
  126. data/vendor/Console/doc/files/Console_rdoc.html +964 -0
  127. data/vendor/Console/doc/files/lib/Win32/Console/ANSI_rb.html +123 -0
  128. data/vendor/Console/doc/files/lib/Win32/Console_rb.html +297 -0
  129. data/vendor/Console/doc/fr_class_index.html +32 -0
  130. data/vendor/Console/doc/fr_file_index.html +31 -0
  131. data/vendor/Console/doc/fr_method_index.html +106 -0
  132. data/vendor/Console/doc/index.html +24 -0
  133. data/vendor/Console/doc/rdoc-style.css +172 -0
  134. data/vendor/Console/extconf.rb +18 -0
  135. data/vendor/Console/lib/Term/ansicolor.rb +76 -0
  136. data/vendor/Console/lib/Win32/Console.rb +970 -0
  137. data/vendor/Console/lib/Win32/Console/ANSI.rb +305 -0
  138. data/vendor/Console/test/test_cursor.rb +9 -0
  139. data/vendor/Console/test/test_mouse.rb +6 -0
  140. data/vendor/Console/test/test_readinput.rb +62 -0
  141. data/vendor/Console/test/test_readoutput.rb +52 -0
  142. data/vendor/Console/test/test_sendevent.rb +17 -0
  143. data/vendor/Console/test/test_title.rb +14 -0
  144. data/vendor/Console/test/test_write.rb +36 -0
  145. 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
+
@@ -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
+
@@ -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
+