Skip to content
17 changes: 17 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,20 @@ jobs:
run: bundle install
- name: Run test
run: rake compile test

spec:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: ruby/setup-ruby@v1
with:
ruby-version: ruby
- uses: actions/checkout@v5
with:
repository: ruby/spec
path: rubyspec
- name: Clone MSpec
run: git clone https://github.com/ruby/mspec.git ../mspec
- run: bundle install
- run: rake compile
- run: ../mspec/bin/mspec -Ilib rubyspec/library/pathname
68 changes: 39 additions & 29 deletions lib/pathname.rb
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,13 @@ module ::Kernel
# === File property and manipulation methods
#
# These methods are a facade for File:
# - #each_line(*args, &block)
# - #read(*args)
# - #binread(*args)
# - #readlines(*args)
# - #sysopen(*args)
# - #write(*args)
# - #binwrite(*args)
# - #atime
# - #birthtime
# - #ctime
Expand Down Expand Up @@ -184,17 +191,6 @@ module ::Kernel
# - #mkdir(*args)
# - #opendir(*args)
#
# === IO
#
# These methods are a facade for IO:
# - #each_line(*args, &block)
# - #read(*args)
# - #binread(*args)
# - #readlines(*args)
# - #sysopen(*args)
# - #write(*args)
# - #binwrite(*args)
#
# === Utilities
#
# These methods are a mixture of Find, FileUtils, and others:
Expand Down Expand Up @@ -238,7 +234,11 @@ class Pathname
# If +path+ contains a NUL character (<tt>\0</tt>), an ArgumentError is raised.
#
def initialize(path)
path = path.to_path if path.respond_to? :to_path
unless String === path
path = path.to_path if path.respond_to? :to_path
raise TypeError unless String === path
end

if path.include?("\0")
raise ArgumentError, "pathname contains \\0: #{path.inspect}"
end
Expand Down Expand Up @@ -852,42 +852,38 @@ def relative_path_from(base_directory)
end
end

class Pathname # * IO *
class Pathname # * File *
#
# #each_line iterates over the line in the file. It yields a String object
# for each line.
#
# This method has existed since 1.8.1.
#
def each_line(...) # :yield: line
IO.foreach(@path, ...)
File.foreach(@path, ...)
end

# See <tt>IO.read</tt>. Returns all data from the file, or the first +N+ bytes
# See <tt>File.read</tt>. Returns all data from the file, or the first +N+ bytes
# if specified.
def read(...) IO.read(@path, ...) end
def read(...) File.read(@path, ...) end

# See <tt>IO.binread</tt>. Returns all the bytes from the file, or the first +N+
# See <tt>File.binread</tt>. Returns all the bytes from the file, or the first +N+
# if specified.
def binread(...) IO.binread(@path, ...) end
def binread(...) File.binread(@path, ...) end

# See <tt>IO.readlines</tt>. Returns all the lines from the file.
def readlines(...) IO.readlines(@path, ...) end
# See <tt>File.readlines</tt>. Returns all the lines from the file.
def readlines(...) File.readlines(@path, ...) end

# See <tt>IO.sysopen</tt>.
def sysopen(...) IO.sysopen(@path, ...) end
# See <tt>File.sysopen</tt>.
def sysopen(...) File.sysopen(@path, ...) end

# Writes +contents+ to the file. See <tt>File.write</tt>.
def write(...) IO.write(@path, ...) end
def write(...) File.write(@path, ...) end

# Writes +contents+ to the file, opening it in binary mode.
#
# See File.binwrite.
def binwrite(...) IO.binwrite(@path, ...) end
end


class Pathname # * File *
def binwrite(...) File.binwrite(@path, ...) end

# See <tt>File.atime</tt>. Returns last access time.
def atime() File.atime(@path) end
Expand Down Expand Up @@ -956,6 +952,13 @@ def truncate(length) File.truncate(@path, length) end
# See <tt>File.utime</tt>. Update the access and modification times.
def utime(atime, mtime) File.utime(atime, mtime, @path) end

# Update the access and modification times of the file.
#
# Same as Pathname#utime, but does not follow symbolic links.
#
# See File.lutime.
def lutime(atime, mtime) File.lutime(atime, mtime, @path) end

# See <tt>File.basename</tt>. Returns the last component of the path.
def basename(...) self.class.new(File.basename(@path, ...)) end

Expand All @@ -982,6 +985,13 @@ def split()
#
# All components of the pathname must exist when this method is called.
def realpath(...) self.class.new(File.realpath(@path, ...)) end

# Returns the real (absolute) pathname of +self+ in the actual filesystem.
#
# Does not contain symlinks or useless dots, +..+ and +.+.
#
# The last component of the real pathname can be nonexistent.
def realdirpath(...) self.class.new(File.realdirpath(@path, ...)) end
end


Expand Down Expand Up @@ -1219,5 +1229,5 @@ def Pathname(path) # :doc:
return path if Pathname === path
Pathname.new(path)
end
private :Pathname
module_function :Pathname
end
12 changes: 9 additions & 3 deletions test/pathname/test_pathname.rb
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ def has_symlink?
rescue NotImplementedError
return false
rescue Errno::ENOENT
return false
return true
rescue Errno::EACCES
return false
end
Expand All @@ -370,10 +370,11 @@ def has_hardlink?
end

def realpath(path, basedir=nil)
Pathname.new(path).realpath(basedir).to_s
Pathname.new(path).realpath(*basedir).to_s
end

def test_realpath
omit "not working yet" if RUBY_ENGINE == "jruby"
return if !has_symlink?
with_tmpchdir('rubytest-pathname') {|dir|
assert_raise(Errno::ENOENT) { realpath("#{dir}/not-exist") }
Expand Down Expand Up @@ -434,6 +435,7 @@ def realdirpath(path)
end

def test_realdirpath
omit "not working yet" if RUBY_ENGINE == "jruby"
return if !has_symlink?
Dir.mktmpdir('rubytest-pathname') {|dir|
rdir = realpath(dir)
Expand Down Expand Up @@ -1054,7 +1056,11 @@ def test_lutime
latime = Time.utc(2000)
lmtime = Time.utc(1999)
File.symlink("a", "l")
Pathname("l").utime(latime, lmtime)
begin
Pathname("l").lutime(latime, lmtime)
rescue NotImplementedError
next
end
s = File.lstat("a")
ls = File.lstat("l")
assert_equal(atime, s.atime)
Expand Down
Loading