Skip to content

Commit 90ad687

Browse files
authored
Merge pull request #61 from ruby/backport-from-ruby-core
Sync `pathname_builtin.rb` from ruby/ruby
2 parents 658648c + bd24853 commit 90ad687

File tree

2 files changed

+79
-36
lines changed

2 files changed

+79
-36
lines changed

ext/pathname/pathname.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
static VALUE rb_cPathname;
44
static ID id_at_path;
55
static ID id_sub;
6+
static ID id_realdirpath;
67

78
static VALUE
89
get_strpath(VALUE obj)
@@ -83,6 +84,22 @@ path_sub(int argc, VALUE *argv, VALUE self)
8384
return rb_class_new_instance(1, &str, rb_obj_class(self));
8485
}
8586

87+
/*
88+
* Returns the real (absolute) pathname of +self+ in the actual filesystem.
89+
*
90+
* Does not contain symlinks or useless dots, +..+ and +.+.
91+
*
92+
* The last component of the real pathname can be nonexistent.
93+
*/
94+
static VALUE
95+
path_realdirpath(int argc, VALUE *argv, VALUE self)
96+
{
97+
VALUE basedir, str;
98+
rb_scan_args(argc, argv, "01", &basedir);
99+
str = rb_funcall(rb_cFile, id_realdirpath, 2, get_strpath(self), basedir);
100+
return rb_class_new_instance(1, &str, rb_obj_class(self));
101+
}
102+
86103
static void init_ids(void);
87104

88105
void
@@ -102,6 +119,7 @@ InitVM_pathname(void)
102119
rb_cPathname = rb_define_class("Pathname", rb_cObject);
103120
rb_define_method(rb_cPathname, "<=>", path_cmp, 1);
104121
rb_define_method(rb_cPathname, "sub", path_sub, -1);
122+
rb_define_method(rb_cPathname, "realdirpath", path_realdirpath, -1);
105123
}
106124

107125
void
@@ -110,4 +128,5 @@ init_ids(void)
110128
#undef rb_intern
111129
id_at_path = rb_intern("@path");
112130
id_sub = rb_intern("sub");
131+
id_realdirpath = rb_intern("realdirpath");
113132
}

lib/pathname.rb

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ module ::Kernel
146146
# === File property and manipulation methods
147147
#
148148
# These methods are a facade for File:
149+
# - #each_line(*args, &block)
150+
# - #read(*args)
151+
# - #binread(*args)
152+
# - #readlines(*args)
153+
# - #write(*args)
154+
# - #binwrite(*args)
149155
# - #atime
150156
# - #birthtime
151157
# - #ctime
@@ -186,14 +192,8 @@ module ::Kernel
186192
#
187193
# === IO
188194
#
189-
# These methods are a facade for IO:
190-
# - #each_line(*args, &block)
191-
# - #read(*args)
192-
# - #binread(*args)
193-
# - #readlines(*args)
195+
# This method is a facade for IO:
194196
# - #sysopen(*args)
195-
# - #write(*args)
196-
# - #binwrite(*args)
197197
#
198198
# === Utilities
199199
#
@@ -214,6 +214,7 @@ module ::Kernel
214214
#
215215
class Pathname
216216

217+
# The version string.
217218
VERSION = "0.4.0"
218219

219220
# :stopdoc:
@@ -239,6 +240,9 @@ class Pathname
239240
#
240241
def initialize(path)
241242
path = path.to_path if path.respond_to? :to_path
243+
244+
raise TypeError unless path.is_a?(String) # Compatibility for C version
245+
242246
if path.include?("\0")
243247
raise ArgumentError, "pathname contains \\0: #{path.inspect}"
244248
end
@@ -338,14 +342,42 @@ def sub_ext(repl)
338342
end
339343

