ptools 1.5.0 → 1.5.2
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 +14 -0
- data/Rakefile +1 -0
- data/lib/ptools.rb +35 -34
- data/ptools.gemspec +4 -2
- data/spec/binary_spec.rb +1 -1
- data/spec/constants_spec.rb +1 -1
- data/spec/head_spec.rb +1 -1
- data/spec/tail_spec.rb +1 -1
- data/spec/wc_spec.rb +1 -1
- data/spec/whereis_spec.rb +4 -3
- data/spec/which_spec.rb +9 -6
- data.tar.gz.sig +0 -0
- metadata +5 -6
- 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: 52a384685fb45ac34ece293d9737f556d741f78072e000a36747ef940944f269
|
|
4
|
+
data.tar.gz: 6c0958dbcbd53d5f95787b16356c0f5b5f741a605ef572460b1332ae01e8bce9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 77fbacd1d02cd4f9b3c9b934d841f5f546709f524f63f67b87bc11d24afd94d14699811958c826fa81a67e29325467993602d99d8fe035978e6328b8ed6142a4
|
|
7
|
+
data.tar.gz: b322c4c6e990af6dade89f9182b745abccfb54e108752ffe6ffd63f392f94d86b930a3ff73912f1a3c9a62b9023bc55f2b586d157bdfe228ee79cdb490184c7f
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 1.5.2 - 4-Dec-2025
|
|
2
|
+
* Reverted a change that was causing frozen string warnings in Ruby 3.4.x.
|
|
3
|
+
Thanks go to Daniel Straßner for the report.
|
|
4
|
+
* Fixed a potential warning in the wc method.
|
|
5
|
+
* Updated the Rakefile to run specs with warnings enabled by default.
|
|
6
|
+
|
|
7
|
+
## 1.5.1 - 27-Nov-2025
|
|
8
|
+
* Refactoring release.
|
|
9
|
+
* The wc('all') method now only does a single read instead of a double read.
|
|
10
|
+
* The nl_convert method simplified to use the block form of File.open.
|
|
11
|
+
* More consistent binary encoding calls.
|
|
12
|
+
* Some magic numbers were replaced with constants.
|
|
13
|
+
* Specs run in documentation mode.
|
|
14
|
+
|
|
1
15
|
## 1.5.0 - 5-Dec-2022
|
|
2
16
|
* Change license to Apache-2.0.
|
|
3
17
|
* Altered the File.binary? method. It no longer accepts a second argument,
|
data/Rakefile
CHANGED
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.5.
|
|
6
|
+
PTOOLS_VERSION = '1.5.2'.freeze
|
|
7
7
|
|
|
8
8
|
# :stopdoc:
|
|
9
9
|
|
|
@@ -11,7 +11,7 @@ class File
|
|
|
11
11
|
if File::ALT_SEPARATOR
|
|
12
12
|
MSWINDOWS = true
|
|
13
13
|
if ENV['PATHEXT']
|
|
14
|
-
WIN32EXTS = ".{#{ENV['PATHEXT'].tr(';', ',').tr('.', '')}}".downcase
|
|
14
|
+
WIN32EXTS = String.new(".{#{ENV['PATHEXT'].tr(';', ',').tr('.', '')}}").downcase
|
|
15
15
|
else
|
|
16
16
|
WIN32EXTS = '.{exe,com,bat}'.freeze
|
|
17
17
|
end
|
|
@@ -26,6 +26,10 @@ class File
|
|
|
26
26
|
|
|
27
27
|
IMAGE_EXT = %w[.bmp .gif .jpg .jpeg .png .ico].freeze
|
|
28
28
|
|
|
29
|
+
# Constants for file operations
|
|
30
|
+
BLOCK_SIZE = 512
|
|
31
|
+
TAIL_CHUNK_SIZE = 2**16 # 64k chunks
|
|
32
|
+
|
|
29
33
|
# :startdoc:
|
|
30
34
|
|
|
31
35
|
# Returns whether or not the file is an image. Only JPEG, PNG, BMP,
|
|
@@ -90,7 +94,7 @@ class File
|
|
|
90
94
|
# File.which('ruby') # => '/usr/local/bin/ruby'
|
|
91
95
|
# File.which('foo') # => nil
|
|
92
96
|
#
|
|
93
|
-
def self.which(program, path = ENV
|
|
97
|
+
def self.which(program, path = ENV.fetch('PATH', nil))
|
|
94
98
|
raise ArgumentError, 'path cannot be empty' if path.nil? || path.empty?
|
|
95
99
|
|
|
96
100
|
# Bail out early if an absolute path is provided.
|
|
@@ -143,7 +147,7 @@ class File
|
|
|
143
147
|
# File.whereis('ruby') # => ['/usr/bin/ruby', '/usr/local/bin/ruby']
|
|
144
148
|
# File.whereis('foo') # => nil
|
|
145
149
|
#
|
|
146
|
-
def self.whereis(program, path = ENV
|
|
150
|
+
def self.whereis(program, path = ENV.fetch('PATH', nil))
|
|
147
151
|
raise ArgumentError, 'path cannot be empty' if path.nil? || path.empty?
|
|
148
152
|
|
|
149
153
|
paths = []
|
|
@@ -232,13 +236,11 @@ class File
|
|
|
232
236
|
# to be configured in the future as an optional 3rd argument.
|
|
233
237
|
#
|
|
234
238
|
def self.tail(filename, num_lines = 10, &block)
|
|
235
|
-
tail_size = 2**16 # 64k chunks
|
|
236
|
-
|
|
237
239
|
# MS Windows gets unhappy if you try to seek backwards past the
|
|
238
240
|
# end of the file, so we have some extra checks here and later.
|
|
239
241
|
file_size = File.size(filename)
|
|
240
|
-
read_bytes = file_size %
|
|
241
|
-
read_bytes =
|
|
242
|
+
read_bytes = file_size % TAIL_CHUNK_SIZE
|
|
243
|
+
read_bytes = TAIL_CHUNK_SIZE if read_bytes == 0
|
|
242
244
|
|
|
243
245
|
line_sep = File::ALT_SEPARATOR ? "\r\n" : "\n"
|
|
244
246
|
|
|
@@ -252,7 +254,7 @@ class File
|
|
|
252
254
|
while buf.scan(line_sep).size <= num_lines and position >= 0
|
|
253
255
|
fh.seek(position, IO::SEEK_SET)
|
|
254
256
|
buf = fh.read(read_bytes) + buf
|
|
255
|
-
read_bytes =
|
|
257
|
+
read_bytes = TAIL_CHUNK_SIZE
|
|
256
258
|
position -= read_bytes
|
|
257
259
|
end
|
|
258
260
|
end
|
|
@@ -288,24 +290,23 @@ class File
|
|
|
288
290
|
if old_file == new_file
|
|
289
291
|
require 'tempfile'
|
|
290
292
|
temp_name = Time.new.strftime('%Y%m%d%H%M%S')
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
nf.open if old_file == new_file
|
|
298
|
-
File.foreach(old_file) do |line|
|
|
299
|
-
line.chomp!
|
|
300
|
-
nf.print("#{line}#{format}")
|
|
301
|
-
end
|
|
302
|
-
ensure
|
|
303
|
-
nf.close if nf && !nf.closed?
|
|
304
|
-
if old_file == new_file
|
|
293
|
+
Tempfile.open("ruby_temp_#{temp_name}") do |nf|
|
|
294
|
+
File.foreach(old_file) do |line|
|
|
295
|
+
line.chomp!
|
|
296
|
+
nf.print("#{line}#{format}")
|
|
297
|
+
end
|
|
298
|
+
nf.close
|
|
305
299
|
require 'fileutils'
|
|
306
300
|
File.delete(old_file)
|
|
307
301
|
FileUtils.mv(nf.path, old_file)
|
|
308
302
|
end
|
|
303
|
+
else
|
|
304
|
+
File.open(new_file, 'w') do |nf|
|
|
305
|
+
File.foreach(old_file) do |line|
|
|
306
|
+
line.chomp!
|
|
307
|
+
nf.print("#{line}#{format}")
|
|
308
|
+
end
|
|
309
|
+
end
|
|
309
310
|
end
|
|
310
311
|
|
|
311
312
|
self
|
|
@@ -331,7 +332,7 @@ class File
|
|
|
331
332
|
# 'lines'.
|
|
332
333
|
#
|
|
333
334
|
def self.wc(filename, option = 'all')
|
|
334
|
-
option.downcase
|
|
335
|
+
option = option.downcase
|
|
335
336
|
valid = %w[all bytes characters chars lines words]
|
|
336
337
|
|
|
337
338
|
raise ArgumentError, "Invalid option: '#{option}'" unless valid.include?(option)
|
|
@@ -358,13 +359,13 @@ class File
|
|
|
358
359
|
n
|
|
359
360
|
else
|
|
360
361
|
bytes, chars, lines, words = 0, 0, 0, 0
|
|
361
|
-
File.foreach(filename) do |line|
|
|
362
|
-
lines += 1
|
|
363
|
-
words += line.split.length
|
|
364
|
-
chars += line.chars.length
|
|
365
|
-
end
|
|
366
362
|
File.open(filename) do |f|
|
|
367
|
-
|
|
363
|
+
while (line = f.gets)
|
|
364
|
+
lines += 1
|
|
365
|
+
words += line.split.length
|
|
366
|
+
chars += line.chars.length
|
|
367
|
+
bytes += line.bytesize
|
|
368
|
+
end
|
|
368
369
|
end
|
|
369
370
|
[bytes, chars, words, lines]
|
|
370
371
|
end
|
|
@@ -382,7 +383,7 @@ class File
|
|
|
382
383
|
#
|
|
383
384
|
def self.sparse?(file)
|
|
384
385
|
stats = File.stat(file)
|
|
385
|
-
stats.size > stats.blocks *
|
|
386
|
+
stats.size > stats.blocks * BLOCK_SIZE
|
|
386
387
|
end
|
|
387
388
|
end
|
|
388
389
|
|
|
@@ -423,19 +424,19 @@ class File
|
|
|
423
424
|
#
|
|
424
425
|
def self.bmp?(file)
|
|
425
426
|
data = File.read(file, 6, nil, :encoding => 'binary')
|
|
426
|
-
data[0,2] == 'BM' && File.size(file) == data[2,4].
|
|
427
|
+
data[0, 2] == 'BM' && File.size(file) == data[2, 4].unpack1('i')
|
|
427
428
|
end
|
|
428
429
|
|
|
429
430
|
# Is the file a jpeg file?
|
|
430
431
|
#
|
|
431
432
|
def self.jpg?(file)
|
|
432
|
-
File.read(file, 10, nil, :encoding => 'binary') == "\377\330\377\340\000\020JFIF".force_encoding(Encoding::BINARY)
|
|
433
|
+
File.read(file, 10, nil, :encoding => 'binary') == String.new("\377\330\377\340\000\020JFIF").force_encoding(Encoding::BINARY)
|
|
433
434
|
end
|
|
434
435
|
|
|
435
436
|
# Is the file a png file?
|
|
436
437
|
#
|
|
437
438
|
def self.png?(file)
|
|
438
|
-
File.read(file, 4, nil, :encoding => 'binary') == "\211PNG".force_encoding(Encoding::BINARY)
|
|
439
|
+
File.read(file, 4, nil, :encoding => 'binary') == String.new("\211PNG").force_encoding(Encoding::BINARY)
|
|
439
440
|
end
|
|
440
441
|
|
|
441
442
|
# Is the file a gif?
|
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.5.
|
|
5
|
+
spec.version = '1.5.2'
|
|
6
6
|
spec.license = 'Apache-2.0'
|
|
7
7
|
spec.author = 'Daniel J. Berger'
|
|
8
8
|
spec.email = 'djberg96@gmail.com'
|
|
@@ -25,7 +25,9 @@ Gem::Specification.new do |spec|
|
|
|
25
25
|
'documentation_uri' => 'https://github.com/djberg96/ptools/wiki',
|
|
26
26
|
'source_code_uri' => 'https://github.com/djberg96/ptools',
|
|
27
27
|
'wiki_uri' => 'https://github.com/djberg96/ptools/wiki',
|
|
28
|
-
'rubygems_mfa_required' => 'true'
|
|
28
|
+
'rubygems_mfa_required' => 'true',
|
|
29
|
+
'github_repo' => 'https://github.com/djberg96/ptools',
|
|
30
|
+
'funding_uri' => 'https://github.com/sponsors/djberg96'
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
spec.add_development_dependency('rake')
|
data/spec/binary_spec.rb
CHANGED
|
@@ -10,7 +10,7 @@ require 'ptools'
|
|
|
10
10
|
|
|
11
11
|
RSpec.describe File, :binary do
|
|
12
12
|
let(:dirname) { described_class.dirname(__FILE__) }
|
|
13
|
-
let(:bin_file) { File::ALT_SEPARATOR ? described_class.join(ENV
|
|
13
|
+
let(:bin_file) { File::ALT_SEPARATOR ? described_class.join(ENV.fetch('windir', nil), 'notepad.exe') : '/bin/ls' }
|
|
14
14
|
|
|
15
15
|
before do
|
|
16
16
|
@txt_file = described_class.join(dirname, 'txt', 'english.txt')
|
data/spec/constants_spec.rb
CHANGED
|
@@ -13,7 +13,7 @@ RSpec.describe File, :constants do
|
|
|
13
13
|
let(:windows) { File::ALT_SEPARATOR }
|
|
14
14
|
|
|
15
15
|
example 'PTOOLS_VERSION constant is set to expected value' do
|
|
16
|
-
expect(File::PTOOLS_VERSION).to eq('1.5.
|
|
16
|
+
expect(File::PTOOLS_VERSION).to eq('1.5.2')
|
|
17
17
|
expect(File::PTOOLS_VERSION.frozen?).to be true
|
|
18
18
|
end
|
|
19
19
|
|
data/spec/head_spec.rb
CHANGED
|
@@ -29,7 +29,7 @@ RSpec.describe File, :head do
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
example 'head method returns the expected results' do
|
|
32
|
-
expect(described_class.head(test_file)).to
|
|
32
|
+
expect(described_class.head(test_file)).to be_a(Array)
|
|
33
33
|
expect(described_class.head(test_file)).to eq(@expected_head1)
|
|
34
34
|
expect(described_class.head(test_file, 5)).to eq(@expected_head2)
|
|
35
35
|
end
|
data/spec/tail_spec.rb
CHANGED
|
@@ -74,7 +74,7 @@ RSpec.describe File, :tail do
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
example 'tail returns the expected values' do
|
|
77
|
-
expect(described_class.tail(test_file1)).to
|
|
77
|
+
expect(described_class.tail(test_file1)).to be_a(Array)
|
|
78
78
|
expect(described_class.tail(test_file1)).to eq(@expected_tail1)
|
|
79
79
|
expect(described_class.tail(test_file1, 5)).to eq(@expected_tail2)
|
|
80
80
|
end
|
data/spec/wc_spec.rb
CHANGED
|
@@ -35,7 +35,7 @@ RSpec.describe File, :wc do
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
example 'wc with no option returns expected results' do
|
|
38
|
-
expect(described_class.wc(test_file)).to
|
|
38
|
+
expect(described_class.wc(test_file)).to be_a(Array)
|
|
39
39
|
expect(described_class.wc(test_file)).to eq([166, 166, 25, 25])
|
|
40
40
|
end
|
|
41
41
|
|
data/spec/whereis_spec.rb
CHANGED
|
@@ -34,7 +34,7 @@ RSpec.describe File, :whereis do
|
|
|
34
34
|
example 'whereis basic functionality' do
|
|
35
35
|
expect(described_class).to respond_to(:whereis)
|
|
36
36
|
expect{ described_class.whereis('ruby') }.not_to raise_error
|
|
37
|
-
expect(described_class.whereis('ruby')).to
|
|
37
|
+
expect(described_class.whereis('ruby')).to be_a(Array).or be_nil
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
example 'whereis accepts an optional second argument' do
|
|
@@ -43,8 +43,9 @@ RSpec.describe File, :whereis do
|
|
|
43
43
|
|
|
44
44
|
example 'whereis returns expected values' do
|
|
45
45
|
expect{ @actual_locs = described_class.whereis(ruby) }.not_to raise_error
|
|
46
|
-
expect(@actual_locs).to
|
|
47
|
-
expect(
|
|
46
|
+
expect(@actual_locs).to be_a(Array)
|
|
47
|
+
expect(@actual_locs).not_to be_empty
|
|
48
|
+
expect(@actual_locs.first).to include(ruby)
|
|
48
49
|
end
|
|
49
50
|
|
|
50
51
|
example 'whereis returns nil if program not found' do
|
data/spec/which_spec.rb
CHANGED
|
@@ -18,8 +18,8 @@ describe File, :which do
|
|
|
18
18
|
|
|
19
19
|
Dir.mkdir(@dir) unless described_class.exist?(@dir)
|
|
20
20
|
FileUtils.touch(@non_exe)
|
|
21
|
-
described_class.chmod(
|
|
22
|
-
described_class.chmod(
|
|
21
|
+
described_class.chmod(0775, @dir)
|
|
22
|
+
described_class.chmod(0644, @non_exe)
|
|
23
23
|
|
|
24
24
|
@exe = described_class.join(
|
|
25
25
|
RbConfig::CONFIG['bindir'],
|
|
@@ -40,7 +40,7 @@ describe File, :which do
|
|
|
40
40
|
example 'which method basic functionality' do
|
|
41
41
|
expect(described_class).to respond_to(:which)
|
|
42
42
|
expect{ described_class.which(@ruby) }.not_to raise_error
|
|
43
|
-
expect(described_class.which(@ruby)).to
|
|
43
|
+
expect(described_class.which(@ruby)).to be_a(String)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
example 'which accepts an optional path to search' do
|
|
@@ -63,7 +63,10 @@ describe File, :which do
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
example 'which returns argument if an existent absolute path is provided' do
|
|
66
|
-
|
|
66
|
+
result = described_class.which(@ruby)
|
|
67
|
+
expect(result).not_to be_nil
|
|
68
|
+
expect(described_class.exist?(result)).to be true
|
|
69
|
+
expect(described_class.executable?(result)).to be true
|
|
67
70
|
end
|
|
68
71
|
|
|
69
72
|
example 'which returns nil if a non-existent absolute path is provided' do
|
|
@@ -92,10 +95,10 @@ describe File, :which do
|
|
|
92
95
|
end
|
|
93
96
|
|
|
94
97
|
example 'resolves with with ~', :unix_only => true do
|
|
95
|
-
old_home =
|
|
98
|
+
old_home = Dir.home
|
|
96
99
|
ENV['HOME'] = Dir::Tmpname.tmpdir
|
|
97
100
|
program = Tempfile.new(['program', '.sh'])
|
|
98
|
-
described_class.chmod(
|
|
101
|
+
described_class.chmod(0755, program.path)
|
|
99
102
|
|
|
100
103
|
expect(described_class.which(described_class.basename(program.path), '~/')).not_to be_nil
|
|
101
104
|
ensure
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ptools
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.5.
|
|
4
|
+
version: 1.5.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel J. Berger
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain:
|
|
11
10
|
- |
|
|
@@ -35,7 +34,7 @@ cert_chain:
|
|
|
35
34
|
ORVCZpRuCPpmC8qmqxUnARDArzucjaclkxjLWvCVHeFa9UP7K3Nl9oTjJNv+7/jM
|
|
36
35
|
WZs4eecIcUc4tKdHxcAJ0MO/Dkqq7hGaiHpwKY76wQ1+8xAh
|
|
37
36
|
-----END CERTIFICATE-----
|
|
38
|
-
date:
|
|
37
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
39
38
|
dependencies:
|
|
40
39
|
- !ruby/object:Gem::Dependency
|
|
41
40
|
name: rake
|
|
@@ -145,7 +144,8 @@ metadata:
|
|
|
145
144
|
source_code_uri: https://github.com/djberg96/ptools
|
|
146
145
|
wiki_uri: https://github.com/djberg96/ptools/wiki
|
|
147
146
|
rubygems_mfa_required: 'true'
|
|
148
|
-
|
|
147
|
+
github_repo: https://github.com/djberg96/ptools
|
|
148
|
+
funding_uri: https://github.com/sponsors/djberg96
|
|
149
149
|
rdoc_options: []
|
|
150
150
|
require_paths:
|
|
151
151
|
- lib
|
|
@@ -160,8 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
160
160
|
- !ruby/object:Gem::Version
|
|
161
161
|
version: '0'
|
|
162
162
|
requirements: []
|
|
163
|
-
rubygems_version: 3.
|
|
164
|
-
signing_key:
|
|
163
|
+
rubygems_version: 3.6.9
|
|
165
164
|
specification_version: 4
|
|
166
165
|
summary: Extra methods for the File class
|
|
167
166
|
test_files: []
|
metadata.gz.sig
CHANGED
|
Binary file
|