diff options
author | Samuel Williams <samuel.williams@oriontransfer.co.nz> | 2022-12-08 18:19:53 +1300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-08 18:19:53 +1300 |
commit | 6fd5d2dc003bda5ce0685abd2b975d7ac7079d46 (patch) | |
tree | a7cffd3b1b2f40b76511d785b5c00f3d35245ee6 | |
parent | b2764752b2bccb8e4574891d380d0f0a3d67add0 (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.def | 1 | ||||
-rw-r--r-- | error.c | 6 | ||||
-rw-r--r-- | file.c | 37 | ||||
-rw-r--r-- | io.c | 43 | ||||
-rw-r--r-- | spec/ruby/core/file/shared/path.rb | 14 | ||||
-rw-r--r-- | spec/ruby/core/io/path_spec.rb | 11 | ||||
-rw-r--r-- | test/ruby/test_file.rb | 2 | ||||
-rw-r--r-- | test/ruby/test_io.rb | 6 | ||||
-rw-r--r-- | test/zlib/test_zlib.rb | 4 | ||||
-rw-r--r-- | yjit/src/cruby_bindings.inc.rs | 78 |
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 @@ -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); @@ -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); @@ -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; |