Module: Philiprehberger::PathnameKit

Defined in:
lib/philiprehberger/pathname_kit.rb,
lib/philiprehberger/pathname_kit/version.rb

Defined Under Namespace

Classes: Error

Constant Summary collapse

VERSION =
'0.5.0'

Class Method Summary collapse

Class Method Details

.append(path, content) ⇒ String

Append content to a file, creating parent directories if needed. Creates the file if it does not exist.

Parameters:

  • path (String)

    the file path

  • content (String)

    the content to append

Returns:

  • (String)

    the path written

Raises:

  • (Error)

    if path is nil or empty



259
260
261
262
263
264
265
266
267
# File 'lib/philiprehberger/pathname_kit.rb', line 259

def self.append(path, content)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?

  path_str = path.to_s
  ensure_directory(File.dirname(path_str))
  File.open(path_str, 'a') { |f| f.write(content.to_s) }
  path_str
end

.atomic_write(path) {|IO| ... } ⇒ void

This method returns an undefined value.

Write content atomically by writing to a temp file then renaming.

Parameters:

  • path (String)

    the file path to write to

Yields:

  • (IO)

    the temporary file to write to

Raises:

  • (Error)

    if path is nil or empty



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/philiprehberger/pathname_kit.rb', line 20

def self.atomic_write(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?

  dir = File.dirname(path)
  ensure_directory(dir)

  temp = Tempfile.new(['atomic', File.extname(path)], dir)
  begin
    yield temp
    temp.close
    FileUtils.mv(temp.path, path)
  rescue StandardError
    temp.close
    temp.unlink
    raise
  end
end

.basename(path) ⇒ String

Get the filename component of a path (without directory).

Parameters:

  • path (String)

    the file path

Returns:

  • (String)

    the filename

Raises:

  • (Error)

    if path is nil or empty



352
353
354
355
356
357
# File 'lib/philiprehberger/pathname_kit.rb', line 352

def self.basename(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?

  File.basename(path.to_s)
end

.checksum(path, algorithm: :sha256) ⇒ String

Computes a digest checksum of a file.

Parameters:

  • path (String)

    file path

  • algorithm (Symbol) (defaults to: :sha256)

    :md5, :sha1, :sha256, or :sha512

Returns:

  • (String)

    hex digest string

Raises:

  • (PathnameKit::Error)

    if path is nil/empty, file doesn’t exist, or algorithm is invalid



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/philiprehberger/pathname_kit.rb', line 235

def self.checksum(path, algorithm: :sha256)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?

  path_str = path.to_s
  raise Error, "file does not exist: #{path_str}" unless File.exist?(path_str)

  digest_class = case algorithm
                 when :md5 then Digest::MD5
                 when :sha1 then Digest::SHA1
                 when :sha256 then Digest::SHA256
                 when :sha512 then Digest::SHA512
                 else raise Error, "unsupported algorithm: #{algorithm}"
                 end
  digest_class.file(path_str).hexdigest
end

.copy(src, dest) ⇒ String

Copies a file to a destination, creating parent directories as needed.

Parameters:

  • src (String)

    source file path

  • dest (String)

    destination file path

Returns:

  • (String)

    destination path

Raises:



127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/philiprehberger/pathname_kit.rb', line 127

def self.copy(src, dest)
  raise Error, 'source path cannot be nil' if src.nil?
  raise Error, 'source path cannot be empty' if src.to_s.empty?
  raise Error, 'destination path cannot be nil' if dest.nil?
  raise Error, 'destination path cannot be empty' if dest.to_s.empty?
  raise Error, "source file does not exist: #{src}" unless File.exist?(src.to_s)

  dest_str = dest.to_s
  FileUtils.mkdir_p(File.dirname(dest_str))
  FileUtils.cp(src.to_s, dest_str)
  dest_str
end

.directory?(path) ⇒ Boolean

Check if the given path is a directory.

Parameters:

  • path (String)

    the path to check

Returns:

  • (Boolean)

    true if the path is a directory

Raises:

  • (Error)

    if path is nil or empty



340
341
342
343
344
345
# File 'lib/philiprehberger/pathname_kit.rb', line 340

def self.directory?(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?

  File.directory?(path.to_s)
end

.dirname(path) ⇒ String

Get the directory component of a path.

Parameters:

  • path (String)

    the file path

Returns:

  • (String)

    the directory portion

Raises:

  • (Error)

    if path is nil or empty



364
365
366
367
368
369
# File 'lib/philiprehberger/pathname_kit.rb', line 364

def self.dirname(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?

  File.dirname(path.to_s)
end

.each_line(path) {|String| ... } ⇒ Enumerator

Stream a file line by line without loading it entirely into memory.

Parameters:

  • path (String)

    the file path

Yields:

  • (String)

    each line, including the trailing newline if present

Returns:

  • (Enumerator)

    when no block is given

Raises:

  • (Error)

    if path is nil/empty or the file does not exist



192
193
194
195
196
197
198
199
200
# File 'lib/philiprehberger/pathname_kit.rb', line 192

def self.each_line(path, &block)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?
  raise Error, "file not found: #{path}" unless File.exist?(path.to_s)

  return File.foreach(path.to_s).each unless block

  File.foreach(path.to_s, &block)
end

.empty?(path) ⇒ Boolean

Check if a file is empty (zero bytes).

Parameters:

  • path (String)

    the file path

Returns:

  • (Boolean)

    true if the file is empty

Raises:

  • (Error)

    if path is nil/empty or the file does not exist



291
292
293
294
295
296
297
# File 'lib/philiprehberger/pathname_kit.rb', line 291

def self.empty?(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?
  raise Error, "file not found: #{path}" unless File.exist?(path.to_s)

  File.empty?(path.to_s)
end

.ensure_directory(path) ⇒ void

This method returns an undefined value.

Ensure a directory exists, creating it and all parents if needed.

Parameters:

  • path (String)

    the directory path

Raises:

  • (Error)

    if path is nil or empty



44
45
46
47
48
49
# File 'lib/philiprehberger/pathname_kit.rb', line 44

def self.ensure_directory(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?

  FileUtils.mkdir_p(path)
end

.exists?(path) ⇒ Boolean

Check if a file or directory exists at the given path.

Parameters:

  • path (String)

    the file or directory path

Returns:

  • (Boolean)

    true if the path exists

Raises:

  • (Error)

    if path is nil or empty



328
329
330
331
332
333
# File 'lib/philiprehberger/pathname_kit.rb', line 328

def self.exists?(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?

  File.exist?(path.to_s)
end

.expand(path) ⇒ String

Expand a path to its absolute form with tilde expansion.

Parameters:

  • path (String)

    the file path

Returns:

  • (String)

    the expanded absolute path

Raises:

  • (Error)

    if path is nil or empty



316
317
318
319
320
321
# File 'lib/philiprehberger/pathname_kit.rb', line 316

def self.expand(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?

  File.expand_path(path.to_s)
end

.extension(path) ⇒ String

Get the file extension including the leading dot.

Parameters:

  • path (String)

    the file path

Returns:

  • (String)

    the extension (e.g. “.rb”) or empty string

Raises:

  • (Error)

    if path is nil or empty



304
305
306
307
308
309
# File 'lib/philiprehberger/pathname_kit.rb', line 304

def self.extension(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?

  File.extname(path.to_s)
end

.find(glob) ⇒ Array<String>

Find files matching a glob pattern.

Parameters:

  • glob (String)

    the glob pattern

Returns:

  • (Array<String>)

    matching file paths

Raises:

  • (Error)

    if glob is nil or empty



71
72
73
74
75
76
# File 'lib/philiprehberger/pathname_kit.rb', line 71

def self.find(glob)
  raise Error, 'glob cannot be nil' if glob.nil?
  raise Error, 'glob cannot be empty' if glob.to_s.empty?

  Dir.glob(glob)
end

.identical?(path1, path2) ⇒ Boolean

Compare two files by SHA-256 digest.

Parameters:

  • path1 (String)

    first file path

  • path2 (String)

    second file path

Returns:

  • (Boolean)

    true if files have identical contents

Raises:

  • (Error)

    if either path is nil/empty or does not exist



275
276
277
278
279
280
281
282
283
284
# File 'lib/philiprehberger/pathname_kit.rb', line 275

def self.identical?(path1, path2)
  raise Error, 'first path cannot be nil' if path1.nil?
  raise Error, 'first path cannot be empty' if path1.to_s.empty?
  raise Error, 'second path cannot be nil' if path2.nil?
  raise Error, 'second path cannot be empty' if path2.to_s.empty?
  raise Error, "file does not exist: #{path1}" unless File.exist?(path1.to_s)
  raise Error, "file does not exist: #{path2}" unless File.exist?(path2.to_s)

  Digest::SHA256.file(path1.to_s).hexdigest == Digest::SHA256.file(path2.to_s).hexdigest
end

.line_count(path) ⇒ Integer

Count the number of lines in a file.

Parameters:

  • path (String)

    the file path

Returns:

  • (Integer)

    the number of lines

Raises:

  • (Error)

    if path is nil or empty

  • (Error)

    if the file does not exist



113
114
115
116
117
118
119
# File 'lib/philiprehberger/pathname_kit.rb', line 113

def self.line_count(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?
  raise Error, "file not found: #{path}" unless File.exist?(path)

  File.readlines(path).size
end

.move(src, dest) ⇒ String

Moves a file to a destination, creating parent directories as needed.

Parameters:

  • src (String)

    source file path

  • dest (String)

    destination file path

Returns:

  • (String)

    destination path

Raises:



146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/philiprehberger/pathname_kit.rb', line 146

def self.move(src, dest)
  raise Error, 'source path cannot be nil' if src.nil?
  raise Error, 'source path cannot be empty' if src.to_s.empty?
  raise Error, 'destination path cannot be nil' if dest.nil?
  raise Error, 'destination path cannot be empty' if dest.to_s.empty?
  raise Error, "source file does not exist: #{src}" unless File.exist?(src.to_s)

  dest_str = dest.to_s
  FileUtils.mkdir_p(File.dirname(dest_str))
  FileUtils.mv(src.to_s, dest_str)
  dest_str
end

.mtime(path) ⇒ Time

Get the last modification time of a file or directory.

Parameters:

  • path (String)

    the file or directory path

Returns:

  • (Time)

    the modification time

Raises:

  • (Error)

    if path is nil/empty or does not exist



376
377
378
379
380
381
382
# File 'lib/philiprehberger/pathname_kit.rb', line 376

def self.mtime(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?
  raise Error, "path not found: #{path}" unless File.exist?(path.to_s)

  File.mtime(path.to_s)
end

.read(path) ⇒ String

Read a file’s contents.

Parameters:

  • path (String)

    the file path

Returns:

  • (String)

Raises:

  • (Error)

    if path is nil/empty or the file does not exist



164
165
166
167
168
169
170
# File 'lib/philiprehberger/pathname_kit.rb', line 164

def self.read(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?
  raise Error, "file not found: #{path}" unless File.exist?(path.to_s)

  File.read(path.to_s)
end

.safe_delete(path) ⇒ Boolean

Safely delete a file, returning true if deleted and false if not found.

Parameters:

  • path (String)

    the file path to delete

Returns:

  • (Boolean)

    true if the file was deleted

Raises:

  • (Error)

    if path is nil or empty



56
57
58
59
60
61
62
63
64
# File 'lib/philiprehberger/pathname_kit.rb', line 56

def self.safe_delete(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?

  return false unless File.exist?(path)

  File.delete(path)
  true
end

.size(path) ⇒ Integer

Get the size of a file in bytes.

Parameters:

  • path (String)

    the file path

Returns:

  • (Integer)

Raises:

  • (Error)

    if path is nil/empty or the file does not exist



207
208
209
210
211
212
213
# File 'lib/philiprehberger/pathname_kit.rb', line 207

def self.size(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?
  raise Error, "file not found: #{path}" unless File.exist?(path.to_s)

  File.size(path.to_s)
end

.tempfile(ext = '.tmp') {|String| ... } ⇒ Object

Create a temporary file with a given extension and yield its path.

Parameters:

  • ext (String) (defaults to: '.tmp')

    the file extension (e.g. ‘.txt’)

Yields:

  • (String)

    the temporary file path

Returns:

  • (Object)

    the block return value



83
84
85
86
87
88
89
90
91
# File 'lib/philiprehberger/pathname_kit.rb', line 83

def self.tempfile(ext = '.tmp')
  temp = Tempfile.new(['tmp', ext])
  begin
    yield temp.path
  ensure
    temp.close
    temp.unlink
  end
end

.touch(path) ⇒ void

This method returns an undefined value.

Touch a file, creating it if it does not exist and updating its mtime.

Parameters:

  • path (String)

    the file path

Raises:

  • (Error)

    if path is nil or empty



98
99
100
101
102
103
104
105
# File 'lib/philiprehberger/pathname_kit.rb', line 98

def self.touch(path)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?

  dir = File.dirname(path)
  ensure_directory(dir)
  FileUtils.touch(path)
end

.with_tempdir {|String| ... } ⇒ Object

Create a temporary directory and yield its path. The directory and all its contents are removed when the block returns.

Yields:

  • (String)

    the temporary directory path

Returns:

  • (Object)

    the block return value



220
221
222
223
224
225
226
227
# File 'lib/philiprehberger/pathname_kit.rb', line 220

def self.with_tempdir
  dir = Dir.mktmpdir
  begin
    yield dir
  ensure
    FileUtils.rm_rf(dir)
  end
end

.write(path, content) ⇒ String

Atomically write content to a file, creating parent directories as needed.

Parameters:

  • path (String)

    the file path

  • content (String)

    the content to write

Returns:

  • (String)

    the path written

Raises:

  • (Error)

    if path is nil/empty



178
179
180
181
182
183
184
# File 'lib/philiprehberger/pathname_kit.rb', line 178

def self.write(path, content)
  raise Error, 'path cannot be nil' if path.nil?
  raise Error, 'path cannot be empty' if path.to_s.empty?

  atomic_write(path.to_s) { |f| f.write(content.to_s) }
  path.to_s
end