340344
if File.dirname('A:') == 'A:.' # DOSish drive letter
341-
ABSOLUTE_PATH = /\A(?:[A-Za-z]:|#{SEPARATOR_PAT})/o
345+
ABSOLUTE_PATH = /\A(?:[A-Za-z]:|#{SEPARATOR_PAT})/
342346
else
343-
ABSOLUTE_PATH = /\A#{SEPARATOR_PAT}/o
347+
ABSOLUTE_PATH = /\A#{SEPARATOR_PAT}/
344348
end
345349
private_constant :ABSOLUTE_PATH
346350

347351
# :startdoc:
348352

353+
# Creates a full path, including any intermediate directories that don't yet
354+
# exist.
355+
#
356+
# See FileUtils.mkpath and FileUtils.mkdir_p
357+
def mkpath(mode: nil)
358+
path = @path == '/' ? @path : @path.chomp('/')
359+
360+
stack = []
361+
until File.directory?(path) || File.dirname(path) == path
362+
stack.push path
363+
path = File.dirname(path)
364+
end
365+
366+
stack.reverse_each do |dir|
367+
dir = dir == '/' ? dir : dir.chomp('/')
368+
if mode
369+
Dir.mkdir dir, mode
370+
File.chmod mode, dir
371+
else
372+
Dir.mkdir dir
373+
end
374+
rescue SystemCallError
375+
raise unless File.directory?(dir)
376+
end
377+
378+
self
379+
end
380+
349381
# chop_basename(path) -> [pre-basename, basename] or nil
350382
def chop_basename(path) # :nodoc:
351383
base = File.basename(path)
@@ -853,41 +885,39 @@ def relative_path_from(base_directory)
853885
end
854886

855887
class Pathname # * IO *
888+
# See <tt>IO.sysopen</tt>.
889+
def sysopen(...) IO.sysopen(@path, ...) end
890+
end
891+
892+
class Pathname # * File *
856893
#
857894
# #each_line iterates over the line in the file. It yields a String object
858895
# for each line.
859896
#
860897
# This method has existed since 1.8.1.
861898
#
862899
def each_line(...) # :yield: line
863-
IO.foreach(@path, ...)
900+
File.foreach(@path, ...)
864901
end
865902

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

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

874-
# See <tt>IO.readlines</tt>. Returns all the lines from the file.
875-
def readlines(...) IO.readlines(@path, ...) end
876-
877-
# See <tt>IO.sysopen</tt>.
878-
def sysopen(...) IO.sysopen(@path, ...) end
911+
# See <tt>File.readlines</tt>. Returns all the lines from the file.
912+
def readlines(...) File.readlines(@path, ...) end
879913

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

883917
# Writes +contents+ to the file, opening it in binary mode.
884918
#
885919
# See File.binwrite.
886-
def binwrite(...) IO.binwrite(@path, ...) end
887-
end
888-
889-
890-
class Pathname # * File *
920+
def binwrite(...) File.binwrite(@path, ...) end
891921

892922
# See <tt>File.atime</tt>. Returns last access time.
893923
def atime() File.atime(@path) end
@@ -1157,16 +1187,6 @@ def find(ignore_error: true) # :yield: pathname
11571187

11581188

11591189
class Pathname # * FileUtils *
1160-
# Creates a full path, including any intermediate directories that don't yet
1161-
# exist.
1162-
#
1163-
# See FileUtils.mkpath and FileUtils.mkdir_p
1164-
def mkpath(mode: nil)
1165-
require 'fileutils'
1166-
FileUtils.mkpath(@path, mode: mode)
1167-
self
1168-
end
1169-
11701190
# Recursively deletes a directory, including all directories beneath it.
11711191
#
11721192
# See FileUtils.rm_rf
@@ -1216,8 +1236,12 @@ module Kernel
12161236
#
12171237
# This method is available since 1.8.5.
12181238
def Pathname(path) # :doc:
1239+
Kernel.Pathname(path)
1240+
end
1241+
private :Pathname
1242+
1243+
def self.Pathname(path) # Compatibility for C version
12191244
return path if Pathname === path
12201245
Pathname.new(path)
12211246
end
1222-
private :Pathname
12231247
end

0 commit comments

Comments
 (0)