epitools 0.5.124 → 0.5.130
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.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/epitools/autoloads.rb +25 -16
- data/lib/epitools/clitools.rb +17 -0
- data/lib/epitools/core_ext.rb +9 -2
- data/lib/epitools/core_ext/argv.rb +59 -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/misc.rb +0 -73
- data/lib/epitools/core_ext/numbers.rb +19 -8
- data/lib/epitools/core_ext/uri.rb +103 -0
- data/lib/epitools/job_runner.rb +97 -0
- data/lib/epitools/minimal.rb +9 -41
- data/lib/epitools/sys.rb +1 -0
- data/lib/epitools/wm.rb +1 -18
- data/spec/core_ext_spec.rb +60 -23
- metadata +9 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d5b52f237d17762dca9dfa53fa0cbdae372f867f84fb455ca97656a9863d6763
|
|
4
|
+
data.tar.gz: 25f2741a4a12dc257ef1d540dcbfea1e6fa7945267de324e1ddba4e860d44334
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 264e9ab8322afd8b6e08b3445dde07c4bf214a9da6e0b087e2c1117a5f0366edd5db361afd64a91faa24988618cf6fccf940ab7bfa7e76b63d8d53a905ef32ae
|
|
7
|
+
data.tar.gz: 0bb9e187d248d149e60c05fbf7a5757a79d560e1452a6ccf808294fc0cb0816d6e9de53d997e2fdeba49056c09a0d55bb8de6b06332174bcdfafe2c6fc004fbb
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.5.
|
|
1
|
+
0.5.130
|
data/lib/epitools/autoloads.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
## Standard library
|
|
2
2
|
|
|
3
3
|
autoload :Set, 'set'
|
|
4
|
-
autoload :URI, 'uri'
|
|
5
4
|
autoload :Zlib, 'zlib'
|
|
6
5
|
autoload :FileUtils, 'fileutils'
|
|
7
6
|
autoload :Tempfile, 'tempfile'
|
|
@@ -23,6 +22,10 @@ autoload :CSV, 'csv'
|
|
|
23
22
|
autoload :SDBM, 'sdbm'
|
|
24
23
|
autoload :StringScanner, 'strscan'
|
|
25
24
|
|
|
25
|
+
autoreq :URI do
|
|
26
|
+
require 'epitools/core_ext/uri'
|
|
27
|
+
end
|
|
28
|
+
|
|
26
29
|
module Digest
|
|
27
30
|
autoload :SHA1, 'digest/sha1'
|
|
28
31
|
autoload :SHA2, 'digest/sha2'
|
|
@@ -62,26 +65,32 @@ autoload :IPAddr, 'ipaddr'
|
|
|
62
65
|
|
|
63
66
|
## Nonstandard library (epitools)
|
|
64
67
|
|
|
65
|
-
autoload :Path,
|
|
66
|
-
autoload :Ezdb,
|
|
67
|
-
autoload :Browser,
|
|
68
|
-
autoload :Rash,
|
|
69
|
-
autoload :Ratio,
|
|
70
|
-
autoload :ProgressBar,
|
|
71
|
-
autoload :Trie,
|
|
72
|
-
autoload :MimeMagic,
|
|
73
|
-
autoload :Term,
|
|
74
|
-
autoload :Iter,
|
|
75
|
-
autoload :WM,
|
|
76
|
-
autoload :TypedStruct,
|
|
77
|
-
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'
|
|
78
82
|
autoload :SemanticVersion, 'epitools/semantic_version'
|
|
79
83
|
|
|
80
84
|
autoload :Matrix, 'epitools/core_ext/matrix'
|
|
81
85
|
autoreq(:Vector) { Matrix }
|
|
82
86
|
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
## Bundled slop
|
|
88
|
+
module Epi
|
|
89
|
+
autoload :Slop, 'epitools/slop'
|
|
90
|
+
end
|
|
91
|
+
autoreq(:Slop) do
|
|
92
|
+
Slop = Epi::Slop
|
|
93
|
+
end
|
|
85
94
|
|
|
86
95
|
## Gems (common)
|
|
87
96
|
|
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
|
data/lib/epitools/core_ext.rb
CHANGED
|
@@ -5,16 +5,23 @@ require 'epitools'
|
|
|
5
5
|
require 'epitools/core_ext/object'
|
|
6
6
|
require 'epitools/core_ext/class'
|
|
7
7
|
require 'epitools/core_ext/module'
|
|
8
|
+
|
|
8
9
|
require 'epitools/core_ext/string'
|
|
10
|
+
|
|
9
11
|
require 'epitools/core_ext/array'
|
|
10
|
-
require 'epitools/core_ext/file'
|
|
11
|
-
require 'epitools/core_ext/io'
|
|
12
12
|
require 'epitools/core_ext/enumerable'
|
|
13
13
|
require 'epitools/core_ext/hash'
|
|
14
|
+
|
|
14
15
|
require 'epitools/core_ext/numbers'
|
|
15
16
|
require 'epitools/core_ext/truthiness'
|
|
16
17
|
require 'epitools/core_ext/range'
|
|
17
18
|
require 'epitools/core_ext/time'
|
|
19
|
+
|
|
20
|
+
require 'epitools/core_ext/argv'
|
|
21
|
+
require 'epitools/core_ext/file'
|
|
22
|
+
require 'epitools/core_ext/io'
|
|
23
|
+
require 'epitools/core_ext/uri'
|
|
24
|
+
|
|
18
25
|
require 'epitools/core_ext/misc'
|
|
19
26
|
|
|
20
27
|
##############################################################################
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
class << ARGV
|
|
2
|
+
|
|
3
|
+
def parse!
|
|
4
|
+
unless @opts or @args
|
|
5
|
+
@opts, @args = partition { |arg| arg[/^--?\w{1,2}/].nil? }
|
|
6
|
+
@opts = @opts.map { |opt| key, val = opt.strip(/^-+/).split("=") }.to_ostruct
|
|
7
|
+
if @opts.help
|
|
8
|
+
@help_handler.call
|
|
9
|
+
exit
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
[@opts, @args]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def parse
|
|
17
|
+
parse!
|
|
18
|
+
[@opts, @args]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def help?
|
|
22
|
+
!!@opts["help"]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def opts
|
|
26
|
+
parse! unless @opts
|
|
27
|
+
@opts
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def args
|
|
31
|
+
@args ? @args : opts && @args
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def paths
|
|
35
|
+
map(&:to_Path)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def paths_R
|
|
39
|
+
recursive_proc = proc do |paths|
|
|
40
|
+
paths.map { |path| path.dir? ? the_expander.(path.ls_R) : path }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
recursive_proc.(paths)
|
|
44
|
+
end
|
|
45
|
+
alias_method :recursive_paths, :paths_R
|
|
46
|
+
|
|
47
|
+
def on_help(&block)
|
|
48
|
+
@help_handler = block
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def regexes(escaped: true, case_sensitive: false)
|
|
52
|
+
if case_sensitive
|
|
53
|
+
map { |arg| /#{escaped ? Regexp.escape(arg) : arg}/ } # NO 'i'
|
|
54
|
+
else
|
|
55
|
+
map { |arg| /#{escaped ? Regexp.escape(arg) : arg}/i }
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
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
|
|
@@ -128,79 +128,6 @@ end
|
|
|
128
128
|
|
|
129
129
|
|
|
130
130
|
|
|
131
|
-
module URI
|
|
132
|
-
|
|
133
|
-
#
|
|
134
|
-
# Return a Hash of the variables in the query string
|
|
135
|
-
#
|
|
136
|
-
def params
|
|
137
|
-
query ? query.to_params : {}
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
#
|
|
141
|
-
# URIs are strings, dammit!
|
|
142
|
-
#
|
|
143
|
-
def to_str
|
|
144
|
-
to_s
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
#
|
|
148
|
-
# Default user agent for the 'get' method
|
|
149
|
-
#
|
|
150
|
-
# USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0"
|
|
151
|
-
|
|
152
|
-
#
|
|
153
|
-
# Get this URI using Net::HTTP
|
|
154
|
-
#
|
|
155
|
-
def get(headers={}, redirect_limit=10)
|
|
156
|
-
raise "Sorry, URI can't get from #{scheme.inspect} URIs yet" unless scheme =~ /^https?$/
|
|
157
|
-
raise 'Too many HTTP redirections' if redirect_limit == 0
|
|
158
|
-
|
|
159
|
-
# headers['User-Agent'] ||= USER_AGENT
|
|
160
|
-
|
|
161
|
-
# response = Net::HTTP.start(host, port) do |http|
|
|
162
|
-
# # the_path = path.empty? ? "/" : path
|
|
163
|
-
# req = Net::HTTP::Get.new(self, headers)
|
|
164
|
-
# http.request(req)
|
|
165
|
-
# end
|
|
166
|
-
|
|
167
|
-
response = Net::HTTP.get_response(self)
|
|
168
|
-
|
|
169
|
-
case response
|
|
170
|
-
when Net::HTTPSuccess
|
|
171
|
-
response
|
|
172
|
-
when Net::HTTPRedirection
|
|
173
|
-
# puts "redirect: #{response['location']}"
|
|
174
|
-
URI(response['location']).get(headers, redirect_limit-1)
|
|
175
|
-
else
|
|
176
|
-
response.error!
|
|
177
|
-
end
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
#
|
|
183
|
-
# Stupid workaround for URI blowing up when it receives a [ or ] character
|
|
184
|
-
#
|
|
185
|
-
module Better_URI_RFC3986_Parser # ::RFC3986_relative_ref
|
|
186
|
-
ESCAPE_ME_PLZ = "[]{}!"
|
|
187
|
-
|
|
188
|
-
def split(uri)
|
|
189
|
-
subsitutions = ESCAPE_ME_PLZ.chars.map { |c| [c, CGI.escape(c)] }
|
|
190
|
-
subsitutions << [" ", "%20"]
|
|
191
|
-
|
|
192
|
-
subsitutions.each do |find, replace|
|
|
193
|
-
uri = uri.gsub(find, replace)
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
super(uri)
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
URI::RFC3986_Parser.prepend(Better_URI_RFC3986_Parser)
|
|
202
|
-
|
|
203
|
-
|
|
204
131
|
|
|
205
132
|
#
|
|
206
133
|
# Give ObjectSpace Enumerable powers (select, map, etc.)
|
|
@@ -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,14 @@ 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
|
+
|
|
246
256
|
end
|
|
247
257
|
|
|
248
258
|
|
|
@@ -442,7 +452,8 @@ end
|
|
|
442
452
|
class Prime
|
|
443
453
|
|
|
444
454
|
#
|
|
445
|
-
# Return an array of prime numbers within the specified range
|
|
455
|
+
# Return an array of prime numbers within the specified range.
|
|
456
|
+
# (It still has to generate all the primes less than the lower bound, so, yeah... be warned.)
|
|
446
457
|
#
|
|
447
458
|
def [](range)
|
|
448
459
|
ubound = range.end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
|
|
3
|
+
class URI::Generic
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
# Get the query string
|
|
7
|
+
#
|
|
8
|
+
def query
|
|
9
|
+
params.to_query
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
#
|
|
13
|
+
# Return a Hash of the variables in the query string
|
|
14
|
+
#
|
|
15
|
+
def params
|
|
16
|
+
@params ||= (@query ? @query.to_params : {})
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
#
|
|
20
|
+
# Update all the params at once
|
|
21
|
+
#
|
|
22
|
+
def params=(new_params)
|
|
23
|
+
# self.query = new_params.to_params
|
|
24
|
+
raise "params must be a Hash" unless new_params.is_a? Hash
|
|
25
|
+
@params = new_params
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# #
|
|
29
|
+
# # Update one URI parameter
|
|
30
|
+
# #
|
|
31
|
+
# def set_param(key, value)
|
|
32
|
+
# current = params
|
|
33
|
+
# current[key] = value
|
|
34
|
+
# self.query = current.to_query
|
|
35
|
+
# end
|
|
36
|
+
|
|
37
|
+
#
|
|
38
|
+
# URIs *are* strings, dammit!
|
|
39
|
+
#
|
|
40
|
+
def to_str
|
|
41
|
+
to_s
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
module URI
|
|
47
|
+
|
|
48
|
+
#
|
|
49
|
+
# Default user agent for the 'get' method
|
|
50
|
+
#
|
|
51
|
+
# USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0"
|
|
52
|
+
|
|
53
|
+
#
|
|
54
|
+
# Get this URI using Net::HTTP
|
|
55
|
+
#
|
|
56
|
+
def get(headers={}, redirect_limit=10)
|
|
57
|
+
raise "Sorry, URI can't get from #{scheme.inspect} URIs yet" unless scheme =~ /^https?$/
|
|
58
|
+
raise 'Too many HTTP redirections' if redirect_limit == 0
|
|
59
|
+
|
|
60
|
+
# headers['User-Agent'] ||= USER_AGENT
|
|
61
|
+
|
|
62
|
+
# response = Net::HTTP.start(host, port) do |http|
|
|
63
|
+
# # the_path = path.empty? ? "/" : path
|
|
64
|
+
# req = Net::HTTP::Get.new(self, headers)
|
|
65
|
+
# http.request(req)
|
|
66
|
+
# end
|
|
67
|
+
|
|
68
|
+
response = Net::HTTP.get_response(self)
|
|
69
|
+
|
|
70
|
+
case response
|
|
71
|
+
when Net::HTTPSuccess
|
|
72
|
+
response
|
|
73
|
+
when Net::HTTPRedirection
|
|
74
|
+
# puts "redirect: #{response['location']}"
|
|
75
|
+
URI(response['location']).get(headers, redirect_limit-1)
|
|
76
|
+
else
|
|
77
|
+
response.error!
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
#
|
|
84
|
+
# Stupid workaround for URI blowing up when it receives a [ or ] character
|
|
85
|
+
#
|
|
86
|
+
module Better_URI_RFC3986_Parser # ::RFC3986_relative_ref
|
|
87
|
+
ESCAPE_ME_PLZ = "[]{}!"
|
|
88
|
+
|
|
89
|
+
def split(uri)
|
|
90
|
+
subsitutions = ESCAPE_ME_PLZ.chars.map { |c| [c, CGI.escape(c)] }
|
|
91
|
+
subsitutions << [" ", "%20"]
|
|
92
|
+
|
|
93
|
+
subsitutions.each do |find, replace|
|
|
94
|
+
uri = uri.gsub(find, replace)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
super(uri)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
URI::RFC3986_Parser.prepend(Better_URI_RFC3986_Parser)
|
|
103
|
+
|
|
@@ -0,0 +1,97 @@
|
|
|
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)
|
|
30
|
+
@threads = []
|
|
31
|
+
@results = Thread::Queue.new
|
|
32
|
+
@jobs = []
|
|
33
|
+
@started = false
|
|
34
|
+
|
|
35
|
+
if blocks.any?
|
|
36
|
+
blocks.each { |block| add &block }
|
|
37
|
+
else
|
|
38
|
+
yield self if block_given?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def add(&block)
|
|
43
|
+
@jobs << block
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def reap!
|
|
47
|
+
@threads.delete_if { |t| not t.alive? } if @threads.any?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def go!
|
|
51
|
+
raise "Error: already started" if @started
|
|
52
|
+
@started = true
|
|
53
|
+
@jobs.each do |job|
|
|
54
|
+
@threads << Thread.new do
|
|
55
|
+
@results << job.call
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def each_result
|
|
61
|
+
go! unless @started
|
|
62
|
+
|
|
63
|
+
loop do
|
|
64
|
+
yield @results.pop
|
|
65
|
+
reap!
|
|
66
|
+
break if @threads.empty? and @results.empty?
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
@started = false
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
if __FILE__ == $0
|
|
75
|
+
JobRunner.new do |jr|
|
|
76
|
+
jr.add { 3 }
|
|
77
|
+
jr.add { sleep 0.1; 2 }
|
|
78
|
+
jr.add { sleep 0.2; 1 }
|
|
79
|
+
|
|
80
|
+
jr.each_result do |result|
|
|
81
|
+
p result
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
puts
|
|
86
|
+
|
|
87
|
+
jr = JobRunner.new(
|
|
88
|
+
proc { 1 },
|
|
89
|
+
proc { 2 },
|
|
90
|
+
proc { 3 }
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
2.times do
|
|
94
|
+
jr.each_result { |r| p r }
|
|
95
|
+
puts
|
|
96
|
+
end
|
|
97
|
+
end
|
data/lib/epitools/minimal.rb
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
####################################################################################
|
|
1
2
|
#
|
|
2
3
|
# If you require 'epitools/minimal' instead of 'epitools',
|
|
3
4
|
# this is what you get: core_ext monkeypatches and all the
|
|
4
5
|
# autoloads; the barest essentials for survival.
|
|
5
6
|
#
|
|
7
|
+
####################################################################################
|
|
6
8
|
|
|
7
9
|
if RUBY_VERSION[/^1.8/]
|
|
8
10
|
require 'enumerator'
|
|
@@ -14,6 +16,7 @@ RbConfig = Config unless defined? RbConfig
|
|
|
14
16
|
Infinity = Float::INFINITY
|
|
15
17
|
Inf = Float::INFINITY
|
|
16
18
|
|
|
19
|
+
####################################################################################
|
|
17
20
|
class Object
|
|
18
21
|
|
|
19
22
|
unless defined?(__DIR__)
|
|
@@ -164,14 +167,13 @@ class Object
|
|
|
164
167
|
#
|
|
165
168
|
# eg: stuff.group_by(&:self)
|
|
166
169
|
#
|
|
167
|
-
|
|
170
|
+
def self
|
|
168
171
|
if block_given?
|
|
169
172
|
yield self
|
|
170
173
|
else
|
|
171
174
|
self
|
|
172
175
|
end
|
|
173
176
|
end
|
|
174
|
-
alias_method :fap, :self
|
|
175
177
|
|
|
176
178
|
def ancestors
|
|
177
179
|
self.class.ancestors
|
|
@@ -179,6 +181,7 @@ class Object
|
|
|
179
181
|
end
|
|
180
182
|
|
|
181
183
|
|
|
184
|
+
####################################################################################
|
|
182
185
|
#
|
|
183
186
|
# Patch 'Module#const_missing' to support 'autoreq' (which can autoload gems)
|
|
184
187
|
#
|
|
@@ -213,6 +216,8 @@ class Module
|
|
|
213
216
|
end
|
|
214
217
|
|
|
215
218
|
|
|
219
|
+
|
|
220
|
+
####################################################################################
|
|
216
221
|
module Kernel
|
|
217
222
|
|
|
218
223
|
#
|
|
@@ -254,10 +259,8 @@ module Kernel
|
|
|
254
259
|
end
|
|
255
260
|
|
|
256
261
|
end
|
|
257
|
-
####################################################################################
|
|
258
|
-
|
|
259
|
-
|
|
260
262
|
|
|
263
|
+
####################################################################################
|
|
261
264
|
class String
|
|
262
265
|
|
|
263
266
|
#
|
|
@@ -270,6 +273,7 @@ class String
|
|
|
270
273
|
|
|
271
274
|
end
|
|
272
275
|
|
|
276
|
+
####################################################################################
|
|
273
277
|
#
|
|
274
278
|
# Path("/some/path") is an alias for Path["/some/path"]
|
|
275
279
|
#
|
|
@@ -277,43 +281,7 @@ def Path(arg)
|
|
|
277
281
|
Path[arg]
|
|
278
282
|
end
|
|
279
283
|
|
|
280
|
-
####################################################################
|
|
281
|
-
|
|
282
|
-
# class << ARGV
|
|
283
|
-
|
|
284
|
-
# def opts
|
|
285
|
-
# @opts, @args ||= partition { |arg| arg[/^--?\w{1,2}/].nil? }
|
|
286
|
-
# end
|
|
287
|
-
|
|
288
|
-
# def args
|
|
289
|
-
# @args ? @args : opts && @args
|
|
290
|
-
# end
|
|
291
|
-
|
|
292
|
-
# def paths
|
|
293
|
-
# map(&:to_Path)
|
|
294
|
-
# end
|
|
295
|
-
|
|
296
|
-
# def paths_R
|
|
297
|
-
# recursive_proc = proc do |paths|
|
|
298
|
-
# paths.map { |path| path.dir? ? the_expander.(path.ls_R) : path }
|
|
299
|
-
# end
|
|
300
|
-
|
|
301
|
-
# recursive_proc.(paths)
|
|
302
|
-
# end
|
|
303
|
-
# alias_method :recursive_paths, :paths_R
|
|
304
|
-
|
|
305
|
-
# def regexes(escaped: true, case_sensitive: false)
|
|
306
|
-
# if case_sensitive
|
|
307
|
-
# map { |arg| /#{escaped ? Regexp.escape(arg) : arg}/ } # NO 'i'
|
|
308
|
-
# else
|
|
309
|
-
# map { |arg| /#{escaped ? Regexp.escape(arg) : arg}/i }
|
|
310
|
-
# end
|
|
311
|
-
# end
|
|
312
|
-
|
|
313
|
-
# end
|
|
314
284
|
|
|
315
285
|
####################################################################
|
|
316
|
-
|
|
317
286
|
require 'epitools/autoloads'
|
|
318
|
-
|
|
319
287
|
####################################################################
|
data/lib/epitools/sys.rb
CHANGED
data/lib/epitools/wm.rb
CHANGED
|
@@ -61,7 +61,7 @@ module WM
|
|
|
61
61
|
|
|
62
62
|
def self.all
|
|
63
63
|
# FIXME: Windows owned by linux-namespaced processes (firejail) report their namspaced pid to X11. `window.process` ends up pointing at either nil, or the wrong process.
|
|
64
|
-
`wmctrl -lpG`.lines.map(&:strip).map { |line| Window.from_line(line) }
|
|
64
|
+
`wmctrl -lpG`.lines.map(&:strip).map { |line| Window.from_line(line) unless line.blank? }.compact
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def self.from_line(line)
|
|
@@ -106,23 +106,6 @@ module WM
|
|
|
106
106
|
system "wmctrl", "-i", "-a", window_id
|
|
107
107
|
end
|
|
108
108
|
|
|
109
|
-
def maximized?
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def maximize!
|
|
113
|
-
system "wmctrl", "-i", "-a", window_id
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
def unmazimize!
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def minimized?
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def minimize!
|
|
124
|
-
end
|
|
125
|
-
|
|
126
109
|
#
|
|
127
110
|
# string is made up of regular text, plus <>'d keypresses
|
|
128
111
|
# eg: "Hello<Ctrl-T><Ctrl-L><Ctrl-Shift-K><Return>!!!"
|
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
|
|
|
@@ -1242,6 +1259,16 @@ describe File do
|
|
|
1242
1259
|
|
|
1243
1260
|
end
|
|
1244
1261
|
|
|
1262
|
+
describe ARGV do
|
|
1263
|
+
|
|
1264
|
+
# it "parses args" do
|
|
1265
|
+
# ARGV.clear
|
|
1266
|
+
# ARGV << "-d"
|
|
1267
|
+
# ARGV.parse!
|
|
1268
|
+
# p ARGV.opts
|
|
1269
|
+
# end
|
|
1270
|
+
|
|
1271
|
+
end
|
|
1245
1272
|
|
|
1246
1273
|
describe "Anything" do
|
|
1247
1274
|
|
|
@@ -1275,5 +1302,15 @@ describe URI do
|
|
|
1275
1302
|
(response.size > 0).should == true
|
|
1276
1303
|
end
|
|
1277
1304
|
|
|
1305
|
+
it "params=" do
|
|
1306
|
+
u = "http://butt.cx/?q=1".to_uri
|
|
1307
|
+
u.query.should == "q=1"
|
|
1308
|
+
u.params.should == {"q" => "1"}
|
|
1309
|
+
u.params["q"] = 2
|
|
1310
|
+
u.params["q"].should == 2
|
|
1311
|
+
u.params.should == {"q" => 2}
|
|
1312
|
+
u.query.should == "q=2"
|
|
1313
|
+
end
|
|
1314
|
+
|
|
1278
1315
|
end
|
|
1279
1316
|
|
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.130
|
|
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: 2020-11-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|
|
@@ -51,6 +51,7 @@ files:
|
|
|
51
51
|
- lib/epitools/clitools.rb
|
|
52
52
|
- lib/epitools/colored.rb
|
|
53
53
|
- lib/epitools/core_ext.rb
|
|
54
|
+
- lib/epitools/core_ext/argv.rb
|
|
54
55
|
- lib/epitools/core_ext/array.rb
|
|
55
56
|
- lib/epitools/core_ext/class.rb
|
|
56
57
|
- lib/epitools/core_ext/enumerable.rb
|
|
@@ -66,10 +67,12 @@ files:
|
|
|
66
67
|
- lib/epitools/core_ext/string.rb
|
|
67
68
|
- lib/epitools/core_ext/time.rb
|
|
68
69
|
- lib/epitools/core_ext/truthiness.rb
|
|
70
|
+
- lib/epitools/core_ext/uri.rb
|
|
69
71
|
- lib/epitools/daemonize.rb
|
|
70
72
|
- lib/epitools/hexdump.rb
|
|
71
73
|
- lib/epitools/iter.rb
|
|
72
74
|
- lib/epitools/its.rb
|
|
75
|
+
- lib/epitools/job_runner.rb
|
|
73
76
|
- lib/epitools/lcs.rb
|
|
74
77
|
- lib/epitools/mimemagic.rb
|
|
75
78
|
- lib/epitools/mimemagic_tables.rb
|
|
@@ -124,7 +127,7 @@ homepage: http://github.com/epitron/epitools
|
|
|
124
127
|
licenses:
|
|
125
128
|
- WTFPL
|
|
126
129
|
metadata: {}
|
|
127
|
-
post_install_message:
|
|
130
|
+
post_install_message:
|
|
128
131
|
rdoc_options: []
|
|
129
132
|
require_paths:
|
|
130
133
|
- lib
|
|
@@ -139,8 +142,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
139
142
|
- !ruby/object:Gem::Version
|
|
140
143
|
version: '0'
|
|
141
144
|
requirements: []
|
|
142
|
-
rubygems_version: 3.
|
|
143
|
-
signing_key:
|
|
145
|
+
rubygems_version: 3.1.4
|
|
146
|
+
signing_key:
|
|
144
147
|
specification_version: 3
|
|
145
148
|
summary: Not utils... METILS!
|
|
146
149
|
test_files: []
|