ptools 1.4.2 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGES.md +11 -0
- data/LICENSE +177 -0
- data/MANIFEST.md +2 -0
- data/README.md +27 -25
- data/Rakefile +4 -1
- data/lib/ptools.rb +95 -129
- data/ptools.gemspec +11 -8
- data/spec/binary_spec.rb +31 -30
- data/spec/constants_spec.rb +3 -3
- data/spec/head_spec.rb +18 -18
- data/spec/image_spec.rb +163 -26
- data/spec/img/jpg_no_ext +0 -0
- data/spec/img/test.bmp +0 -0
- data/spec/img/test.tiff +0 -0
- data/spec/nlconvert_spec.rb +51 -53
- data/spec/sparse_spec.rb +17 -21
- data/spec/spec_helper.rb +7 -0
- data/spec/tail_spec.rb +55 -55
- data/spec/touch_spec.rb +22 -22
- data/spec/wc_spec.rb +28 -28
- data/spec/whereis_spec.rb +29 -30
- data/spec/which_spec.rb +52 -60
- data.tar.gz.sig +0 -0
- metadata +39 -5
- metadata.gz.sig +2 -4
data/lib/ptools.rb
CHANGED
@@ -3,7 +3,7 @@ require 'win32/file' if File::ALT_SEPARATOR
|
|
3
3
|
|
4
4
|
class File
|
5
5
|
# The version of the ptools library.
|
6
|
-
PTOOLS_VERSION = '1.
|
6
|
+
PTOOLS_VERSION = '1.5.0'.freeze
|
7
7
|
|
8
8
|
# :stopdoc:
|
9
9
|
|
@@ -11,9 +11,9 @@ class File
|
|
11
11
|
if File::ALT_SEPARATOR
|
12
12
|
MSWINDOWS = true
|
13
13
|
if ENV['PATHEXT']
|
14
|
-
WIN32EXTS =
|
14
|
+
WIN32EXTS = ".{#{ENV['PATHEXT'].tr(';', ',').tr('.', '')}}".downcase
|
15
15
|
else
|
16
|
-
WIN32EXTS = '.{exe,com,bat}'
|
16
|
+
WIN32EXTS = '.{exe,com,bat}'.freeze
|
17
17
|
end
|
18
18
|
else
|
19
19
|
MSWINDOWS = false
|
@@ -24,7 +24,7 @@ class File
|
|
24
24
|
private_constant :MSWINDOWS
|
25
25
|
end
|
26
26
|
|
27
|
-
IMAGE_EXT = %w[.bmp .gif .jpg .jpeg .png .ico]
|
27
|
+
IMAGE_EXT = %w[.bmp .gif .jpg .jpeg .png .ico].freeze
|
28
28
|
|
29
29
|
# :startdoc:
|
30
30
|
|
@@ -47,42 +47,34 @@ class File
|
|
47
47
|
# The approach I used here is based on information found at
|
48
48
|
# http://en.wikipedia.org/wiki/Magic_number_(programming)
|
49
49
|
#
|
50
|
-
def self.image?(file, check_file_extension
|
50
|
+
def self.image?(file, check_file_extension: true)
|
51
51
|
bool = bmp?(file) || jpg?(file) || png?(file) || gif?(file) || tiff?(file) || ico?(file)
|
52
52
|
|
53
|
-
if check_file_extension
|
54
|
-
bool = bool && IMAGE_EXT.include?(File.extname(file).downcase)
|
55
|
-
end
|
53
|
+
bool &&= IMAGE_EXT.include?(File.extname(file).downcase) if check_file_extension
|
56
54
|
|
57
55
|
bool
|
58
56
|
end
|
59
57
|
|
60
58
|
# Returns whether or not +file+ is a binary non-image file, i.e. executable,
|
61
|
-
# shared object,
|
62
|
-
# It performs a "best guess" based on a simple test of the first
|
63
|
-
# +File.blksize+ characters, or 4096, whichever is smaller.
|
59
|
+
# shared object, etc.
|
64
60
|
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
61
|
+
# Internally this method simply looks for a double null sequence. This will
|
62
|
+
# work for the vast majority of cases, but it is not guaranteed to be
|
63
|
+
# absolutely accurate.
|
68
64
|
#
|
69
65
|
# Example:
|
70
66
|
#
|
71
67
|
# File.binary?('somefile.exe') # => true
|
72
68
|
# File.binary?('somefile.txt') # => false
|
73
|
-
#--
|
74
|
-
# Based on code originally provided by Ryan Davis (which, in turn, is
|
75
|
-
# based on Perl's -B switch).
|
76
69
|
#
|
77
|
-
def self.binary?(file
|
70
|
+
def self.binary?(file)
|
78
71
|
return false if File.stat(file).zero?
|
79
72
|
return false if image?(file)
|
80
73
|
return false if check_bom?(file)
|
74
|
+
|
81
75
|
bytes = File.stat(file).blksize
|
82
76
|
bytes = 4096 if bytes > 4096
|
83
|
-
|
84
|
-
s = s.encode('US-ASCII', :undef => :replace).split(//)
|
85
|
-
((s.size - s.grep(" ".."~").size) / s.size.to_f) > percentage
|
77
|
+
(File.read(file, bytes) || '').include?("\u0000\u0000")
|
86
78
|
end
|
87
79
|
|
88
80
|
# Looks for the first occurrence of +program+ within +path+.
|
@@ -98,10 +90,8 @@ class File
|
|
98
90
|
# File.which('ruby') # => '/usr/local/bin/ruby'
|
99
91
|
# File.which('foo') # => nil
|
100
92
|
#
|
101
|
-
def self.which(program, path=ENV['PATH'])
|
102
|
-
if path.nil? || path.empty?
|
103
|
-
raise ArgumentError, "path cannot be empty"
|
104
|
-
end
|
93
|
+
def self.which(program, path = ENV['PATH'])
|
94
|
+
raise ArgumentError, 'path cannot be empty' if path.nil? || path.empty?
|
105
95
|
|
106
96
|
# Bail out early if an absolute path is provided.
|
107
97
|
if program =~ /^\/|^[a-z]:[\\\/]/i
|
@@ -115,16 +105,17 @@ class File
|
|
115
105
|
end
|
116
106
|
|
117
107
|
# Iterate over each path glob the dir + program.
|
118
|
-
path.split(File::PATH_SEPARATOR).each
|
108
|
+
path.split(File::PATH_SEPARATOR).each do |dir|
|
119
109
|
dir = File.expand_path(dir)
|
120
110
|
|
121
111
|
next unless File.exist?(dir) # In case of bogus second argument
|
112
|
+
|
122
113
|
file = File.join(dir, program)
|
123
114
|
|
124
115
|
# Dir[] doesn't handle backslashes properly, so convert them. Also, if
|
125
116
|
# the program name doesn't have an extension, try them all.
|
126
117
|
if MSWINDOWS
|
127
|
-
file = file.tr(
|
118
|
+
file = file.tr(File::ALT_SEPARATOR, File::SEPARATOR)
|
128
119
|
file += WIN32EXTS if File.extname(program).empty?
|
129
120
|
end
|
130
121
|
|
@@ -135,7 +126,7 @@ class File
|
|
135
126
|
found.tr!(File::SEPARATOR, File::ALT_SEPARATOR) if File::ALT_SEPARATOR
|
136
127
|
return found
|
137
128
|
end
|
138
|
-
|
129
|
+
end
|
139
130
|
|
140
131
|
nil
|
141
132
|
end
|
@@ -152,21 +143,19 @@ class File
|
|
152
143
|
# File.whereis('ruby') # => ['/usr/bin/ruby', '/usr/local/bin/ruby']
|
153
144
|
# File.whereis('foo') # => nil
|
154
145
|
#
|
155
|
-
def self.whereis(program, path=ENV['PATH'])
|
156
|
-
if path.nil? || path.empty?
|
157
|
-
raise ArgumentError, "path cannot be empty"
|
158
|
-
end
|
146
|
+
def self.whereis(program, path = ENV['PATH'])
|
147
|
+
raise ArgumentError, 'path cannot be empty' if path.nil? || path.empty?
|
159
148
|
|
160
149
|
paths = []
|
161
150
|
|
162
151
|
# Bail out early if an absolute path is provided.
|
163
152
|
if program =~ /^\/|^[a-z]:[\\\/]/i
|
164
153
|
program += WIN32EXTS if MSWINDOWS && File.extname(program).empty?
|
165
|
-
program = program.tr(
|
154
|
+
program = program.tr(File::ALT_SEPARATOR, File::SEPARATOR) if MSWINDOWS
|
166
155
|
found = Dir[program]
|
167
156
|
if found[0] && File.executable?(found[0]) && !File.directory?(found[0])
|
168
157
|
if File::ALT_SEPARATOR
|
169
|
-
return found.map{ |f| f.tr(
|
158
|
+
return found.map{ |f| f.tr(File::SEPARATOR, File::ALT_SEPARATOR) }
|
170
159
|
else
|
171
160
|
return found
|
172
161
|
end
|
@@ -176,14 +165,15 @@ class File
|
|
176
165
|
end
|
177
166
|
|
178
167
|
# Iterate over each path glob the dir + program.
|
179
|
-
path.split(File::PATH_SEPARATOR).each
|
168
|
+
path.split(File::PATH_SEPARATOR).each do |dir|
|
180
169
|
next unless File.exist?(dir) # In case of bogus second argument
|
170
|
+
|
181
171
|
file = File.join(dir, program)
|
182
172
|
|
183
173
|
# Dir[] doesn't handle backslashes properly, so convert them. Also, if
|
184
174
|
# the program name doesn't have an extension, try them all.
|
185
175
|
if MSWINDOWS
|
186
|
-
file = file.tr(
|
176
|
+
file = file.tr(File::ALT_SEPARATOR, File::SEPARATOR)
|
187
177
|
file += WIN32EXTS if File.extname(program).empty?
|
188
178
|
end
|
189
179
|
|
@@ -194,7 +184,7 @@ class File
|
|
194
184
|
found.tr!(File::SEPARATOR, File::ALT_SEPARATOR) if File::ALT_SEPARATOR
|
195
185
|
paths << found
|
196
186
|
end
|
197
|
-
|
187
|
+
end
|
198
188
|
|
199
189
|
paths.empty? ? nil : paths.uniq
|
200
190
|
end
|
@@ -210,20 +200,21 @@ class File
|
|
210
200
|
# # Use a block
|
211
201
|
# File.head('somefile.txt'){ |line| puts line }
|
212
202
|
#
|
213
|
-
def self.head(filename, num_lines=10)
|
203
|
+
def self.head(filename, num_lines = 10)
|
214
204
|
a = []
|
215
205
|
|
216
|
-
|
206
|
+
File.foreach(filename) do |line|
|
217
207
|
break if num_lines <= 0
|
208
|
+
|
218
209
|
num_lines -= 1
|
219
210
|
if block_given?
|
220
211
|
yield line
|
221
212
|
else
|
222
213
|
a << line
|
223
214
|
end
|
224
|
-
|
215
|
+
end
|
225
216
|
|
226
|
-
|
217
|
+
a.empty? ? nil : a # Return nil in block form
|
227
218
|
end
|
228
219
|
|
229
220
|
# In block form, yields the last +num_lines+ of file +filename+.
|
@@ -240,7 +231,7 @@ class File
|
|
240
231
|
# Internally I'm using a 64 chunk of memory at a time. I may allow the size
|
241
232
|
# to be configured in the future as an optional 3rd argument.
|
242
233
|
#
|
243
|
-
def self.tail(filename, num_lines=10)
|
234
|
+
def self.tail(filename, num_lines = 10, &block)
|
244
235
|
tail_size = 2**16 # 64k chunks
|
245
236
|
|
246
237
|
# MS Windows gets unhappy if you try to seek backwards past the
|
@@ -254,7 +245,7 @@ class File
|
|
254
245
|
buf = ''
|
255
246
|
|
256
247
|
# Open in binary mode to ensure line endings aren't converted.
|
257
|
-
File.open(filename, 'rb')
|
248
|
+
File.open(filename, 'rb') do |fh|
|
258
249
|
position = file_size - read_bytes # Set the starting read position
|
259
250
|
|
260
251
|
# Loop until we have the lines or run out of file
|
@@ -264,12 +255,12 @@ class File
|
|
264
255
|
read_bytes = tail_size
|
265
256
|
position -= read_bytes
|
266
257
|
end
|
267
|
-
|
258
|
+
end
|
268
259
|
|
269
260
|
lines = buf.split(line_sep).pop(num_lines)
|
270
261
|
|
271
262
|
if block_given?
|
272
|
-
lines.each
|
263
|
+
lines.each(&block)
|
273
264
|
else
|
274
265
|
lines
|
275
266
|
end
|
@@ -290,47 +281,33 @@ class File
|
|
290
281
|
# ArgumentError is raised.
|
291
282
|
#
|
292
283
|
def self.nl_convert(old_file, new_file = old_file, platform = 'local')
|
293
|
-
unless File::Stat.new(old_file).file?
|
294
|
-
raise ArgumentError, 'Only valid for plain text files'
|
295
|
-
end
|
284
|
+
raise ArgumentError, 'Only valid for plain text files' unless File::Stat.new(old_file).file?
|
296
285
|
|
297
286
|
format = nl_for_platform(platform)
|
298
287
|
|
299
|
-
orig = $\ # $OUTPUT_RECORD_SEPARATOR
|
300
|
-
$\ = format
|
301
|
-
|
302
288
|
if old_file == new_file
|
303
|
-
require 'fileutils'
|
304
289
|
require 'tempfile'
|
290
|
+
temp_name = Time.new.strftime('%Y%m%d%H%M%S')
|
291
|
+
nf = Tempfile.new("ruby_temp_#{temp_name}")
|
292
|
+
else
|
293
|
+
nf = File.new(new_file, 'w')
|
294
|
+
end
|
305
295
|
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
IO.foreach(old_file){ |line|
|
312
|
-
line.chomp!
|
313
|
-
tf.print line
|
314
|
-
}
|
315
|
-
ensure
|
316
|
-
tf.close if tf && !tf.closed?
|
296
|
+
begin
|
297
|
+
nf.open if old_file == new_file
|
298
|
+
File.foreach(old_file) do |line|
|
299
|
+
line.chomp!
|
300
|
+
nf.print("#{line}#{format}")
|
317
301
|
end
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
nf
|
324
|
-
IO.foreach(old_file){ |line|
|
325
|
-
line.chomp!
|
326
|
-
nf.print line
|
327
|
-
}
|
328
|
-
ensure
|
329
|
-
nf.close if nf && !nf.closed?
|
302
|
+
ensure
|
303
|
+
nf.close if nf && !nf.closed?
|
304
|
+
if old_file == new_file
|
305
|
+
require 'fileutils'
|
306
|
+
File.delete(old_file)
|
307
|
+
FileUtils.mv(nf.path, old_file)
|
330
308
|
end
|
331
309
|
end
|
332
310
|
|
333
|
-
$\ = orig
|
334
311
|
self
|
335
312
|
end
|
336
313
|
|
@@ -353,49 +330,43 @@ class File
|
|
353
330
|
# Valid options are 'bytes', 'characters' (or just 'chars'), 'words' and
|
354
331
|
# 'lines'.
|
355
332
|
#
|
356
|
-
def self.wc(filename, option='all')
|
333
|
+
def self.wc(filename, option = 'all')
|
357
334
|
option.downcase!
|
358
|
-
valid = %w
|
335
|
+
valid = %w[all bytes characters chars lines words]
|
359
336
|
|
360
|
-
unless valid.include?(option)
|
361
|
-
raise ArgumentError, "Invalid option: '#{option}'"
|
362
|
-
end
|
337
|
+
raise ArgumentError, "Invalid option: '#{option}'" unless valid.include?(option)
|
363
338
|
|
364
339
|
n = 0
|
365
340
|
|
366
341
|
if option == 'lines'
|
367
|
-
|
368
|
-
|
342
|
+
File.foreach(filename){ n += 1 }
|
343
|
+
n
|
369
344
|
elsif option == 'bytes'
|
370
|
-
File.open(filename)
|
345
|
+
File.open(filename) do |f|
|
371
346
|
f.each_byte{ n += 1 }
|
372
|
-
|
373
|
-
|
374
|
-
elsif
|
375
|
-
File.open(filename)
|
376
|
-
while f.getc
|
377
|
-
|
378
|
-
|
379
|
-
}
|
380
|
-
return n
|
347
|
+
end
|
348
|
+
n
|
349
|
+
elsif %w[characters chars].include?(option)
|
350
|
+
File.open(filename) do |f|
|
351
|
+
n += 1 while f.getc
|
352
|
+
end
|
353
|
+
n
|
381
354
|
elsif option == 'words'
|
382
|
-
|
355
|
+
File.foreach(filename) do |line|
|
383
356
|
n += line.split.length
|
384
|
-
|
385
|
-
|
357
|
+
end
|
358
|
+
n
|
386
359
|
else
|
387
|
-
bytes,chars,lines,words = 0,0,0,0
|
388
|
-
|
360
|
+
bytes, chars, lines, words = 0, 0, 0, 0
|
361
|
+
File.foreach(filename) do |line|
|
389
362
|
lines += 1
|
390
363
|
words += line.split.length
|
391
|
-
chars += line.
|
392
|
-
|
393
|
-
File.open(filename)
|
394
|
-
while f.getc
|
395
|
-
|
396
|
-
|
397
|
-
}
|
398
|
-
return [bytes,chars,words,lines]
|
364
|
+
chars += line.chars.length
|
365
|
+
end
|
366
|
+
File.open(filename) do |f|
|
367
|
+
bytes += 1 while f.getc
|
368
|
+
end
|
369
|
+
[bytes, chars, words, lines]
|
399
370
|
end
|
400
371
|
end
|
401
372
|
|
@@ -422,9 +393,9 @@ class File
|
|
422
393
|
text = File.read(file, 4).force_encoding('utf-8')
|
423
394
|
|
424
395
|
bool = false
|
425
|
-
bool = true if text[0,3] == "\xEF\xBB\xBF"
|
426
|
-
bool = true if text[0,4] == "\x00\x00\xFE\xFF" || text[0,4] == "\xFF\xFE\x00\x00"
|
427
|
-
bool = true if text[0,2] == "\xFF\xFE" || text[0,2] == "\xFE\xFF"
|
396
|
+
bool = true if text[0, 3] == "\xEF\xBB\xBF"
|
397
|
+
bool = true if text[0, 4] == "\x00\x00\xFE\xFF" || text[0, 4] == "\xFF\xFE\x00\x00"
|
398
|
+
bool = true if text[0, 2] == "\xFF\xFE" || text[0, 2] == "\xFE\xFF"
|
428
399
|
|
429
400
|
bool
|
430
401
|
end
|
@@ -434,42 +405,43 @@ class File
|
|
434
405
|
# Returns the newline characters for the given platform.
|
435
406
|
#
|
436
407
|
def self.nl_for_platform(platform)
|
437
|
-
platform = RbConfig::CONFIG[
|
408
|
+
platform = RbConfig::CONFIG['host_os'] if platform == 'local'
|
438
409
|
|
439
410
|
case platform
|
440
411
|
when /dos|windows|win32|mswin|mingw/i
|
441
|
-
|
412
|
+
"\cM\cJ"
|
442
413
|
when /unix|linux|bsd|cygwin|osx|darwin|solaris|sunos/i
|
443
|
-
|
414
|
+
"\cJ"
|
444
415
|
when /mac|apple|macintosh/i
|
445
|
-
|
416
|
+
"\cM"
|
446
417
|
else
|
447
|
-
raise ArgumentError,
|
418
|
+
raise ArgumentError, 'Invalid platform string'
|
448
419
|
end
|
449
420
|
end
|
450
421
|
|
451
422
|
# Is the file a bitmap file?
|
452
423
|
#
|
453
424
|
def self.bmp?(file)
|
454
|
-
|
425
|
+
data = File.read(file, 6, nil, :encoding => 'binary')
|
426
|
+
data[0,2] == 'BM' && File.size(file) == data[2,4].unpack('i').first
|
455
427
|
end
|
456
428
|
|
457
429
|
# Is the file a jpeg file?
|
458
430
|
#
|
459
431
|
def self.jpg?(file)
|
460
|
-
|
432
|
+
File.read(file, 10, nil, :encoding => 'binary') == "\377\330\377\340\000\020JFIF".force_encoding(Encoding::BINARY)
|
461
433
|
end
|
462
434
|
|
463
435
|
# Is the file a png file?
|
464
436
|
#
|
465
437
|
def self.png?(file)
|
466
|
-
|
438
|
+
File.read(file, 4, nil, :encoding => 'binary') == "\211PNG".force_encoding(Encoding::BINARY)
|
467
439
|
end
|
468
440
|
|
469
441
|
# Is the file a gif?
|
470
442
|
#
|
471
443
|
def self.gif?(file)
|
472
|
-
[
|
444
|
+
%w[GIF89a GIF97a].include?(File.read(file, 6))
|
473
445
|
end
|
474
446
|
|
475
447
|
# Is the file a tiff?
|
@@ -477,20 +449,14 @@ class File
|
|
477
449
|
def self.tiff?(file)
|
478
450
|
return false if File.size(file) < 12
|
479
451
|
|
480
|
-
bytes =
|
452
|
+
bytes = File.read(file, 4)
|
481
453
|
|
482
454
|
# II is Intel, MM is Motorola
|
483
|
-
if bytes[0..1] != 'II' && bytes[0..1] != 'MM'
|
484
|
-
return false
|
485
|
-
end
|
455
|
+
return false if bytes[0..1] != 'II' && bytes[0..1] != 'MM'
|
486
456
|
|
487
|
-
if bytes[0..1] == 'II' && bytes[2..3].ord != 42
|
488
|
-
return false
|
489
|
-
end
|
457
|
+
return false if bytes[0..1] == 'II' && bytes[2..3].ord != 42
|
490
458
|
|
491
|
-
if bytes[0..1] == 'MM' && bytes[2..3].reverse.ord != 42
|
492
|
-
return false
|
493
|
-
end
|
459
|
+
return false if bytes[0..1] == 'MM' && bytes[2..3].reverse.ord != 42
|
494
460
|
|
495
461
|
true
|
496
462
|
end
|
@@ -498,6 +464,6 @@ class File
|
|
498
464
|
# Is the file an ico file?
|
499
465
|
#
|
500
466
|
def self.ico?(file)
|
501
|
-
["\000\000\001\000", "\000\000\002\000"].include?(
|
467
|
+
["\000\000\001\000", "\000\000\002\000"].include?(File.read(file, 4, nil, :encoding => 'binary'))
|
502
468
|
end
|
503
469
|
end
|
data/ptools.gemspec
CHANGED
@@ -2,8 +2,8 @@ require 'rbconfig'
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = 'ptools'
|
5
|
-
spec.version = '1.
|
6
|
-
spec.license = '
|
5
|
+
spec.version = '1.5.0'
|
6
|
+
spec.license = 'Apache-2.0'
|
7
7
|
spec.author = 'Daniel J. Berger'
|
8
8
|
spec.email = 'djberg96@gmail.com'
|
9
9
|
spec.homepage = 'https://github.com/djberg96/ptools'
|
@@ -19,16 +19,19 @@ Gem::Specification.new do |spec|
|
|
19
19
|
EOF
|
20
20
|
|
21
21
|
spec.metadata = {
|
22
|
-
'homepage_uri'
|
23
|
-
'bug_tracker_uri'
|
24
|
-
'changelog_uri'
|
25
|
-
'documentation_uri'
|
26
|
-
'source_code_uri'
|
27
|
-
'wiki_uri'
|
22
|
+
'homepage_uri' => 'https://github.com/djberg96/ptools',
|
23
|
+
'bug_tracker_uri' => 'https://github.com/djberg96/ptools/issues',
|
24
|
+
'changelog_uri' => 'https://github.com/djberg96/ptools/blob/main/CHANGES.md',
|
25
|
+
'documentation_uri' => 'https://github.com/djberg96/ptools/wiki',
|
26
|
+
'source_code_uri' => 'https://github.com/djberg96/ptools',
|
27
|
+
'wiki_uri' => 'https://github.com/djberg96/ptools/wiki',
|
28
|
+
'rubygems_mfa_required' => 'true'
|
28
29
|
}
|
29
30
|
|
30
31
|
spec.add_development_dependency('rake')
|
31
32
|
spec.add_development_dependency('rspec', '~> 3.9')
|
33
|
+
spec.add_development_dependency('rubocop')
|
34
|
+
spec.add_development_dependency('rubocop-rspec')
|
32
35
|
|
33
36
|
if File::ALT_SEPARATOR
|
34
37
|
spec.platform = Gem::Platform.new(['universal', 'mingw32'])
|
data/spec/binary_spec.rb
CHANGED
@@ -9,51 +9,52 @@ require 'rspec'
|
|
9
9
|
require 'ptools'
|
10
10
|
|
11
11
|
RSpec.describe File, :binary do
|
12
|
-
let(:dirname) {
|
13
|
-
let(:bin_file) { File::ALT_SEPARATOR ?
|
12
|
+
let(:dirname) { described_class.dirname(__FILE__) }
|
13
|
+
let(:bin_file) { File::ALT_SEPARATOR ? described_class.join(ENV['windir'], 'notepad.exe') : '/bin/ls' }
|
14
14
|
|
15
15
|
before do
|
16
|
-
@txt_file =
|
17
|
-
@emp_file =
|
18
|
-
@uni_file =
|
19
|
-
@utf_file =
|
20
|
-
@png_file =
|
21
|
-
@jpg_file =
|
22
|
-
@gif_file =
|
16
|
+
@txt_file = described_class.join(dirname, 'txt', 'english.txt')
|
17
|
+
@emp_file = described_class.join(dirname, 'txt', 'empty.txt')
|
18
|
+
@uni_file = described_class.join(dirname, 'txt', 'korean.txt')
|
19
|
+
@utf_file = described_class.join(dirname, 'txt', 'english.utf16')
|
20
|
+
@png_file = described_class.join(dirname, 'img', 'test.png')
|
21
|
+
@jpg_file = described_class.join(dirname, 'img', 'test.jpg')
|
22
|
+
@gif_file = described_class.join(dirname, 'img', 'test.gif')
|
23
23
|
end
|
24
24
|
|
25
|
-
example
|
26
|
-
expect(
|
27
|
-
expect{
|
25
|
+
example 'File.binary? basic functionality' do
|
26
|
+
expect(described_class).to respond_to(:binary?)
|
27
|
+
expect{ described_class.binary?(@txt_file) }.not_to raise_error
|
28
28
|
end
|
29
29
|
|
30
|
-
example
|
31
|
-
expect(
|
30
|
+
example 'File.binary? returns true for binary files' do
|
31
|
+
expect(described_class.binary?(bin_file)).to be true
|
32
32
|
end
|
33
33
|
|
34
|
-
example
|
35
|
-
expect(
|
36
|
-
expect(
|
37
|
-
expect(
|
38
|
-
expect(File.binary?(@utf_file)).to be false
|
34
|
+
example 'File.binary? returns true for unix binary files', :unix_only => true do
|
35
|
+
expect(described_class.binary?('/bin/df')).to be true
|
36
|
+
expect(described_class.binary?('/bin/chmod')).to be true
|
37
|
+
expect(described_class.binary?('/bin/cat')).to be true
|
39
38
|
end
|
40
39
|
|
41
|
-
example
|
42
|
-
expect(
|
43
|
-
expect(
|
44
|
-
expect(
|
40
|
+
example 'File.binary? returns false for text files' do
|
41
|
+
expect(described_class.binary?(@emp_file)).to be false
|
42
|
+
expect(described_class.binary?(@txt_file)).to be false
|
43
|
+
expect(described_class.binary?(@uni_file)).to be false
|
44
|
+
expect(described_class.binary?(@utf_file)).to be false
|
45
45
|
end
|
46
46
|
|
47
|
-
example
|
48
|
-
expect(
|
49
|
-
expect(
|
47
|
+
example 'File.binary? returns false for image files' do
|
48
|
+
expect(described_class.binary?(@png_file)).to be false
|
49
|
+
expect(described_class.binary?(@jpg_file)).to be false
|
50
|
+
expect(described_class.binary?(@gif_file)).to be false
|
50
51
|
end
|
51
52
|
|
52
|
-
example
|
53
|
-
expect{
|
53
|
+
example 'File.binary? raises an error if the file cannot be found' do
|
54
|
+
expect{ described_class.binary?('bogus') }.to raise_error(SystemCallError)
|
54
55
|
end
|
55
56
|
|
56
|
-
example
|
57
|
-
expect{
|
57
|
+
example 'File.binary? only accepts one argument' do
|
58
|
+
expect{ described_class.binary?(@txt_file, bin_file) }.to raise_error(ArgumentError)
|
58
59
|
end
|
59
60
|
end
|
data/spec/constants_spec.rb
CHANGED
@@ -12,12 +12,12 @@ require 'ptools'
|
|
12
12
|
RSpec.describe File, :constants do
|
13
13
|
let(:windows) { File::ALT_SEPARATOR }
|
14
14
|
|
15
|
-
example
|
16
|
-
expect(File::PTOOLS_VERSION).to eq('1.
|
15
|
+
example 'PTOOLS_VERSION constant is set to expected value' do
|
16
|
+
expect(File::PTOOLS_VERSION).to eq('1.5.0')
|
17
17
|
expect(File::PTOOLS_VERSION.frozen?).to be true
|
18
18
|
end
|
19
19
|
|
20
|
-
example
|
20
|
+
example 'IMAGE_EXT constant is set to array of values' do
|
21
21
|
expect(File::IMAGE_EXT).to match_array(%w[.bmp .gif .ico .jpeg .jpg .png])
|
22
22
|
end
|
23
23
|
end
|
data/spec/head_spec.rb
CHANGED
@@ -11,31 +11,31 @@ RSpec.describe File, :head do
|
|
11
11
|
let(:test_file) { 'test_file_head.txt' }
|
12
12
|
|
13
13
|
before do
|
14
|
-
|
15
|
-
@expected_head1 = [
|
16
|
-
@expected_head1.push("line6\n","line7\n","line8\n","line9\n","line10\n")
|
17
|
-
@expected_head2 = [
|
14
|
+
described_class.open(test_file, 'w'){ |fh| 25.times{ |n| fh.puts "line#{n+1}" } }
|
15
|
+
@expected_head1 = %W[line1\n line2\n line3\n line4\n line5\n]
|
16
|
+
@expected_head1.push("line6\n", "line7\n", "line8\n", "line9\n", "line10\n")
|
17
|
+
@expected_head2 = %W[line1\n line2\n line3\n line4\n line5\n]
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
expect{ File.head(test_file) }.not_to raise_error
|
23
|
-
expect{ File.head(test_file, 5) }.not_to raise_error
|
24
|
-
expect{ File.head(test_file){} }.not_to raise_error
|
20
|
+
after do
|
21
|
+
described_class.delete(test_file) if described_class.exist?(test_file)
|
25
22
|
end
|
26
23
|
|
27
|
-
example
|
28
|
-
expect(
|
29
|
-
expect
|
30
|
-
expect
|
24
|
+
example 'head method basic functionality' do
|
25
|
+
expect(described_class).to respond_to(:head)
|
26
|
+
expect{ described_class.head(test_file) }.not_to raise_error
|
27
|
+
expect{ described_class.head(test_file, 5) }.not_to raise_error
|
28
|
+
expect{ described_class.head(test_file){} }.not_to raise_error
|
31
29
|
end
|
32
30
|
|
33
|
-
example
|
34
|
-
expect
|
35
|
-
expect
|
31
|
+
example 'head method returns the expected results' do
|
32
|
+
expect(described_class.head(test_file)).to be_kind_of(Array)
|
33
|
+
expect(described_class.head(test_file)).to eq(@expected_head1)
|
34
|
+
expect(described_class.head(test_file, 5)).to eq(@expected_head2)
|
36
35
|
end
|
37
36
|
|
38
|
-
|
39
|
-
|
37
|
+
example 'head method requires two arguments' do
|
38
|
+
expect{ described_class.head(test_file, 5, 'foo') }.to raise_error(ArgumentError)
|
39
|
+
expect{ described_class.head('bogus') }.to raise_error(Errno::ENOENT)
|
40
40
|
end
|
41
41
|
end
|