summaryrefslogtreecommitdiff
path: root/object.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-12-14 02:25:58 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-12-14 02:25:58 +0000
commit241ca7bfff26b1f624ef64212b68d76efcb78f9d (patch)
tree63b20717be85a882ae66cac86e213da3c49d314d /object.c
parenta68c69d196b76d42cf74aba497a37cbf1be87bf9 (diff)
object.c: nested path const_defined?
* object.c (rb_mod_const_defined): support nested class path as well as const_get. [Feature #7414] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44194 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'object.c')
-rw-r--r--object.c88
1 files changed, 78 insertions, 10 deletions
diff --git a/object.c b/object.c
index 9c84fe5..9b8ca74 100644
--- a/object.c
+++ b/object.c
@@ -2213,6 +2213,8 @@ static VALUE
rb_mod_const_defined(int argc, VALUE *argv, VALUE mod)
{
VALUE name, recur;
+ rb_encoding *enc;
+ const char *pbeg, *p, *path, *pend;
ID id;
if (argc == 1) {
@@ -2222,20 +2224,86 @@ rb_mod_const_defined(int argc, VALUE *argv, VALUE mod)
else {
rb_scan_args(argc, argv, "11", &name, &recur);
}
- if (!(id = rb_check_id(&name))) {
- if (rb_is_const_name(name)) {
- return Qfalse;
+
+ if (SYMBOL_P(name)) {
+ id = SYM2ID(name);
+ if (!rb_is_const_id(id)) goto wrong_id;
+ return RTEST(recur) ? rb_const_defined(mod, id) : rb_const_defined_at(mod, id);
+ }
+
+ path = StringValuePtr(name);
+ enc = rb_enc_get(name);
+
+ if (!rb_enc_asciicompat(enc)) {
+ rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
+ }
+
+ pbeg = p = path;
+ pend = path + RSTRING_LEN(name);
+
+ if (p >= pend || !*p) {
+ wrong_name:
+ rb_raise(rb_eNameError, "wrong constant name %"PRIsVALUE,
+ QUOTE(name));
+ }
+
+ if (p + 2 < pend && p[0] == ':' && p[1] == ':') {
+ mod = rb_cObject;
+ p += 2;
+ pbeg = p;
+ }
+
+ while (p < pend) {
+ VALUE part;
+ long len, beglen;
+
+ while (p < pend && *p != ':') p++;
+
+ if (pbeg == p) goto wrong_name;
+
+ id = rb_check_id_cstr(pbeg, len = p-pbeg, enc);
+ beglen = pbeg-path;
+
+ if (p < pend && p[0] == ':') {
+ if (p + 2 >= pend || p[1] != ':') goto wrong_name;
+ p += 2;
+ pbeg = p;
+ }
+
+ if (!id) {
+ if (!ISUPPER(*pbeg) || !rb_enc_symname2_p(pbeg, len, enc)) {
+ part = rb_str_subseq(name, beglen, len);
+ rb_name_error_str(part, "wrong constant name %"PRIsVALUE,
+ QUOTE(part));
+ }
+ else {
+ return Qfalse;
+ }
+ }
+ if (!rb_is_const_id(id)) {
+ wrong_id:
+ rb_name_error(id, "wrong constant name %"PRIsVALUE,
+ QUOTE_ID(id));
+ }
+ if (RTEST(recur)) {
+ if (!rb_const_defined(mod, id))
+ return Qfalse;
+ mod = rb_const_get(mod, id);
}
else {
- rb_name_error_str(name, "wrong constant name %"PRIsVALUE,
- QUOTE(name));
+ if (!rb_const_defined_at(mod, id))
+ return Qfalse;
+ mod = rb_const_get_at(mod, id);
+ }
+ recur = Qfalse;
+
+ if (p < pend && !RB_TYPE_P(mod, T_MODULE) && !RB_TYPE_P(mod, T_CLASS)) {
+ rb_raise(rb_eTypeError, "%"PRIsVALUE" does not refer to class/module",
+ QUOTE(name));
}
}
- if (!rb_is_const_id(id)) {
- rb_name_error(id, "wrong constant name %"PRIsVALUE,
- QUOTE_ID(id));
- }
- return RTEST(recur) ? rb_const_defined(mod, id) : rb_const_defined_at(mod, id);
+
+ return Qtrue;
}
/*