Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions ext/pathname/pathname.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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");
}
96 changes: 60 additions & 36 deletions lib/pathname.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
#
Expand All @@ -214,6 +214,7 @@ module ::Kernel
#
class Pathname

# The version string.
VERSION = "0.4.0"

# :stopdoc:
Expand All @@ -239,6 +240,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
Expand Down Expand Up @@ -338,14 +342,42 @@ 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

# :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)
Expand Down Expand Up @@ -853,41 +885,39 @@ def relative_path_from(base_directory)
end

class Pathname # * IO *
# See <tt>IO.sysopen</tt>.
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.
#
# 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>IO.sysopen</tt>.
def sysopen(...) IO.sysopen(@path, ...) end
# See <tt>File.readlines</tt>. Returns all the lines from the file.
def readlines(...) File.readlines(@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 @@ -1157,16 +1187,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
Expand Down Expand Up @@ -1216,8 +1236,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
Loading