[ruby-dev:39671] [Feature:trunk] hide the internal of anonymous Enumerator

View: New views
2 Messages — Rating Filter:   Alert me  

[ruby-dev:39671] [Feature:trunk] hide the internal of anonymous Enumerator

by Yusuke ENDOH :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

遠藤です。

[ruby-dev:39665] より引用。

2009年11月12日0:38 Akinori MUSHA <knu@...>:
>  Yielder/Generator という組合せによる実装は実験的なもので、特に
> 後者は外部に公開する必要がないので敢えて伏せていました。公開仕様に
> すると制約になるので、需要が生じるまでは非公開の方がいいのではない
> でしょうか。

ということなら、なるべく内部実装をユーザから見えないようにしませんか?

- Enumerator::Generator を匿名クラスにする (ARGF のように)
- Generator.new や Yielder.new を禁止する
- Enumerator#inspect で Generator の存在は隠す

とするパッチを書いてみました。どうでしょう。


diff --git a/enumerator.c b/enumerator.c
index 7c50f3d..88c37fd 100644
--- a/enumerator.c
+++ b/enumerator.c
@@ -886,29 +886,34 @@ inspect_enumerator(VALUE obj, VALUE dummy, int recur)
     untrusted = OBJ_UNTRUSTED(eobj);

     /* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>" */
-    str = rb_sprintf("#<%s: ", cname);
-    rb_str_concat(str, rb_inspect(eobj));
-    rb_str_buf_cat2(str, ":");
-    rb_str_buf_cat2(str, rb_id2name(e->meth));
+    if (rb_obj_is_kind_of(eobj, rb_cGenerator)) {
+ str = rb_sprintf("#<%s:%p>", cname, (void*)eobj);
+    }
+    else {
+ str = rb_sprintf("#<%s: ", cname);
+ rb_str_concat(str, rb_inspect(eobj));
+ rb_str_buf_cat2(str, ":");
+ rb_str_buf_cat2(str, rb_id2name(e->meth));

-    if (e->args) {
- long   argc = RARRAY_LEN(e->args);
- VALUE *argv = RARRAY_PTR(e->args);
+        if (e->args) {
+    long   argc = RARRAY_LEN(e->args);
+    VALUE *argv = RARRAY_PTR(e->args);

- rb_str_buf_cat2(str, "(");
+    rb_str_buf_cat2(str, "(");

- while (argc--) {
-    VALUE arg = *argv++;
+    while (argc--) {
+ VALUE arg = *argv++;

-    rb_str_concat(str, rb_inspect(arg));
-    rb_str_buf_cat2(str, argc > 0 ? ", " : ")");
+ rb_str_concat(str, rb_inspect(arg));
+ rb_str_buf_cat2(str, argc > 0 ? ", " : ")");

-    if (OBJ_TAINTED(arg)) tainted = TRUE;
-    if (OBJ_UNTRUSTED(arg)) untrusted = TRUE;
- }
-    }
+ if (OBJ_TAINTED(arg)) tainted = TRUE;
+ if (OBJ_UNTRUSTED(arg)) untrusted = TRUE;
+    }
+        }

-    rb_str_buf_cat2(str, ">");
+ rb_str_buf_cat2(str, ">");
+    }

     if (tainted) OBJ_TAINT(str);
     if (untrusted) OBJ_UNTRUST(str);
@@ -1223,17 +1228,17 @@ Init_Enumerator(void)
     rb_define_method(rb_eStopIteration, "result", stop_result, 0);

     /* Generator */
-    rb_cGenerator = rb_define_class_under(rb_cEnumerator,
"Generator", rb_cObject);
+    rb_cGenerator = rb_class_new(rb_cObject);
+    rb_undef_alloc_func(rb_cGenerator);
+    rb_set_class_path(rb_cGenerator, rb_cObject, "Enumerator::Generator");
     rb_include_module(rb_cGenerator, rb_mEnumerable);
-    rb_define_alloc_func(rb_cGenerator, generator_allocate);
-    rb_define_method(rb_cGenerator, "initialize", generator_initialize, -1);
-    rb_define_method(rb_cGenerator, "initialize_copy", generator_init_copy, 1);
     rb_define_method(rb_cGenerator, "each", generator_each, 0);
+    rb_obj_freeze(rb_cGenerator);
+    rb_gc_register_mark_object(rb_cGenerator);

     /* Yielder */
     rb_cYielder = rb_define_class_under(rb_cEnumerator, "Yielder", rb_cObject);
-    rb_define_alloc_func(rb_cYielder, yielder_allocate);
-    rb_define_method(rb_cYielder, "initialize", yielder_initialize, 0);
+    rb_undef_alloc_func(rb_cYielder);
     rb_define_method(rb_cYielder, "yield", yielder_yield, -2);
     rb_define_method(rb_cYielder, "<<", yielder_yield_push, -2);


--
Yusuke ENDOH <mame@...>


[ruby-dev:39674] Re: [Feature:trunk] hide the internal of anonymous Enumerator

by Akinori MUSHA :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

At Thu, 12 Nov 2009 20:53:54 +0900,
Yusuke ENDOH wrote:

> [ruby-dev:39665] より引用。
>
> 2009年11月12日0:38 Akinori MUSHA <knu@...>:
> >  Yielder/Generator という組合せによる実装は実験的なもので、特に
> > 後者は外部に公開する必要がないので敢えて伏せていました。公開仕様に
> > すると制約になるので、需要が生じるまでは非公開の方がいいのではない
> > でしょうか。
>
> ということなら、なるべく内部実装をユーザから見えないようにしませんか?
>
> - Enumerator::Generator を匿名クラスにする (ARGF のように)
> - Generator.new や Yielder.new を禁止する
> - Enumerator#inspect で Generator の存在は隠す
>
> とするパッチを書いてみました。どうでしょう。
 そこまでする必要はないかと思っていたんですが、どうでしょうね。
いじられてSEGVするようなものでなければ、デバッグのためには隠し
すぎない方がいいんじゃないかとか、互換性は保証しないけどそれを
敢えて使って実験的なライブラリを書く自由までは奪いたくないとか、
そういう考えもあるんですよね。まあ、一言で言うと私の都合ですが。

 とはいえ、undocumentedであっても見えると一般利用されて、それが
メジャーになると、互換性を崩すとruby側に文句が来たりするかなあ。
難しいですね…。

--
Akinori MUSHA / http://akinori.org/


attachment0 (203 bytes) Download Attachment