From a9ef32efbbe5da84e4ba2cdb3ea123dcb322c7b8 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 22 Aug 2025 12:03:14 +0900 Subject: [PATCH 1/7] Restore Pathname#realdirpath --- ext/pathname/pathname.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/ext/pathname/pathname.c b/ext/pathname/pathname.c index 10d055f..73be963 100644 --- a/ext/pathname/pathname.c +++ b/ext/pathname/pathname.c @@ -3,6 +3,7 @@ static VALUE rb_cPathname; static ID id_at_path; static ID id_sub; +static ID id_realdirpath; static VALUE get_strpath(VALUE obj) @@ -83,6 +84,22 @@ path_sub(int argc, VALUE *argv, VALUE self) return rb_class_new_instance(1, &str, rb_obj_class(self)); } +/* + * 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. + */ +static VALUE +path_realdirpath(int argc, VALUE *argv, VALUE self) +{ + VALUE basedir, str; + rb_scan_args(argc, argv, "01", &basedir); + str = rb_funcall(rb_cFile, id_realdirpath, 2, get_strpath(self), basedir); + return rb_class_new_instance(1, &str, rb_obj_class(self)); +} + static void init_ids(void); void @@ -102,6 +119,7 @@ InitVM_pathname(void) rb_cPathname = rb_define_class("Pathname", rb_cObject); rb_define_method(rb_cPathname, "<=>", path_cmp, 1); rb_define_method(rb_cPathname, "sub", path_sub, -1); + rb_define_method(rb_cPathname, "realdirpath", path_realdirpath, -1); } void @@ -110,4 +128,5 @@ init_ids(void) #undef rb_intern id_at_path = rb_intern("@path"); id_sub = rb_intern("sub"); + id_realdirpath = rb_intern("realdirpath"); } From 6cb25f4b41b5148595d2ddccd61c5d97e0cfdb4f Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 22 Aug 2025 12:10:16 +0900 Subject: [PATCH 2/7] Raise TypeError without String argument same as C version --- lib/pathname.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pathname.rb b/lib/pathname.rb index 03edc42..b1f102b 100644 --- a/lib/pathname.rb +++ b/lib/pathname.rb @@ -239,6 +239,9 @@ class Pathname # def initialize(path) path = path.to_path if path.respond_to? :to_path + + raise TypeError unless path.is_a?(String) # Compatibility for C version + if path.include?("\0") raise ArgumentError, "pathname contains \\0: #{path.inspect}" end From e1ce1b8e6458337c51ac7f6459400a9785a6f2c5 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 22 Aug 2025 12:04:20 +0900 Subject: [PATCH 3/7] Make Kernel.Pathname as public again --- lib/pathname.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pathname.rb b/lib/pathname.rb index b1f102b..2f4bbcc 100644 --- a/lib/pathname.rb +++ b/lib/pathname.rb @@ -1219,8 +1219,12 @@ module Kernel # # This method is available since 1.8.5. def Pathname(path) # :doc: + Kernel.Pathname(path) + end + private :Pathname + + def self.Pathname(path) # Compatibility for C version return path if Pathname === path Pathname.new(path) end - private :Pathname end From 2bc9cb3e3428e7112de2eb1eb9b054624b0753f2 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 22 Aug 2025 15:47:51 +0900 Subject: [PATCH 4/7] Suppress CodeQL warnings to use File methods instead of IO --- lib/pathname.rb | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/lib/pathname.rb b/lib/pathname.rb index 2f4bbcc..d39c284 100644 --- a/lib/pathname.rb +++ b/lib/pathname.rb @@ -146,6 +146,12 @@ module ::Kernel # === File property and manipulation methods # # These methods are a facade for File: +# - #each_line(*args, &block) +# - #read(*args) +# - #binread(*args) +# - #readlines(*args) +# - #write(*args) +# - #binwrite(*args) # - #atime # - #birthtime # - #ctime @@ -186,14 +192,8 @@ module ::Kernel # # === IO # -# These methods are a facade for IO: -# - #each_line(*args, &block) -# - #read(*args) -# - #binread(*args) -# - #readlines(*args) +# This method is a facade for IO: # - #sysopen(*args) -# - #write(*args) -# - #binwrite(*args) # # === Utilities # @@ -856,6 +856,11 @@ def relative_path_from(base_directory) end class Pathname # * IO * + # See IO.sysopen. + def sysopen(...) IO.sysopen(@path, ...) end +end + +class Pathname # * File * # # #each_line iterates over the line in the file. It yields a String object # for each line. @@ -863,34 +868,27 @@ class Pathname # * IO * # This method has existed since 1.8.1. # def each_line(...) # :yield: line - IO.foreach(@path, ...) + File.foreach(@path, ...) end - # See IO.read. Returns all data from the file, or the first +N+ bytes + # See File.read. 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 IO.binread. Returns all the bytes from the file, or the first +N+ + # See File.binread. Returns all the bytes from the file, or the first +N+ # if specified. - def binread(...) IO.binread(@path, ...) end - - # See IO.readlines. Returns all the lines from the file. - def readlines(...) IO.readlines(@path, ...) end + def binread(...) File.binread(@path, ...) end - # See IO.sysopen. - def sysopen(...) IO.sysopen(@path, ...) end + # See File.readlines. Returns all the lines from the file. + def readlines(...) File.readlines(@path, ...) end # Writes +contents+ to the file. See File.write. - 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 File.atime. Returns last access time. def atime() File.atime(@path) end From 0cb8b753ca22363f50438e9001a5595c3f8e2e31 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Tue, 15 Jul 2025 11:46:55 +0200 Subject: [PATCH 5/7] Make Pathname#mkpath builtin [Feature #17473] --- lib/pathname.rb | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/lib/pathname.rb b/lib/pathname.rb index d39c284..ec248d1 100644 --- a/lib/pathname.rb +++ b/lib/pathname.rb @@ -349,6 +349,34 @@ def sub_ext(repl) # :startdoc: + # Creates a full path, including any intermediate directories that don't yet + # exist. + # + # See FileUtils.mkpath and FileUtils.mkdir_p + def mkpath(mode: nil) + path = @path == '/' ? @path : @path.chomp('/') + + stack = [] + until File.directory?(path) || File.dirname(path) == path + stack.push path + path = File.dirname(path) + end + + stack.reverse_each do |dir| + dir = dir == '/' ? dir : dir.chomp('/') + if mode + Dir.mkdir dir, mode + File.chmod mode, dir + else + Dir.mkdir dir + end + rescue SystemCallError + raise unless File.directory?(dir) + end + + self + end + # chop_basename(path) -> [pre-basename, basename] or nil def chop_basename(path) # :nodoc: base = File.basename(path) @@ -1158,16 +1186,6 @@ def find(ignore_error: true) # :yield: pathname class Pathname # * FileUtils * - # Creates a full path, including any intermediate directories that don't yet - # exist. - # - # See FileUtils.mkpath and FileUtils.mkdir_p - def mkpath(mode: nil) - require 'fileutils' - FileUtils.mkpath(@path, mode: mode) - self - end - # Recursively deletes a directory, including all directories beneath it. # # See FileUtils.rm_rf From 034fbeb96d6f94e5ff6e280d9a918f5a94d9fa36 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Sun, 3 Aug 2025 15:49:16 +0200 Subject: [PATCH 6/7] pathname_buitin.rb: Remove useless `o` modifier --- lib/pathname.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pathname.rb b/lib/pathname.rb index ec248d1..5c4c8f9 100644 --- a/lib/pathname.rb +++ b/lib/pathname.rb @@ -341,9 +341,9 @@ def sub_ext(repl) end if File.dirname('A:') == 'A:.' # DOSish drive letter - ABSOLUTE_PATH = /\A(?:[A-Za-z]:|#{SEPARATOR_PAT})/o + ABSOLUTE_PATH = /\A(?:[A-Za-z]:|#{SEPARATOR_PAT})/ else - ABSOLUTE_PATH = /\A#{SEPARATOR_PAT}/o + ABSOLUTE_PATH = /\A#{SEPARATOR_PAT}/ end private_constant :ABSOLUTE_PATH From bd24853e1e0afaacecfd2c1b09246a666a77f989 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Mon, 25 Aug 2025 16:28:28 +0900 Subject: [PATCH 7/7] Fill undocumented documents Co-authored-by: Nobuyoshi Nakada --- lib/pathname.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pathname.rb b/lib/pathname.rb index 5c4c8f9..404be1a 100644 --- a/lib/pathname.rb +++ b/lib/pathname.rb @@ -214,6 +214,7 @@ module ::Kernel # class Pathname + # The version string. VERSION = "0.4.0" # :stopdoc: