summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Williams <samuel.williams@oriontransfer.co.nz>2022-12-08 18:19:53 +1300
committerGitHub <noreply@github.com>2022-12-08 18:19:53 +1300
commit6fd5d2dc003bda5ce0685abd2b975d7ac7079d46 (patch)
treea7cffd3b1b2f40b76511d785b5c00f3d35245ee6
parentb2764752b2bccb8e4574891d380d0f0a3d67add0 (diff)
Introduce `IO.new(..., path:)` and promote `File#path` to `IO#path`. (#6867)
Notes
Notes: Merged-By: ioquatix <samuel@codeotaku.com>
-rw-r--r--defs/id.def1
-rw-r--r--error.c6
-rw-r--r--file.c37
-rw-r--r--io.c43
-rw-r--r--spec/ruby/core/file/shared/path.rb14
-rw-r--r--spec/ruby/core/io/path_spec.rb11
-rw-r--r--test/ruby/test_file.rb2
-rw-r--r--test/ruby/test_io.rb6
-rw-r--r--test/zlib/test_zlib.rb4
-rw-r--r--yjit/src/cruby_bindings.inc.rs78
10 files changed, 112 insertions, 90 deletions
diff --git a/defs/id.def b/defs/id.def
index 94af02b12f..a3a383f532 100644
--- a/defs/id.def
+++ b/defs/id.def
@@ -58,6 +58,7 @@ firstline, predefined = __LINE__+1, %[\
quo
name
nil
+ path
_ UScore
diff --git a/error.c b/error.c
index e256f3bf37..bf3725bc47 100644
--- a/error.c
+++ b/error.c
@@ -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);
diff --git a/file.c b/file.c
index 5b17093ca3..705bb5ce62 100644
--- a/file.c
+++ b/file.c
@@ -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)
{
@@ -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);
diff --git a/io.c b/io.c
index 33226ec7cb..1c47a6dcbb 100644
--- a/io.c
+++ b/io.c
@@ -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:
@@ -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);
@@ -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);
diff --git a/spec/ruby/core/file/shared/path.rb b/spec/ruby/core/file/shared/path.rb
index 0a5abe33f0..ee8109ba05 100644
--- a/spec/ruby/core/file/shared/path.rb
+++ b/spec/ruby/core/file/shared/path.rb
@@ -78,13 +78,15 @@ describe :file_path, shared: true do
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
diff --git a/spec/ruby/core/io/path_spec.rb b/spec/ruby/core/io/path_spec.rb
new file mode 100644
index 0000000000..51055673d7
--- /dev/null
+++ b/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
diff --git a/test/ruby/test_file.rb b/test/ruby/test_file.rb
index 669b004b83..409d21fc4e 100644
--- a/test/ruby/test_file.rb
+++ b/test/ruby/test_file.rb
@@ -527,7 +527,7 @@ class TestFile < Test::Unit::TestCase
io.write "foo"
io.flush
assert_equal 3, io.size
- assert_raise(IOError) { io.path }
+ assert_nil io.path
ensure
io&.close
end
diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb
index 0bf24960c6..5ea9a8e574 100644
--- a/test/ruby/test_io.rb
+++ b/test/ruby/test_io.rb
@@ -1639,6 +1639,12 @@ class TestIO < Test::Unit::TestCase
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)
diff --git a/test/zlib/test_zlib.rb b/test/zlib/test_zlib.rb
index 00a13af95b..f57b7f2730 100644
--- a/test/zlib/test_zlib.rb
+++ b/test/zlib/test_zlib.rb
@@ -804,10 +804,10 @@ if defined? Zlib
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
diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs
index 1555196a06..b57c235cec 100644
--- a/yjit/src/cruby_bindings.inc.rs
+++ b/yjit/src/cruby_bindings.inc.rs
@@ -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;
@@ -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;