epitools 0.5.126 → 0.5.133

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b1368a1c1aa01948548b464ea158ae289a7055f0e55766edda4862d1c672d20
4
- data.tar.gz: f51d54c3c41d14c09acf5e0c5f47a8602e2acb3df0a9d0d424fe15d61f806c70
3
+ metadata.gz: db1a5a887e1a937b76e39d061a8865503f7bfeb33f03094f5d7b8ce3749420e7
4
+ data.tar.gz: b5075843f8bd030de2e5313e9af3f53f97cae26fc0b52a609a06137fc015324c
5
5
  SHA512:
6
- metadata.gz: 980029d3207e237d28b640c3c22dbedf99aa30121440e9350803f98d6c2564acb237066c5a62a1b03597430698b76d1c38e1c2e6bab44a7cd2b3f503f624848a
7
- data.tar.gz: 8bb84dd89d32f3cb7694c737e5c5ac647e727f3105efb1a3fb0edb30649170cb44e7b6879c1df9b83b7ee9260d1a7fd1d65d6ecdf3626265e3a76086c2e78c9d
6
+ metadata.gz: 0f13ae895b759edc3612970e335b743301bd102a4c73f619c16028acab0792a1d229d65ff40626d6c11334f95b020b055f9a18e6afc70a37ae74824b439c2f24
7
+ data.tar.gz: 8bac272ee77ee4bd4c493b2b6f6c394e1143bd57e73b77196f9798326e73749b1c940622e22ea792875718b59e7a01380d2766296df5c19a3a259a3f7e34fcd3
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.126
1
+ 0.5.133
@@ -65,19 +65,20 @@ autoload :IPAddr, 'ipaddr'
65
65
 
66
66
  ## Nonstandard library (epitools)
67
67
 
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'
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
 
@@ -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
- end
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
- args = args.map(&:inspect)
39
- args << "&block" if block
40
- $stderr.puts "[*] #{parent}##{meth}(#{args.join(", ")})"
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,4 +1,7 @@
1
+ require 'epitools/core_ext/array'
2
+
1
3
  module Enumerable
4
+ include Array::ToCSV
2
5
 
3
6
  #
4
7
  # 'true' if the Enumerable has no elements
@@ -1,5 +1,5 @@
1
1
 
2
- Number = Numeric # "obj.is_a? Number" just sounds better.
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
- [:cos,
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 # units
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, seconds = seconds.divmod(86400)
217
- hours, seconds = seconds.divmod(3600)
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, seconds = seconds.divmod(86400)
233
- hours, seconds = seconds.divmod(3600)
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
@@ -130,10 +130,9 @@ class String
130
130
  #
131
131
  # Is there anything in the string? (ignoring whitespace/newlines)
132
132
  #
133
- def any?
133
+ def present?
134
134
  not blank?
135
135
  end
136
- alias_method :present?, :any?
137
136
 
138
137
  #
139
138
  # Does this string contain something that means roughly "true"?
@@ -1,35 +1,58 @@
1
1
  require 'uri'
2
2
 
3
- module URI
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
- # Mutate the query
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=(key, value)
17
- current = params
18
- current[key] = value
19
- self.query = current.to_query
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
- def query
23
- params.to_query
24
- end
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
@@ -24,7 +24,7 @@ class Numeric
24
24
 
25
25
  # 20-90
26
26
  NAMES_MEDIUM = [
27
- "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety"
27
+ "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"
28
28
  ]
29
29
 
30
30
  # >= 100
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 =~ %r{^[a-z\-]+://}i # URL?
160
- Path::URI.new(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.exists? newpath
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.exists? path
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.exists?(path)
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&param2=value2&...
1640
1649
  #
1641
- def to_s
1642
- uri.to_s
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
- Kernel.open(to_s, mode, &block)
1705
+ ::URI.open(to_s, mode, &block)
1697
1706
  else
1698
- Kernel.open(to_s, mode)
1707
+ ::URI.open(to_s, mode)
1699
1708
  end
1700
1709
  end
1701
1710
 
data/lib/epitools/sys.rb CHANGED
@@ -4,6 +4,7 @@ require 'epitools/minimal'
4
4
  # Cross-platform operating system functions.
5
5
  # Includes: process listing, platform detection, etc.
6
6
  #
7
+ require 'epitools/sys/os'
7
8
  require 'epitools/sys/ps'
8
9
  require 'epitools/sys/mounts'
9
10
  require 'epitools/sys/misc'
@@ -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 d
149
+ def a
170
150
  end
171
151
 
172
- def e
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.new("1111.1234567").commatize.should == "1,111.1234567"
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
- response = URI("http://google.com/").get
1284
- response.body.size
1285
- (response.size > 0).should == true
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.com/?q=1".to_uri
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.126
4
+ version: 0.5.133
5
5
  platform: ruby
6
6
  authors:
7
7
  - epitron
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-29 00:00:00.000000000 Z
11
+ date: 2021-04-30 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.2
145
- signing_key:
145
+ rubygems_version: 3.2.15
146
+ signing_key:
146
147
  specification_version: 3
147
148
  summary: Not utils... METILS!
148
149
  test_files: []