epitools 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,1135 +0,0 @@
1
- require 'epitools'
2
-
3
- ## Alias "Enumerator" to "Enum"
4
-
5
- if RUBY_VERSION["1.8"]
6
- require 'enumerator'
7
- Enumerator = Enumerable::Enumerator unless defined? Enumerator
8
- end
9
-
10
- unless defined? Enum
11
- if defined? Enumerator
12
- Enum = Enumerator
13
- else
14
- $stderr.puts "WARNING: Couldn't find the Enumerator class. Enum will not be available."
15
- end
16
- end
17
-
18
- RbConfig = Config unless defined? RbConfig
19
-
20
- class Object
21
-
22
- #
23
- # Slightly gross hack to add a class method.
24
- #
25
- def self.alias_class_method(dest, src)
26
- metaclass.send(:alias_method, dest, src)
27
- end
28
-
29
- #
30
- # Default "integer?" behaviour.
31
- #
32
- def integer?; false; end
33
-
34
- #
35
- # `truthy?` means `not blank?`
36
- #
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?
53
-
54
- end
55
-
56
- class TrueClass
57
- def truthy?; true; end
58
- end
59
-
60
- class FalseClass
61
- def truthy?; false; end
62
- end
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
-
87
- class Numeric
88
-
89
- def integer?; true; end
90
-
91
- def truthy?; self > 0; end
92
-
93
- def commatize
94
- to_s.gsub(/(\d)(?=\d{3}+(?:\.|$))(\d{3}\..*)?/,'\1,\2')
95
- end
96
-
97
- #
98
- # Time methods
99
- #
100
- {
101
-
102
- 'second' => 1,
103
- 'minute' => 60,
104
- 'hour' => 60 * 60,
105
- 'day' => 60 * 60 * 24,
106
- 'week' => 60 * 60 * 24 * 7,
107
- 'month' => 60 * 60 * 24 * 30,
108
- 'year' => 60 * 60 * 24 * 364.25,
109
-
110
- }.each do |unit, scale|
111
- define_method(unit) { self * scale }
112
- define_method(unit+'s') { self * scale }
113
- end
114
-
115
- def ago
116
- Time.now - self
117
- end
118
-
119
- def from_now
120
- Time.now + self
121
- end
122
-
123
- end
124
-
125
- class Integer
126
-
127
- #
128
- # 'true' if the integer is 0
129
- #
130
- def blank?; self == 0; end
131
-
132
- #
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.)
135
- #
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
154
-
155
- #
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
159
- #
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
-
180
- #
181
- # Returns the all the prime factors of a number.
182
- #
183
- def factors
184
- Prime # autoload the prime module
185
- prime_division.map { |n,count| [n]*count }.flatten
186
- end
187
-
188
- end
189
-
190
-
191
- #
192
- # Monkeypatch [] into Bignum and Fixnum using class_eval.
193
- #
194
- # (This is necessary because [] is defined directly on the classes, and a mixin
195
- # module will still be overridden by Big/Fixnum's native [] method.)
196
- #
197
- [Bignum, Fixnum].each do |klass|
198
-
199
- klass.class_eval do
200
-
201
- alias_method :bit, :"[]"
202
-
203
- #
204
- # Extends [] so that Integers can be sliced as if they were arrays.
205
- #
206
- def [](arg)
207
- case arg
208
- when Integer
209
- self.bit(arg)
210
- when Range
211
- self.bits[arg]
212
- end
213
- end
214
-
215
- end
216
-
217
- end
218
-
219
-
220
- class String
221
-
222
- #
223
- # Could this string be cast to an integer?
224
- #
225
- def integer?
226
- strip.match(/^\d+$/) ? true : false
227
- end
228
-
229
- #
230
- # 'true' if the string's length is 0 (after whitespace has been stripped from the ends)
231
- #
232
- def blank?
233
- strip.size == 0
234
- end
235
-
236
- #
237
- # Does this string contain something that means roughly "true"?
238
- #
239
- def truthy?
240
- case strip.downcase
241
- when "1", "true", "yes", "on", "enabled", "affirmative"
242
- true
243
- else
244
- false
245
- end
246
- end
247
-
248
- #
249
- # Convert \r\n to \n
250
- #
251
- def to_unix
252
- gsub("\r\n", "\n")
253
- end
254
-
255
- #
256
- # Remove redundant whitespaces (not including newlines).
257
- #
258
- def tighten
259
- gsub(/[\t ]+/,' ').strip
260
- end
261
-
262
- #
263
- # Remove redundant whitespace AND newlines.
264
- #
265
- def dewhitespace
266
- gsub(/\s+/,' ').strip
267
- end
268
-
269
- #
270
- # Remove ANSI color codes.
271
- #
272
- def strip_color
273
- gsub(/\e\[.*?(\d)+m/, '')
274
- end
275
- alias_method :strip_ansi, :strip_color
276
-
277
- #
278
- # Like #lines, but skips empty lines and removes \n's.
279
- #
280
- def nice_lines
281
- # note: $/ is the platform's newline separator
282
- split($/).select{|l| not l.blank? }
283
- end
284
-
285
- alias_method :nicelines, :nice_lines
286
- alias_method :clean_lines, :nice_lines
287
-
288
- #
289
- # The Infamous Caesar-Cipher. Unbreakable to this day.
290
- #
291
- def rot13
292
- tr('n-za-mN-ZA-M', 'a-zA-Z')
293
- end
294
-
295
- #
296
- # Convert non-URI characters into %XXes.
297
- #
298
- def urlencode
299
- URI.escape(self)
300
- end
301
-
302
- #
303
- # Convert an URI's %XXes into regular characters.
304
- #
305
- def urldecode
306
- URI.unescape(self)
307
- end
308
-
309
- #
310
- # Convert a query string to a hash of params
311
- #
312
- def to_params
313
- CGI.parse(self).map_values do |v|
314
- # CGI.parse wraps every value in an array. Unwrap them!
315
- if v.is_a?(Array) and v.size == 1
316
- v.first
317
- else
318
- v
319
- end
320
- end
321
- end
322
-
323
-
324
- #
325
- # Cached constants for base62 decoding.
326
- #
327
- BASE62_DIGITS = Hash[ Integer::BASE62_DIGITS.zip((0...Integer::BASE62_DIGITS.size).to_a) ]
328
- BASE62_BASE = Integer::BASE62_BASE
329
-
330
- #
331
- # Convert a string (encoded in base16 "hex" -- for example, an MD5 or SHA1 hash)
332
- # into "base62" format. (See Integer#to_base62 for more info.)
333
- #
334
- def to_base62
335
- to_i(16).to_base62
336
- end
337
-
338
- #
339
- # Convert a string encoded in base62 into an integer.
340
- # (See Integer#to_base62 for more info.)
341
- #
342
- def from_base62
343
- accumulator = 0
344
- digits = chars.map { |c| BASE62_DIGITS[c] }.reverse
345
- digits.each_with_index do |digit, power|
346
- accumulator += (BASE62_BASE**power) * digit if digit > 0
347
- end
348
- accumulator
349
- end
350
-
351
- #
352
- # Decode a mime64/base64 encoded string
353
- #
354
- def from_base64
355
- Base64.decode64 self
356
- end
357
- alias_method :decode64, :from_base64
358
-
359
- #
360
- # Encode into a mime64/base64 string
361
- #
362
- def to_base64
363
- Base64.encode64 self
364
- end
365
- alias_method :base64, :to_base64
366
- alias_method :encode64, :to_base64
367
-
368
- #
369
- # MD5 the string
370
- #
371
- def md5
372
- Digest::MD5.hexdigest self
373
- end
374
-
375
- #
376
- # SHA1 the string
377
- #
378
- def sha1
379
- Digest::SHA1.hexdigest self
380
- end
381
-
382
- #
383
- # gzip the string
384
- #
385
- def gzip(level=nil)
386
- zipped = StringIO.new
387
- Zlib::GzipWriter.wrap(zipped, level) { |io| io.write(self) }
388
- zipped.string
389
- end
390
-
391
- #
392
- # gunzip the string
393
- #
394
- def gunzip
395
- data = StringIO.new(self)
396
- Zlib::GzipReader.new(data).read
397
- end
398
-
399
- #
400
- # deflate the string
401
- #
402
- def deflate(level=nil)
403
- Zlib::Deflate.deflate(self, level)
404
- end
405
-
406
- #
407
- # inflate the string
408
- #
409
- def inflate
410
- Zlib::Inflate.inflate(self)
411
- end
412
-
413
- # `true` if this string starts with the substring
414
- #
415
- def startswith(substring)
416
- self[0...substring.size] == substring
417
- end
418
-
419
- #
420
- # `true` if this string ends with the substring
421
- #
422
- def endswith(substring)
423
- self[-substring.size..-1] == substring
424
- end
425
-
426
- #
427
- # Parse object as JSON
428
- #
429
- def from_json
430
- JSON.parse self
431
- end
432
-
433
- #
434
- # Convert the string to a Path object.
435
- #
436
- def as_path
437
- Path[self]
438
- end
439
- alias_method :to_p, :as_path
440
-
441
- def unmarshal
442
- Marshal.restore self
443
- end
444
-
445
- end
446
-
447
-
448
- class Array
449
-
450
- #
451
- # flatten.compact.uniq
452
- #
453
- def squash
454
- flatten.compact.uniq
455
- end
456
-
457
- #
458
- # Removes the elements from the array for which the block evaluates to true.
459
- # In addition, return the removed elements.
460
- #
461
- # For example, if you wanted to split an array into evens and odds:
462
- #
463
- # nums = [1,2,3,4,5,6,7,8,9,10,11,12]
464
- # even = nums.remove_if { |n| n.even? } # remove all even numbers from the "nums" array and return them
465
- # odd = nums # "nums" now only contains odd numbers
466
- #
467
- def remove_if(&block)
468
- removed = []
469
-
470
- delete_if do |x|
471
- if block.call(x)
472
- removed << x
473
- true
474
- else
475
- false
476
- end
477
- end
478
-
479
- removed
480
- end
481
-
482
- #
483
- # zip from the right (or reversed zip.)
484
- #
485
- # eg:
486
- # >> [5,39].rzip([:hours, :mins, :secs])
487
- # => [ [:mins, 5], [:secs, 39] ]
488
- #
489
- def rzip(other)
490
- # That's a lotta reverses!
491
- reverse.zip(other.reverse).reverse
492
- end
493
-
494
- #
495
- # Pick the middle element.
496
- #
497
- def middle
498
- self[(size-1) / 2]
499
- end
500
-
501
- #
502
- # XOR operator
503
- #
504
- def ^(other)
505
- (self | other) - (self & other)
506
- end
507
-
508
- #
509
- # Pick a random element.
510
- #
511
- def pick
512
- self[rand(size)]
513
- end
514
-
515
- #
516
- # Divide the array into n pieces.
517
- #
518
- def / pieces
519
- piece_size = (size.to_f / pieces).ceil
520
- each_slice(piece_size).to_a
521
- end
522
-
523
-
524
- alias_method :unzip, :transpose
525
-
526
- end
527
-
528
-
529
- module Enumerable
530
-
531
- #
532
- # 'true' if the Enumerable has no elements
533
- #
534
- def blank?
535
- not any?
536
- end
537
-
538
- #
539
- # I enjoy typing ".all" more than ".to_a"
540
- #
541
- alias_method :all, :to_a
542
-
543
- #
544
- # Split this enumerable into chunks, given some boundary condition. (Returns an array of arrays.)
545
- #
546
- # Options:
547
- # :include_boundary => true #=> include the element that you're splitting at in the results
548
- # (default: false)
549
- # :after => true #=> split after the matched element (only has an effect when used with :include_boundary)
550
- # (default: false)
551
- # :once => flase #=> only perform one split (default: false)
552
- #
553
- # Examples:
554
- # [1,2,3,4,5].split{ |e| e == 3 }
555
- # #=> [ [1,2], [4,5] ]
556
- #
557
- # [1,2,3,4,5].split(:include_boundary=>true) { |e| e == 3 }
558
- # #=> [ [1,2], [3,4,5] ]
559
- #
560
- # chapters = File.read("ebook.txt").split(/Chapter \d+/, :include_boundary=>true)
561
- # #=> [ ["Chapter 1", ...], ["Chapter 2", ...], etc. ]
562
- #
563
- def split_at(matcher=nil, options={}, &block)
564
- # TODO: Ruby 1.9 returns Enumerators for everything now. Maybe use that?
565
-
566
- return self unless self.any?
567
-
568
- include_boundary = options[:include_boundary] || false
569
-
570
- if matcher.nil?
571
- boundary_test_proc = block
572
- else
573
- if matcher.is_a? String or matcher.is_a? Regexp
574
- boundary_test_proc = proc { |element| element[matcher] rescue nil }
575
- else
576
- boundary_test_proc = proc { |element| element == matcher }
577
- #raise "I don't know how to split with #{matcher}"
578
- end
579
- end
580
-
581
- chunks = []
582
- current_chunk = []
583
-
584
- splits = 0
585
- max_splits = options[:once] == true ? 1 : options[:max_splits]
586
-
587
- each do |e|
588
-
589
- if boundary_test_proc.call(e) and (max_splits == nil or splits < max_splits)
590
-
591
- if current_chunk.empty? and not include_boundary
592
- next # hit 2 boundaries in a row... just keep moving, people!
593
- end
594
-
595
- if options[:after]
596
- # split after boundary
597
- current_chunk << e if include_boundary # include the boundary, if necessary
598
- chunks << current_chunk # shift everything after the boundary into the resultset
599
- current_chunk = [] # start a new result
600
- else
601
- # split before boundary
602
- chunks << current_chunk # shift before the boundary into the resultset
603
- current_chunk = [] # start a new result
604
- current_chunk << e if include_boundary # include the boundary, if necessary
605
- end
606
-
607
- splits += 1
608
-
609
- else
610
- current_chunk << e
611
- end
612
-
613
- end
614
-
615
- chunks << current_chunk if current_chunk.any?
616
-
617
- chunks # resultset
618
- end
619
-
620
- #
621
- # Split the array into chunks, cutting between the matched element and the next element.
622
- #
623
- # Example:
624
- # [1,2,3,4].split_after{|e| e == 3 } #=> [ [1,2,3], [4] ]
625
- #
626
- def split_after(matcher=nil, options={}, &block)
627
- options[:after] ||= true
628
- options[:include_boundary] ||= true
629
- split_at(matcher, options, &block)
630
- end
631
-
632
- #
633
- # Split the array into chunks, cutting between the matched element and the previous element.
634
- #
635
- # Example:
636
- # [1,2,3,4].split_before{|e| e == 3 } #=> [ [1,2], [3,4] ]
637
- #
638
- def split_before(matcher=nil, options={}, &block)
639
- options[:include_boundary] ||= true
640
- split_at(matcher, options, &block)
641
- end
642
-
643
- #
644
- # Sum the elements
645
- #
646
- def sum
647
- if block_given?
648
- inject(0) { |total,elem| total + yield(elem) }
649
- else
650
- inject(0) { |total,elem| total + elem }
651
- end
652
- end
653
-
654
- #
655
- # Average the elements
656
- #
657
- def average
658
- count = 0
659
- sum = inject(0) { |total,n| count += 1; total + n }
660
- sum / count.to_f
661
- end
662
-
663
- #
664
- # The same as "map", except that if an element is an Array or Enumerable, map is called
665
- # recursively on that element.
666
- #
667
- # Example:
668
- # [ [1,2], [3,4] ].map_recursively{|e| e ** 2 } #=> [ [1,4], [9,16] ]
669
- #
670
- def recursive_map(*args, &block)
671
- map(*args) do |e|
672
- if e.is_a? Array or e.is_a? Enumerable
673
- e.map(*args, &block)
674
- else
675
- block.call(e)
676
- end
677
- end
678
- end
679
-
680
- alias_method :map_recursively, :recursive_map
681
- alias_method :map_recursive, :recursive_map
682
-
683
-
684
- #
685
- # Identical to "reduce" in ruby1.9 (or foldl in haskell.)
686
- #
687
- # Example:
688
- # array.foldl{|a,b| a + b } == array[1..-1].inject(array[0]){|a,b| a + b }
689
- #
690
- def foldl(methodname=nil, &block)
691
- result = nil
692
-
693
- raise "Error: pass a parameter OR a block, not both!" unless !!methodname ^ block_given?
694
-
695
- if methodname
696
-
697
- each_with_index do |e,i|
698
- if i == 0
699
- result = e
700
- next
701
- end
702
-
703
- result = result.send(methodname, e)
704
- end
705
-
706
- else
707
-
708
- each_with_index do |e,i|
709
- if i == 0
710
- result = e
711
- next
712
- end
713
-
714
- result = block.call(result, e)
715
- end
716
-
717
- end
718
-
719
- result
720
- end
721
-
722
- #
723
- # Returns the powerset of the Enumerable
724
- #
725
- # Example:
726
- # [1,2].powerset #=> [[], [1], [2], [1, 2]]
727
- #
728
- def powerset
729
- # the bit pattern of the numbers from 0..2^(elements)-1 can be used to select the elements of the set...
730
- a = to_a
731
- (0...2**a.size).map do |bitmask|
732
- a.select.with_index{ |e, i| bitmask[i] == 1 }
733
- end
734
- end
735
-
736
- #
737
- # Does the opposite of #zip -- converts [ [:a, 1], [:b, 2] ] to [ [:a, :b], [1, 2] ]
738
- #
739
- def unzip
740
- # TODO: make it work for arrays containing uneven-length contents
741
- to_a.transpose
742
- end
743
-
744
- #
745
- # Associative grouping; groups all elements who share something in common with each other.
746
- # You supply a block which takes two elements, and have it return true if they are "neighbours"
747
- # (eg: belong in the same group).
748
- #
749
- # Example:
750
- # [1,2,5,6].group_neighbours_by { |a,b| b-a <= 1 } #=> [ [1,2], [5,6] ]
751
- #
752
- # (Note: This is a very fast one-pass algorithm -- therefore, the groups must be pre-sorted.)
753
- #
754
- def group_neighbours_by(&block)
755
- result = []
756
- cluster = [first]
757
- each_cons(2) do |a,b|
758
- if yield(a,b)
759
- cluster << b
760
- else
761
- result << cluster
762
- cluster = [b]
763
- end
764
- end
765
-
766
- result << cluster if cluster.any?
767
-
768
- result
769
- end
770
- alias_method :group_neighbors_by, :group_neighbours_by
771
-
772
- end
773
-
774
-
775
- class Object
776
-
777
- #
778
- # Gives you a copy of the object with its attributes changed to whatever was
779
- # passed in the options hash.
780
- #
781
- # Example:
782
- # >> cookie = Cookie.new(:size=>10, :chips=>200)
783
- # => #<Cookie:0xffffffe @size=10, @chips=200>
784
- # >> cookie.with(:chips=>50)
785
- # => #<Cookie:0xfffffff @size=10, @chips=50>
786
- #
787
- # (All this method does is dup the object, then call "key=(value)" for each
788
- # key/value in the options hash.)
789
- #
790
- def with(options={})
791
- obj = dup
792
- options.each { |key, value| obj.send "#{key}=", value }
793
- obj
794
- end
795
-
796
-
797
- #
798
- # Return a copy of the class with modules mixed into it.
799
- #
800
- def self.using(*args)
801
- if block_given?
802
- yield using(*args)
803
- else
804
- copy = self.dup
805
- args.each { |arg| copy.send(:include, arg) }
806
- copy
807
- end
808
- end
809
-
810
-
811
- #
812
- # Instead of:
813
- # if cookie_jar.include? cookie
814
- # Now you can do:
815
- # if cookie.in? cookie_jar
816
- #
817
- def in?(enumerable)
818
- enumerable.include? self
819
- end
820
-
821
- #
822
- # Instead of:
823
- # @person ? @person.name : nil
824
- # Now you can do:
825
- # @person.try(:name)
826
- #
827
- def try(method, *args, &block)
828
- send(method, *args, &block) if respond_to? method
829
- end
830
-
831
- #
832
- # Benchmark a block!
833
- #
834
- def bench(message=nil)
835
- start = Time.now
836
- result = yield
837
- elapsed = Time.now - start
838
-
839
- print "[#{message}] " if message
840
- puts "elapsed time: %0.5fs" % elapsed
841
- result
842
- end
843
- alias time bench
844
-
845
-
846
- #
847
- # A decorator that makes any block-accepting method return an
848
- # Enumerator whenever the method is called without a block.
849
- #
850
- def self.enumerable *meths
851
- meths.each do |meth|
852
- alias_method "#{meth}_without_enumerator", meth
853
- class_eval %{
854
- def #{meth}(*args, &block)
855
- return Enum.new(self, #{meth.inspect}, *args, &block) unless block_given?
856
- #{meth}_without_enumerator(*args, &block)
857
- end
858
- }
859
- end
860
- end
861
-
862
- end
863
-
864
-
865
-
866
- class Hash
867
-
868
- #
869
- # 'true' if the Hash has no entries
870
- #
871
- def blank?
872
- not any?
873
- end
874
-
875
- #
876
- # Runs "remove_blank_values" on self.
877
- #
878
- def remove_blank_values!
879
- delete_if{|k,v| v.blank?}
880
- self
881
- end
882
-
883
- #
884
- # Returns a new Hash where blank values have been removed.
885
- # (It checks if the value is blank by calling #blank? on it)
886
- #
887
- def remove_blank_values
888
- dup.remove_blank_values!
889
- end
890
-
891
- #
892
- # Runs map_values on self.
893
- #
894
- def map_values!(&block)
895
- keys.each do |key|
896
- value = self[key]
897
- self[key] = yield(value)
898
- end
899
- self
900
- end
901
-
902
- #
903
- # Transforms the values of the hash by passing them into the supplied
904
- # block, and then using the block's result as the new value.
905
- #
906
- def map_values(&block)
907
- dup.map_values!(&block)
908
- end
909
-
910
- #
911
- # Runs map_keys on self.
912
- #
913
- def map_keys!(&block)
914
- keys.each do |key|
915
- value = delete(key)
916
- self[yield(key)] = value
917
- end
918
- self
919
- end
920
-
921
- #
922
- # Transforms the keys of the hash by passing them into the supplied block,
923
- # and then using the blocks result as the new key.
924
- #
925
- def map_keys(&block)
926
- dup.map_keys!(&block)
927
- end
928
-
929
- #
930
- # Returns a new Hash whose values default to empty arrays. (Good for collecting things!)
931
- #
932
- # eg:
933
- # Hash.of_arrays[:yays] << "YAY!"
934
- #
935
- def self.of_arrays
936
- new {|h,k| h[k] = [] }
937
- end
938
-
939
- #
940
- # Returns a new Hash whose values default to 0. (Good for counting things!)
941
- #
942
- # eg:
943
- # Hash.of_integers[:yays] += 1
944
- #
945
- def self.of_integers
946
- new(0)
947
- end
948
-
949
- #
950
- # Makes each element in the `path` array point to a hash containing the next element in the `path`.
951
- # Useful for turning a bunch of strings (paths, module names, etc.) into a tree.
952
- #
953
- # Example:
954
- # h = {}
955
- # h.mkdir_p(["a", "b", "c"]) #=> {"a"=>{"b"=>{"c"=>{}}}}
956
- # h.mkdir_p(["a", "b", "whoa"]) #=> {"a"=>{"b"=>{"c"=>{}, "whoa"=>{}}}}
957
- #
958
- def mkdir_p(path)
959
- return if path.empty?
960
- dir = path.first
961
- self[dir] ||= {}
962
- self[dir].mkdir_p(path[1..-1])
963
- self
964
- end
965
-
966
- #
967
- # Turn some nested hashes into a tree (returns an array of strings, padded on the left with indents.)
968
- #
969
- def tree(level=0, indent=" ")
970
- result = []
971
- dent = indent * level
972
- each do |key, val|
973
- result << dent+key
974
- result += val.tree(level+1) if val.any?
975
- end
976
- result
977
- end
978
-
979
- #
980
- # Print the result of `tree`
981
- #
982
- def print_tree
983
- tree.each { |row| puts row }
984
- nil
985
- end
986
-
987
- #
988
- # Convert the hash into a GET query.
989
- #
990
- def to_query
991
- params = ''
992
- stack = []
993
-
994
- each do |k, v|
995
- if v.is_a?(Hash)
996
- stack << [k,v]
997
- else
998
- params << "#{k}=#{v}&"
999
- end
1000
- end
1001
-
1002
- stack.each do |parent, hash|
1003
- hash.each do |k, v|
1004
- if v.is_a?(Hash)
1005
- stack << ["#{parent}[#{k}]", v]
1006
- else
1007
- params << "#{parent}[#{k}]=#{v}&"
1008
- end
1009
- end
1010
- end
1011
-
1012
- params.chop! # trailing &
1013
- params
1014
- end
1015
-
1016
- end
1017
-
1018
- unless defined?(BasicObject)
1019
- #
1020
- # A BasicObject class for Ruby 1.8
1021
- #
1022
- class BasicObject
1023
- instance_methods.each { |m| undef_method m unless m =~ /^__/ }
1024
- end
1025
- end
1026
-
1027
-
1028
-
1029
- class NotWrapper < BasicObject # :nodoc:
1030
- def initialize(orig)
1031
- @orig = orig
1032
- end
1033
-
1034
- def inspect
1035
- "{NOT #{@orig.inspect}}"
1036
- end
1037
-
1038
- def method_missing(meth, *args, &block)
1039
- result = @orig.send(meth, *args, &block)
1040
- if result.is_a? ::TrueClass or result.is_a? ::FalseClass
1041
- !result
1042
- else
1043
- raise "Sorry, I don't know how to invert #{result.inspect}"
1044
- end
1045
- end
1046
- end
1047
-
1048
- class Object
1049
-
1050
- #
1051
- # Negates a boolean, chained-method style.
1052
- #
1053
- # Example:
1054
- # >> 10.even?
1055
- # => true
1056
- # >> 10.not.even?
1057
- # => false
1058
- #
1059
- def not
1060
- NotWrapper.new(self)
1061
- end
1062
-
1063
- end
1064
-
1065
- # Metaclass
1066
- class Object
1067
- # The hidden singleton lurks behind everyone
1068
- def metaclass
1069
- class << self
1070
- self
1071
- end
1072
- end
1073
-
1074
- def meta_eval &blk
1075
- metaclass.instance_eval &blk
1076
- end
1077
-
1078
- # Adds methods to a metaclass
1079
- def meta_def name, &blk
1080
- meta_eval { define_method name, &blk }
1081
- end
1082
-
1083
- # Defines an instance method within a class
1084
- def class_def name, &blk
1085
- class_eval { define_method name, &blk }
1086
- end
1087
- end
1088
-
1089
- unless IO.respond_to? :copy_stream
1090
-
1091
- class IO
1092
-
1093
- def self.copy_stream(input, output)
1094
- while chunk = input.read(8192)
1095
- output.write(chunk)
1096
- end
1097
- end
1098
-
1099
- end
1100
-
1101
- end
1102
-
1103
- #
1104
- # Emit a quick debug message (only if $DEBUG is true)
1105
- #
1106
- def dmsg(msg)
1107
- if $DEBUG
1108
- case msg
1109
- when String
1110
- puts msg
1111
- else
1112
- puts msg.inspect
1113
- end
1114
- end
1115
- end
1116
-
1117
-
1118
- def del(x)
1119
- case thing
1120
- when String
1121
- del(x.to_sym)
1122
- when Class, Module
1123
- Object.send(:remove_const, x)
1124
- when Method
1125
- x.owner.send(:undef_method, x.name)
1126
- when Symbol
1127
- if Object.const_get(x)
1128
- Object.send(:remove_const, x)
1129
- elsif method(x)
1130
- undef_method x
1131
- end
1132
- else
1133
- raise "Error: don't know how to 'del #{x.inspect}'"
1134
- end
1135
- end