epitools 0.4.49 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/TODO +16 -0
- data/VERSION +1 -1
- data/epitools.gemspec +14 -7
- data/lib/epitools.rb +3 -2
- data/lib/epitools/autoloads.rb +11 -1
- data/lib/epitools/basetypes.rb +220 -71
- data/lib/epitools/browser.rb +1 -0
- data/lib/epitools/clitools.rb +7 -3
- data/lib/epitools/colored.rb +45 -23
- data/lib/epitools/ezdb.rb +100 -0
- data/lib/epitools/path.rb +354 -80
- data/lib/epitools/term.rb +147 -0
- data/lib/epitools/trie.rb +422 -0
- data/lib/epitools/zopen.rb +2 -2
- data/spec/basetypes_spec.rb +42 -2
- data/spec/ezdb_spec.rb +47 -0
- data/spec/path_spec.rb +49 -3
- data/spec/rash_spec.rb +1 -1
- data/spec/term_spec.rb +35 -0
- metadata +16 -11
data/TODO
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
===========================
|
2
|
+
TODOs
|
3
|
+
===========================
|
4
|
+
|
5
|
+
+ Logger
|
6
|
+
|_ colourized ("ramaze" has a nice style)
|
7
|
+
|_ output to STDERR (default)
|
8
|
+
|_ no setup (default)
|
9
|
+
|_ Log "message" <- defaults to info
|
10
|
+
|_ Log.warn "message"
|
11
|
+
|_ Log object <- prettyprints it
|
12
|
+
|_ Verbose mode shows the calling method's info
|
13
|
+
|_ eg: [file:line:method]
|
14
|
+
|_ "gsmartcontrol" has good warning messages
|
15
|
+
ie: "|13<warn> |07[hz] Warning: exit: The device error log contains records of errors."
|
16
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/epitools.gemspec
CHANGED
@@ -5,22 +5,24 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{epitools}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.5.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = [
|
12
|
-
s.date = %q{2011-
|
11
|
+
s.authors = [%q{epitron}]
|
12
|
+
s.date = %q{2011-10-13}
|
13
13
|
s.description = %q{Miscellaneous utility libraries to make my life easier.}
|
14
14
|
s.email = %q{chris@ill-logic.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
|
-
"README.rdoc"
|
17
|
+
"README.rdoc",
|
18
|
+
"TODO"
|
18
19
|
]
|
19
20
|
s.files = [
|
20
21
|
".document",
|
21
22
|
"LICENSE",
|
22
23
|
"README.rdoc",
|
23
24
|
"Rakefile",
|
25
|
+
"TODO",
|
24
26
|
"VERSION",
|
25
27
|
"epitools.gemspec",
|
26
28
|
"lib/epitools.rb",
|
@@ -31,6 +33,7 @@ Gem::Specification.new do |s|
|
|
31
33
|
"lib/epitools/browser/mechanize_progressbar.rb",
|
32
34
|
"lib/epitools/clitools.rb",
|
33
35
|
"lib/epitools/colored.rb",
|
36
|
+
"lib/epitools/ezdb.rb",
|
34
37
|
"lib/epitools/hexdump.rb",
|
35
38
|
"lib/epitools/its.rb",
|
36
39
|
"lib/epitools/lcs.rb",
|
@@ -47,12 +50,15 @@ Gem::Specification.new do |s|
|
|
47
50
|
"lib/epitools/ratio.rb",
|
48
51
|
"lib/epitools/string_to_proc.rb",
|
49
52
|
"lib/epitools/sys.rb",
|
53
|
+
"lib/epitools/term.rb",
|
54
|
+
"lib/epitools/trie.rb",
|
50
55
|
"lib/epitools/zopen.rb",
|
51
56
|
"spec/autoreq_spec.rb",
|
52
57
|
"spec/basetypes_spec.rb",
|
53
58
|
"spec/browser_spec.rb",
|
54
59
|
"spec/clitools_spec.rb",
|
55
60
|
"spec/colored_spec.rb",
|
61
|
+
"spec/ezdb_spec.rb",
|
56
62
|
"spec/lcs_spec.rb",
|
57
63
|
"spec/numwords_spec.rb",
|
58
64
|
"spec/path_spec.rb",
|
@@ -62,12 +68,13 @@ Gem::Specification.new do |s|
|
|
62
68
|
"spec/spec.opts",
|
63
69
|
"spec/spec_helper.rb",
|
64
70
|
"spec/sys_spec.rb",
|
71
|
+
"spec/term_spec.rb",
|
65
72
|
"spec/zopen_spec.rb"
|
66
73
|
]
|
67
74
|
s.homepage = %q{http://github.com/epitron/epitools}
|
68
|
-
s.licenses = [
|
69
|
-
s.require_paths = [
|
70
|
-
s.rubygems_version = %q{1.6
|
75
|
+
s.licenses = [%q{WTFPL}]
|
76
|
+
s.require_paths = [%q{lib}]
|
77
|
+
s.rubygems_version = %q{1.8.6}
|
71
78
|
s.summary = %q{NOT UTILS... METILS!}
|
72
79
|
|
73
80
|
if s.respond_to? :specification_version then
|
data/lib/epitools.rb
CHANGED
data/lib/epitools/autoloads.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
## Standard library
|
2
|
+
autoload :Set, 'set'
|
2
3
|
autoload :URI, 'uri'
|
3
4
|
autoload :CGI, 'cgi'
|
4
5
|
autoload :Base64, 'base64'
|
@@ -10,6 +11,10 @@ autoload :Tempfile, 'tempfile'
|
|
10
11
|
autoload :BigDecimal, 'bigdecimal'
|
11
12
|
autoload :StringIO, 'stringio'
|
12
13
|
autoload :Curses, 'curses'
|
14
|
+
autoload :DateTime, 'date'
|
15
|
+
autoload :Date, 'date'
|
16
|
+
autoload :Open3, 'open3'
|
17
|
+
#autoload :DelegateClass, 'delegate'
|
13
18
|
|
14
19
|
module Digest
|
15
20
|
autoload :SHA1, 'digest/sha1'
|
@@ -18,11 +23,16 @@ module Digest
|
|
18
23
|
end
|
19
24
|
|
20
25
|
## Nonstandard library
|
21
|
-
autoload :MimeMagic, 'epitools/mimemagic'
|
22
26
|
autoload :Path, 'epitools/path'
|
27
|
+
autoload :Ezdb, 'epitools/ezdb'
|
23
28
|
autoload :Browser, 'epitools/browser'
|
24
29
|
autoload :Rash, 'epitools/rash'
|
25
30
|
autoload :Ratio, 'epitools/ratio'
|
26
31
|
autoload :Sys, 'epitools/sys'
|
27
32
|
autoload :ProgressBar, 'epitools/progressbar'
|
33
|
+
autoload :Trie, 'epitools/trie'
|
34
|
+
autoload :MimeMagic, 'epitools/mimemagic'
|
35
|
+
autoload :Term, 'epitools/term'
|
28
36
|
|
37
|
+
## Gems
|
38
|
+
autoreq :ANSI, 'ansi'
|
data/lib/epitools/basetypes.rb
CHANGED
@@ -15,6 +15,8 @@ unless defined? Enum
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
RbConfig = Config unless defined? RbConfig
|
19
|
+
|
18
20
|
class Object
|
19
21
|
|
20
22
|
#
|
@@ -32,7 +34,22 @@ class Object
|
|
32
34
|
#
|
33
35
|
# `truthy?` means `not blank?`
|
34
36
|
#
|
35
|
-
def truthy
|
37
|
+
def truthy?
|
38
|
+
if respond_to? :blank?
|
39
|
+
not blank?
|
40
|
+
else
|
41
|
+
not nil?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def marshal
|
46
|
+
Marshal.dump self
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Lets you say: `object.is_an? Array`
|
51
|
+
#
|
52
|
+
alias_method :is_an?, :is_a?
|
36
53
|
|
37
54
|
end
|
38
55
|
|
@@ -44,7 +61,31 @@ class FalseClass
|
|
44
61
|
def truthy?; false; end
|
45
62
|
end
|
46
63
|
|
64
|
+
class Float
|
65
|
+
#
|
66
|
+
# 'true' if the float is 0.0
|
67
|
+
#
|
68
|
+
def blank?; self == 0.0; end
|
69
|
+
end
|
70
|
+
|
71
|
+
class NilClass
|
72
|
+
#
|
73
|
+
# Always 'true'; nil is considered blank.
|
74
|
+
#
|
75
|
+
def blank?; true; end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Symbol
|
79
|
+
#
|
80
|
+
# Symbols are never blank.
|
81
|
+
#
|
82
|
+
def blank?; false; end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
|
47
87
|
class Numeric
|
88
|
+
|
48
89
|
def integer?; true; end
|
49
90
|
|
50
91
|
def truthy?; self > 0; end
|
@@ -53,8 +94,9 @@ class Numeric
|
|
53
94
|
to_s.gsub(/(\d)(?=\d{3}+(?:\.|$))(\d{3}\..*)?/,'\1,\2')
|
54
95
|
end
|
55
96
|
|
56
|
-
#
|
57
|
-
|
97
|
+
#
|
98
|
+
# Time methods
|
99
|
+
#
|
58
100
|
{
|
59
101
|
|
60
102
|
'second' => 1,
|
@@ -77,29 +119,95 @@ class Numeric
|
|
77
119
|
def from_now
|
78
120
|
Time.now + self
|
79
121
|
end
|
122
|
+
|
80
123
|
end
|
81
124
|
|
82
|
-
class
|
125
|
+
class Integer
|
126
|
+
|
83
127
|
#
|
84
|
-
# 'true' if the
|
128
|
+
# 'true' if the integer is 0
|
85
129
|
#
|
86
|
-
def blank?; self == 0
|
87
|
-
end
|
130
|
+
def blank?; self == 0; end
|
88
131
|
|
89
|
-
class NilClass
|
90
132
|
#
|
91
|
-
#
|
133
|
+
# Convert the number into a hexadecimal string representation.
|
134
|
+
# (Identical to to_s(16), except that numbers < 16 will have a 0 in front of them.)
|
92
135
|
#
|
93
|
-
def
|
94
|
-
|
136
|
+
def to_hex
|
137
|
+
"%0.2x" % self
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# Convert the number to an array of bits (least significant digit first, or little-endian).
|
142
|
+
#
|
143
|
+
def to_bits
|
144
|
+
# TODO: Why does thos go into an infinite loop in 1.8.7?
|
145
|
+
("%b" % self).chars.to_a.reverse.map(&:to_i)
|
146
|
+
end
|
147
|
+
alias_method :bits, :to_bits
|
148
|
+
|
149
|
+
#
|
150
|
+
# Cached constants for base62 encoding
|
151
|
+
#
|
152
|
+
BASE62_DIGITS = ['0'..'9', 'A'..'Z', 'a'..'z'].map(&:to_a).flatten
|
153
|
+
BASE62_BASE = BASE62_DIGITS.size
|
95
154
|
|
96
|
-
class Symbol
|
97
155
|
#
|
98
|
-
#
|
156
|
+
# Convert a number to a string representation (in "base62" encoding).
|
157
|
+
#
|
158
|
+
# Base62 encoding represents the number using the characters: 0..9, A..Z, a..z
|
99
159
|
#
|
100
|
-
|
160
|
+
# It's the same scheme that url shorteners and YouTube uses for their
|
161
|
+
# ID strings. (eg: http://www.youtube.com/watch?v=dQw4w9WgXcQ)
|
162
|
+
#
|
163
|
+
def to_base62
|
164
|
+
result = []
|
165
|
+
remainder = self
|
166
|
+
max_power = ( Math.log(self) / Math.log(BASE62_BASE) ).floor
|
167
|
+
|
168
|
+
max_power.downto(0) do |power|
|
169
|
+
divisor = BASE62_BASE**power
|
170
|
+
#p [:div, divisor, :rem, remainder]
|
171
|
+
digit, remainder = remainder.divmod(divisor)
|
172
|
+
result << digit
|
173
|
+
end
|
174
|
+
|
175
|
+
result << remainder if remainder > 0
|
176
|
+
|
177
|
+
result.map{|digit| BASE62_DIGITS[digit]}.join ''
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
#
|
183
|
+
# Monkeypatch [] into Bignum and Fixnum using class_eval.
|
184
|
+
#
|
185
|
+
# (This is necessary because [] is defined directly on the classes, and a mixin
|
186
|
+
# module will still be overridden by Big/Fixnum's native [] method.)
|
187
|
+
#
|
188
|
+
[Bignum, Fixnum].each do |klass|
|
189
|
+
|
190
|
+
klass.class_eval do
|
191
|
+
|
192
|
+
alias_method :bit, :"[]"
|
193
|
+
|
194
|
+
#
|
195
|
+
# Extends [] so that Integers can be sliced as if they were arrays.
|
196
|
+
#
|
197
|
+
def [](arg)
|
198
|
+
case arg
|
199
|
+
when Integer
|
200
|
+
self.bit(arg)
|
201
|
+
when Range
|
202
|
+
self.bits[arg]
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
101
208
|
end
|
102
209
|
|
210
|
+
|
103
211
|
class String
|
104
212
|
|
105
213
|
#
|
@@ -141,7 +249,7 @@ class String
|
|
141
249
|
def tighten
|
142
250
|
gsub(/[\t ]+/,' ').strip
|
143
251
|
end
|
144
|
-
|
252
|
+
|
145
253
|
#
|
146
254
|
# Remove redundant whitespace AND newlines.
|
147
255
|
#
|
@@ -149,6 +257,14 @@ class String
|
|
149
257
|
gsub(/\s+/,' ').strip
|
150
258
|
end
|
151
259
|
|
260
|
+
#
|
261
|
+
# Remove ANSI color codes.
|
262
|
+
#
|
263
|
+
def strip_color
|
264
|
+
gsub(/\e\[.*?(\d)+m/, '')
|
265
|
+
end
|
266
|
+
alias_method :strip_ansi, :strip_color
|
267
|
+
|
152
268
|
#
|
153
269
|
# Like #lines, but skips empty lines and removes \n's.
|
154
270
|
#
|
@@ -157,6 +273,7 @@ class String
|
|
157
273
|
split($/).select{|l| not l.blank? }
|
158
274
|
end
|
159
275
|
|
276
|
+
alias_method :nicelines, :nice_lines
|
160
277
|
alias_method :clean_lines, :nice_lines
|
161
278
|
|
162
279
|
#
|
@@ -194,20 +311,51 @@ class String
|
|
194
311
|
end
|
195
312
|
end
|
196
313
|
|
314
|
+
|
315
|
+
|
316
|
+
#
|
317
|
+
# Cached constants for base62 decoding.
|
318
|
+
#
|
319
|
+
BASE62_DIGITS = Hash[ Integer::BASE62_DIGITS.map.with_index{|letter,index| [letter,index]} ]
|
320
|
+
BASE62_BASE = Integer::BASE62_BASE
|
321
|
+
|
322
|
+
#
|
323
|
+
# Convert a string (encoded in base16 "hex" -- for example, an MD5 or SHA1 hash)
|
324
|
+
# into "base62" format. (See Integer#to_base62 for more info.)
|
325
|
+
#
|
326
|
+
def to_base62
|
327
|
+
to_i(16).to_base62
|
328
|
+
end
|
329
|
+
|
330
|
+
#
|
331
|
+
# Convert a string encoded in base62 into an integer.
|
332
|
+
# (See Integer#to_base62 for more info.)
|
333
|
+
#
|
334
|
+
def from_base62
|
335
|
+
accumulator = 0
|
336
|
+
digits = chars.map { |c| BASE62_DIGITS[c] }.reverse
|
337
|
+
digits.each_with_index do |digit, power|
|
338
|
+
accumulator += (BASE62_BASE**power) * digit if digit > 0
|
339
|
+
end
|
340
|
+
accumulator
|
341
|
+
end
|
342
|
+
|
197
343
|
#
|
198
344
|
# Decode a mime64/base64 encoded string
|
199
345
|
#
|
200
|
-
def
|
346
|
+
def from_base64
|
201
347
|
Base64.decode64 self
|
202
348
|
end
|
349
|
+
alias_method :decode64, :from_base64
|
203
350
|
|
204
351
|
#
|
205
352
|
# Encode into a mime64/base64 string
|
206
353
|
#
|
207
|
-
def
|
354
|
+
def to_base64
|
208
355
|
Base64.encode64 self
|
209
356
|
end
|
210
|
-
alias_method :base64,
|
357
|
+
alias_method :base64, :to_base64
|
358
|
+
alias_method :encode64, :to_base64
|
211
359
|
|
212
360
|
#
|
213
361
|
# MD5 the string
|
@@ -274,59 +422,16 @@ class String
|
|
274
422
|
JSON.parse self
|
275
423
|
end
|
276
424
|
|
277
|
-
end
|
278
|
-
|
279
|
-
|
280
|
-
class Integer
|
281
|
-
|
282
|
-
#
|
283
|
-
# 'true' if the integer is 0
|
284
|
-
#
|
285
|
-
def blank?; self == 0; end
|
286
|
-
|
287
425
|
#
|
288
|
-
# Convert the
|
426
|
+
# Convert the string to a Path object.
|
289
427
|
#
|
290
|
-
def
|
291
|
-
|
428
|
+
def as_path
|
429
|
+
Path[self]
|
292
430
|
end
|
293
|
-
|
294
|
-
#
|
295
|
-
# Convert the number to an array of bits (least significant digit first, or little-endian).
|
296
|
-
#
|
297
|
-
def to_bits
|
298
|
-
# TODO: Why does thos go into an infinite loop in 1.8.7?
|
299
|
-
("%b" % self).chars.to_a.reverse.map(&:to_i)
|
300
|
-
end
|
301
|
-
alias_method :bits, :to_bits
|
302
|
-
|
303
|
-
end
|
304
|
-
|
305
|
-
|
306
|
-
#
|
307
|
-
# Monkeypatch [] into Bignum and Fixnum using class_eval.
|
308
|
-
#
|
309
|
-
# (This is necessary because [] is defined directly on the classes, and a mixin
|
310
|
-
# module will still be overridden by Big/Fixnum's native [] method.)
|
311
|
-
#
|
312
|
-
[Bignum, Fixnum].each do |klass|
|
431
|
+
alias_method :to_p, :as_path
|
313
432
|
|
314
|
-
|
315
|
-
|
316
|
-
alias_method :bit, :"[]"
|
317
|
-
|
318
|
-
#
|
319
|
-
# Extends [] so that Integers can be sliced as if they were arrays.
|
320
|
-
#
|
321
|
-
def [](arg)
|
322
|
-
case arg
|
323
|
-
when Integer
|
324
|
-
self.bit(arg)
|
325
|
-
when Range
|
326
|
-
self.bits[arg]
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
433
|
+
def unmarshal
|
434
|
+
Marshal.restore self
|
330
435
|
end
|
331
436
|
|
332
437
|
end
|
@@ -392,6 +497,21 @@ class Array
|
|
392
497
|
(self | other) - (self & other)
|
393
498
|
end
|
394
499
|
|
500
|
+
#
|
501
|
+
# Pick a random element.
|
502
|
+
#
|
503
|
+
def pick
|
504
|
+
self[rand(size)]
|
505
|
+
end
|
506
|
+
|
507
|
+
#
|
508
|
+
# Divide the array into n pieces.
|
509
|
+
#
|
510
|
+
def / pieces
|
511
|
+
piece_size = (size.to_f / pieces).ceil
|
512
|
+
each_slice(piece_size).to_a
|
513
|
+
end
|
514
|
+
|
395
515
|
end
|
396
516
|
|
397
517
|
|
@@ -417,6 +537,7 @@ module Enumerable
|
|
417
537
|
# (default: false)
|
418
538
|
# :after => true #=> split after the matched element (only has an effect when used with :include_boundary)
|
419
539
|
# (default: false)
|
540
|
+
# :once => flase #=> only perform one split (default: false)
|
420
541
|
#
|
421
542
|
# Examples:
|
422
543
|
# [1,2,3,4,5].split{ |e| e == 3 }
|
@@ -448,10 +569,13 @@ module Enumerable
|
|
448
569
|
|
449
570
|
chunks = []
|
450
571
|
current_chunk = []
|
572
|
+
|
573
|
+
splits = 0
|
574
|
+
max_splits = options[:once] == true ? 1 : options[:max_splits]
|
451
575
|
|
452
576
|
each do |e|
|
453
577
|
|
454
|
-
if boundary_test_proc.call(e)
|
578
|
+
if boundary_test_proc.call(e) and (max_splits == nil or splits < max_splits)
|
455
579
|
|
456
580
|
if current_chunk.empty? and not include_boundary
|
457
581
|
next # hit 2 boundaries in a row... just keep moving, people!
|
@@ -468,6 +592,8 @@ module Enumerable
|
|
468
592
|
current_chunk = [] # start a new result
|
469
593
|
current_chunk << e if include_boundary # include the boundary, if necessary
|
470
594
|
end
|
595
|
+
|
596
|
+
splits += 1
|
471
597
|
|
472
598
|
else
|
473
599
|
current_chunk << e
|
@@ -507,7 +633,11 @@ module Enumerable
|
|
507
633
|
# Sum the elements
|
508
634
|
#
|
509
635
|
def sum
|
510
|
-
|
636
|
+
if block_given?
|
637
|
+
inject(0) { |total,elem| total + yield(elem) }
|
638
|
+
else
|
639
|
+
inject(0) { |total,elem| total + elem }
|
640
|
+
end
|
511
641
|
end
|
512
642
|
|
513
643
|
#
|
@@ -656,11 +786,12 @@ class Object
|
|
656
786
|
#
|
657
787
|
def bench(message=nil)
|
658
788
|
start = Time.now
|
659
|
-
yield
|
789
|
+
result = yield
|
660
790
|
elapsed = Time.now - start
|
661
791
|
|
662
792
|
print "[#{message}] " if message
|
663
|
-
puts "elapsed time: %0.5fs" % elapsed
|
793
|
+
puts "elapsed time: %0.5fs" % elapsed
|
794
|
+
result
|
664
795
|
end
|
665
796
|
alias time bench
|
666
797
|
|
@@ -937,3 +1068,21 @@ def dmsg(msg)
|
|
937
1068
|
end
|
938
1069
|
|
939
1070
|
|
1071
|
+
def del(x)
|
1072
|
+
case thing
|
1073
|
+
when String
|
1074
|
+
del(x.to_sym)
|
1075
|
+
when Class, Module
|
1076
|
+
Object.send(:remove_const, x)
|
1077
|
+
when Method
|
1078
|
+
x.owner.send(:undef_method, x.name)
|
1079
|
+
when Symbol
|
1080
|
+
if Object.const_get(x)
|
1081
|
+
Object.send(:remove_const, x)
|
1082
|
+
elsif method(x)
|
1083
|
+
undef_method x
|
1084
|
+
end
|
1085
|
+
else
|
1086
|
+
raise "Error: don't know how to 'del #{x.inspect}'"
|
1087
|
+
end
|
1088
|
+
end
|