From 385ac07fd8f5a50825aee8db459086e617f492aa Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Mon, 4 May 2020 16:56:45 +0200 Subject: [PATCH] Use receiver #name rather than #inspect to build NameError message --- error.c | 15 +++++++++++++- spec/ruby/language/constants_spec.rb | 30 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/error.c b/error.c index 31ffc32723..553f9c7daa 100644 --- a/error.c +++ b/error.c @@ -1761,6 +1761,17 @@ name_err_mesg_equal(VALUE obj1, VALUE obj2) return Qtrue; } +/* :nodoc: */ +static VALUE +name_err_mesg_receiver_name(VALUE obj) +{ + if (RB_SPECIAL_CONST_P(obj)) return Qundef; + if (RB_BUILTIN_TYPE(obj) == T_MODULE || RB_BUILTIN_TYPE(obj) == T_CLASS) { + return rb_check_funcall(obj, rb_intern("name"), 0, 0); + } + return Qundef; +} + /* :nodoc: */ static VALUE name_err_mesg_to_str(VALUE obj) @@ -1789,7 +1800,9 @@ name_err_mesg_to_str(VALUE obj) d = FAKE_CSTR(&d_str, "false"); break; default: - d = rb_protect(rb_inspect, obj, &state); + d = rb_protect(name_err_mesg_receiver_name, obj, &state); + if (state || d == Qundef || d == Qnil) + d = rb_protect(rb_inspect, obj, &state); if (state) rb_set_errinfo(Qnil); if (NIL_P(d)) { diff --git a/spec/ruby/language/constants_spec.rb b/spec/ruby/language/constants_spec.rb index 95b0dcace9..47897234b9 100644 --- a/spec/ruby/language/constants_spec.rb +++ b/spec/ruby/language/constants_spec.rb @@ -154,6 +154,36 @@ describe "Literal (A::X) constant resolution" do -> { ConstantSpecs::ParentA::CS_CONSTX }.should raise_error(NameError) end + ruby_version_is "2.8" do + it "uses the module or class #name to craft the error message" do + mod = Module.new do + def self.name + "ModuleName" + end + + def self.inspect + "" + end + end + + -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant ModuleName::DOES_NOT_EXIST/) + end + + it "uses the module or class #inspect to craft the error message if they are anonymous" do + mod = Module.new do + def self.name + nil + end + + def self.inspect + "" + end + end + + -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant ::DOES_NOT_EXIST/) + end + end + it "sends #const_missing to the original class or module scope" do ConstantSpecs::ClassA::CS_CONSTX.should == :CS_CONSTX end