ptools 1.4.2-universal-mingw32 → 1.4.3-universal-mingw32
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
- checksums.yaml.gz.sig +0 -0
- data/CHANGES.md +5 -0
- data/MANIFEST.md +1 -0
- data/README.md +29 -24
- data/Rakefile +4 -1
- data/lib/ptools.rb +92 -119
- data/ptools.gemspec +10 -7
- data/spec/binary_spec.rb +30 -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 +37 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 62ddf1987bbb18bc423f29d935e20c777be8a4c7b8761868dea85e2b0dfd34b0
|
4
|
+
data.tar.gz: 0c159601c5f2c369c6dea2a5690c852f1bd4f2f2758a56a46bfe68aac5634558
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e555a0fb96caedb8f3dbc19d932aa4399ba21f711f0b7fc1cdddc585d0b6623fbb59a81f5ec204e44bafc3f0ebeea2138556cc2b2755042a82f8b9827c118a9
|
7
|
+
data.tar.gz: 6beaaabc8fe9dd953153adf0a0a03727584a9abd905c09b52b22d7881ff8eb30155b415e46375a64e750c9016cb2bb2fb04482f98bfa1e4dd59e5b4d2845a16b
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
## 1.4.3 - 26-Nov-2022
|
2
|
+
* Added more image specs.
|
3
|
+
* Updated the File.bmp? method. It now looks at the first six bytes, and
|
4
|
+
uses four of those bytes to verify the file size.
|
5
|
+
|
1
6
|
## 1.4.2 - 6-Jan-2021
|
2
7
|
* Fixed a private access modifier that wasn't actually working as intended.
|
3
8
|
* Two Windows constants that were never meant for public consumption have been marked private.
|
data/MANIFEST.md
CHANGED
data/README.md
CHANGED
@@ -1,13 +1,18 @@
|
|
1
|
+
[](https://github.com/djberg96/ptools/actions/workflows/ruby.yml)
|
2
|
+
|
1
3
|
## Description
|
2
|
-
|
3
|
-
|
4
|
+
The ptools (power tools) library is an additional set of commands for the
|
5
|
+
File class based on Unix command line tools.
|
4
6
|
|
5
7
|
## Prerequisites
|
6
|
-
|
8
|
+
On MS Windows you will need the win32-file gem.
|
7
9
|
|
8
10
|
## Installation
|
9
11
|
`gem install ptools`
|
10
12
|
|
13
|
+
## Adding the trusted cert
|
14
|
+
`gem cert --add <(curl -Ls https://raw.githubusercontent.com/djberg96/ptools/main/certs/djberg96_pub.pem)`
|
15
|
+
|
11
16
|
## Synopsis
|
12
17
|
```ruby
|
13
18
|
require "ptools"
|
@@ -29,42 +34,42 @@ File.nl_convert("myfile", "newfile", "dos")
|
|
29
34
|
```
|
30
35
|
|
31
36
|
## Known Bugs
|
32
|
-
|
33
|
-
|
37
|
+
The File.which and File.whereis methods may fail when using JRuby on Windows.
|
38
|
+
See https://github.com/jruby/jruby/issues/2291 for details.
|
34
39
|
|
35
|
-
|
40
|
+
Please report any other issues on the github project page.
|
36
41
|
|
37
|
-
|
42
|
+
http://www.github.com/djberg96/ptools
|
38
43
|
|
39
44
|
## Acknowledgements
|
40
|
-
|
41
|
-
|
42
|
-
|
45
|
+
The `File.which` method was originally adopted from the `FileWhich` code posted
|
46
|
+
by Michael Granger on the now defunct rubygarden.org website. That code was
|
47
|
+
later replaced by a version based on the `ruby-which` library.
|
43
48
|
|
44
|
-
|
45
|
-
|
49
|
+
The `File.nl_convert` method is based on the nlcvt program found at
|
50
|
+
http://www.perl.com/language/ppt/src/nlcvt/nlcvt, written by Tom Christiansen.
|
46
51
|
|
47
|
-
|
48
|
-
|
52
|
+
The `binary?` method was based almost entirely on a blog post by Ryan
|
53
|
+
Davis (who, in turn, based his code on Perl's -B switch).
|
49
54
|
|
50
|
-
|
55
|
+
Thanks go to Matt Hoyle for help with the File.tail method.
|
51
56
|
|
52
|
-
|
57
|
+
And thanks to any and all contributors!
|
53
58
|
|
54
59
|
## Future Plans
|
55
|
-
|
60
|
+
Add whatever other tools people think might be useful.
|
56
61
|
|
57
62
|
## License
|
58
|
-
|
63
|
+
Artistic-2.0
|
59
64
|
|
60
65
|
## Copyright
|
61
|
-
|
62
|
-
|
66
|
+
(C) 2003-2022 Daniel J. Berger
|
67
|
+
All Rights Reserved.
|
63
68
|
|
64
69
|
## Warranty
|
65
|
-
|
66
|
-
|
67
|
-
|
70
|
+
This package is provided "as is" and without any express or
|
71
|
+
implied warranties, including, without limitation, the implied
|
72
|
+
warranties of merchantability and fitness for a particular purpose.
|
68
73
|
|
69
74
|
## Author
|
70
|
-
|
75
|
+
Daniel J. Berger
|
data/Rakefile
CHANGED
@@ -3,6 +3,7 @@ require 'rake/clean'
|
|
3
3
|
require 'rake/testtask'
|
4
4
|
require 'rbconfig'
|
5
5
|
require 'rspec/core/rake_task'
|
6
|
+
require 'rubocop/rake_task'
|
6
7
|
include RbConfig
|
7
8
|
|
8
9
|
CLEAN.include("**/*.gem", "**/*.rbc", "**/*coverage*", "**/*.lock")
|
@@ -18,7 +19,7 @@ namespace 'gem' do
|
|
18
19
|
desc 'Create the ptools gem'
|
19
20
|
task :create => [:clean] do
|
20
21
|
require 'rubygems/package'
|
21
|
-
spec =
|
22
|
+
spec = Gem::Specification.load('ptools.gemspec')
|
22
23
|
spec.signing_key = File.join(Dir.home, '.ssh', 'gem-private_key.pem')
|
23
24
|
Gem::Package.build(spec)
|
24
25
|
end
|
@@ -84,4 +85,6 @@ namespace 'spec' do
|
|
84
85
|
end
|
85
86
|
end
|
86
87
|
|
88
|
+
RuboCop::RakeTask.new
|
89
|
+
|
87
90
|
task :default => 'spec:all'
|
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.4.
|
6
|
+
PTOOLS_VERSION = '1.4.3'.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,12 +47,10 @@ 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
|
@@ -78,11 +76,12 @@ class File
|
|
78
76
|
return false if File.stat(file).zero?
|
79
77
|
return false if image?(file)
|
80
78
|
return false if check_bom?(file)
|
79
|
+
|
81
80
|
bytes = File.stat(file).blksize
|
82
81
|
bytes = 4096 if bytes > 4096
|
83
|
-
s = (File.read(file, bytes) ||
|
84
|
-
s = s.encode('US-ASCII', :undef => :replace).
|
85
|
-
((s.size - s.grep(
|
82
|
+
s = (File.read(file, bytes) || '')
|
83
|
+
s = s.encode('US-ASCII', :undef => :replace).chars
|
84
|
+
((s.size - s.grep(' '..'~').size) / s.size.to_f) > percentage
|
86
85
|
end
|
87
86
|
|
88
87
|
# Looks for the first occurrence of +program+ within +path+.
|
@@ -98,10 +97,8 @@ class File
|
|
98
97
|
# File.which('ruby') # => '/usr/local/bin/ruby'
|
99
98
|
# File.which('foo') # => nil
|
100
99
|
#
|
101
|
-
def self.which(program, path=ENV['PATH'])
|
102
|
-
if path.nil? || path.empty?
|
103
|
-
raise ArgumentError, "path cannot be empty"
|
104
|
-
end
|
100
|
+
def self.which(program, path = ENV['PATH'])
|
101
|
+
raise ArgumentError, 'path cannot be empty' if path.nil? || path.empty?
|
105
102
|
|
106
103
|
# Bail out early if an absolute path is provided.
|
107
104
|
if program =~ /^\/|^[a-z]:[\\\/]/i
|
@@ -115,16 +112,17 @@ class File
|
|
115
112
|
end
|
116
113
|
|
117
114
|
# Iterate over each path glob the dir + program.
|
118
|
-
path.split(File::PATH_SEPARATOR).each
|
115
|
+
path.split(File::PATH_SEPARATOR).each do |dir|
|
119
116
|
dir = File.expand_path(dir)
|
120
117
|
|
121
118
|
next unless File.exist?(dir) # In case of bogus second argument
|
119
|
+
|
122
120
|
file = File.join(dir, program)
|
123
121
|
|
124
122
|
# Dir[] doesn't handle backslashes properly, so convert them. Also, if
|
125
123
|
# the program name doesn't have an extension, try them all.
|
126
124
|
if MSWINDOWS
|
127
|
-
file = file.tr(
|
125
|
+
file = file.tr(File::ALT_SEPARATOR, File::SEPARATOR)
|
128
126
|
file += WIN32EXTS if File.extname(program).empty?
|
129
127
|
end
|
130
128
|
|
@@ -135,7 +133,7 @@ class File
|
|
135
133
|
found.tr!(File::SEPARATOR, File::ALT_SEPARATOR) if File::ALT_SEPARATOR
|
136
134
|
return found
|
137
135
|
end
|
138
|
-
|
136
|
+
end
|
139
137
|
|
140
138
|
nil
|
141
139
|
end
|
@@ -152,21 +150,19 @@ class File
|
|
152
150
|
# File.whereis('ruby') # => ['/usr/bin/ruby', '/usr/local/bin/ruby']
|
153
151
|
# File.whereis('foo') # => nil
|
154
152
|
#
|
155
|
-
def self.whereis(program, path=ENV['PATH'])
|
156
|
-
if path.nil? || path.empty?
|
157
|
-
raise ArgumentError, "path cannot be empty"
|
158
|
-
end
|
153
|
+
def self.whereis(program, path = ENV['PATH'])
|
154
|
+
raise ArgumentError, 'path cannot be empty' if path.nil? || path.empty?
|
159
155
|
|
160
156
|
paths = []
|
161
157
|
|
162
158
|
# Bail out early if an absolute path is provided.
|
163
159
|
if program =~ /^\/|^[a-z]:[\\\/]/i
|
164
160
|
program += WIN32EXTS if MSWINDOWS && File.extname(program).empty?
|
165
|
-
program = program.tr(
|
161
|
+
program = program.tr(File::ALT_SEPARATOR, File::SEPARATOR) if MSWINDOWS
|
166
162
|
found = Dir[program]
|
167
163
|
if found[0] && File.executable?(found[0]) && !File.directory?(found[0])
|
168
164
|
if File::ALT_SEPARATOR
|
169
|
-
return found.map{ |f| f.tr(
|
165
|
+
return found.map{ |f| f.tr(File::SEPARATOR, File::ALT_SEPARATOR) }
|
170
166
|
else
|
171
167
|
return found
|
172
168
|
end
|
@@ -176,14 +172,15 @@ class File
|
|
176
172
|
end
|
177
173
|
|
178
174
|
# Iterate over each path glob the dir + program.
|
179
|
-
path.split(File::PATH_SEPARATOR).each
|
175
|
+
path.split(File::PATH_SEPARATOR).each do |dir|
|
180
176
|
next unless File.exist?(dir) # In case of bogus second argument
|
177
|
+
|
181
178
|
file = File.join(dir, program)
|
182
179
|
|
183
180
|
# Dir[] doesn't handle backslashes properly, so convert them. Also, if
|
184
181
|
# the program name doesn't have an extension, try them all.
|
185
182
|
if MSWINDOWS
|
186
|
-
file = file.tr(
|
183
|
+
file = file.tr(File::ALT_SEPARATOR, File::SEPARATOR)
|
187
184
|
file += WIN32EXTS if File.extname(program).empty?
|
188
185
|
end
|
189
186
|
|
@@ -194,7 +191,7 @@ class File
|
|
194
191
|
found.tr!(File::SEPARATOR, File::ALT_SEPARATOR) if File::ALT_SEPARATOR
|
195
192
|
paths << found
|
196
193
|
end
|
197
|
-
|
194
|
+
end
|
198
195
|
|
199
196
|
paths.empty? ? nil : paths.uniq
|
200
197
|
end
|
@@ -210,20 +207,21 @@ class File
|
|
210
207
|
# # Use a block
|
211
208
|
# File.head('somefile.txt'){ |line| puts line }
|
212
209
|
#
|
213
|
-
def self.head(filename, num_lines=10)
|
210
|
+
def self.head(filename, num_lines = 10)
|
214
211
|
a = []
|
215
212
|
|
216
|
-
|
213
|
+
File.foreach(filename) do |line|
|
217
214
|
break if num_lines <= 0
|
215
|
+
|
218
216
|
num_lines -= 1
|
219
217
|
if block_given?
|
220
218
|
yield line
|
221
219
|
else
|
222
220
|
a << line
|
223
221
|
end
|
224
|
-
|
222
|
+
end
|
225
223
|
|
226
|
-
|
224
|
+
a.empty? ? nil : a # Return nil in block form
|
227
225
|
end
|
228
226
|
|
229
227
|
# In block form, yields the last +num_lines+ of file +filename+.
|
@@ -240,7 +238,7 @@ class File
|
|
240
238
|
# Internally I'm using a 64 chunk of memory at a time. I may allow the size
|
241
239
|
# to be configured in the future as an optional 3rd argument.
|
242
240
|
#
|
243
|
-
def self.tail(filename, num_lines=10)
|
241
|
+
def self.tail(filename, num_lines = 10, &block)
|
244
242
|
tail_size = 2**16 # 64k chunks
|
245
243
|
|
246
244
|
# MS Windows gets unhappy if you try to seek backwards past the
|
@@ -254,7 +252,7 @@ class File
|
|
254
252
|
buf = ''
|
255
253
|
|
256
254
|
# Open in binary mode to ensure line endings aren't converted.
|
257
|
-
File.open(filename, 'rb')
|
255
|
+
File.open(filename, 'rb') do |fh|
|
258
256
|
position = file_size - read_bytes # Set the starting read position
|
259
257
|
|
260
258
|
# Loop until we have the lines or run out of file
|
@@ -264,12 +262,12 @@ class File
|
|
264
262
|
read_bytes = tail_size
|
265
263
|
position -= read_bytes
|
266
264
|
end
|
267
|
-
|
265
|
+
end
|
268
266
|
|
269
267
|
lines = buf.split(line_sep).pop(num_lines)
|
270
268
|
|
271
269
|
if block_given?
|
272
|
-
lines.each
|
270
|
+
lines.each(&block)
|
273
271
|
else
|
274
272
|
lines
|
275
273
|
end
|
@@ -290,47 +288,33 @@ class File
|
|
290
288
|
# ArgumentError is raised.
|
291
289
|
#
|
292
290
|
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
|
291
|
+
raise ArgumentError, 'Only valid for plain text files' unless File::Stat.new(old_file).file?
|
296
292
|
|
297
293
|
format = nl_for_platform(platform)
|
298
294
|
|
299
|
-
orig = $\ # $OUTPUT_RECORD_SEPARATOR
|
300
|
-
$\ = format
|
301
|
-
|
302
295
|
if old_file == new_file
|
303
|
-
require 'fileutils'
|
304
296
|
require 'tempfile'
|
297
|
+
temp_name = Time.new.strftime('%Y%m%d%H%M%S')
|
298
|
+
nf = Tempfile.new("ruby_temp_#{temp_name}")
|
299
|
+
else
|
300
|
+
nf = File.new(new_file, 'w')
|
301
|
+
end
|
305
302
|
|
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?
|
303
|
+
begin
|
304
|
+
nf.open if old_file == new_file
|
305
|
+
File.foreach(old_file) do |line|
|
306
|
+
line.chomp!
|
307
|
+
nf.print("#{line}#{format}")
|
317
308
|
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?
|
309
|
+
ensure
|
310
|
+
nf.close if nf && !nf.closed?
|
311
|
+
if old_file == new_file
|
312
|
+
require 'fileutils'
|
313
|
+
File.delete(old_file)
|
314
|
+
FileUtils.mv(nf.path, old_file)
|
330
315
|
end
|
331
316
|
end
|
332
317
|
|
333
|
-
$\ = orig
|
334
318
|
self
|
335
319
|
end
|
336
320
|
|
@@ -353,49 +337,43 @@ class File
|
|
353
337
|
# Valid options are 'bytes', 'characters' (or just 'chars'), 'words' and
|
354
338
|
# 'lines'.
|
355
339
|
#
|
356
|
-
def self.wc(filename, option='all')
|
340
|
+
def self.wc(filename, option = 'all')
|
357
341
|
option.downcase!
|
358
|
-
valid = %w
|
342
|
+
valid = %w[all bytes characters chars lines words]
|
359
343
|
|
360
|
-
unless valid.include?(option)
|
361
|
-
raise ArgumentError, "Invalid option: '#{option}'"
|
362
|
-
end
|
344
|
+
raise ArgumentError, "Invalid option: '#{option}'" unless valid.include?(option)
|
363
345
|
|
364
346
|
n = 0
|
365
347
|
|
366
348
|
if option == 'lines'
|
367
|
-
|
368
|
-
|
349
|
+
File.foreach(filename){ n += 1 }
|
350
|
+
n
|
369
351
|
elsif option == 'bytes'
|
370
|
-
File.open(filename)
|
352
|
+
File.open(filename) do |f|
|
371
353
|
f.each_byte{ n += 1 }
|
372
|
-
|
373
|
-
|
374
|
-
elsif
|
375
|
-
File.open(filename)
|
376
|
-
while f.getc
|
377
|
-
|
378
|
-
|
379
|
-
}
|
380
|
-
return n
|
354
|
+
end
|
355
|
+
n
|
356
|
+
elsif %w[characters chars].include?(option)
|
357
|
+
File.open(filename) do |f|
|
358
|
+
n += 1 while f.getc
|
359
|
+
end
|
360
|
+
n
|
381
361
|
elsif option == 'words'
|
382
|
-
|
362
|
+
File.foreach(filename) do |line|
|
383
363
|
n += line.split.length
|
384
|
-
|
385
|
-
|
364
|
+
end
|
365
|
+
n
|
386
366
|
else
|
387
|
-
bytes,chars,lines,words = 0,0,0,0
|
388
|
-
|
367
|
+
bytes, chars, lines, words = 0, 0, 0, 0
|
368
|
+
File.foreach(filename) do |line|
|
389
369
|
lines += 1
|
390
370
|
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]
|
371
|
+
chars += line.chars.length
|
372
|
+
end
|
373
|
+
File.open(filename) do |f|
|
374
|
+
bytes += 1 while f.getc
|
375
|
+
end
|
376
|
+
[bytes, chars, words, lines]
|
399
377
|
end
|
400
378
|
end
|
401
379
|
|
@@ -422,9 +400,9 @@ class File
|
|
422
400
|
text = File.read(file, 4).force_encoding('utf-8')
|
423
401
|
|
424
402
|
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"
|
403
|
+
bool = true if text[0, 3] == "\xEF\xBB\xBF"
|
404
|
+
bool = true if text[0, 4] == "\x00\x00\xFE\xFF" || text[0, 4] == "\xFF\xFE\x00\x00"
|
405
|
+
bool = true if text[0, 2] == "\xFF\xFE" || text[0, 2] == "\xFE\xFF"
|
428
406
|
|
429
407
|
bool
|
430
408
|
end
|
@@ -434,42 +412,43 @@ class File
|
|
434
412
|
# Returns the newline characters for the given platform.
|
435
413
|
#
|
436
414
|
def self.nl_for_platform(platform)
|
437
|
-
platform = RbConfig::CONFIG[
|
415
|
+
platform = RbConfig::CONFIG['host_os'] if platform == 'local'
|
438
416
|
|
439
417
|
case platform
|
440
418
|
when /dos|windows|win32|mswin|mingw/i
|
441
|
-
|
419
|
+
"\cM\cJ"
|
442
420
|
when /unix|linux|bsd|cygwin|osx|darwin|solaris|sunos/i
|
443
|
-
|
421
|
+
"\cJ"
|
444
422
|
when /mac|apple|macintosh/i
|
445
|
-
|
423
|
+
"\cM"
|
446
424
|
else
|
447
|
-
raise ArgumentError,
|
425
|
+
raise ArgumentError, 'Invalid platform string'
|
448
426
|
end
|
449
427
|
end
|
450
428
|
|
451
429
|
# Is the file a bitmap file?
|
452
430
|
#
|
453
431
|
def self.bmp?(file)
|
454
|
-
|
432
|
+
data = File.read(file, 6, nil, :encoding => 'binary')
|
433
|
+
data[0,2] == 'BM' && File.size(file) == data[2,4].unpack('i').first
|
455
434
|
end
|
456
435
|
|
457
436
|
# Is the file a jpeg file?
|
458
437
|
#
|
459
438
|
def self.jpg?(file)
|
460
|
-
|
439
|
+
File.read(file, 10, nil, :encoding => 'binary') == "\377\330\377\340\000\020JFIF".force_encoding(Encoding::BINARY)
|
461
440
|
end
|
462
441
|
|
463
442
|
# Is the file a png file?
|
464
443
|
#
|
465
444
|
def self.png?(file)
|
466
|
-
|
445
|
+
File.read(file, 4, nil, :encoding => 'binary') == "\211PNG".force_encoding(Encoding::BINARY)
|
467
446
|
end
|
468
447
|
|
469
448
|
# Is the file a gif?
|
470
449
|
#
|
471
450
|
def self.gif?(file)
|
472
|
-
[
|
451
|
+
%w[GIF89a GIF97a].include?(File.read(file, 6))
|
473
452
|
end
|
474
453
|
|
475
454
|
# Is the file a tiff?
|
@@ -477,20 +456,14 @@ class File
|
|
477
456
|
def self.tiff?(file)
|
478
457
|
return false if File.size(file) < 12
|
479
458
|
|
480
|
-
bytes =
|
459
|
+
bytes = File.read(file, 4)
|
481
460
|
|
482
461
|
# II is Intel, MM is Motorola
|
483
|
-
if bytes[0..1] != 'II' && bytes[0..1] != 'MM'
|
484
|
-
return false
|
485
|
-
end
|
462
|
+
return false if bytes[0..1] != 'II' && bytes[0..1] != 'MM'
|
486
463
|
|
487
|
-
if bytes[0..1] == 'II' && bytes[2..3].ord != 42
|
488
|
-
return false
|
489
|
-
end
|
464
|
+
return false if bytes[0..1] == 'II' && bytes[2..3].ord != 42
|
490
465
|
|
491
|
-
if bytes[0..1] == 'MM' && bytes[2..3].reverse.ord != 42
|
492
|
-
return false
|
493
|
-
end
|
466
|
+
return false if bytes[0..1] == 'MM' && bytes[2..3].reverse.ord != 42
|
494
467
|
|
495
468
|
true
|
496
469
|
end
|
@@ -498,6 +471,6 @@ class File
|
|
498
471
|
# Is the file an ico file?
|
499
472
|
#
|
500
473
|
def self.ico?(file)
|
501
|
-
["\000\000\001\000", "\000\000\002\000"].include?(
|
474
|
+
["\000\000\001\000", "\000\000\002\000"].include?(File.read(file, 4, nil, :encoding => 'binary'))
|
502
475
|
end
|
503
476
|
end
|
data/ptools.gemspec
CHANGED
@@ -2,7 +2,7 @@ require 'rbconfig'
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = 'ptools'
|
5
|
-
spec.version = '1.4.
|
5
|
+
spec.version = '1.4.3'
|
6
6
|
spec.license = 'Artistic-2.0'
|
7
7
|
spec.author = 'Daniel J. Berger'
|
8
8
|
spec.email = 'djberg96@gmail.com'
|
@@ -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'])
|