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 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.4.49
1
+ 0.5.0
@@ -5,22 +5,24 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{epitools}
8
- s.version = "0.4.49"
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 = ["epitron"]
12
- s.date = %q{2011-06-29}
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 = ["WTFPL"]
69
- s.require_paths = ["lib"]
70
- s.rubygems_version = %q{1.6.2}
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
@@ -82,11 +82,12 @@ require_wrapper = proc do |mod|
82
82
  end
83
83
  end
84
84
 
85
- ## Require the tools
85
+ #
86
+ # Make all the modules autoload, and require all the monkeypatches
87
+ #
86
88
  %w[
87
89
  autoloads
88
90
  basetypes
89
- niceprint
90
91
  string_to_proc
91
92
  zopen
92
93
  colored
@@ -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'
@@ -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?; not blank?; end
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
- # Time
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 Float
125
+ class Integer
126
+
83
127
  #
84
- # 'true' if the float is 0.0
128
+ # 'true' if the integer is 0
85
129
  #
86
- def blank?; self == 0.0; end
87
- end
130
+ def blank?; self == 0; end
88
131
 
89
- class NilClass
90
132
  #
91
- # Always 'true'; nil is considered blank.
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 blank?; true; end
94
- end
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
- # Symbols are never blank.
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
- def blank?; false; end
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 decode64
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 encode64
354
+ def to_base64
208
355
  Base64.encode64 self
209
356
  end
210
- alias_method :base64, :encode64
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 number into a hexadecimal string representation.
426
+ # Convert the string to a Path object.
289
427
  #
290
- def to_hex
291
- "%0.2x" % self
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
- klass.class_eval do
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
- inject(0) { |total,n| total + n }
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