epitools 0.5.1 → 0.5.2
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/Guardfile +16 -0
- data/VERSION +1 -1
- data/epitools.gemspec +13 -6
- data/lib/epitools.rb +48 -6
- data/lib/epitools/autoloads.rb +14 -3
- data/lib/epitools/browser.rb +8 -1
- data/lib/epitools/core_ext.rb +207 -0
- data/lib/epitools/core_ext/array.rb +98 -0
- data/lib/epitools/core_ext/enumerable.rb +306 -0
- data/lib/epitools/core_ext/hash.rb +201 -0
- data/lib/epitools/core_ext/numbers.rb +254 -0
- data/lib/epitools/core_ext/object.rb +195 -0
- data/lib/epitools/core_ext/string.rb +338 -0
- data/lib/epitools/core_ext/truthiness.rb +64 -0
- data/lib/epitools/iter.rb +22 -8
- data/lib/epitools/mimemagic.rb +0 -1
- data/lib/epitools/path.rb +149 -36
- data/lib/epitools/rash.rb +49 -37
- data/lib/epitools/term.rb +5 -1
- data/spec/{basetypes_spec.rb → core_ext_spec.rb} +190 -37
- data/spec/iter_spec.rb +9 -27
- data/spec/path_spec.rb +104 -46
- data/spec/permutations_spec.rb +3 -2
- data/spec/rash_spec.rb +21 -7
- data/spec/spec_helper.rb +36 -5
- metadata +34 -12
- data/lib/epitools/basetypes.rb +0 -1135
- data/lib/epitools/string_to_proc.rb +0 -78
data/Guardfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
#guard 'spork', :wait => 50 do
|
5
|
+
# watch('Gemfile')
|
6
|
+
# watch('Gemfile.lock')
|
7
|
+
# watch('spec/spec_helper.rb')
|
8
|
+
#end
|
9
|
+
|
10
|
+
guard :rspec, :version => 2, :cli => "--color", :bundler => false, :all_after_pass => false, :all_on_start => false, :keep_failed => false do
|
11
|
+
#guard 'rspec', :version => 2 do
|
12
|
+
watch(%r{^spec/.+_spec\.rb$})
|
13
|
+
watch(%r{^lib/epitools/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
14
|
+
watch('spec/spec_helper.rb') { "spec" }
|
15
|
+
end
|
16
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.2
|
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.2"
|
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 = "
|
12
|
+
s.date = "2012-04-05"
|
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 = [
|
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
]
|
20
20
|
s.files = [
|
21
21
|
".document",
|
22
|
+
"Guardfile",
|
22
23
|
"LICENSE",
|
23
24
|
"README.rdoc",
|
24
25
|
"Rakefile",
|
@@ -27,12 +28,19 @@ Gem::Specification.new do |s|
|
|
27
28
|
"epitools.gemspec",
|
28
29
|
"lib/epitools.rb",
|
29
30
|
"lib/epitools/autoloads.rb",
|
30
|
-
"lib/epitools/basetypes.rb",
|
31
31
|
"lib/epitools/browser.rb",
|
32
32
|
"lib/epitools/browser/cache.rb",
|
33
33
|
"lib/epitools/browser/mechanize_progressbar.rb",
|
34
34
|
"lib/epitools/clitools.rb",
|
35
35
|
"lib/epitools/colored.rb",
|
36
|
+
"lib/epitools/core_ext.rb",
|
37
|
+
"lib/epitools/core_ext/array.rb",
|
38
|
+
"lib/epitools/core_ext/enumerable.rb",
|
39
|
+
"lib/epitools/core_ext/hash.rb",
|
40
|
+
"lib/epitools/core_ext/numbers.rb",
|
41
|
+
"lib/epitools/core_ext/object.rb",
|
42
|
+
"lib/epitools/core_ext/string.rb",
|
43
|
+
"lib/epitools/core_ext/truthiness.rb",
|
36
44
|
"lib/epitools/ezdb.rb",
|
37
45
|
"lib/epitools/hexdump.rb",
|
38
46
|
"lib/epitools/iter.rb",
|
@@ -49,16 +57,15 @@ Gem::Specification.new do |s|
|
|
49
57
|
"lib/epitools/rails.rb",
|
50
58
|
"lib/epitools/rash.rb",
|
51
59
|
"lib/epitools/ratio.rb",
|
52
|
-
"lib/epitools/string_to_proc.rb",
|
53
60
|
"lib/epitools/sys.rb",
|
54
61
|
"lib/epitools/term.rb",
|
55
62
|
"lib/epitools/trie.rb",
|
56
63
|
"lib/epitools/zopen.rb",
|
57
64
|
"spec/autoreq_spec.rb",
|
58
|
-
"spec/basetypes_spec.rb",
|
59
65
|
"spec/browser_spec.rb",
|
60
66
|
"spec/clitools_spec.rb",
|
61
67
|
"spec/colored_spec.rb",
|
68
|
+
"spec/core_ext_spec.rb",
|
62
69
|
"spec/ezdb_spec.rb",
|
63
70
|
"spec/iter_spec.rb",
|
64
71
|
"spec/lcs_spec.rb",
|
@@ -76,7 +83,7 @@ Gem::Specification.new do |s|
|
|
76
83
|
s.homepage = "http://github.com/epitron/epitools"
|
77
84
|
s.licenses = ["WTFPL"]
|
78
85
|
s.require_paths = ["lib"]
|
79
|
-
s.rubygems_version = "1.8.
|
86
|
+
s.rubygems_version = "1.8.21"
|
80
87
|
s.summary = "NOT UTILS... METILS!"
|
81
88
|
|
82
89
|
if s.respond_to? :specification_version then
|
data/lib/epitools.rb
CHANGED
@@ -35,20 +35,63 @@ class Object
|
|
35
35
|
Module.autoreqs[const] = path
|
36
36
|
end
|
37
37
|
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Remove an object, method, constant, etc.
|
41
|
+
#
|
42
|
+
def del(x)
|
43
|
+
case x
|
44
|
+
when String
|
45
|
+
del(x.to_sym)
|
46
|
+
when Class, Module
|
47
|
+
Object.send(:remove_const, x.name)
|
48
|
+
when Method
|
49
|
+
x.owner.send(:undef_method, x.name)
|
50
|
+
when Symbol
|
51
|
+
if Object.const_get(x)
|
52
|
+
Object.send(:remove_const, x)
|
53
|
+
elsif method(x)
|
54
|
+
undef_method x
|
55
|
+
end
|
56
|
+
else
|
57
|
+
raise "Error: don't know how to 'del #{x.inspect}'"
|
58
|
+
end
|
59
|
+
end
|
38
60
|
|
61
|
+
# The hidden singleton lurks behind everyone
|
62
|
+
def metaclass
|
63
|
+
class << self
|
64
|
+
self
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def meta_eval &blk
|
69
|
+
metaclass.instance_eval &blk
|
70
|
+
end
|
71
|
+
|
72
|
+
# Adds methods to a metaclass
|
73
|
+
def meta_def name, &blk
|
74
|
+
meta_eval { define_method name, &blk }
|
75
|
+
end
|
76
|
+
|
77
|
+
# Defines an instance method within a class
|
78
|
+
def class_def name, &blk
|
79
|
+
class_eval { define_method name, &blk }
|
80
|
+
end
|
81
|
+
|
39
82
|
end
|
40
83
|
|
41
84
|
#
|
42
|
-
# Patch 'Module#const_missing' to support 'autoreq'
|
85
|
+
# Patch 'Module#const_missing' to support 'autoreq' (which can autoload gems)
|
43
86
|
#
|
44
87
|
class Module
|
45
88
|
|
46
|
-
@@
|
89
|
+
@@autoreq_is_searching_for = nil
|
47
90
|
|
48
91
|
alias const_missing_without_autoreq const_missing
|
49
92
|
|
50
93
|
def const_missing(const)
|
51
|
-
return if const == @@
|
94
|
+
return if const == @@autoreq_is_searching_for
|
52
95
|
|
53
96
|
if thing = autoreqs[const]
|
54
97
|
case thing
|
@@ -61,7 +104,7 @@ class Module
|
|
61
104
|
end
|
62
105
|
end
|
63
106
|
|
64
|
-
@@
|
107
|
+
@@autoreq_is_searching_for = const
|
65
108
|
const_get(const) || const_missing_without_autoreq(const)
|
66
109
|
end
|
67
110
|
|
@@ -87,8 +130,7 @@ end
|
|
87
130
|
#
|
88
131
|
%w[
|
89
132
|
autoloads
|
90
|
-
|
91
|
-
string_to_proc
|
133
|
+
core_ext
|
92
134
|
zopen
|
93
135
|
colored
|
94
136
|
clitools
|
data/lib/epitools/autoloads.rb
CHANGED
@@ -4,7 +4,6 @@ autoload :URI, 'uri'
|
|
4
4
|
autoload :CGI, 'cgi'
|
5
5
|
autoload :Base64, 'base64'
|
6
6
|
autoload :JSON, 'json'
|
7
|
-
autoload :YAML, 'yaml'
|
8
7
|
autoload :Zlib, 'zlib'
|
9
8
|
autoload :FileUtils, 'fileutils'
|
10
9
|
autoload :Tempfile, 'tempfile'
|
@@ -14,8 +13,18 @@ autoload :Curses, 'curses'
|
|
14
13
|
autoload :DateTime, 'date'
|
15
14
|
autoload :Date, 'date'
|
16
15
|
autoload :Open3, 'open3'
|
16
|
+
autoload :Timeout, 'timeout'
|
17
|
+
autoload :Find, 'find'
|
18
|
+
autoload :Benchmark, 'benchmark'
|
17
19
|
#autoload :DelegateClass, 'delegate'
|
18
20
|
|
21
|
+
# YAML is sometimes loaded improperly.
|
22
|
+
if defined? YAML and not defined? YAML.parse
|
23
|
+
del YAML # remove the existing module
|
24
|
+
end
|
25
|
+
|
26
|
+
autoload :YAML, 'yaml'
|
27
|
+
|
19
28
|
if RUBY_VERSION["1.8.7"]
|
20
29
|
autoload :Prime, 'mathn'
|
21
30
|
else
|
@@ -41,5 +50,7 @@ autoload :MimeMagic, 'epitools/mimemagic'
|
|
41
50
|
autoload :Term, 'epitools/term'
|
42
51
|
autoload :Iter, 'epitools/iter'
|
43
52
|
|
44
|
-
## Gems
|
45
|
-
autoreq :
|
53
|
+
## Gems (common)
|
54
|
+
autoreq :Nokogiri, 'nokogiri'
|
55
|
+
autoreq :ANSI, 'ansi'
|
56
|
+
autoreq :BSON, 'bson'
|
data/lib/epitools/browser.rb
CHANGED
@@ -140,6 +140,8 @@ class Browser
|
|
140
140
|
puts "[ GET #{url} (using cache: #{use_cache}) ]"
|
141
141
|
|
142
142
|
delay unless cached_already
|
143
|
+
max_retries = 4
|
144
|
+
retries = 0
|
143
145
|
|
144
146
|
begin
|
145
147
|
|
@@ -154,9 +156,14 @@ class Browser
|
|
154
156
|
puts
|
155
157
|
|
156
158
|
rescue Net::HTTPBadResponse, Errno::ECONNRESET, SocketError, Timeout::Error, SOCKSError => e
|
159
|
+
raise if e.message == "getaddrinfo: Name or service not known"
|
160
|
+
|
161
|
+
retries += 1
|
162
|
+
return if retries >= max_retries
|
163
|
+
|
157
164
|
puts " |_ ERROR: #{e.inspect} -- retrying"
|
158
165
|
delay(5)
|
159
|
-
retry
|
166
|
+
retry
|
160
167
|
|
161
168
|
=begin
|
162
169
|
rescue Mechanize::ResponseCodeError => e
|
@@ -0,0 +1,207 @@
|
|
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
|
+
|
21
|
+
class Object
|
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
|
+
end
|
30
|
+
|
31
|
+
require 'epitools/core_ext/object'
|
32
|
+
require 'epitools/core_ext/string'
|
33
|
+
require 'epitools/core_ext/array'
|
34
|
+
require 'epitools/core_ext/enumerable'
|
35
|
+
require 'epitools/core_ext/hash'
|
36
|
+
require 'epitools/core_ext/numbers'
|
37
|
+
require 'epitools/core_ext/truthiness'
|
38
|
+
|
39
|
+
|
40
|
+
class MatchData
|
41
|
+
|
42
|
+
#
|
43
|
+
# Return a hash of named matches
|
44
|
+
#
|
45
|
+
def to_hash
|
46
|
+
Hash[ names.zip(captures) ]
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
class Binding
|
53
|
+
|
54
|
+
def [](key)
|
55
|
+
eval(key.to_s)
|
56
|
+
end
|
57
|
+
|
58
|
+
def []=(key, val)
|
59
|
+
Thread.current[:_alter_binding_local_] = val
|
60
|
+
eval("#{key} = Thread.current[:_alter_binding_local_]")
|
61
|
+
Thread.current[:_alter_binding_local_] = nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def local_variables
|
65
|
+
eval("local_variables")
|
66
|
+
end
|
67
|
+
alias_method :keys, :local_variables
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
class Proc
|
73
|
+
|
74
|
+
#
|
75
|
+
# Joins two procs together, returning a new proc.
|
76
|
+
#
|
77
|
+
# Example:
|
78
|
+
# newproc = proc { 1 } & proc { 2 }
|
79
|
+
# newproc.call #=> [1, 2]
|
80
|
+
#
|
81
|
+
def join(other=nil, &block)
|
82
|
+
other ||= block
|
83
|
+
proc { |*args| [self.call(*args), other.call(*args)] }
|
84
|
+
end
|
85
|
+
alias_method :&, :join
|
86
|
+
|
87
|
+
#
|
88
|
+
# Chains two procs together, returning a new proc. The output from each proc is passed into
|
89
|
+
# the input of the next one.
|
90
|
+
#
|
91
|
+
# Example:
|
92
|
+
# chain = proc { 1 } | proc { |input| input + 1 }
|
93
|
+
# chain.call #=> 2
|
94
|
+
#
|
95
|
+
def chain(other=nil, &block)
|
96
|
+
other ||= block
|
97
|
+
proc { |*args| other.call( self.call(*args) ) }
|
98
|
+
end
|
99
|
+
alias_method :|, :chain
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
unless defined?(BasicObject)
|
105
|
+
#
|
106
|
+
# A BasicObject class for Ruby 1.8
|
107
|
+
#
|
108
|
+
class BasicObject
|
109
|
+
instance_methods.each { |m| undef_method m unless m =~ /^__/ }
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
class NotWrapper < BasicObject # :nodoc:
|
116
|
+
def initialize(orig)
|
117
|
+
@orig = orig
|
118
|
+
end
|
119
|
+
|
120
|
+
def inspect
|
121
|
+
"{NOT #{@orig.inspect}}"
|
122
|
+
end
|
123
|
+
|
124
|
+
def method_missing(meth, *args, &block)
|
125
|
+
result = @orig.send(meth, *args, &block)
|
126
|
+
if result.is_a? ::TrueClass or result.is_a? ::FalseClass
|
127
|
+
!result
|
128
|
+
else
|
129
|
+
raise "Sorry, I don't know how to invert #{result.inspect}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
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
|
150
|
+
|
151
|
+
unless IO.respond_to? :copy_stream
|
152
|
+
|
153
|
+
class IO
|
154
|
+
|
155
|
+
def self.copy_stream(input, output)
|
156
|
+
while chunk = input.read(8192)
|
157
|
+
output.write(chunk)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
class Range
|
167
|
+
|
168
|
+
#
|
169
|
+
# Pick a random number from the range.
|
170
|
+
#
|
171
|
+
def rand
|
172
|
+
magnitude = last-first
|
173
|
+
magnitude += 1 if not exclude_end?
|
174
|
+
Kernel.rand(magnitude)+first
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
class Struct
|
181
|
+
|
182
|
+
#
|
183
|
+
# Transform this struct into a JSON hash
|
184
|
+
#
|
185
|
+
def to_hash
|
186
|
+
hash = {}
|
187
|
+
each_pair { |k,v| hash[k] = v }
|
188
|
+
hash
|
189
|
+
end
|
190
|
+
|
191
|
+
#
|
192
|
+
# Transform the struct into a simple JSON hash.
|
193
|
+
#
|
194
|
+
def to_json(*args)
|
195
|
+
to_hash.to_json
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
module URI
|
202
|
+
|
203
|
+
def params
|
204
|
+
query.to_params
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
|
2
|
+
class Array
|
3
|
+
|
4
|
+
#
|
5
|
+
# flatten.compact.uniq
|
6
|
+
#
|
7
|
+
def squash
|
8
|
+
flatten.compact.uniq
|
9
|
+
end
|
10
|
+
|
11
|
+
#
|
12
|
+
# Removes the elements from the array for which the block evaluates to true.
|
13
|
+
# In addition, return the removed elements.
|
14
|
+
#
|
15
|
+
# For example, if you wanted to split an array into evens and odds:
|
16
|
+
#
|
17
|
+
# nums = [1,2,3,4,5,6,7,8,9,10,11,12]
|
18
|
+
# even = nums.remove_if { |n| n.even? } # remove all even numbers from the "nums" array and return them
|
19
|
+
# odd = nums # "nums" now only contains odd numbers
|
20
|
+
#
|
21
|
+
def remove_if(&block)
|
22
|
+
removed = []
|
23
|
+
|
24
|
+
delete_if do |x|
|
25
|
+
if block.call(x)
|
26
|
+
removed << x
|
27
|
+
true
|
28
|
+
else
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
removed
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# zip from the right (or reversed zip.)
|
38
|
+
#
|
39
|
+
# eg:
|
40
|
+
# >> [5,39].rzip([:hours, :mins, :secs])
|
41
|
+
# => [ [:mins, 5], [:secs, 39] ]
|
42
|
+
#
|
43
|
+
def rzip(other)
|
44
|
+
# That's a lotta reverses!
|
45
|
+
reverse.zip(other.reverse).reverse
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Pick the middle element.
|
50
|
+
#
|
51
|
+
def middle
|
52
|
+
self[(size-1) / 2]
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# XOR operator
|
57
|
+
#
|
58
|
+
def ^(other)
|
59
|
+
(self | other) - (self & other)
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Shuffle the array
|
64
|
+
#
|
65
|
+
unless defined? shuffle
|
66
|
+
def shuffle
|
67
|
+
sort_by{rand}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Pick (a) random element(s).
|
73
|
+
#
|
74
|
+
unless defined? sample
|
75
|
+
def sample(n=1)
|
76
|
+
if n == 1
|
77
|
+
self[rand(size)]
|
78
|
+
else
|
79
|
+
shuffle[0...n]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
alias_method :pick, :sample
|
84
|
+
|
85
|
+
#
|
86
|
+
# Divide the array into n pieces.
|
87
|
+
#
|
88
|
+
def / pieces
|
89
|
+
piece_size = (size.to_f / pieces).ceil
|
90
|
+
each_slice(piece_size).to_a
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
alias_method :unzip, :transpose
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
|