epitools 0.5.57 → 0.5.58
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/browser.rb +4 -2
- data/lib/epitools/core_ext/enumerable.rb +1 -0
- data/lib/epitools/core_ext/misc.rb +1 -1
- data/lib/epitools/core_ext/numbers.rb +26 -10
- data/lib/epitools/core_ext/range.rb +3 -2
- data/lib/epitools/core_ext/string.rb +8 -6
- data/lib/epitools/hexdump.rb +12 -12
- data/lib/epitools/path.rb +111 -33
- data/spec/path_spec.rb +19 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f476bb597f8724e520b4d9c8dda3a051c4e3bb77
|
|
4
|
+
data.tar.gz: 3974e9c35019dc899060337650af381aac362c83
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ef2db918b34d5ecfc0ad79f3709947fd26c194488aa2371502cf69fffcf28c83c9a5949f8cba8230816abf38a31522bdd4e54f805e9f9e91f987304a6232af71
|
|
7
|
+
data.tar.gz: f02ee7dacfdb34acfefd48bde5112dd097d18470963fbbfa5a7aba8a6761e373ace0ed98e9896923ace059d1145bd82491ec12990c88b1ab6c877700bad67627
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.5.
|
|
1
|
+
0.5.58
|
data/lib/epitools/browser.rb
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
require 'epitools'
|
|
2
|
-
gem 'mechanize', '~> 1.0'
|
|
3
2
|
require 'mechanize'
|
|
4
3
|
require 'epitools/browser/cache'
|
|
5
|
-
|
|
4
|
+
|
|
5
|
+
if Mechanize::VERSION[/^1\./]
|
|
6
|
+
require 'epitools/browser/mechanize_progressbar'
|
|
7
|
+
end
|
|
6
8
|
|
|
7
9
|
# TODO: Make socksify optional (eg: if proxy is specified)
|
|
8
10
|
#require 'socksify'
|
|
@@ -187,6 +187,23 @@ class Numeric
|
|
|
187
187
|
result
|
|
188
188
|
end
|
|
189
189
|
|
|
190
|
+
def to_hms_in_words
|
|
191
|
+
seconds = self
|
|
192
|
+
|
|
193
|
+
days, seconds = seconds.divmod(86400)
|
|
194
|
+
hours, seconds = seconds.divmod(3600)
|
|
195
|
+
minutes, seconds = seconds.divmod(60)
|
|
196
|
+
seconds, frac = seconds.divmod(1)
|
|
197
|
+
|
|
198
|
+
result = "#{seconds} sec"
|
|
199
|
+
result = "#{minutes} min, " + result if minutes > 0
|
|
200
|
+
result = "#{"hour".amount(hours)}, " + result if hours > 0 or days > 0
|
|
201
|
+
result = "#{"day".amount(days)}, " + result if days > 0
|
|
202
|
+
# result += ("." + frac.round(2).to_s.split(".").last) if frac > 0
|
|
203
|
+
|
|
204
|
+
result
|
|
205
|
+
end
|
|
206
|
+
|
|
190
207
|
end
|
|
191
208
|
|
|
192
209
|
|
|
@@ -304,19 +321,18 @@ end
|
|
|
304
321
|
end
|
|
305
322
|
end
|
|
306
323
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
def bytes
|
|
313
|
-
nbytes = (bit_length / 8.0).ceil
|
|
324
|
+
#
|
|
325
|
+
# Convert the integer into its sequence of bytes (little endian format: lowest-order-byte first)
|
|
326
|
+
#
|
|
327
|
+
def bytes
|
|
328
|
+
nbytes = (bit_length / 8.0).ceil
|
|
314
329
|
|
|
315
|
-
|
|
316
|
-
|
|
330
|
+
(0..nbytes).map do |current_byte|
|
|
331
|
+
(self >> (8 * current_byte)) & 0xFF
|
|
332
|
+
end
|
|
317
333
|
end
|
|
334
|
+
|
|
318
335
|
end
|
|
319
|
-
|
|
320
336
|
end
|
|
321
337
|
|
|
322
338
|
class Time
|
|
@@ -8,11 +8,12 @@ class Range
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
#
|
|
11
|
-
# The middle
|
|
11
|
+
# The number in the middle of this range.
|
|
12
12
|
#
|
|
13
|
-
def
|
|
13
|
+
def mid
|
|
14
14
|
(min + max) / 2
|
|
15
15
|
end
|
|
16
|
+
alias_method :middle, :mid
|
|
16
17
|
|
|
17
18
|
#
|
|
18
19
|
# Return a new range which is the intersection of the two ranges
|
|
@@ -387,6 +387,14 @@ class String
|
|
|
387
387
|
nums_and_units.map { |num, units| num.send(units) }.sum
|
|
388
388
|
end
|
|
389
389
|
|
|
390
|
+
#
|
|
391
|
+
# Print a hexdump of the string to STDOUT (coloured, if the terminal supports it)
|
|
392
|
+
#
|
|
393
|
+
def hexdump
|
|
394
|
+
Hex.dump(self)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
|
|
390
398
|
unless public_method_defined? :to_proc
|
|
391
399
|
|
|
392
400
|
#
|
|
@@ -462,12 +470,6 @@ class String
|
|
|
462
470
|
|
|
463
471
|
end # unless public_method_defined? :to_proc
|
|
464
472
|
|
|
465
|
-
|
|
466
|
-
def highlight(type=nil)
|
|
467
|
-
# Coderay highlighting
|
|
468
|
-
end
|
|
469
|
-
alias_method :syntax_highlight, :highlight
|
|
470
|
-
|
|
471
473
|
end
|
|
472
474
|
|
|
473
475
|
|
data/lib/epitools/hexdump.rb
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
require 'epitools'
|
|
2
2
|
|
|
3
|
-
ASCII_PRINTABLE = (33..126)
|
|
4
|
-
|
|
5
3
|
=begin
|
|
6
4
|
000352c0 ed 33 8c 85 6e cc f6 f7 72 79 1c e3 3a b4 c2 c6 |.3..n...ry..:...|
|
|
7
5
|
000352d0 c8 8d d6 ee 3e 68 a1 a5 ae b2 b7 97 a4 1d 5f a7 |....>h........_.|
|
|
@@ -19,6 +17,8 @@ ASCII_PRINTABLE = (33..126)
|
|
|
19
17
|
|
|
20
18
|
module Hex
|
|
21
19
|
|
|
20
|
+
ASCII_PRINTABLE = (33..126)
|
|
21
|
+
|
|
22
22
|
DUMP_COLORS = Rash.new(
|
|
23
23
|
/\d/ => 13,
|
|
24
24
|
/\w/ => 3,
|
|
@@ -31,15 +31,15 @@ module Hex
|
|
|
31
31
|
color = options[:color].nil? ? true : options[:color]
|
|
32
32
|
highlight = options[:highlight]
|
|
33
33
|
|
|
34
|
-
p options
|
|
35
|
-
p color
|
|
34
|
+
# p options
|
|
35
|
+
# p color
|
|
36
36
|
|
|
37
37
|
lines = data.scan(/.{1,16}/m)
|
|
38
38
|
max_offset = (base_offset + data.size) / 16 * 16
|
|
39
39
|
max_offset_width = max_offset.to_s.size
|
|
40
40
|
max_hex_width = 3 * 16 + 1
|
|
41
41
|
|
|
42
|
-
p [max_offset, max_offset_width]
|
|
42
|
+
# p [max_offset, max_offset_width]
|
|
43
43
|
lines.each_with_index do |line,n|
|
|
44
44
|
offset = base_offset + n*16
|
|
45
45
|
bytes = line.unpack("C*")
|
|
@@ -53,21 +53,21 @@ module Hex
|
|
|
53
53
|
end
|
|
54
54
|
end.join('')
|
|
55
55
|
|
|
56
|
-
puts "<11>#{offset.to_s.ljust(max_offset_width)}<3>: <14>#{hex.ljust(max_hex_width)} <8>|<15>#{plain}<8>|".colorize
|
|
56
|
+
puts "<11>#{offset.to_s.ljust(max_offset_width)}<3>: <14>#{hex.ljust(max_hex_width)} <8>|<15>#{plain}<8>|".colorize(:strip => !color)
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
def hexdump(*args)
|
|
63
|
-
Hex.dump(*args)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
62
|
if $0 == __FILE__
|
|
67
63
|
data = (0..64).map{ rand(255).chr }.join('')
|
|
68
|
-
|
|
69
|
-
puts
|
|
64
|
+
|
|
65
|
+
puts "Random data"
|
|
70
66
|
Hex.dump(data, :color=>false)
|
|
67
|
+
|
|
68
|
+
puts "Random data (now in colour!):"
|
|
69
|
+
Hex.dump(data)
|
|
70
|
+
|
|
71
71
|
puts
|
|
72
72
|
|
|
73
73
|
data = "1234567890"*10
|
data/lib/epitools/path.rb
CHANGED
|
@@ -10,48 +10,100 @@ require 'epitools/core_ext/string'
|
|
|
10
10
|
#
|
|
11
11
|
# Path: An object-oriented wrapper for files. (Combines useful methods from FileUtils, File, Dir, and more!)
|
|
12
12
|
#
|
|
13
|
-
#
|
|
13
|
+
# To create a path object, or array of path objects, throw whatever you want into Path[]:
|
|
14
14
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# dir => just the directory
|
|
20
|
-
# dirs => an array of directories
|
|
15
|
+
# These returns a single path object:
|
|
16
|
+
# passwd = Path["/etc/passwd"]
|
|
17
|
+
# also_passwd = Path["/etc"] / "passwd" # joins two paths
|
|
18
|
+
# parent_dir = Path["/usr/local/bin"] / ".." # joins two paths (up one dir)
|
|
21
19
|
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
20
|
+
# These return an array of path objects:
|
|
21
|
+
# pictures = Path["photos/*.{jpg,png}"] # globbing
|
|
22
|
+
# notes = Path["notes/2014/**/*.txt"] # recursive globbing
|
|
23
|
+
# everything = Path["/etc"].ls
|
|
24
24
|
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
25
|
+
# Each Path object has the following attributes, which can all be modified:
|
|
26
|
+
#
|
|
27
|
+
# path => the absolute path, as a string
|
|
28
|
+
# filename => just the name and extension
|
|
29
|
+
# basename => just the filename (without extension)
|
|
30
|
+
# ext => just the extension
|
|
31
|
+
# dir => just the directory
|
|
32
|
+
# dirs => an array of directories
|
|
33
|
+
#
|
|
34
|
+
# Some commonly used methods:
|
|
35
|
+
#
|
|
36
|
+
# path.file?
|
|
37
|
+
# path.exists?
|
|
38
|
+
# path.dir?
|
|
39
|
+
# path.mtime
|
|
40
|
+
# path.xattrs
|
|
41
|
+
# path.symlink?
|
|
42
|
+
# path.broken_symlink?
|
|
43
|
+
# path.symlink_target
|
|
44
|
+
# path.executable?
|
|
45
|
+
# path.chmod(0o666)
|
|
46
|
+
#
|
|
47
|
+
# Interesting examples:
|
|
48
|
+
#
|
|
49
|
+
# Path["*.jpeg"].each { |path| path.rename(:ext=>"jpg") } # renames .jpeg to .jpg
|
|
50
|
+
#
|
|
51
|
+
# files = Path["/etc"].ls # all files in directory
|
|
52
|
+
# morefiles = Path["/etc"].ls_R # all files in directory tree
|
|
53
|
+
#
|
|
54
|
+
# Path["*.txt"].each(&:gzip!)
|
|
55
|
+
#
|
|
56
|
+
# Path["filename.txt"] << "Append data!" # appends data to a file
|
|
57
|
+
#
|
|
58
|
+
# string = Path["filename.txt"].read # read all file data into a string
|
|
59
|
+
# json = Path["filename.json"].read_json # read and parse JSON
|
|
60
|
+
# doc = Path["filename.html"].read_html # read and parse HTML
|
|
61
|
+
# xml = Path["filename.xml"].parse # figure out the format and parse it (as XML)
|
|
62
|
+
#
|
|
63
|
+
# Path["saved_data.marshal"].write(data.marshal) # Save your data!
|
|
64
|
+
# data = Path["saved_data.marshal"].unmarshal # Load your data!
|
|
65
|
+
#
|
|
66
|
+
# Path["unknown_file"].mimetype # sniff the file to determine its mimetype
|
|
67
|
+
# Path["unknown_file"].mimetype.image? # ...is this some kind of image?
|
|
68
|
+
#
|
|
69
|
+
# Path["otherdir/"].cd do # temporarily change to "otherdir/"
|
|
70
|
+
# p Path.ls
|
|
71
|
+
# end
|
|
72
|
+
# p Path.ls
|
|
73
|
+
#
|
|
74
|
+
# The `Path#dirs` attribute is a split up version of the directory
|
|
75
|
+
# (eg: Path["/usr/local/bin"].dirs => ["usr", "local", "bin"]).
|
|
76
|
+
#
|
|
77
|
+
# You can modify the dirs array to change subsets of the directory. Here's an example that
|
|
78
|
+
# finds out if you're in a git repo:
|
|
79
|
+
#
|
|
80
|
+
# def inside_a_git_repo?
|
|
81
|
+
# path = Path.pwd # start at the current directory
|
|
28
82
|
# while path.dirs.any?
|
|
29
|
-
#
|
|
30
|
-
#
|
|
83
|
+
# if (path/".git").exists?
|
|
84
|
+
# return true
|
|
85
|
+
# else
|
|
86
|
+
# path.dirs.pop # go up one level
|
|
87
|
+
# end
|
|
31
88
|
# end
|
|
32
89
|
# false
|
|
33
90
|
# end
|
|
34
91
|
#
|
|
35
|
-
# More examples:
|
|
36
|
-
#
|
|
37
|
-
# Path["*.jpeg"].each { |path| path.rename(:ext=>"jpg") }
|
|
38
|
-
# Path["filename.txt"] << "Append data!"
|
|
39
|
-
# etcfiles = Path["/etc"].ls
|
|
40
|
-
# Path["*.txt"].each(&:gzip)
|
|
41
|
-
#
|
|
42
92
|
# Swap two files:
|
|
43
93
|
#
|
|
44
94
|
# a, b = Path["file_a", "file_b"]
|
|
45
|
-
# temp = a.with(:ext=>a.ext+".swapping") # return a modified version of this object
|
|
95
|
+
# temp = a.with(:ext => a.ext+".swapping") # return a modified version of this object
|
|
46
96
|
# a.mv(temp)
|
|
47
97
|
# b.mv(a)
|
|
48
98
|
# temp.mv(b)
|
|
49
99
|
#
|
|
50
|
-
# Paths can be created for existant and non-existant files.
|
|
51
|
-
#
|
|
100
|
+
# Paths can be created for existant and non-existant files.
|
|
101
|
+
#
|
|
102
|
+
# To create a nonexistant path object that thinks it's a directory, just add a '/' at the end.
|
|
103
|
+
# (eg: Path["/etc/nonexistant/"]).
|
|
52
104
|
#
|
|
53
105
|
# Performance has been an important factor in Path's design, so doing crazy things with Path
|
|
54
|
-
# usually doesn't kill
|
|
106
|
+
# usually doesn't kill performance. Go nuts!
|
|
55
107
|
#
|
|
56
108
|
#
|
|
57
109
|
class Path
|
|
@@ -196,7 +248,7 @@ class Path
|
|
|
196
248
|
end
|
|
197
249
|
|
|
198
250
|
#
|
|
199
|
-
# Reload this path (
|
|
251
|
+
# Reload this path (updates cached values.)
|
|
200
252
|
#
|
|
201
253
|
def reload!
|
|
202
254
|
temp = path
|
|
@@ -286,6 +338,14 @@ class Path
|
|
|
286
338
|
extensions
|
|
287
339
|
end
|
|
288
340
|
|
|
341
|
+
###############################################################################
|
|
342
|
+
# inspect
|
|
343
|
+
###############################################################################
|
|
344
|
+
|
|
345
|
+
def inspect
|
|
346
|
+
"#<Path:#{path}>"
|
|
347
|
+
end
|
|
348
|
+
|
|
289
349
|
###############################################################################
|
|
290
350
|
# fstat
|
|
291
351
|
###############################################################################
|
|
@@ -546,8 +606,21 @@ class Path
|
|
|
546
606
|
#
|
|
547
607
|
# All the lines in this file, chomped.
|
|
548
608
|
#
|
|
549
|
-
def
|
|
550
|
-
io.
|
|
609
|
+
def each_line
|
|
610
|
+
io.each_line
|
|
611
|
+
end
|
|
612
|
+
alias_method :lines, :each_line
|
|
613
|
+
|
|
614
|
+
def grep(pat)
|
|
615
|
+
return to_enum(:grep, pat).to_a unless block_given?
|
|
616
|
+
|
|
617
|
+
each_line do |line|
|
|
618
|
+
yield line if line =~ pat
|
|
619
|
+
end
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
def nicelines
|
|
623
|
+
lines.map(&:chomp)
|
|
551
624
|
end
|
|
552
625
|
|
|
553
626
|
def unmarshal
|
|
@@ -733,7 +806,7 @@ class Path
|
|
|
733
806
|
# Renames the file, but doesn't change the current Path object, and returns a Path that points at the new filename.
|
|
734
807
|
#
|
|
735
808
|
# Examples:
|
|
736
|
-
# Path["file"].rename("newfile")
|
|
809
|
+
# Path["file"].rename("newfile") #=> Path["newfile"]
|
|
737
810
|
# Path["SongySong.mp3"].rename(:basename=>"Songy Song")
|
|
738
811
|
# Path["Songy Song.mp3"].rename(:ext=>"aac")
|
|
739
812
|
# Path["Songy Song.aac"].rename(:dir=>"/music2")
|
|
@@ -851,8 +924,7 @@ class Path
|
|
|
851
924
|
end
|
|
852
925
|
|
|
853
926
|
def ln_s(dest)
|
|
854
|
-
|
|
855
|
-
FileUtils.ln_s(self, dest)
|
|
927
|
+
Path.ln_s(self, dest)
|
|
856
928
|
end
|
|
857
929
|
|
|
858
930
|
## Owners and permissions
|
|
@@ -1179,10 +1251,13 @@ class Path
|
|
|
1179
1251
|
orig = pwd
|
|
1180
1252
|
|
|
1181
1253
|
Dir.chdir(dest)
|
|
1182
|
-
yield
|
|
1254
|
+
result = yield dest
|
|
1183
1255
|
Dir.chdir(orig)
|
|
1256
|
+
|
|
1257
|
+
result
|
|
1184
1258
|
else
|
|
1185
1259
|
Dir.chdir(dest)
|
|
1260
|
+
dest
|
|
1186
1261
|
end
|
|
1187
1262
|
end
|
|
1188
1263
|
|
|
@@ -1190,7 +1265,10 @@ class Path
|
|
|
1190
1265
|
|
|
1191
1266
|
def self.ls_r(path); Path[path].ls_r; end
|
|
1192
1267
|
|
|
1193
|
-
def self.ln_s(src, dest)
|
|
1268
|
+
def self.ln_s(src, dest)
|
|
1269
|
+
FileUtils.ln_s(src, dest)
|
|
1270
|
+
Path[dest]
|
|
1271
|
+
end
|
|
1194
1272
|
|
|
1195
1273
|
## TODO: Verbose mode
|
|
1196
1274
|
#def self.verbose=(value); @@verbose = value; end
|
data/spec/path_spec.rb
CHANGED
|
@@ -460,7 +460,7 @@ describe Path do
|
|
|
460
460
|
(path.mode & 0o666).should > 0
|
|
461
461
|
end
|
|
462
462
|
|
|
463
|
-
it 'symlinks
|
|
463
|
+
it 'symlinks files' do
|
|
464
464
|
path = Path.tmpfile
|
|
465
465
|
path << "some data"
|
|
466
466
|
|
|
@@ -474,6 +474,24 @@ describe Path do
|
|
|
474
474
|
target.symlink_target.should == path
|
|
475
475
|
end
|
|
476
476
|
|
|
477
|
+
it 'symlinks relative dirs' do
|
|
478
|
+
dir = Path["/tmp/dir/"]
|
|
479
|
+
dir.mkdir
|
|
480
|
+
tmp = Path["/tmp/symlinktarget"]
|
|
481
|
+
tmp << "data"
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
link = (dir/"symlink")
|
|
485
|
+
link.ln_s "../file"
|
|
486
|
+
|
|
487
|
+
link.symlink?.should == true
|
|
488
|
+
|
|
489
|
+
tmp.read.should ==
|
|
490
|
+
|
|
491
|
+
tmp.rm
|
|
492
|
+
dir.rm
|
|
493
|
+
end
|
|
494
|
+
|
|
477
495
|
it 'swaps two files' do
|
|
478
496
|
# swap two regular files
|
|
479
497
|
|
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.58
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- epitron
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-
|
|
11
|
+
date: 2014-12-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|