epitools 0.5.125 → 0.5.131
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/epitools/autoloads.rb +15 -14
- data/lib/epitools/clitools.rb +17 -0
- data/lib/epitools/core_ext/array.rb +28 -1
- data/lib/epitools/core_ext/class.rb +5 -19
- data/lib/epitools/core_ext/enumerable.rb +3 -0
- data/lib/epitools/core_ext/numbers.rb +27 -8
- data/lib/epitools/core_ext/uri.rb +35 -12
- data/lib/epitools/job_runner.rb +115 -0
- data/lib/epitools/minimal.rb +1 -2
- data/lib/epitools/path.rb +19 -10
- data/lib/epitools/sys.rb +1 -0
- data/spec/core_ext_spec.rb +52 -29
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 467e7148825ac612d6b8acc25da6c09e89521d734c38f64568b189f4c7df8b6e
|
4
|
+
data.tar.gz: 3319cb92d01f19e597cc00c4b30eb0b847e652e2fa53f8e63a96fff2dc6f2bc5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 518b4e0a4014fa2a0dbdeed3d2a3656887035526398062c29acfaf62b3acaf8a3fba81b55a15dc33efdc77818d359bf63c2dcb1cc1ecec0f14772052fadb25a2
|
7
|
+
data.tar.gz: f888b96dd3f917eb45977567bcd66b1a9972bae7ccaf3a8d82902964b7af569e1474dccbaade2379fa2ebb6e4073b74114e1c6b548a826481e6462de6979607a
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.131
|
data/lib/epitools/autoloads.rb
CHANGED
@@ -65,19 +65,20 @@ autoload :IPAddr, 'ipaddr'
|
|
65
65
|
|
66
66
|
## Nonstandard library (epitools)
|
67
67
|
|
68
|
-
autoload :Path,
|
69
|
-
autoload :Ezdb,
|
70
|
-
autoload :Browser,
|
71
|
-
autoload :Rash,
|
72
|
-
autoload :Ratio,
|
73
|
-
autoload :ProgressBar,
|
74
|
-
autoload :Trie,
|
75
|
-
autoload :MimeMagic,
|
76
|
-
autoload :Term,
|
77
|
-
autoload :Iter,
|
78
|
-
autoload :WM,
|
79
|
-
autoload :TypedStruct,
|
80
|
-
autoload :Sys,
|
68
|
+
autoload :Path, 'epitools/path'
|
69
|
+
autoload :Ezdb, 'epitools/ezdb'
|
70
|
+
autoload :Browser, 'epitools/browser'
|
71
|
+
autoload :Rash, 'epitools/rash'
|
72
|
+
autoload :Ratio, 'epitools/ratio'
|
73
|
+
autoload :ProgressBar, 'epitools/progressbar'
|
74
|
+
autoload :Trie, 'epitools/trie'
|
75
|
+
autoload :MimeMagic, 'epitools/mimemagic'
|
76
|
+
autoload :Term, 'epitools/term'
|
77
|
+
autoload :Iter, 'epitools/iter'
|
78
|
+
autoload :WM, 'epitools/wm'
|
79
|
+
autoload :TypedStruct, 'epitools/typed_struct'
|
80
|
+
autoload :Sys, 'epitools/sys'
|
81
|
+
autoload :JobRunner, 'epitools/job_runner'
|
81
82
|
autoload :SemanticVersion, 'epitools/semantic_version'
|
82
83
|
|
83
84
|
autoload :Matrix, 'epitools/core_ext/matrix'
|
@@ -87,7 +88,7 @@ autoreq(:Vector) { Matrix }
|
|
87
88
|
module Epi
|
88
89
|
autoload :Slop, 'epitools/slop'
|
89
90
|
end
|
90
|
-
autoreq(:Slop) do
|
91
|
+
autoreq(:Slop) do
|
91
92
|
Slop = Epi::Slop
|
92
93
|
end
|
93
94
|
|
data/lib/epitools/clitools.rb
CHANGED
@@ -230,3 +230,20 @@ def notify_send(title, body=nil, icon: nil, time: 5)
|
|
230
230
|
fork { system *cmd }
|
231
231
|
end
|
232
232
|
|
233
|
+
def curl(url)
|
234
|
+
curl_open(url).read
|
235
|
+
end
|
236
|
+
|
237
|
+
def curl_open(url, headers={})
|
238
|
+
# headers["User-Agent"] ||= "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/85 Version/11.1.1 Safari/605.1.15"
|
239
|
+
cmd = ["curl", "-LSs"]
|
240
|
+
headers.each { |k,v| cmd += ["-H", "#{k}: #{v}"] }
|
241
|
+
cmd << url
|
242
|
+
IO.popen(cmd)
|
243
|
+
rescue Errno::ENOENT
|
244
|
+
raise "Error: 'curl' isn't installed."
|
245
|
+
end
|
246
|
+
|
247
|
+
def curl_json(url)
|
248
|
+
JSON.parse(curl(url))
|
249
|
+
end
|
@@ -324,6 +324,33 @@ class Array
|
|
324
324
|
super.to_a
|
325
325
|
end
|
326
326
|
|
327
|
-
|
327
|
+
module ToCSV
|
328
|
+
#
|
329
|
+
# Convert this enumerable into a CSV string (nb: enumerable must contain either all Hashes or all Arrays)
|
330
|
+
#
|
331
|
+
def to_csv(delimiter=",")
|
332
|
+
types = count_by(&:class)
|
333
|
+
|
334
|
+
unless types.size == 1 and (types[Array] > 0 or types[Hash] > 0)
|
335
|
+
raise "Error: this array must contain nothing but arrays, or nothing but hashes (actually contains: #{types.inspect})"
|
336
|
+
end
|
337
|
+
|
338
|
+
options = {}
|
339
|
+
options[:col_sep] = delimiter
|
340
|
+
options[:headers] = flat_map(&:keys).uniq if types[Hash] > 0
|
328
341
|
|
342
|
+
CSV.generate(nil, **options) do |csv|
|
343
|
+
each { |obj| csv << obj }
|
344
|
+
end
|
345
|
+
end
|
329
346
|
|
347
|
+
#
|
348
|
+
# Like #to_csv, but with tab-separated CSV fields
|
349
|
+
#
|
350
|
+
def to_tsv
|
351
|
+
to_csv("\t")
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
prepend ToCSV # dirty hack to stop the CSV module from clobbering the to_csv method
|
356
|
+
end
|
@@ -1,31 +1,17 @@
|
|
1
1
|
class Class
|
2
2
|
|
3
|
-
#
|
4
|
-
# Return a copy of the class with modules mixed into it.
|
5
|
-
#
|
6
|
-
def self.using(*args)
|
7
|
-
if block_given?
|
8
|
-
yield using(*args)
|
9
|
-
else
|
10
|
-
copy = self.dup
|
11
|
-
args.each { |arg| copy.send(:include, arg) }
|
12
|
-
copy
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
|
17
3
|
#
|
18
4
|
# Trace the specified method calls (`meths`, as symbols) to descendends of this class (or all methods if `:*` is supplied).
|
19
5
|
# Output is printed to $stderr.
|
20
6
|
#
|
21
7
|
def trace_messages_to(*meths)
|
22
8
|
return unless $DEBUG
|
23
|
-
|
9
|
+
|
24
10
|
tracers = Module.new
|
25
11
|
parent = self
|
26
12
|
|
27
13
|
$stderr.puts "[*] Tracing messages sent to #{parent} (messages: #{meths.join(", ")})"
|
28
|
-
|
14
|
+
|
29
15
|
meths.each do |meth|
|
30
16
|
case meth
|
31
17
|
when :*
|
@@ -35,9 +21,9 @@ class Class
|
|
35
21
|
end
|
36
22
|
else
|
37
23
|
tracers.define_method(meth) do |*args, &block|
|
38
|
-
|
39
|
-
|
40
|
-
$stderr.puts "[*] #{parent}##{meth}(#{
|
24
|
+
arg_names = args.map(&:inspect)
|
25
|
+
arg_names << "&block" if block
|
26
|
+
$stderr.puts "[*] #{parent}##{meth}(#{arg_names.join(", ")})"
|
41
27
|
if block
|
42
28
|
super(*args, &block)
|
43
29
|
else
|
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
Number = Numeric # "obj.is_a? Number"
|
2
|
+
Number = Numeric # because "obj.is_a? Number" sounds better!
|
3
3
|
|
4
4
|
class Numeric
|
5
5
|
|
@@ -84,7 +84,8 @@ class Numeric
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
-
[
|
87
|
+
[
|
88
|
+
:cos,
|
88
89
|
:sin,
|
89
90
|
:tan,
|
90
91
|
:acos,
|
@@ -186,7 +187,8 @@ class Numeric
|
|
186
187
|
end
|
187
188
|
|
188
189
|
BYTE_SIZE_TABLE = {
|
189
|
-
# power
|
190
|
+
# power
|
191
|
+
# of 1024 # units
|
190
192
|
0 => "",
|
191
193
|
1 => "KB",
|
192
194
|
2 => "MB",
|
@@ -213,8 +215,8 @@ class Numeric
|
|
213
215
|
def to_hms
|
214
216
|
seconds = self
|
215
217
|
|
216
|
-
days,
|
217
|
-
hours,
|
218
|
+
days, seconds = seconds.divmod(86400)
|
219
|
+
hours, seconds = seconds.divmod(3600)
|
218
220
|
minutes, seconds = seconds.divmod(60)
|
219
221
|
seconds, frac = seconds.divmod(1)
|
220
222
|
|
@@ -229,8 +231,8 @@ class Numeric
|
|
229
231
|
def to_hms_in_words
|
230
232
|
seconds = self
|
231
233
|
|
232
|
-
days,
|
233
|
-
hours,
|
234
|
+
days, seconds = seconds.divmod(86400)
|
235
|
+
hours, seconds = seconds.divmod(3600)
|
234
236
|
minutes, seconds = seconds.divmod(60)
|
235
237
|
seconds, frac = seconds.divmod(1)
|
236
238
|
|
@@ -243,6 +245,22 @@ class Numeric
|
|
243
245
|
result
|
244
246
|
end
|
245
247
|
|
248
|
+
def to_farenheit
|
249
|
+
(self * 9.0 / 5.0) + 32
|
250
|
+
end
|
251
|
+
|
252
|
+
def to_celcius
|
253
|
+
(self - 32) * 5.0 / 9.0
|
254
|
+
end
|
255
|
+
|
256
|
+
def to_lbs
|
257
|
+
self / 0.45359237
|
258
|
+
end
|
259
|
+
|
260
|
+
def to_kg
|
261
|
+
self * 0.45359237
|
262
|
+
end
|
263
|
+
|
246
264
|
end
|
247
265
|
|
248
266
|
|
@@ -442,7 +460,8 @@ end
|
|
442
460
|
class Prime
|
443
461
|
|
444
462
|
#
|
445
|
-
# Return an array of prime numbers within the specified range
|
463
|
+
# Return an array of prime numbers within the specified range.
|
464
|
+
# (It still has to generate all the primes less than the lower bound, so, yeah... be warned.)
|
446
465
|
#
|
447
466
|
def [](range)
|
448
467
|
ubound = range.end
|
@@ -1,35 +1,58 @@
|
|
1
1
|
require 'uri'
|
2
2
|
|
3
|
-
|
3
|
+
class URI::Generic
|
4
|
+
|
5
|
+
#
|
6
|
+
# Get the query string
|
7
|
+
#
|
8
|
+
def query
|
9
|
+
params.to_query
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# Set the query string
|
14
|
+
#
|
15
|
+
def query=(new_query)
|
16
|
+
@params = new_query.to_params
|
17
|
+
@query = new_query
|
18
|
+
end
|
4
19
|
|
5
20
|
#
|
6
21
|
# Return a Hash of the variables in the query string
|
7
22
|
#
|
8
23
|
def params
|
9
|
-
(@query ? @query.to_params : {})
|
24
|
+
@params ||= (@query ? @query.to_params : {})
|
10
25
|
end
|
11
26
|
|
12
27
|
#
|
13
|
-
#
|
14
|
-
# NB: This is super slow. To make it faster, store params directly in a locally cached dict, and only call `to_query` when query is accesed, or to_s/inspect are called
|
28
|
+
# Update all the params at once
|
15
29
|
#
|
16
|
-
def params=(
|
17
|
-
|
18
|
-
|
19
|
-
|
30
|
+
def params=(new_params)
|
31
|
+
# self.query = new_params.to_params
|
32
|
+
raise "params must be a Hash" unless new_params.is_a? Hash
|
33
|
+
@params = new_params
|
20
34
|
end
|
21
35
|
|
22
|
-
|
23
|
-
|
24
|
-
|
36
|
+
# #
|
37
|
+
# # Update one URI parameter
|
38
|
+
# #
|
39
|
+
# def set_param(key, value)
|
40
|
+
# current = params
|
41
|
+
# current[key] = value
|
42
|
+
# self.query = current.to_query
|
43
|
+
# end
|
25
44
|
|
26
45
|
#
|
27
|
-
# URIs are strings, dammit!
|
46
|
+
# URIs *are* strings, dammit!
|
28
47
|
#
|
29
48
|
def to_str
|
30
49
|
to_s
|
31
50
|
end
|
32
51
|
|
52
|
+
end
|
53
|
+
|
54
|
+
module URI
|
55
|
+
|
33
56
|
#
|
34
57
|
# Default user agent for the 'get' method
|
35
58
|
#
|
@@ -0,0 +1,115 @@
|
|
1
|
+
#
|
2
|
+
# Runs many jobs in parallel, and returns their interleaved results.
|
3
|
+
# (NOTE: The JobRunner can be run multiple times; each time the blocks
|
4
|
+
# will be executed again.)
|
5
|
+
#
|
6
|
+
# Examples:
|
7
|
+
#
|
8
|
+
# JobRunner.new do |jr|
|
9
|
+
# jr.add { 3 }
|
10
|
+
# jr.add { sleep 0.1; 2 }
|
11
|
+
# jr.add { sleep 0.2; 1 }
|
12
|
+
#
|
13
|
+
# jr.each_result do |result|
|
14
|
+
# p result
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# jr = JobRunner.new(
|
19
|
+
# proc { 1 },
|
20
|
+
# proc { 2 },
|
21
|
+
# proc { 3 }
|
22
|
+
# )
|
23
|
+
#
|
24
|
+
# 2.times do
|
25
|
+
# jr.each_result { |result| p result }
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
class JobRunner
|
29
|
+
def initialize(*blocks, debug: false)
|
30
|
+
@threads = []
|
31
|
+
@results = Thread::Queue.new
|
32
|
+
@jobs = []
|
33
|
+
@started = false
|
34
|
+
@debug = debug
|
35
|
+
|
36
|
+
if blocks.any?
|
37
|
+
blocks.each { |block| add &block }
|
38
|
+
else
|
39
|
+
yield self if block_given?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def dmsg(msg)
|
44
|
+
puts "[#{Time.now}] #{msg}" if @debug
|
45
|
+
end
|
46
|
+
|
47
|
+
def add(&block)
|
48
|
+
dmsg("added job #{block}")
|
49
|
+
@jobs << block
|
50
|
+
end
|
51
|
+
|
52
|
+
def reap!
|
53
|
+
if @threads.any?
|
54
|
+
dmsg("reaping #{@threads.size} threads")
|
55
|
+
@threads.delete_if { |t| not t.alive? }
|
56
|
+
else
|
57
|
+
dmsg("reap failed: no threads")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def go!
|
62
|
+
if @started
|
63
|
+
raise "Error: already started"
|
64
|
+
else
|
65
|
+
dmsg("starting #{@threads.size} jobs")
|
66
|
+
end
|
67
|
+
|
68
|
+
@started = true
|
69
|
+
@jobs.each do |job|
|
70
|
+
dmsg("adding #{job}")
|
71
|
+
@threads << Thread.new do
|
72
|
+
@results << job.call
|
73
|
+
dmsg("job #{job} complete")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def each_result
|
79
|
+
go! unless @started
|
80
|
+
|
81
|
+
loop do
|
82
|
+
yield @results.pop
|
83
|
+
reap!
|
84
|
+
break if @threads.empty? and @results.empty?
|
85
|
+
end
|
86
|
+
|
87
|
+
@started = false
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
if __FILE__ == $0
|
93
|
+
JobRunner.new(debug: true) do |jr|
|
94
|
+
jr.add { 3 }
|
95
|
+
jr.add { sleep 0.1; 2 }
|
96
|
+
jr.add { sleep 0.2; 1 }
|
97
|
+
|
98
|
+
jr.each_result do |result|
|
99
|
+
p result
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
puts
|
104
|
+
|
105
|
+
jr = JobRunner.new(
|
106
|
+
proc { 1 },
|
107
|
+
proc { 2 },
|
108
|
+
proc { 3 }
|
109
|
+
)
|
110
|
+
|
111
|
+
2.times do
|
112
|
+
jr.each_result { |r| p r }
|
113
|
+
puts
|
114
|
+
end
|
115
|
+
end
|
data/lib/epitools/minimal.rb
CHANGED
@@ -167,14 +167,13 @@ class Object
|
|
167
167
|
#
|
168
168
|
# eg: stuff.group_by(&:self)
|
169
169
|
#
|
170
|
-
|
170
|
+
def self
|
171
171
|
if block_given?
|
172
172
|
yield self
|
173
173
|
else
|
174
174
|
self
|
175
175
|
end
|
176
176
|
end
|
177
|
-
alias_method :fap, :self
|
178
177
|
|
179
178
|
def ancestors
|
180
179
|
self.class.ancestors
|
data/lib/epitools/path.rb
CHANGED
@@ -119,11 +119,20 @@ class Path
|
|
119
119
|
# The file extension, including the . (eg: ".mp3")
|
120
120
|
attr_reader :ext
|
121
121
|
|
122
|
+
URI_RE = %r{^[a-z\-]+://}i
|
122
123
|
|
123
124
|
###############################################################################
|
124
125
|
# Initializers
|
125
126
|
###############################################################################
|
126
127
|
|
128
|
+
def self.new(*args)
|
129
|
+
if args.first =~ URI_RE and self != Path::URI
|
130
|
+
Path::URI.new(args.first)
|
131
|
+
else
|
132
|
+
super(*args)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
127
136
|
def initialize(newpath, hints={})
|
128
137
|
send("path=", newpath, hints)
|
129
138
|
|
@@ -156,8 +165,8 @@ class Path
|
|
156
165
|
path
|
157
166
|
when String
|
158
167
|
|
159
|
-
if path =~
|
160
|
-
Path
|
168
|
+
if path =~ URI_RE
|
169
|
+
Path.new(path)
|
161
170
|
|
162
171
|
else
|
163
172
|
# TODO: highlight backgrounds of codeblocks to show indent level & put boxes (or rules?) around (between?) double-spaced regions
|
@@ -186,7 +195,7 @@ class Path
|
|
186
195
|
# Note: The `hints` parameter contains options so `path=` doesn't have to touch the filesytem as much.
|
187
196
|
#
|
188
197
|
def path=(newpath, hints={})
|
189
|
-
if hints[:type] or File.
|
198
|
+
if hints[:type] or File.exist? newpath
|
190
199
|
if hints[:type] == :dir or File.directory? newpath
|
191
200
|
self.dir = newpath
|
192
201
|
else
|
@@ -357,7 +366,7 @@ class Path
|
|
357
366
|
###############################################################################
|
358
367
|
|
359
368
|
def exists?
|
360
|
-
File.
|
369
|
+
File.exist? path
|
361
370
|
end
|
362
371
|
|
363
372
|
def size
|
@@ -430,7 +439,7 @@ class Path
|
|
430
439
|
end
|
431
440
|
|
432
441
|
def broken_symlink?
|
433
|
-
File.symlink?(path) and not File.
|
442
|
+
File.symlink?(path) and not File.exist?(path)
|
434
443
|
end
|
435
444
|
|
436
445
|
def symlink_target
|
@@ -1638,9 +1647,9 @@ class Path::URI < Path
|
|
1638
1647
|
#
|
1639
1648
|
# When this is: http://host.com:port/path/filename.ext?param1=value1¶m2=value2&...
|
1640
1649
|
#
|
1641
|
-
def to_s
|
1642
|
-
|
1643
|
-
end
|
1650
|
+
def to_s; uri.to_s; end
|
1651
|
+
def to_path; to_s; end
|
1652
|
+
def to_str; to_s; end
|
1644
1653
|
|
1645
1654
|
def inspect
|
1646
1655
|
"#<Path::URI:#{to_s}>"
|
@@ -1693,9 +1702,9 @@ class Path::URI < Path
|
|
1693
1702
|
def open(mode="r", &block)
|
1694
1703
|
require 'open-uri'
|
1695
1704
|
if block_given?
|
1696
|
-
|
1705
|
+
::URI.open(to_s, mode, &block)
|
1697
1706
|
else
|
1698
|
-
|
1707
|
+
::URI.open(to_s, mode)
|
1699
1708
|
end
|
1700
1709
|
end
|
1701
1710
|
|
data/lib/epitools/sys.rb
CHANGED
data/spec/core_ext_spec.rb
CHANGED
@@ -127,26 +127,6 @@ end
|
|
127
127
|
|
128
128
|
describe Class do
|
129
129
|
|
130
|
-
it "uses" do
|
131
|
-
module Test1
|
132
|
-
def test1; :test1; end
|
133
|
-
end
|
134
|
-
|
135
|
-
module Test2
|
136
|
-
def test2; :test2; end
|
137
|
-
end
|
138
|
-
|
139
|
-
Hash.using(Test1).new.test1.should == :test1
|
140
|
-
Hash.using(Test2).new.test2.should == :test2
|
141
|
-
h = Hash.using(Test1, Test2).new
|
142
|
-
h.test1.should == :test1
|
143
|
-
h.test2.should == :test2
|
144
|
-
|
145
|
-
Hash.using(Test1) do |h|
|
146
|
-
h.new.test1.should == :test1
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
130
|
it "traces messages (when $DEBUG is set)" do
|
151
131
|
$DEBUG = true
|
152
132
|
|
@@ -166,10 +146,10 @@ describe Class do
|
|
166
146
|
class ButtTest
|
167
147
|
trace_messages_to :*
|
168
148
|
|
169
|
-
def
|
149
|
+
def a
|
170
150
|
end
|
171
151
|
|
172
|
-
def
|
152
|
+
def b
|
173
153
|
end
|
174
154
|
end
|
175
155
|
|
@@ -197,7 +177,7 @@ describe Numeric do
|
|
197
177
|
-12983287123.commatize.should == "-12,983,287,123"
|
198
178
|
-12983287123.4411.commatize.should == "-12,983,287,123.4411"
|
199
179
|
1111.1234567.commatize.should == "1,111.1234567"
|
200
|
-
BigDecimal
|
180
|
+
BigDecimal("1111.1234567").commatize.should == "1,111.1234567"
|
201
181
|
-1234567.1234567.underscorize.should == "-1_234_567.1234567"
|
202
182
|
end
|
203
183
|
|
@@ -237,6 +217,11 @@ describe Numeric do
|
|
237
217
|
32583128.human_size(2).should == "31.07MB"
|
238
218
|
end
|
239
219
|
|
220
|
+
it "temperatures" do
|
221
|
+
t = 18.0
|
222
|
+
t.to_farenheit.to_celcius.should be_within(0.001).of(t)
|
223
|
+
end
|
224
|
+
|
240
225
|
end
|
241
226
|
|
242
227
|
|
@@ -795,6 +780,38 @@ describe Enumerable do
|
|
795
780
|
ps.sort_numerically.map(&:filename).should == proper
|
796
781
|
end
|
797
782
|
|
783
|
+
it "to_csvs and to_tsvs" do
|
784
|
+
data = [
|
785
|
+
["1", "2", "3"],
|
786
|
+
["4", "5", "6"],
|
787
|
+
["7", "8", "9", "10"],
|
788
|
+
]
|
789
|
+
|
790
|
+
hash_data = [
|
791
|
+
{a: 1, b: 2, c: 3},
|
792
|
+
{a: 4, b: 5, c: 6},
|
793
|
+
{a: 7, b: 8, c: 9, d: 10},
|
794
|
+
]
|
795
|
+
|
796
|
+
class EnumedData
|
797
|
+
include Enumerable
|
798
|
+
def initialize(data); @data=data; end
|
799
|
+
def each(&block); @data.each(&block); end
|
800
|
+
end
|
801
|
+
|
802
|
+
[data, hash_data, EnumedData.new(data)].each do |a|
|
803
|
+
str = a.to_csv
|
804
|
+
str.each_line.count.should == 3
|
805
|
+
str.should_not be_nil
|
806
|
+
str["1,2,3"].should_not be_nil
|
807
|
+
|
808
|
+
str = a.to_tsv
|
809
|
+
str.should_not be_nil
|
810
|
+
str["1\t2\t3"].should_not be_nil
|
811
|
+
end
|
812
|
+
|
813
|
+
end
|
814
|
+
|
798
815
|
end
|
799
816
|
|
800
817
|
|
@@ -1279,18 +1296,24 @@ describe URI do
|
|
1279
1296
|
uri.params.should == opts
|
1280
1297
|
end
|
1281
1298
|
|
1282
|
-
it "gets" do
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
end
|
1299
|
+
# it "gets" do
|
1300
|
+
# response = URI("http://google.com/").get
|
1301
|
+
# response.body.size
|
1302
|
+
# (response.size > 0).should == true
|
1303
|
+
# end
|
1287
1304
|
|
1288
1305
|
it "params=" do
|
1289
|
-
u = "http://butt.
|
1306
|
+
u = "http://butt.cx/?q=1".to_uri
|
1290
1307
|
u.query.should == "q=1"
|
1308
|
+
u.params.should == {"q" => "1"}
|
1291
1309
|
u.params["q"] = 2
|
1292
1310
|
u.params["q"].should == 2
|
1311
|
+
u.params.should == {"q" => 2}
|
1293
1312
|
u.query.should == "q=2"
|
1313
|
+
|
1314
|
+
subbed = u.with(query: u.params.reject{|k,v| u.params.keys.include? 'q' }.to_query)
|
1315
|
+
subbed.params.should == {}
|
1316
|
+
subbed.query.should == ""
|
1294
1317
|
end
|
1295
1318
|
|
1296
1319
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: epitools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.131
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- epitron
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -72,6 +72,7 @@ files:
|
|
72
72
|
- lib/epitools/hexdump.rb
|
73
73
|
- lib/epitools/iter.rb
|
74
74
|
- lib/epitools/its.rb
|
75
|
+
- lib/epitools/job_runner.rb
|
75
76
|
- lib/epitools/lcs.rb
|
76
77
|
- lib/epitools/mimemagic.rb
|
77
78
|
- lib/epitools/mimemagic_tables.rb
|
@@ -126,7 +127,7 @@ homepage: http://github.com/epitron/epitools
|
|
126
127
|
licenses:
|
127
128
|
- WTFPL
|
128
129
|
metadata: {}
|
129
|
-
post_install_message:
|
130
|
+
post_install_message:
|
130
131
|
rdoc_options: []
|
131
132
|
require_paths:
|
132
133
|
- lib
|
@@ -141,8 +142,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
142
|
- !ruby/object:Gem::Version
|
142
143
|
version: '0'
|
143
144
|
requirements: []
|
144
|
-
rubygems_version: 3.1.
|
145
|
-
signing_key:
|
145
|
+
rubygems_version: 3.1.4
|
146
|
+
signing_key:
|
146
147
|
specification_version: 3
|
147
148
|
summary: Not utils... METILS!
|
148
149
|
test_files: []
|