philiprehberger-pathname_kit 0.5.0 → 0.7.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 022ccd8f2453dd90ab6292f5205556455f03bb4e2cca39e8257cd07cdfa0b0e4
4
- data.tar.gz: c187ad87694fb30b811f4aa63df279a1bec167bbc0ed13abfaa8d766b97bf17d
3
+ metadata.gz: 20819d82a21880e8492296309312b448ff83c13c08c6cabedfd1a4a9b931765a
4
+ data.tar.gz: ac0609e05c9f3ffe88267588c4c1b5554445719a0fa290521e56735324a48297
5
5
  SHA512:
6
- metadata.gz: 68aa6e2e50196068b4f317e8e9f55437ed796d0c021574f8c95f0bdd92b9afb7d573b9c02de444dfa0b72e11974450b084f2637f15c22797669e511f1c2a0e73
7
- data.tar.gz: faceb9ba3beebd59965beea08d5f7cc6afb1ec76c6f03ede7c30d41fdd25fb8b923442f2eca9995e4bb98d1b6602d11bb785c9db818492a94a4ecc67f121e28d
6
+ metadata.gz: '08fd38afb8c71fb98eecdabe34daccad18236b604a32a6eb62e1c4a32611f7b61e709105e252985b8f156b0a69b3772a9de2562685475d6ded4888bad27630cd'
7
+ data.tar.gz: 41b84e7711008b394b62746cf95edd4db1ff2e8de8f735d8451abc3b520e7c10c843b1c45dc0495984aefb0faf9538f735af2d9d3d55436425e2cbe653d491ef
data/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.7.0] - 2026-04-28
11
+
12
+ ### Added
13
+ - `tail(path, n = 10)` — return the last `n` lines of a file as an Array. Streams the file through a bounded ring so memory usage stays constant for large files.
14
+
15
+ ## [0.6.0] - 2026-04-15
16
+
17
+ ### Added
18
+ - `relative_to(path, base)` for expressing a path relative to a base path
19
+
10
20
  ## [0.5.0] - 2026-04-14
11
21
 
12
22
  ### Added
data/README.md CHANGED
@@ -92,6 +92,16 @@ end
92
92
  Philiprehberger::PathnameKit.size("logs/app.log") # => 4096
93
93
  ```
94
94
 
95
+ ### Tail
96
+
97
+ Read the last `n` lines of a file (defaults to 10). Memory usage is bounded
98
+ regardless of file size:
99
+
100
+ ```ruby
101
+ Philiprehberger::PathnameKit.tail("logs/app.log") # => last 10 lines
102
+ Philiprehberger::PathnameKit.tail("logs/app.log", 50) # => last 50 lines
103
+ ```
104
+
95
105
  ### Tempdir Helper
96
106
 
97
107
  ```ruby
@@ -140,6 +150,13 @@ Philiprehberger::PathnameKit.dirname("/path/to/file.txt") # => "/path/to"
140
150
  Philiprehberger::PathnameKit.mtime("config/app.yml") # => 2026-04-14 12:00:00 +0000
141
151
  ```
142
152
 
153
+ ### Relative Paths
154
+
155
+ ```ruby
156
+ Philiprehberger::PathnameKit.relative_to("/a/b/c.txt", "/a/b") # => "c.txt"
157
+ Philiprehberger::PathnameKit.relative_to("/a/foo", "/a/bar") # => "../foo"
158
+ ```
159
+
143
160
  ## API
144
161
 
145
162
  | Method | Description |
@@ -151,6 +168,7 @@ Philiprehberger::PathnameKit.mtime("config/app.yml") # => 2026-04-14 1
151
168
  | `.tempfile(ext) { \|path\| }` | Create a temp file and yield its path |
152
169
  | `.touch(path)` | Create or update a file's modification time |
153
170
  | `.line_count(path)` | Count the number of lines in a file |
171
+ | `.tail(path, n = 10)` | Return the last n lines of a file as an Array |
154
172
  | `.copy(src, dest)` | Copy file with parent directory creation |
155
173
  | `.move(src, dest)` | Move file with parent directory creation |
156
174
  | `.checksum(path, algorithm: :sha256)` | Compute file digest (md5, sha1, sha256, sha512) |
@@ -169,6 +187,7 @@ Philiprehberger::PathnameKit.mtime("config/app.yml") # => 2026-04-14 1
169
187
  | `.basename(path)` | Get the filename component of a path |
170
188
  | `.dirname(path)` | Get the directory component of a path |
171
189
  | `.mtime(path)` | Get the last modification time |
190
+ | `.relative_to(path, base)` | Express a path relative to a base path |
172
191
 
173
192
  ## Development
174
193
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module PathnameKit
5
- VERSION = '0.5.0'
5
+ VERSION = '0.7.0'
6
6
  end
7
7
  end
@@ -118,6 +118,29 @@ module Philiprehberger
118
118
  File.readlines(path).size
119
119
  end
120
120
 
121
+ # Return the last n lines of a file as an Array.
122
+ #
123
+ # Streams the file line by line through a bounded ring of size n so memory
124
+ # usage stays constant regardless of file size.
125
+ #
126
+ # @param path [String] the file path
127
+ # @param n [Integer] number of trailing lines to return
128
+ # @return [Array<String>] the last n lines (or fewer if the file is shorter)
129
+ # @raise [Error] if path is nil/empty, n is non-positive, or the file does not exist
130
+ def self.tail(path, n = 10)
131
+ raise Error, 'path cannot be nil' if path.nil?
132
+ raise Error, 'path cannot be empty' if path.to_s.empty?
133
+ raise Error, 'n must be positive' unless n.is_a?(Integer) && n.positive?
134
+ raise Error, "file not found: #{path}" unless File.exist?(path)
135
+
136
+ buffer = []
137
+ File.foreach(path) do |line|
138
+ buffer << line
139
+ buffer.shift if buffer.size > n
140
+ end
141
+ buffer
142
+ end
143
+
121
144
  # Copies a file to a destination, creating parent directories as needed.
122
145
  #
123
146
  # @param src [String] source file path
@@ -320,6 +343,25 @@ module Philiprehberger
320
343
  File.expand_path(path.to_s)
321
344
  end
322
345
 
346
+ # Return +path+ expressed relative to +base+ as a String.
347
+ #
348
+ # Both arguments may be String or Pathname. Inputs are wrapped in
349
+ # Pathname and expanded so relative inputs are resolved against the
350
+ # current working directory before the relative path is computed.
351
+ #
352
+ # @param path [String, Pathname] the target path
353
+ # @param base [String, Pathname] the base path to compute relativity against
354
+ # @return [String] the relative path
355
+ # @raise [Error] if either argument is nil or empty
356
+ def self.relative_to(path, base)
357
+ raise Error, 'path cannot be nil' if path.nil?
358
+ raise Error, 'path cannot be empty' if path.to_s.empty?
359
+ raise Error, 'base cannot be nil' if base.nil?
360
+ raise Error, 'base cannot be empty' if base.to_s.empty?
361
+
362
+ Pathname.new(path.to_s).expand_path.relative_path_from(Pathname.new(base.to_s).expand_path).to_s
363
+ end
364
+
323
365
  # Check if a file or directory exists at the given path.
324
366
  #
325
367
  # @param path [String] the file or directory path
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philiprehberger-pathname_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philip Rehberger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-14 00:00:00.000000000 Z
11
+ date: 2026-04-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Pathname utility library providing atomic writes, safe deletes, directory
14
14
  creation, glob-based file finding, tempfile helpers, copy, move, checksum, append,