Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce IO.new(..., path:) and promote File#path to IO#path. #6867

Merged
merged 6 commits into from Dec 8, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions defs/id.def
Expand Up @@ -58,6 +58,7 @@ firstline, predefined = __LINE__+1, %[\
quo
name
nil
path

_ UScore

Expand Down
6 changes: 2 additions & 4 deletions error.c
Expand Up @@ -3024,14 +3024,12 @@ Init_Exception(void)
rb_eSyntaxError = rb_define_class("SyntaxError", rb_eScriptError);
rb_define_method(rb_eSyntaxError, "initialize", syntax_error_initialize, -1);

ID id_path = rb_intern_const("path");

/* the path failed to parse */
rb_attr(rb_eSyntaxError, id_path, TRUE, FALSE, FALSE);
rb_attr(rb_eSyntaxError, idPath, TRUE, FALSE, FALSE);

rb_eLoadError = rb_define_class("LoadError", rb_eScriptError);
/* the path failed to load */
rb_attr(rb_eLoadError, id_path, TRUE, FALSE, FALSE);
rb_attr(rb_eLoadError, idPath, TRUE, FALSE, FALSE);

rb_eNotImpError = rb_define_class("NotImplementedError", rb_eScriptError);

Expand Down
37 changes: 0 additions & 37 deletions file.c
Expand Up @@ -484,41 +484,6 @@ apply2files(int (*func)(const char *, void *), int argc, VALUE *argv, void *arg)
return LONG2FIX(argc);
}

/*
* call-seq:
* path -> filepath
*
* Returns the string filepath used to create +self+:
*
* f = File.new('t.txt') # => #<File:t.txt>
f.path # => "t.txt"
*
* Does not normalize the returned filepath:
*
* f = File.new('../files/t.txt') # => #<File:../files/t.txt>
f.path # => "../files/t.txt"
*
* Raises IOError for a file created using File::Constants::TMPFILE, because it has no filename.
*
* File#to_path is an alias for File#path.
*
*/

static VALUE
rb_file_path(VALUE obj)
{
rb_io_t *fptr;

fptr = RFILE(rb_io_taint_check(obj))->fptr;
rb_io_check_initialized(fptr);

if (NIL_P(fptr->pathv)) {
rb_raise(rb_eIOError, "File is unnamed (TMPFILE?)");
}

return rb_str_dup(fptr->pathv);
}

static size_t
stat_memsize(const void *p)
{
Expand Down Expand Up @@ -7555,8 +7520,6 @@ Init_File(void)
/* Name of the null device */
rb_define_const(rb_mFConst, "NULL", rb_fstring_cstr(ruby_null_device));

rb_define_method(rb_cFile, "path", rb_file_path, 0);
rb_define_method(rb_cFile, "to_path", rb_file_path, 0);
rb_define_global_function("test", rb_f_test, -1);

rb_cStat = rb_define_class_under(rb_cFile, "Stat", rb_cObject);
Expand Down
43 changes: 41 additions & 2 deletions io.c
Expand Up @@ -2908,6 +2908,29 @@ rb_io_pid(VALUE io)
return PIDT2NUM(fptr->pid);
}

/*
* call-seq:
* path -> string or nil
*
* Returns the path associated with the IO, or +nil+ if there is no path
* associated with the IO. It is not guaranteed that the path exists on
* the filesystem.
*
* $stdin.path # => "<STDIN>"
*
* File.open("testfile") {|f| f.path} # => "testfile"
*/

static VALUE
rb_io_path(VALUE io)
{
rb_io_t *fptr = RFILE(io)->fptr;

if (!fptr)
return Qnil;

return rb_obj_dup(fptr->pathv);
}

