epitools 0.5.7 → 0.5.8

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.7
1
+ 0.5.8
data/epitools.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "epitools"
8
- s.version = "0.5.7"
8
+ s.version = "0.5.8"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["epitron"]
12
- s.date = "2012-05-04"
12
+ s.date = "2012-07-08"
13
13
  s.description = "Miscellaneous utility libraries to make my life easier."
14
14
  s.email = "chris@ill-logic.com"
15
15
  s.extra_rdoc_files = [
@@ -87,7 +87,7 @@ Gem::Specification.new do |s|
87
87
  s.homepage = "http://github.com/epitron/epitools"
88
88
  s.licenses = ["WTFPL"]
89
89
  s.require_paths = ["lib"]
90
- s.rubygems_version = "1.8.21"
90
+ s.rubygems_version = "1.8.24"
91
91
  s.summary = "NOT UTILS... METILS!"
92
92
 
93
93
  if s.respond_to? :specification_version then
@@ -16,6 +16,7 @@ autoload :Open3, 'open3'
16
16
  autoload :Timeout, 'timeout'
17
17
  autoload :Find, 'find'
18
18
  autoload :Benchmark, 'benchmark'
19
+ autoload :Tracer, 'tracer'
19
20
  #autoload :DelegateClass, 'delegate'
20
21
 
21
22
  # YAML is sometimes loaded improperly.
@@ -3,13 +3,13 @@ require 'epitools'
3
3
  ## Alias "Enumerator" to "Enum"
4
4
 
5
5
  if RUBY_VERSION["1.8"]
6
- require 'enumerator'
6
+ require 'enumerator'
7
7
  Enumerator = Enumerable::Enumerator unless defined? Enumerator
8
8
  end
9
9
 
10
10
  unless defined? Enum
11
11
  if defined? Enumerator
12
- Enum = Enumerator
12
+ Enum = Enumerator
13
13
  else
14
14
  $stderr.puts "WARNING: Couldn't find the Enumerator class. Enum will not be available."
15
15
  end
@@ -25,7 +25,7 @@ class Object
25
25
  def self.alias_class_method(dest, src)
26
26
  metaclass.send(:alias_method, dest, src)
27
27
  end
28
-
28
+
29
29
  end
30
30
 
31
31
  require 'epitools/core_ext/object'
@@ -45,22 +45,31 @@ class MatchData
45
45
  def to_hash
46
46
  Hash[ names.zip(captures) ]
47
47
  end
48
-
48
+
49
49
  end
50
50
 
51
51
 
52
52
  class Binding
53
53
 
54
+ #
55
+ # Get a variables in this binding
56
+ #
54
57
  def [](key)
55
58
  eval(key.to_s)
56
59
  end
57
-
60
+
61
+ #
62
+ # Set a variable in this binding
63
+ #
58
64
  def []=(key, val)
59
65
  Thread.current[:_alter_binding_local_] = val
60
66
  eval("#{key} = Thread.current[:_alter_binding_local_]")
61
67
  Thread.current[:_alter_binding_local_] = nil
62
68
  end
63
69
 
70
+ #
71
+ # Return all the local variables in the binding
72
+ #
64
73
  def local_variables
65
74
  eval("local_variables")
66
75
  end
@@ -72,9 +81,14 @@ end
72
81
  class Proc
73
82
 
74
83
  #
75
- # Joins two procs together, returning a new proc.
84
+ # Chain two procs together, returning a new proc. Each proc is executed one after the other,
85
+ # with the same input arguments. The return value is an array of all the procs' return values.
76
86
  #
77
- # Example:
87
+ # You can use either the .join method, or the overloaded & operator.
88
+ #
89
+ # Examples:
90
+ # joined = proc1 & proc2
91
+ # joined = proc1.join proc2
78
92
  # newproc = proc { 1 } & proc { 2 }
79
93
  # newproc.call #=> [1, 2]
80
94
  #
@@ -83,7 +97,7 @@ class Proc
83
97
  proc { |*args| [self.call(*args), other.call(*args)] }
84
98
  end
85
99
  alias_method :&, :join
86
-
100
+
87
101
  #
88
102
  # Chains two procs together, returning a new proc. The output from each proc is passed into
89
103
  # the input of the next one.
@@ -96,14 +110,14 @@ class Proc
96
110
  other ||= block
97
111
  proc { |*args| other.call( self.call(*args) ) }
98
112
  end
99
- alias_method :|, :chain
100
-
113
+ alias_method :|, :chain
114
+
101
115
  end
102
116
 
103
117
 
104
118
  unless defined?(BasicObject)
105
119
  #
106
- # A BasicObject class for Ruby 1.8
120
+ # Backported BasicObject for Ruby 1.8
107
121
  #
108
122
  class BasicObject
109
123
  instance_methods.each { |m| undef_method m unless m =~ /^__/ }
@@ -112,15 +126,36 @@ end
112
126
 
113
127
 
114
128
 
129
+ class Object
130
+
131
+ #
132
+ # Negates a boolean, chained-method style.
133
+ #
134
+ # Example:
135
+ # >> 10.even?
136
+ # => true
137
+ # >> 10.not.even?
138
+ # => false
139
+ #
140
+ def not
141
+ NotWrapper.new(self)
142
+ end
143
+
144
+ end
145
+
115
146
  class NotWrapper < BasicObject # :nodoc:
116
147
  def initialize(orig)
117
148
  @orig = orig
118
149
  end
119
-
150
+
120
151
  def inspect
121
152
  "{NOT #{@orig.inspect}}"
122
153
  end
123
-
154
+
155
+ def is_a?(other)
156
+ other === self
157
+ end
158
+
124
159
  def method_missing(meth, *args, &block)
125
160
  result = @orig.send(meth, *args, &block)
126
161
  if result.is_a? ::TrueClass or result.is_a? ::FalseClass
@@ -131,35 +166,23 @@ class NotWrapper < BasicObject # :nodoc:
131
166
  end
132
167
  end
133
168
 
134
- class Object
135
-
136
- #
137
- # Negates a boolean, chained-method style.
138
- #
139
- # Example:
140
- # >> 10.even?
141
- # => true
142
- # >> 10.not.even?
143
- # => false
144
- #
145
- def not
146
- NotWrapper.new(self)
147
- end
148
-
149
- end
169
+
150
170
 
151
171
  unless IO.respond_to? :copy_stream
152
-
172
+
153
173
  class IO
154
-
174
+
175
+ #
176
+ # IO.copy_stream backport
177
+ #
155
178
  def self.copy_stream(input, output)
156
179
  while chunk = input.read(8192)
157
180
  output.write(chunk)
158
181
  end
159
182
  end
160
-
183
+
161
184
  end
162
-
185
+
163
186
  end
164
187
 
165
188
 
@@ -198,8 +221,37 @@ end
198
221
 
199
222
  module URI
200
223
 
224
+ #
225
+ # Return a Hash of the variables in the query string
226
+ #
201
227
  def params
202
228
  query.to_params
203
229
  end
204
230
 
231
+ end
232
+
233
+
234
+ class Time
235
+
236
+ #
237
+ # Which "quarter" of the year does this date fall into?
238
+ #
239
+ def quarter
240
+ (month / 3.0).ceil
241
+ end
242
+
243
+ end
244
+
245
+
246
+ #
247
+ # Give ObjectSpace Enumerable powers (select, map, etc.)
248
+ #
249
+ module ObjectSpace
250
+
251
+ include Enumerable
252
+
253
+ alias_method :each, :each_object
254
+
255
+ extend self
256
+
205
257
  end
@@ -7,9 +7,13 @@ class Array
7
7
  def squash
8
8
  flatten.compact.uniq
9
9
  end
10
-
10
+
11
+ #def to_hash
12
+ # Hash[self]
13
+ #end
14
+
11
15
  #
12
- # Removes the elements from the array for which the block evaluates to true.
16
+ # Removes the elements from the array for which the block evaluates to true.
13
17
  # In addition, return the removed elements.
14
18
  #
15
19
  # For example, if you wanted to split an array into evens and odds:
@@ -20,7 +24,7 @@ class Array
20
24
  #
21
25
  def remove_if(&block)
22
26
  removed = []
23
-
27
+
24
28
  delete_if do |x|
25
29
  if block.call(x)
26
30
  removed << x
@@ -29,29 +33,29 @@ class Array
29
33
  false
30
34
  end
31
35
  end
32
-
36
+
33
37
  removed
34
38
  end
35
-
39
+
36
40
  #
37
41
  # zip from the right (or reversed zip.)
38
42
  #
39
43
  # eg:
40
- # >> [5,39].rzip([:hours, :mins, :secs])
44
+ # >> [5,39].rzip([:hours, :mins, :secs])
41
45
  # => [ [:mins, 5], [:secs, 39] ]
42
46
  #
43
47
  def rzip(other)
44
48
  # That's a lotta reverses!
45
49
  reverse.zip(other.reverse).reverse
46
- end
47
-
50
+ end
51
+
48
52
  #
49
53
  # Pick the middle element.
50
54
  #
51
55
  def middle
52
56
  self[(size-1) / 2]
53
57
  end
54
-
58
+
55
59
  #
56
60
  # XOR operator
57
61
  #
@@ -67,7 +71,7 @@ class Array
67
71
  sort_by{rand}
68
72
  end
69
73
  end
70
-
74
+
71
75
  #
72
76
  # Pick (a) random element(s).
73
77
  #
@@ -81,15 +85,14 @@ class Array
81
85
  end
82
86
  end
83
87
  alias_method :pick, :sample
84
-
88
+
85
89
  #
86
90
  # Divide the array into n pieces.
87
91
  #
88
- def / pieces
92
+ def / pieces
89
93
  piece_size = (size.to_f / pieces).ceil
90
94
  each_slice(piece_size).to_a
91
95
  end
92
-
93
96
 
94
97
  alias_method :unzip, :transpose
95
98
 
@@ -316,3 +316,30 @@ module Enumerable
316
316
  end
317
317
 
318
318
 
319
+ class Enumerator
320
+
321
+ SPINNER = ['-', '\\', '|', '/']
322
+
323
+ #
324
+ # Display a spinner every `every` elements that pass through the Enumerator.
325
+ #
326
+ def with_spinner(every=37)
327
+ Enumerator.new do |yielder|
328
+ spins = 0
329
+
330
+ each.with_index do |e, i|
331
+ if i % every == 0
332
+ print "\b" unless spins == 0
333
+ print SPINNER[spins % 4]
334
+
335
+ spins += 1
336
+ end
337
+
338
+ yielder << e
339
+ end
340
+
341
+ print "\b \b" # erase the spinner when done
342
+ end
343
+ end
344
+
345
+ end
@@ -16,51 +16,60 @@ ASCII_PRINTABLE = (33..126)
16
16
  # 48: d2 b1 6d 31 3e 67 e1 88 99 8b 4b 34 1d 61 05 15 |..m1g....K4.a..|
17
17
  #
18
18
 
19
- def hexdump(data, options={})
20
- base_offset = options[:base_offset] || 0
21
- color = options[:color].nil? ? true : options[:color]
22
- highlight = options[:highlight]
23
-
24
- p options
25
- p color
26
-
27
- lines = data.scan(/.{1,16}/m)
28
- max_offset = (base_offset + data.size) / 16 * 16
29
- max_offset_width = max_offset.to_s.size
30
- max_hex_width = 3 * 16 + 1
31
-
32
- p [max_offset, max_offset_width]
33
- lines.each_with_index do |line,n|
34
- offset = base_offset + n*16
35
- bytes = line.unpack("C*")
36
- hex = bytes.map { |c| "%0.2x" % c }.insert(8, '').join(' ')
37
-
38
- plain = bytes.map do |c|
39
- if ASCII_PRINTABLE.include?(c)
40
- c = c.chr
41
- else
42
- color ? '<9>.</9>' : '.'
43
- end
44
- end.join('')
45
-
46
- if color
47
- outstring = "<light_cyan>%s<cyan>: <light_yellow>%s <default>|<light_white>%s<default>|" % [offset.to_s.ljust(max_offset_width), hex.ljust(max_hex_width), plain]
48
- outstring = outstring.colorize
49
- else
50
- outstring = "%s: %s |%s|" % [offset.to_s.ljust(max_offset_width), hex.ljust(max_hex_width), plain]
19
+
20
+ module Hex
21
+
22
+ DUMP_COLORS = Rash.new(
23
+ /\d/ => 13,
24
+ /\w/ => 3,
25
+ nil => 9,
26
+ :default => 7
27
+ )
28
+
29
+ def self.dump(data, options={})
30
+ base_offset = options[:base_offset] || 0
31
+ color = options[:color].nil? ? true : options[:color]
32
+ highlight = options[:highlight]
33
+
34
+ p options
35
+ p color
36
+
37
+ lines = data.scan(/.{1,16}/m)
38
+ max_offset = (base_offset + data.size) / 16 * 16
39
+ max_offset_width = max_offset.to_s.size
40
+ max_hex_width = 3 * 16 + 1
41
+
42
+ p [max_offset, max_offset_width]
43
+ lines.each_with_index do |line,n|
44
+ offset = base_offset + n*16
45
+ bytes = line.unpack("C*")
46
+ hex = bytes.map { |c| "%0.2x" % c }.insert(8, '').join(' ')
47
+
48
+ plain = bytes.map do |c|
49
+ if ASCII_PRINTABLE.include?(c)
50
+ c = c.chr
51
+ else
52
+ color ? '<9>.</9>' : '.'
53
+ end
54
+ end.join('')
55
+
56
+ puts "<11>#{offset.to_s.ljust(max_offset_width)}<3>: <14>#{hex.ljust(max_hex_width)} <8>|<15>#{plain}<8>|".colorize
51
57
  end
52
- puts outstring
53
- end
58
+ end
59
+
54
60
  end
55
61
 
62
+ def hexdump(*args)
63
+ Hex.dump(*args)
64
+ end
56
65
 
57
66
  if $0 == __FILE__
58
67
  data = (0..64).map{ rand(255).chr }.join('')
59
- hexdump(data)
68
+ Hex.dump(data)
60
69
  puts
61
- hexdump(data, :color=>false)
70
+ Hex.dump(data, :color=>false)
62
71
  puts
63
-
72
+
64
73
  data = "1234567890"*10
65
- hexdump(data)
74
+ Hex.dump(data)
66
75
  end