epitools 0.5.123 → 0.5.129
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/enumerable.rb +3 -0
- data/lib/epitools/core_ext/misc.rb +0 -73
- data/lib/epitools/core_ext/uri.rb +97 -0
- data/lib/epitools/job_runner.rb +97 -0
- data/lib/epitools/minimal.rb +9 -41
- data/lib/epitools/numwords.rb +1 -0
- data/lib/epitools/path.rb +19 -0
- data/lib/epitools/wm.rb +1 -1
- data/spec/core_ext_spec.rb +88 -0
- data/spec/path_spec.rb +19 -0
- 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: 74b341f10e9697a2d9e93aad5aa91b7f799e75a3cd817d712bce3e15cd18428d
|
4
|
+
data.tar.gz: bce241006bd3b743410e3b6833145a5e72052637d7e918caa2562564b6ad4f5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef8edebf3480e814c17e90f5c200fe1dc70a45827d8c2e52d2d7834291f61fb67824c5c5b6f869805f8751ea53d0eb95aa83e86daba42eb748d34ea66061ad6a
|
7
|
+
data.tar.gz: 38abf237811351f91306dd1d1e66e9104040645aa3ff743d13609a155853aa6ffa80b9967961edda5f20e1ad67068ffc298beafac47857210eca9ebb6a4ec87f
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.129
|
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
|
@@ -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.)
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module URI
|
4
|
+
|
5
|
+
#
|
6
|
+
# Return a Hash of the variables in the query string
|
7
|
+
#
|
8
|
+
def params
|
9
|
+
(@query ? @query.to_params : {})
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# Update all the params at once
|
14
|
+
#
|
15
|
+
def params=(new_params)
|
16
|
+
self.query = new_params.to_params
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Update one URI parameter
|
21
|
+
#
|
22
|
+
def set_param(key, value)
|
23
|
+
current = params
|
24
|
+
current[key] = value
|
25
|
+
self.query = current.to_query
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Get the query string
|
30
|
+
#
|
31
|
+
def query
|
32
|
+
params.to_query
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# URIs *are* strings, dammit!
|
37
|
+
#
|
38
|
+
def to_str
|
39
|
+
to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Default user agent for the 'get' method
|
44
|
+
#
|
45
|
+
# USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0"
|
46
|
+
|
47
|
+
#
|
48
|
+
# Get this URI using Net::HTTP
|
49
|
+
#
|
50
|
+
def get(headers={}, redirect_limit=10)
|
51
|
+
raise "Sorry, URI can't get from #{scheme.inspect} URIs yet" unless scheme =~ /^https?$/
|
52
|
+
raise 'Too many HTTP redirections' if redirect_limit == 0
|
53
|
+
|
54
|
+
# headers['User-Agent'] ||= USER_AGENT
|
55
|
+
|
56
|
+
# response = Net::HTTP.start(host, port) do |http|
|
57
|
+
# # the_path = path.empty? ? "/" : path
|
58
|
+
# req = Net::HTTP::Get.new(self, headers)
|
59
|
+
# http.request(req)
|
60
|
+
# end
|
61
|
+
|
62
|
+
response = Net::HTTP.get_response(self)
|
63
|
+
|
64
|
+
case response
|
65
|
+
when Net::HTTPSuccess
|
66
|
+
response
|
67
|
+
when Net::HTTPRedirection
|
68
|
+
# puts "redirect: #{response['location']}"
|
69
|
+
URI(response['location']).get(headers, redirect_limit-1)
|
70
|
+
else
|
71
|
+
response.error!
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# Stupid workaround for URI blowing up when it receives a [ or ] character
|
79
|
+
#
|
80
|
+
module Better_URI_RFC3986_Parser # ::RFC3986_relative_ref
|
81
|
+
ESCAPE_ME_PLZ = "[]{}!"
|
82
|
+
|
83
|
+
def split(uri)
|
84
|
+
subsitutions = ESCAPE_ME_PLZ.chars.map { |c| [c, CGI.escape(c)] }
|
85
|
+
subsitutions << [" ", "%20"]
|
86
|
+
|
87
|
+
subsitutions.each do |find, replace|
|
88
|
+
uri = uri.gsub(find, replace)
|
89
|
+
end
|
90
|
+
|
91
|
+
super(uri)
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
URI::RFC3986_Parser.prepend(Better_URI_RFC3986_Parser)
|
97
|
+
|
@@ -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/numwords.rb
CHANGED
data/lib/epitools/path.rb
CHANGED
@@ -1110,6 +1110,25 @@ class Path
|
|
1110
1110
|
}
|
1111
1111
|
end
|
1112
1112
|
|
1113
|
+
#
|
1114
|
+
# Path.mkcd(path) creates a path if it doesn't exist, and changes to it (temporarily, if a block is provided)
|
1115
|
+
#
|
1116
|
+
def self.mkcd(path, &block)
|
1117
|
+
path = path.to_Path unless path.is_a? Path
|
1118
|
+
path.mkdir_p unless path.exists?
|
1119
|
+
|
1120
|
+
raise "Error: #{path} couldn't be created." unless path.dir?
|
1121
|
+
|
1122
|
+
self.cd(path, &block)
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
#
|
1126
|
+
# Path.mkcd(self)
|
1127
|
+
#
|
1128
|
+
def mkcd(&block)
|
1129
|
+
Path.mkcd(self, &block)
|
1130
|
+
end
|
1131
|
+
|
1113
1132
|
def cp_r(dest)
|
1114
1133
|
FileUtils.cp_r(path, dest) #if Path[dest].exists?
|
1115
1134
|
dest
|
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)
|
data/spec/core_ext_spec.rb
CHANGED
@@ -147,6 +147,44 @@ describe Class do
|
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
150
|
+
it "traces messages (when $DEBUG is set)" do
|
151
|
+
$DEBUG = true
|
152
|
+
|
153
|
+
class TestButt
|
154
|
+
trace_messages_to :a, :b, :c
|
155
|
+
|
156
|
+
def a(x)
|
157
|
+
end
|
158
|
+
|
159
|
+
def b(x)
|
160
|
+
end
|
161
|
+
|
162
|
+
def c(x,y,z,&block)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
class ButtTest
|
167
|
+
trace_messages_to :*
|
168
|
+
|
169
|
+
def d
|
170
|
+
end
|
171
|
+
|
172
|
+
def e
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
t = TestButt.new
|
177
|
+
t.a(1)
|
178
|
+
t.b(2)
|
179
|
+
t.c(3,4,5) { :butt }
|
180
|
+
|
181
|
+
b = ButtTest.new
|
182
|
+
b.a
|
183
|
+
b.b
|
184
|
+
|
185
|
+
$DEBUG = false
|
186
|
+
end
|
187
|
+
|
150
188
|
end
|
151
189
|
|
152
190
|
|
@@ -757,6 +795,38 @@ describe Enumerable do
|
|
757
795
|
ps.sort_numerically.map(&:filename).should == proper
|
758
796
|
end
|
759
797
|
|
798
|
+
it "to_csvs and to_tsvs" do
|
799
|
+
data = [
|
800
|
+
["1", "2", "3"],
|
801
|
+
["4", "5", "6"],
|
802
|
+
["7", "8", "9", "10"],
|
803
|
+
]
|
804
|
+
|
805
|
+
hash_data = [
|
806
|
+
{a: 1, b: 2, c: 3},
|
807
|
+
{a: 4, b: 5, c: 6},
|
808
|
+
{a: 7, b: 8, c: 9, d: 10},
|
809
|
+
]
|
810
|
+
|
811
|
+
class EnumedData
|
812
|
+
include Enumerable
|
813
|
+
def initialize(data); @data=data; end
|
814
|
+
def each(&block); @data.each(&block); end
|
815
|
+
end
|
816
|
+
|
817
|
+
[data, hash_data, EnumedData.new(data)].each do |a|
|
818
|
+
str = a.to_csv
|
819
|
+
str.each_line.count.should == 3
|
820
|
+
str.should_not be_nil
|
821
|
+
str["1,2,3"].should_not be_nil
|
822
|
+
|
823
|
+
str = a.to_tsv
|
824
|
+
str.should_not be_nil
|
825
|
+
str["1\t2\t3"].should_not be_nil
|
826
|
+
end
|
827
|
+
|
828
|
+
end
|
829
|
+
|
760
830
|
end
|
761
831
|
|
762
832
|
|
@@ -1204,6 +1274,16 @@ describe File do
|
|
1204
1274
|
|
1205
1275
|
end
|
1206
1276
|
|
1277
|
+
describe ARGV do
|
1278
|
+
|
1279
|
+
# it "parses args" do
|
1280
|
+
# ARGV.clear
|
1281
|
+
# ARGV << "-d"
|
1282
|
+
# ARGV.parse!
|
1283
|
+
# p ARGV.opts
|
1284
|
+
# end
|
1285
|
+
|
1286
|
+
end
|
1207
1287
|
|
1208
1288
|
describe "Anything" do
|
1209
1289
|
|
@@ -1237,5 +1317,13 @@ describe URI do
|
|
1237
1317
|
(response.size > 0).should == true
|
1238
1318
|
end
|
1239
1319
|
|
1320
|
+
it "params=" do
|
1321
|
+
u = "http://butt.com/?q=1".to_uri
|
1322
|
+
u.query.should == "q=1"
|
1323
|
+
u.params["q"] = 2
|
1324
|
+
u.params["q"].should == 2
|
1325
|
+
u.query.should == "q=2"
|
1326
|
+
end
|
1327
|
+
|
1240
1328
|
end
|
1241
1329
|
|
data/spec/path_spec.rb
CHANGED
@@ -348,6 +348,25 @@ describe Path do
|
|
348
348
|
lambda { tmp2.mkdir_p }.should_not raise_error
|
349
349
|
end
|
350
350
|
|
351
|
+
it "mkcds" do
|
352
|
+
tmp = Path.tmpdir
|
353
|
+
tmp.dir?.should == true
|
354
|
+
tmp.rm
|
355
|
+
tmp.exists?.should == false
|
356
|
+
|
357
|
+
Path.mkcd(tmp) do
|
358
|
+
Path.pwd.path.should == tmp.path
|
359
|
+
end
|
360
|
+
|
361
|
+
tmp.rm
|
362
|
+
|
363
|
+
tmp.mkcd do
|
364
|
+
Path.pwd.path.should == tmp.path
|
365
|
+
end
|
366
|
+
|
367
|
+
tmp.rm
|
368
|
+
end
|
369
|
+
|
351
370
|
it "has classmethods" do
|
352
371
|
path = Path.tmpfile
|
353
372
|
|
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.129
|
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-09-25 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: []
|