From: Kornelius Kalnbach Date: 2010-02-16T11:53:56+09:00 Subject: [ruby-core:28184] [Feature #2740] Extend const_missing to pass in the nesting Issue #2740 has been updated by Kornelius Kalnbach. File const_missing_murphy.patch added Nobu, great to see a patch for this! Thank you. However, it didn't produce the desired results for me. After some debugging, I got a version that works for me: class Object def self.const_missing(id) namespace = "#{name}::" unless self == Object puts "Searching for #{namespace}#{id}..." raise NoConstantError end end class Foo class Bar p Module.nesting Baz rescue nil # [Foo::Bar, Foo] # Searching for Foo::Bar::Baz... # Searching for Foo::Baz... # Searching for Baz... end end class Foo::Bar p Module.nesting Baz rescue nil # [Foo::Bar] # Searching for Foo::Bar::Baz... # Searching for Baz... end It also passes "make test". Yehuda: Your example works as you described with this patch. Index: error.c =================================================================== --- error.c (revision 26674) +++ error.c (working copy) @@ -402,4 +402,6 @@ VALUE rb_eSyntaxError; VALUE rb_eLoadError; +VALUE rb_eNoConstantError; + VALUE rb_eSystemCallError; VALUE rb_mErrno; @@ -1143,4 +1145,5 @@ Init_Exception(void) rb_define_method(rb_eNoMethodError, "initialize", nometh_err_initialize, -1); rb_define_method(rb_eNoMethodError, "args", nometh_err_args, 0); + rb_eNoConstantError = rb_define_class("NoConstantError", rb_eNameError); rb_eRuntimeError = rb_define_class("RuntimeError", rb_eStandardError); Index: variable.c =================================================================== --- variable.c (revision 26674) +++ variable.c (working copy) @@ -1355,9 +1355,31 @@ } static VALUE +const_missing_call(VALUE arg) +{ + VALUE *args = (VALUE *)arg; + ID const_missing_id; + CONST_ID(const_missing_id, "const_missing"); + return rb_check_funcall(args[0], const_missing_id, 1, &args[1]); +} + +static VALUE +const_missing_rescue(VALUE arg, VALUE errinfo) +{ + return arg; +} + +extern VALUE rb_eNoConstantError; + +static VALUE const_missing(VALUE klass, ID id) { - return rb_funcall(klass, rb_intern("const_missing"), 1, ID2SYM(id)); + VALUE args[2]; + args[0] = klass; + args[1] = ID2SYM(id); + return rb_rescue2(const_missing_call, (VALUE)args, + const_missing_rescue, (VALUE)Qundef, + rb_eNoConstantError, (VALUE)0); } @@ -1392,8 +1414,7 @@ VALUE rb_mod_const_missing(VALUE klass, VALUE name) { - rb_frame_pop(); /* pop frame for "const_missing" */ - uninitialized_constant(klass, rb_to_id(name)); + rb_raise(rb_eNoConstantError, "uninitialized constant"); return Qnil; /* not reached */ } @@ -1596,8 +1617,26 @@ tmp = rb_cObject; goto retry; } + + tmp = klass; + if ((value = const_missing(tmp, id)) == Qundef) { + NODE *rb_vm_cref(void); + NODE *cref = rb_vm_cref(); + cref = cref->nd_next; + while (cref && cref->nd_next && + ((cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) || + NIL_P(tmp = cref->nd_clss) || + (value = const_missing(tmp, id)) == Qundef)) { + cref = cref->nd_next; + } + if (value == Qundef) { + if (!exclude && (BUILTIN_TYPE(klass) == T_MODULE || BUILTIN_TYPE(klass) == T_CLASS) && + (value = const_missing(rb_cObject, id)) == Qundef) { + uninitialized_constant(klass, id); + } + } + } - value = const_missing(klass, id); rb_vm_inc_const_missing_count(); return value; } ---------------------------------------- http://redmine.ruby-lang.org/issues/show/2740 ---------------------------------------- http://redmine.ruby-lang.org