[前][次][番号順一覧][スレッド一覧]

ruby-changes:32115

From: nobu <ko1@a...>
Date: Sat, 14 Dec 2013 11:26:02 +0900 (JST)
Subject: [ruby-changes:32115] nobu:r44194 (trunk): object.c: nested path const_defined?

nobu	2013-12-14 11:25:58 +0900 (Sat, 14 Dec 2013)

  New Revision: 44194

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=44194

  Log:
    object.c: nested path const_defined?
    
    * object.c (rb_mod_const_defined): support nested class path as
      well as const_get.  [Feature #7414]

  Modified files:
    trunk/ChangeLog
    trunk/object.c
    trunk/test/ruby/test_module.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 44193)
+++ ChangeLog	(revision 44194)
@@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sat Dec 14 11:25:56 2013  Nobuyoshi Nakada  <nobu@r...>
+
+	* object.c (rb_mod_const_defined): support nested class path as
+	  well as const_get.  [Feature #7414]
+
 Sat Dec 14 01:31:52 2013  Nobuyoshi Nakada  <nobu@r...>
 
 	* eval.c (rb_rescue2): reuse tags pushed for body proc to protect
Index: object.c
===================================================================
--- object.c	(revision 44193)
+++ object.c	(revision 44194)
@@ -2213,6 +2213,8 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/object.c#L2213
 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 *ar https://github.com/ruby/ruby/blob/trunk/object.c#L2224
     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;
 }
 
 /*
Index: test/ruby/test_module.rb
===================================================================
--- test/ruby/test_module.rb	(revision 44193)
+++ test/ruby/test_module.rb	(revision 44194)
@@ -303,6 +303,26 @@ class TestModule < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_module.rb#L303
     end
   end
 
+  def test_nested_defined
+    assert_send([Object, :const_defined?, [self.class.name, 'Other'].join('::')])
+    assert_send([self.class, :const_defined?, 'User::USER'])
+    assert_not_send([self.class, :const_defined?, 'User::Foo'])
+  end
+
+  def test_nested_defined_symbol
+    const = [self.class, Other].join('::').to_sym
+    assert_raise(NameError) {Object.const_defined?(const)}
+
+    const = [User, 'USER'].join('::').to_sym
+    assert_raise(NameError) {self.class.const_defined?(const)}
+  end
+
+  def test_nested_defined_bad_class
+    assert_raise(TypeError) do
+      self.class.const_defined?('User::USER::Foo')
+    end
+  end
+
   def test_const_set
     assert_not_operator(Other, :const_defined?, :KOALA)
     Other.const_set(:KOALA, 99)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]