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 +1 -1
- data/epitools.gemspec +3 -3
- data/lib/epitools/autoloads.rb +1 -0
- data/lib/epitools/core_ext.rb +85 -33
- data/lib/epitools/core_ext/array.rb +16 -13
- data/lib/epitools/core_ext/enumerable.rb +27 -0
- data/lib/epitools/hexdump.rb +47 -38
- data/lib/epitools/iter.rb +1 -1
- data/lib/epitools/numwords.rb +1 -1
- data/lib/epitools/path.rb +215 -185
- data/lib/epitools/sys.rb +25 -1
- data/lib/epitools/term.rb +37 -31
- data/lib/epitools/wm.rb +293 -2
- data/spec/core_ext_spec.rb +20 -1
- data/spec/path_spec.rb +95 -87
- data/spec/wm_spec.rb +10 -0
- metadata +3 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
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.
|
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-
|
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.
|
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
|
data/lib/epitools/autoloads.rb
CHANGED
data/lib/epitools/core_ext.rb
CHANGED
@@ -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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
|
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
|
data/lib/epitools/hexdump.rb
CHANGED
@@ -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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
53
|
-
|
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
|
-
|
68
|
+
Hex.dump(data)
|
60
69
|
puts
|
61
|
-
|
70
|
+
Hex.dump(data, :color=>false)
|
62
71
|
puts
|
63
|
-
|
72
|
+
|
64
73
|
data = "1234567890"*10
|
65
|
-
|
74
|
+
Hex.dump(data)
|
66
75
|
end
|