Feature #12041
openChange the initializer of NameError to take a receiver as the third argument
Description
I would like to change NameError#initialize
to take a receiver object as the third argument. An example would be like this:
receiver_object = Object.new
name_error = NameError.new("Error message", "name", receiver_object)
name_error.receiver.equal?(receiver_object) # => true
The reason I wanted this change is Rails overrides Module#const_missing
and raises an NameError without a receiver object. It has actually affected one of the did_you_mean's spell checkers and thus no suggestions for constant names will be made on Rails. One more use case I can think of is when there's a class that inherits from NameError
or NoMethodError
and an arbitrary receiver needs to be passed to the initializer of the class.
Please let me know if you have any thoughts.
Updated by nobu (Nobuyoshi Nakada) almost 9 years ago
What's about NoMethodError
?
Currently, it is
NoMethodError.new(msg, name [, args]) #-> no_method_error
If NameError#initialize
has third argument, where will it be placed?
The last?
NoMethodError.new(msg, name [, args [,receiver]]) #-> no_method_error
or same as NameError#initialize
?
NoMethodError.new(msg, name [, receiver [, args]]) #-> no_method_error
A patch for the latter.
diff --git i/error.c w/error.c
index f88c19a..0ae9b58 100644
--- i/error.c
+++ w/error.c
@@ -1127,7 +1127,7 @@ rb_name_error_str(VALUE str, const char *fmt, ...)
/*
* call-seq:
- * NameError.new(msg [, name]) -> name_error
+ * NameError.new(msg [, name [, receiver]]) -> name_error
*
* Construct a new NameError exception. If given the <i>name</i>
* parameter may subsequently be examined using the <code>NameError.name</code>
@@ -1138,8 +1138,10 @@ static VALUE
name_err_initialize(int argc, VALUE *argv, VALUE self)
{
VALUE name;
+ VALUE recv;
VALUE iseqw = Qnil;
+ recv = (argc > 2) ? argv[--argc] : Qundef;
name = (argc > 1) ? argv[--argc] : Qnil;
rb_call_super(argc, argv);
rb_ivar_set(self, id_name, name);
@@ -1150,6 +1152,7 @@ name_err_initialize(int argc, VALUE *argv, VALUE self)
if (cfp) iseqw = rb_iseqw_new(cfp->iseq);
}
rb_ivar_set(self, id_iseq, iseqw);
+ if (recv != Qundef) rb_ivar_set(self, id_receiver, recv);
return self;
}
@@ -1192,7 +1195,7 @@ name_err_local_variables(VALUE self)
/*
* call-seq:
- * NoMethodError.new(msg, name [, args]) -> no_method_error
+ * NoMethodError.new(msg, name [, receiver [, args]]) -> no_method_error
*
* Construct a NoMethodError exception for a method of the given name
* called with the given arguments. The name may be accessed using
diff --git i/test/ruby/test_exception.rb w/test/ruby/test_exception.rb
index 91732dd..e546988 100644
--- i/test/ruby/test_exception.rb
+++ w/test/ruby/test_exception.rb
@@ -699,6 +699,11 @@
assert_equal(:foo, e.name)
assert_same(obj, e.receiver)
assert_equal(%i[a b c d e f g], e.local_variables.sort)
+
+ obj = Object.new
+ e = NameError.new("error", :foo, obj)
+ assert_equal(:foo, e.name)
+ assert_same(obj, e.receiver)
end
def test_name_error_info_parent_iseq_mark
Updated by yuki24 (Yuki Nishijima) almost 9 years ago
Speaking of NoMethodError
, I think the former (NoMethodError.new(msg, name [, args [,receiver]])
) makes more sense to me since the latter may break existing apps.
Updated by nobu (Nobuyoshi Nakada) almost 9 years ago
Nobuyoshi Nakada wrote:
or same as
NameError#initialize
?NoMethodError.new(msg, name [, receiver [, args]]) #-> no_method_error
This was wrong.
The previous patch is:
NoMethodError.new(msg, name [[, receiver], args]) #-> no_method_error
Updated by nobu (Nobuyoshi Nakada) almost 9 years ago
I found this causes drb
test failures, since NoMethodError
now refers DRbObject
and Marshal.dump
fails.