/*
* call-seq:
Expand Down Expand Up @@ -9361,14 +9384,26 @@ rb_io_initialize(int argc, VALUE *argv, VALUE io)
rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
}
#endif
if (!NIL_P(opt) && rb_hash_aref(opt, sym_autoclose) == Qfalse) {
fmode |= FMODE_PREP;
VALUE path = Qnil;

if (!NIL_P(opt)) {
if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
fmode |= FMODE_PREP;
}

path = rb_hash_aref(opt, RB_ID2SYM(idPath));
if (!NIL_P(path)) {
StringValue(path);
path = rb_str_new_frozen(path);
}
}

MakeOpenFile(io, fp);
fp->self = io;
fp->fd = fd;
fp->mode = fmode;
fp->encs = convconfig;
fp->pathv = path;
fp->timeout = Qnil;
clear_codeconv(fp);
io_check_tty(fp);
Expand Down Expand Up @@ -15436,6 +15471,10 @@ Init_IO(void)
rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
rb_define_method(rb_cIO, "pid", rb_io_pid, 0);

rb_define_method(rb_cIO, "path", rb_io_path, 0);
rb_define_method(rb_cIO, "to_path", rb_io_path, 0);

rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);

rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
Expand Down
14 changes: 8 additions & 6 deletions spec/ruby/core/file/shared/path.rb
Expand Up @@ -78,13 +78,15 @@
rm_r @dir
end

it "raises IOError if file was opened with File::TMPFILE" do
begin
File.open(@dir, File::RDWR | File::TMPFILE) do |f|
-> { f.send(@method) }.should raise_error(IOError)
ruby_version_is ""..."3.1" do
it "raises IOError if file was opened with File::TMPFILE" do
begin
File.open(@dir, File::RDWR | File::TMPFILE) do |f|
-> { f.send(@method) }.should raise_error(IOError)
end
rescue Errno::EOPNOTSUPP, Errno::EINVAL, Errno::EISDIR
skip "no support from the filesystem"
end
rescue Errno::EOPNOTSUPP, Errno::EINVAL, Errno::EISDIR
skip "no support from the filesystem"
end
end
end
Expand Down
11 changes: 11 additions & 0 deletions spec/ruby/core/io/path_spec.rb
@@ -0,0 +1,11 @@
require_relative '../../spec_helper'

describe "IO#path" do
ruby_version_is "3.2" do
it "returns the path of the file associated with the IO object" do
File.open(tmp("io_path.txt"), "w") do |file|
IO.new(file.fileno, path: file.path, autoclose: false).path.should == file.path
end
end
end
end
2 changes: 1 addition & 1 deletion test/ruby/test_file.rb
Expand Up @@ -527,7 +527,7 @@ def test_open_tempfile_path
io.write "foo"
io.flush
assert_equal 3, io.size
assert_raise(IOError) { io.path }
assert_nil io.path
ensure
io&.close
end
Expand Down
6 changes: 6 additions & 0 deletions test/ruby/test_io.rb
Expand Up @@ -1639,6 +1639,12 @@ def test_write_nonblock_file
end
end

def test_explicit_path
io = IO.for_fd(0, path: "Fake Path", autoclose: false)
assert_match %r"Fake Path", io.inspect
assert_equal "Fake Path", io.path
end

def test_write_nonblock_simple_no_exceptions
pipe(proc do |w|
w.write_nonblock('1', exception: false)
Expand Down
4 changes: 2 additions & 2 deletions test/zlib/test_zlib.rb
Expand Up @@ -804,10 +804,10 @@ def test_path_tmpfile
io.rewind

gz0 = Zlib::GzipWriter.new(io)
assert_raise(NoMethodError) { gz0.path }
assert_nil gz0.path

gz1 = Zlib::GzipReader.new(io)
assert_raise(NoMethodError) { gz1.path }
assert_nil gz1.path
gz0.close
gz1.close
end
Expand Down
78 changes: 40 additions & 38 deletions yjit/src/cruby_bindings.inc.rs
Expand Up @@ -579,31 +579,32 @@ pub const tFdiv: ruby_method_ids = 223;
pub const tQuo: ruby_method_ids = 224;
pub const tName: ruby_method_ids = 225;
pub const tNil: ruby_method_ids = 226;
pub const tUScore: ruby_method_ids = 227;
pub const tNUMPARAM_1: ruby_method_ids = 228;
pub const tNUMPARAM_2: ruby_method_ids = 229;
pub const tNUMPARAM_3: ruby_method_ids = 230;
pub const tNUMPARAM_4: ruby_method_ids = 231;
pub const tNUMPARAM_5: ruby_method_ids = 232;
pub const tNUMPARAM_6: ruby_method_ids = 233;
pub const tNUMPARAM_7: ruby_method_ids = 234;
pub const tNUMPARAM_8: ruby_method_ids = 235;
pub const tNUMPARAM_9: ruby_method_ids = 236;
pub const tTOKEN_LOCAL_END: ruby_method_ids = 237;
pub const tTOKEN_INSTANCE_BEGIN: ruby_method_ids = 236;
pub const tTOKEN_INSTANCE_END: ruby_method_ids = 237;
pub const tTOKEN_GLOBAL_BEGIN: ruby_method_ids = 236;
pub const tLASTLINE: ruby_method_ids = 237;
pub const tBACKREF: ruby_method_ids = 238;
pub const tERROR_INFO: ruby_method_ids = 239;
pub const tTOKEN_GLOBAL_END: ruby_method_ids = 240;
pub const tTOKEN_CONST_BEGIN: ruby_method_ids = 239;
pub const tTOKEN_CONST_END: ruby_method_ids = 240;
pub const tTOKEN_CLASS_BEGIN: ruby_method_ids = 239;
pub const tTOKEN_CLASS_END: ruby_method_ids = 240;
pub const tTOKEN_ATTRSET_BEGIN: ruby_method_ids = 239;
pub const tTOKEN_ATTRSET_END: ruby_method_ids = 240;
pub const tNEXT_ID: ruby_method_ids = 240;
pub const tPath: ruby_method_ids = 227;
pub const tUScore: ruby_method_ids = 228;
pub const tNUMPARAM_1: ruby_method_ids = 229;
pub const tNUMPARAM_2: ruby_method_ids = 230;
pub const tNUMPARAM_3: ruby_method_ids = 231;
pub const tNUMPARAM_4: ruby_method_ids = 232;
pub const tNUMPARAM_5: ruby_method_ids = 233;
pub const tNUMPARAM_6: ruby_method_ids = 234;
pub const tNUMPARAM_7: ruby_method_ids = 235;
pub const tNUMPARAM_8: ruby_method_ids = 236;
pub const tNUMPARAM_9: ruby_method_ids = 237;
pub const tTOKEN_LOCAL_END: ruby_method_ids = 238;
pub const tTOKEN_INSTANCE_BEGIN: ruby_method_ids = 237;
pub const tTOKEN_INSTANCE_END: ruby_method_ids = 238;
pub const tTOKEN_GLOBAL_BEGIN: ruby_method_ids = 237;
pub const tLASTLINE: ruby_method_ids = 238;
pub const tBACKREF: ruby_method_ids = 239;
pub const tERROR_INFO: ruby_method_ids = 240;
pub const tTOKEN_GLOBAL_END: ruby_method_ids = 241;
pub const tTOKEN_CONST_BEGIN: ruby_method_ids = 240;
pub const tTOKEN_CONST_END: ruby_method_ids = 241;
pub const tTOKEN_CLASS_BEGIN: ruby_method_ids = 240;
pub const tTOKEN_CLASS_END: ruby_method_ids = 241;
pub const tTOKEN_ATTRSET_BEGIN: ruby_method_ids = 240;
pub const tTOKEN_ATTRSET_END: ruby_method_ids = 241;
pub const tNEXT_ID: ruby_method_ids = 241;
pub const idMax: ruby_method_ids = 2721;
pub const idMin: ruby_method_ids = 2737;
pub const idFreeze: ruby_method_ids = 2753;
Expand Down Expand Up @@ -661,19 +662,20 @@ pub const idFdiv: ruby_method_ids = 3569;
pub const idQuo: ruby_method_ids = 3585;
pub const idName: ruby_method_ids = 3601;
pub const idNil: ruby_method_ids = 3617;
pub const idUScore: ruby_method_ids = 3633;
pub const idNUMPARAM_1: ruby_method_ids = 3649;
pub const idNUMPARAM_2: ruby_method_ids = 3665;
pub const idNUMPARAM_3: ruby_method_ids = 3681;
pub const idNUMPARAM_4: ruby_method_ids = 3697;
pub const idNUMPARAM_5: ruby_method_ids = 3713;
pub const idNUMPARAM_6: ruby_method_ids = 3729;
pub const idNUMPARAM_7: ruby_method_ids = 3745;
pub const idNUMPARAM_8: ruby_method_ids = 3761;
pub const idNUMPARAM_9: ruby_method_ids = 3777;
pub const idLASTLINE: ruby_method_ids = 3799;
pub const idBACKREF: ruby_method_ids = 3815;
pub const idERROR_INFO: ruby_method_ids = 3831;
pub const idPath: ruby_method_ids = 3633;
pub const idUScore: ruby_method_ids = 3649;
pub const idNUMPARAM_1: ruby_method_ids = 3665;
pub const idNUMPARAM_2: ruby_method_ids = 3681;
pub const idNUMPARAM_3: ruby_method_ids = 3697;
pub const idNUMPARAM_4: ruby_method_ids = 3713;
pub const idNUMPARAM_5: ruby_method_ids = 3729;
pub const idNUMPARAM_6: ruby_method_ids = 3745;
pub const idNUMPARAM_7: ruby_method_ids = 3761;
pub const idNUMPARAM_8: ruby_method_ids = 3777;
pub const idNUMPARAM_9: ruby_method_ids = 3793;
pub const idLASTLINE: ruby_method_ids = 3815;
pub const idBACKREF: ruby_method_ids = 3831;
pub const idERROR_INFO: ruby_method_ids = 3847;
pub const tLAST_OP_ID: ruby_method_ids = 169;
pub const idLAST_OP_ID: ruby_method_ids = 10;
pub type ruby_method_ids = u32;
Expand Down