diff --git a/error.c b/error.c index 77ca3a9..cec6808 100644 --- a/error.c +++ b/error.c @@ -1690,7 +1690,10 @@ Init_Exception(void) rb_eScriptError = rb_define_class("ScriptError", rb_eException); rb_eSyntaxError = rb_define_class("SyntaxError", rb_eScriptError); + rb_eLoadError = rb_define_class("LoadError", rb_eScriptError); + rb_attr(rb_eLoadError, rb_intern("path"), 1, 0, Qfalse); + rb_eNotImpError = rb_define_class("NotImplementedError", rb_eScriptError); rb_eNameError = rb_define_class("NameError", rb_eStandardError); @@ -1741,11 +1744,29 @@ rb_loaderror(const char *fmt, ...) { va_list args; VALUE mesg; + VALUE err; + + va_start(args, fmt); + mesg = rb_enc_vsprintf(rb_locale_encoding(), fmt, args); + va_end(args); + err = rb_exc_new3(rb_eLoadError, mesg); + rb_ivar_set(err, rb_intern("@path"), Qnil); + rb_exc_raise(err); +} + +void +rb_loaderror_with_path(VALUE path, const char *fmt, ...) +{ + va_list args; + VALUE mesg; + VALUE err; va_start(args, fmt); mesg = rb_enc_vsprintf(rb_locale_encoding(), fmt, args); va_end(args); - rb_exc_raise(rb_exc_new3(rb_eLoadError, mesg)); + err = rb_exc_new3(rb_eLoadError, mesg); + rb_ivar_set(err, rb_intern("@path"), path); + rb_exc_raise(err); } void @@ -1888,7 +1909,7 @@ rb_sys_warning(const char *fmt, ...) void rb_load_fail(const char *path) { - rb_loaderror("%s -- %s", strerror(errno), path); + rb_loaderror_with_path(rb_str_new2(path), "%s -- %s", strerror(errno), path); } void diff --git a/include/ruby/intern.h b/include/ruby/intern.h index e0c4710..13ccf5b 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -209,6 +209,7 @@ VALUE rb_exc_new(VALUE, const char*, long); VALUE rb_exc_new2(VALUE, const char*); VALUE rb_exc_new3(VALUE, VALUE); PRINTF_ARGS(NORETURN(void rb_loaderror(const char*, ...)), 1, 2); +PRINTF_ARGS(NORETURN(void rb_loaderror_with_path(VALUE path, const char*, ...)), 2, 3); PRINTF_ARGS(NORETURN(void rb_name_error(ID, const char*, ...)), 2, 3); PRINTF_ARGS(NORETURN(void rb_name_error_str(VALUE, const char*, ...)), 2, 3); NORETURN(void rb_invalid_str(const char*, const char*)); diff --git a/load.c b/load.c index cddd725..67020a1 100644 --- a/load.c +++ b/load.c @@ -495,7 +495,7 @@ rb_f_require_relative(VALUE obj, VALUE fname) { VALUE base = rb_current_realfilepath(); if (NIL_P(base)) { - rb_raise(rb_eLoadError, "cannot infer basepath"); + rb_loaderror("cannot infer basepath"); } base = rb_file_dirname(base); return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level()); @@ -588,12 +588,13 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level) return type ? 's' : 'r'; } +void rb_loaderror_with_path(VALUE path, const char *fmt, ...); + static void load_failed(VALUE fname) { - VALUE mesg = rb_str_buf_new_cstr("cannot load such file -- "); - rb_str_append(mesg, fname); /* should be ASCII compatible */ - rb_exc_raise(rb_exc_new3(rb_eLoadError, mesg)); + rb_loaderror_with_path(fname, "cannot load such file -- %s", RSTRING_PTR(fname)); + RB_GC_GUARD(fname); } static VALUE diff --git a/ruby.c b/ruby.c index 1ad68ca..16e66c8 100644 --- a/ruby.c +++ b/ruby.c @@ -1560,7 +1560,7 @@ load_file_internal(VALUE arg) } } } - rb_raise(rb_eLoadError, "no Ruby script found in input"); + rb_loaderror("no Ruby script found in input"); } c = rb_io_getbyte(f); diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb index 379efec..e0e885d 100644 --- a/test/ruby/test_require.rb +++ b/test/ruby/test_require.rb @@ -5,6 +5,14 @@ require_relative 'envutil' require 'tmpdir' class TestRequire < Test::Unit::TestCase + def test_load_error_path + filename = "should_not_exist" + error = assert_raises(LoadError) do + require filename + end + assert_equal filename, error.path + end + def test_require_invalid_shared_object t = Tempfile.new(["test_ruby_test_require", ".so"]) t.puts "dummy"