ptools 1.4.3 → 1.5.1
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/LICENSE +177 -0
- data/MANIFEST.md +1 -0
- data/README.md +1 -4
- data/Rakefile +1 -0
- data/lib/ptools.rb +43 -49
- data/ptools.gemspec +5 -3
- data/spec/binary_spec.rb +7 -6
- 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 +2 -2
- data/spec/which_spec.rb +5 -5
- data.tar.gz.sig +0 -0
- metadata +7 -7
- metadata.gz.sig +1 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 36d688bdf86ee95a0f1f6d422f75825903fc8ed26d821a69d617134d146a25e3
|
|
4
|
+
data.tar.gz: 574b230aff9a5b095f59cdbb6f1d7b65bc78b27970d4cc2ecc25a1fd67ecbaf0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7a6ede88a24e97f927f6dcc81e9887a0d2b260013fe8e14931796489ec35723d9276651ddcd6ebd6d88cad32f65e0f1298234a0626af95b3b3c0ee157cc1c70a
|
|
7
|
+
data.tar.gz: 4bab6fdf21c8d7f0c3bae158319bb5b2131125d0d757e2d0c24b0d430345b7b7162bcf4b70e44d481c7d7c46aae7b3ead9545f4ad920038023511aa1190dc30d
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 1.5.1 - 27-Nov-2025
|
|
2
|
+
* Refactoring release.
|
|
3
|
+
* The wc('all') method now only does a single read instead of a double read.
|
|
4
|
+
* The nl_convert method simplified to use the block form of File.open.
|
|
5
|
+
* More consistent binary encoding calls.
|
|
6
|
+
* Some magic numbers were replaced with constants.
|
|
7
|
+
* Specs run in documentation mode.
|
|
8
|
+
|
|
9
|
+
## 1.5.0 - 5-Dec-2022
|
|
10
|
+
* Change license to Apache-2.0.
|
|
11
|
+
* Altered the File.binary? method. It no longer accepts a second argument,
|
|
12
|
+
having changed the way it checks for binary files internally, which is
|
|
13
|
+
now much simpler.
|
|
14
|
+
|
|
1
15
|
## 1.4.3 - 26-Nov-2022
|
|
2
16
|
* Added more image specs.
|
|
3
17
|
* Updated the File.bmp? method. It now looks at the first six bytes, and
|
data/LICENSE
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
data/MANIFEST.md
CHANGED
data/README.md
CHANGED
|
@@ -49,9 +49,6 @@ later replaced by a version based on the `ruby-which` library.
|
|
|
49
49
|
The `File.nl_convert` method is based on the nlcvt program found at
|
|
50
50
|
http://www.perl.com/language/ppt/src/nlcvt/nlcvt, written by Tom Christiansen.
|
|
51
51
|
|
|
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).
|
|
54
|
-
|
|
55
52
|
Thanks go to Matt Hoyle for help with the File.tail method.
|
|
56
53
|
|
|
57
54
|
And thanks to any and all contributors!
|
|
@@ -60,7 +57,7 @@ And thanks to any and all contributors!
|
|
|
60
57
|
Add whatever other tools people think might be useful.
|
|
61
58
|
|
|
62
59
|
## License
|
|
63
|
-
|
|
60
|
+
Apache-2.0
|
|
64
61
|
|
|
65
62
|
## Copyright
|
|
66
63
|
(C) 2003-2022 Daniel J. Berger
|
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.
|
|
6
|
+
PTOOLS_VERSION = '1.5.1'.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,
|
|
@@ -56,32 +60,25 @@ class File
|
|
|
56
60
|
end
|
|
57
61
|
|
|
58
62
|
# Returns whether or not +file+ is a binary non-image file, i.e. executable,
|
|
59
|
-
# shared object,
|
|
60
|
-
# It performs a "best guess" based on a simple test of the first
|
|
61
|
-
# +File.blksize+ characters, or 4096, whichever is smaller.
|
|
63
|
+
# shared object, etc.
|
|
62
64
|
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
65
|
+
# Internally this method simply looks for a double null sequence. This will
|
|
66
|
+
# work for the vast majority of cases, but it is not guaranteed to be
|
|
67
|
+
# absolutely accurate.
|
|
66
68
|
#
|
|
67
69
|
# Example:
|
|
68
70
|
#
|
|
69
71
|
# File.binary?('somefile.exe') # => true
|
|
70
72
|
# File.binary?('somefile.txt') # => false
|
|
71
|
-
#--
|
|
72
|
-
# Based on code originally provided by Ryan Davis (which, in turn, is
|
|
73
|
-
# based on Perl's -B switch).
|
|
74
73
|
#
|
|
75
|
-
def self.binary?(file
|
|
74
|
+
def self.binary?(file)
|
|
76
75
|
return false if File.stat(file).zero?
|
|
77
76
|
return false if image?(file)
|
|
78
77
|
return false if check_bom?(file)
|
|
79
78
|
|
|
80
79
|
bytes = File.stat(file).blksize
|
|
81
80
|
bytes = 4096 if bytes > 4096
|
|
82
|
-
|
|
83
|
-
s = s.encode('US-ASCII', :undef => :replace).chars
|
|
84
|
-
((s.size - s.grep(' '..'~').size) / s.size.to_f) > percentage
|
|
81
|
+
(File.read(file, bytes) || '').include?("\u0000\u0000")
|
|
85
82
|
end
|
|
86
83
|
|
|
87
84
|
# Looks for the first occurrence of +program+ within +path+.
|
|
@@ -97,7 +94,7 @@ class File
|
|
|
97
94
|
# File.which('ruby') # => '/usr/local/bin/ruby'
|
|
98
95
|
# File.which('foo') # => nil
|
|
99
96
|
#
|
|
100
|
-
def self.which(program, path = ENV
|
|
97
|
+
def self.which(program, path = ENV.fetch('PATH', nil))
|
|
101
98
|
raise ArgumentError, 'path cannot be empty' if path.nil? || path.empty?
|
|
102
99
|
|
|
103
100
|
# Bail out early if an absolute path is provided.
|
|
@@ -150,7 +147,7 @@ class File
|
|
|
150
147
|
# File.whereis('ruby') # => ['/usr/bin/ruby', '/usr/local/bin/ruby']
|
|
151
148
|
# File.whereis('foo') # => nil
|
|
152
149
|
#
|
|
153
|
-
def self.whereis(program, path = ENV
|
|
150
|
+
def self.whereis(program, path = ENV.fetch('PATH', nil))
|
|
154
151
|
raise ArgumentError, 'path cannot be empty' if path.nil? || path.empty?
|
|
155
152
|
|
|
156
153
|
paths = []
|
|
@@ -239,13 +236,11 @@ class File
|
|
|
239
236
|
# to be configured in the future as an optional 3rd argument.
|
|
240
237
|
#
|
|
241
238
|
def self.tail(filename, num_lines = 10, &block)
|
|
242
|
-
tail_size = 2**16 # 64k chunks
|
|
243
|
-
|
|
244
239
|
# MS Windows gets unhappy if you try to seek backwards past the
|
|
245
240
|
# end of the file, so we have some extra checks here and later.
|
|
246
241
|
file_size = File.size(filename)
|
|
247
|
-
read_bytes = file_size %
|
|
248
|
-
read_bytes =
|
|
242
|
+
read_bytes = file_size % TAIL_CHUNK_SIZE
|
|
243
|
+
read_bytes = TAIL_CHUNK_SIZE if read_bytes == 0
|
|
249
244
|
|
|
250
245
|
line_sep = File::ALT_SEPARATOR ? "\r\n" : "\n"
|
|
251
246
|
|
|
@@ -259,7 +254,7 @@ class File
|
|
|
259
254
|
while buf.scan(line_sep).size <= num_lines and position >= 0
|
|
260
255
|
fh.seek(position, IO::SEEK_SET)
|
|
261
256
|
buf = fh.read(read_bytes) + buf
|
|
262
|
-
read_bytes =
|
|
257
|
+
read_bytes = TAIL_CHUNK_SIZE
|
|
263
258
|
position -= read_bytes
|
|
264
259
|
end
|
|
265
260
|
end
|
|
@@ -295,24 +290,23 @@ class File
|
|
|
295
290
|
if old_file == new_file
|
|
296
291
|
require 'tempfile'
|
|
297
292
|
temp_name = Time.new.strftime('%Y%m%d%H%M%S')
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
nf.open if old_file == new_file
|
|
305
|
-
File.foreach(old_file) do |line|
|
|
306
|
-
line.chomp!
|
|
307
|
-
nf.print("#{line}#{format}")
|
|
308
|
-
end
|
|
309
|
-
ensure
|
|
310
|
-
nf.close if nf && !nf.closed?
|
|
311
|
-
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
|
|
312
299
|
require 'fileutils'
|
|
313
300
|
File.delete(old_file)
|
|
314
301
|
FileUtils.mv(nf.path, old_file)
|
|
315
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
|
|
316
310
|
end
|
|
317
311
|
|
|
318
312
|
self
|
|
@@ -365,13 +359,13 @@ class File
|
|
|
365
359
|
n
|
|
366
360
|
else
|
|
367
361
|
bytes, chars, lines, words = 0, 0, 0, 0
|
|
368
|
-
File.foreach(filename) do |line|
|
|
369
|
-
lines += 1
|
|
370
|
-
words += line.split.length
|
|
371
|
-
chars += line.chars.length
|
|
372
|
-
end
|
|
373
362
|
File.open(filename) do |f|
|
|
374
|
-
|
|
363
|
+
while (line = f.gets)
|
|
364
|
+
lines += 1
|
|
365
|
+
words += line.split.length
|
|
366
|
+
chars += line.chars.length
|
|
367
|
+
bytes += line.bytesize
|
|
368
|
+
end
|
|
375
369
|
end
|
|
376
370
|
[bytes, chars, words, lines]
|
|
377
371
|
end
|
|
@@ -389,7 +383,7 @@ class File
|
|
|
389
383
|
#
|
|
390
384
|
def self.sparse?(file)
|
|
391
385
|
stats = File.stat(file)
|
|
392
|
-
stats.size > stats.blocks *
|
|
386
|
+
stats.size > stats.blocks * BLOCK_SIZE
|
|
393
387
|
end
|
|
394
388
|
end
|
|
395
389
|
|
|
@@ -430,25 +424,25 @@ class File
|
|
|
430
424
|
#
|
|
431
425
|
def self.bmp?(file)
|
|
432
426
|
data = File.read(file, 6, nil, :encoding => 'binary')
|
|
433
|
-
data[0,2] == 'BM' && File.size(file) == data[2,4].
|
|
427
|
+
data[0, 2] == 'BM' && File.size(file) == data[2, 4].unpack1('i')
|
|
434
428
|
end
|
|
435
429
|
|
|
436
430
|
# Is the file a jpeg file?
|
|
437
431
|
#
|
|
438
432
|
def self.jpg?(file)
|
|
439
|
-
File.read(file, 10, nil, :encoding => 'binary') == "\
|
|
433
|
+
File.read(file, 10, nil, :encoding => 'binary') == "\xFF\xD8\xFF\xE0\x00\x10JFIF".force_encoding(Encoding::BINARY)
|
|
440
434
|
end
|
|
441
435
|
|
|
442
436
|
# Is the file a png file?
|
|
443
437
|
#
|
|
444
438
|
def self.png?(file)
|
|
445
|
-
File.read(file, 4, nil, :encoding => 'binary') == "\
|
|
439
|
+
File.read(file, 4, nil, :encoding => 'binary') == "\x89PNG".force_encoding(Encoding::BINARY)
|
|
446
440
|
end
|
|
447
441
|
|
|
448
442
|
# Is the file a gif?
|
|
449
443
|
#
|
|
450
444
|
def self.gif?(file)
|
|
451
|
-
%w[GIF89a GIF97a].include?(File.read(file, 6))
|
|
445
|
+
%w[GIF89a GIF97a].include?(File.read(file, 6, nil, :encoding => 'binary'))
|
|
452
446
|
end
|
|
453
447
|
|
|
454
448
|
# Is the file a tiff?
|
|
@@ -456,7 +450,7 @@ class File
|
|
|
456
450
|
def self.tiff?(file)
|
|
457
451
|
return false if File.size(file) < 12
|
|
458
452
|
|
|
459
|
-
bytes = File.read(file, 4)
|
|
453
|
+
bytes = File.read(file, 4, nil, :encoding => 'binary')
|
|
460
454
|
|
|
461
455
|
# II is Intel, MM is Motorola
|
|
462
456
|
return false if bytes[0..1] != 'II' && bytes[0..1] != 'MM'
|
|
@@ -471,6 +465,6 @@ class File
|
|
|
471
465
|
# Is the file an ico file?
|
|
472
466
|
#
|
|
473
467
|
def self.ico?(file)
|
|
474
|
-
["\
|
|
468
|
+
["\x00\x00\x01\x00".force_encoding(Encoding::BINARY), "\x00\x00\x02\x00".force_encoding(Encoding::BINARY)].include?(File.read(file, 4, nil, :encoding => 'binary'))
|
|
475
469
|
end
|
|
476
470
|
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.1'
|
|
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'
|
|
@@ -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')
|
|
@@ -31,6 +31,12 @@ RSpec.describe File, :binary do
|
|
|
31
31
|
expect(described_class.binary?(bin_file)).to be true
|
|
32
32
|
end
|
|
33
33
|
|
|
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
|
|
38
|
+
end
|
|
39
|
+
|
|
34
40
|
example 'File.binary? returns false for text files' do
|
|
35
41
|
expect(described_class.binary?(@emp_file)).to be false
|
|
36
42
|
expect(described_class.binary?(@txt_file)).to be false
|
|
@@ -44,11 +50,6 @@ RSpec.describe File, :binary do
|
|
|
44
50
|
expect(described_class.binary?(@gif_file)).to be false
|
|
45
51
|
end
|
|
46
52
|
|
|
47
|
-
example 'File.binary? accepts an optional percentage argument' do
|
|
48
|
-
expect(described_class.binary?(@txt_file, 0.50)).to be false
|
|
49
|
-
expect(described_class.binary?(@txt_file, 0.05)).to be true
|
|
50
|
-
end
|
|
51
|
-
|
|
52
53
|
example 'File.binary? raises an error if the file cannot be found' do
|
|
53
54
|
expect{ described_class.binary?('bogus') }.to raise_error(SystemCallError)
|
|
54
55
|
end
|
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.
|
|
16
|
+
expect(File::PTOOLS_VERSION).to eq('1.5.1')
|
|
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,7 +43,7 @@ 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
|
|
46
|
+
expect(@actual_locs).to be_a(Array)
|
|
47
47
|
expect((@expected_locs & @actual_locs).size > 0).to be true
|
|
48
48
|
end
|
|
49
49
|
|
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
|
|
@@ -92,10 +92,10 @@ describe File, :which do
|
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
example 'resolves with with ~', :unix_only => true do
|
|
95
|
-
old_home =
|
|
95
|
+
old_home = Dir.home
|
|
96
96
|
ENV['HOME'] = Dir::Tmpname.tmpdir
|
|
97
97
|
program = Tempfile.new(['program', '.sh'])
|
|
98
|
-
described_class.chmod(
|
|
98
|
+
described_class.chmod(0755, program.path)
|
|
99
99
|
|
|
100
100
|
expect(described_class.which(described_class.basename(program.path), '~/')).not_to be_nil
|
|
101
101
|
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.
|
|
4
|
+
version: 1.5.1
|
|
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
|
|
@@ -104,6 +103,7 @@ extra_rdoc_files: []
|
|
|
104
103
|
files:
|
|
105
104
|
- CHANGES.md
|
|
106
105
|
- Gemfile
|
|
106
|
+
- LICENSE
|
|
107
107
|
- MANIFEST.md
|
|
108
108
|
- README.md
|
|
109
109
|
- Rakefile
|
|
@@ -135,7 +135,7 @@ files:
|
|
|
135
135
|
- spec/which_spec.rb
|
|
136
136
|
homepage: https://github.com/djberg96/ptools
|
|
137
137
|
licenses:
|
|
138
|
-
-
|
|
138
|
+
- Apache-2.0
|
|
139
139
|
metadata:
|
|
140
140
|
homepage_uri: https://github.com/djberg96/ptools
|
|
141
141
|
bug_tracker_uri: https://github.com/djberg96/ptools/issues
|
|
@@ -144,7 +144,8 @@ metadata:
|
|
|
144
144
|
source_code_uri: https://github.com/djberg96/ptools
|
|
145
145
|
wiki_uri: https://github.com/djberg96/ptools/wiki
|
|
146
146
|
rubygems_mfa_required: 'true'
|
|
147
|
-
|
|
147
|
+
github_repo: https://github.com/djberg96/ptools
|
|
148
|
+
funding_uri: https://github.com/sponsors/djberg96
|
|
148
149
|
rdoc_options: []
|
|
149
150
|
require_paths:
|
|
150
151
|
- lib
|
|
@@ -159,8 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
159
160
|
- !ruby/object:Gem::Version
|
|
160
161
|
version: '0'
|
|
161
162
|
requirements: []
|
|
162
|
-
rubygems_version: 3.
|
|
163
|
-
signing_key:
|
|
163
|
+
rubygems_version: 3.6.9
|
|
164
164
|
specification_version: 4
|
|
165
165
|
summary: Extra methods for the File class
|
|
166
166
|
test_files: []
|
metadata.gz.sig
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
���"���ЦF��M��j;B�(��:
|
|
1
|
+
AՇK����p�֑HH]C��Q�m�,hL��e;�ҟ�zƱS�qѶ�[�X���S���WD�sg��NUXm�2��?rDx�&o=�9��a�*X0�8Ӏ��Aml���磰k$5o�S�S���NZ���c+X͙��j�3�=���I{���_�`W���i�r�Qb���* ��i=�r���Y�
|