From: nobuyoshi nakada Date: 2005-06-24T18:21:50+09:00 Subject: Re: string to Class object Hi, At Fri, 24 Jun 2005 16:07:18 +0900, Mark Hubbart wrote in [ruby-talk:146353]: > What about adding a Kernel#const_get that does this? That might > separate things a little better; a global method that decodes any > class name, nested or not, based on current context. Kernel also is one of modules. $ ruby -e 'p Kernel.const_get("Object")' Object Index: object.c =================================================================== RCS file: /cvs/ruby/src/ruby/object.c,v retrieving revision 1.169 diff -U2 -p -r1.169 object.c --- object.c 11 May 2005 07:00:32 -0000 1.169 +++ object.c 24 Jun 2005 04:37:33 -0000 @@ -1715,9 +1715,46 @@ rb_mod_attr_accessor(argc, argv, klass) } +static ID +mod_const_id(namep) + volatile VALUE *namep; +{ + VALUE tmp, name = *namep; + ID id; + + switch (TYPE(name)) { + case T_STRING: + break; + case T_FIXNUM: + rb_warn("do not use Fixnums as Symbols"); + id = FIX2LONG(name); + if (!rb_id2name(id)) { + rb_raise(rb_eArgError, "%ld is not a symbol", id); + } + return id; + case T_SYMBOL: + return SYM2ID(name); + default: + tmp = rb_check_string_type(name); + if (NIL_P(tmp)) { + rb_raise(rb_eTypeError, "%s is not a symbol", RSTRING(rb_inspect(name))->ptr); + } + *namep = name = tmp; + } + if (RSTRING(name)->ptr && strchr(RSTRING(name)->ptr, ':')) + return 0; + + id = str_to_id(name); + if (!rb_is_const_id(id)) { + rb_name_error(id, "wrong constant name %s", rb_id2name(id)); + } + + return id; +} + /* * call-seq: * mod.const_get(sym) => obj * - * Returns the value of the named constant in mod. + * Returns the value of the named constant under mod. * * Math.const_get(:PI) #=> 3.14159265358979 @@ -1728,9 +1765,10 @@ rb_mod_const_get(mod, name) VALUE mod, name; { - ID id = rb_to_id(name); + ID id = mod_const_id(&name); - if (!rb_is_const_id(id)) { - rb_name_error(id, "wrong constant name %s", rb_id2name(id)); + if (!id) { + return rb_path2const(RSTRING(name)->ptr, mod, Qtrue); } + return rb_const_get(mod, id); } Index: variable.c =================================================================== RCS file: /cvs/ruby/src/ruby/variable.c,v retrieving revision 1.121 diff -U2 -p -r1.121 variable.c --- variable.c 13 May 2005 08:56:14 -0000 1.121 +++ variable.c 24 Jun 2005 04:17:48 -0000 @@ -234,11 +234,21 @@ rb_set_class_path(klass, under, name) VALUE -rb_path2class(path) +rb_path2const(path, cbase, idcheck) const char *path; + VALUE cbase; + int idcheck; { const char *pbeg, *p; ID id; - VALUE c = rb_cObject; + VALUE c = cbase; + switch (TYPE(cbase)) { + case T_MODULE: + case T_CLASS: + break; + default: + rb_raise(rb_eTypeError, "class or module required but %s given", + rb_obj_classname(cbase)); + } if (path[0] == '#') { rb_raise(rb_eArgError, "can't retrieve anonymous class %s", path); @@ -249,6 +259,9 @@ rb_path2class(path) while (*p && *p != ':') p++; - str = rb_str_new(pbeg, p-pbeg); + *(volatile VALUE *)&str = rb_str_new(pbeg, p-pbeg); id = rb_intern(RSTRING(str)->ptr); + if (idcheck && !rb_is_const_id(id)) { + rb_name_error(id, "wrong constant name %s", RSTRING(str)->ptr); + } if (p[0] == ':') { if (p[1] != ':') goto undefined_class; @@ -258,7 +271,15 @@ rb_path2class(path) if (!rb_const_defined(c, id)) { undefined_class: - rb_raise(rb_eArgError, "undefined class/module %.*s", p-path, path); + if (cbase == rb_cObject) { + rb_raise(rb_eArgError, "undefined class/module %s", + RSTRING(str)->ptr); + } + else { + rb_raise(rb_eArgError, "undefined class/module %s under %s", + RSTRING(str)->ptr, rb_class2name(c)); + } } c = rb_const_get_at(c, id); + if (!*p) break; switch (TYPE(c)) { case T_MODULE: @@ -273,4 +294,21 @@ rb_path2class(path) } +VALUE +rb_path2class(path) + const char *path; +{ + VALUE c = rb_path2const(path, rb_cObject, Qfalse); + + switch (TYPE(c)) { + case T_MODULE: + case T_CLASS: + break; + default: + rb_raise(rb_eTypeError, "%s does not refer class/module", path); + } + + return c; +} + void rb_name_class(klass, id) Index: intern.h =================================================================== RCS file: /cvs/ruby/src/ruby/intern.h,v retrieving revision 1.170 diff -U2 -p -r1.170 intern.h --- intern.h 12 Jun 2005 16:56:05 -0000 1.170 +++ intern.h 24 Jun 2005 03:57:26 -0000 @@ -504,6 +504,7 @@ VALUE rb_mod_name _((VALUE)); VALUE rb_class_path _((VALUE)); void rb_set_class_path _((VALUE, VALUE, const char*)); +VALUE rb_path2const _((const char*, VALUE, int)); VALUE rb_path2class _((const char*)); void rb_name_class _((VALUE, ID)); VALUE rb_class_name _((VALUE)); -- Nobu Nakada