ptools 1.4.2-universal-mingw32 → 1.4.3-universal-mingw32
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 +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
|
+
[![Ruby](https://github.com/djberg96/ptools/actions/workflows/ruby.yml/badge.svg)](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'])
|