[#28681] ブロックパラメータと多値について — Takaaki Tateishi <ttate@...>

11 messages 2006/06/02

[#28708] 1.8.5 release schedule? — URABE Shyouhei <root@...>

というわけで今日の基調講演で8月に1.8.5が出ることになったわけですが。

105 messages 2006/06/10
[#28709] Re: 1.8.5 release schedule? — Yukihiro Matsumoto <matz@...> 2006/06/10

まつもと ゆきひろです

[#28711] Re: 1.8.5 release schedule? — URABE Shyouhei <root@...> 2006/06/11

卜部です。

[#28751] Re: 1.8.5 release schedule? — URABE Shyouhei <root@...> 2006/06/19

卜部です。

[#28752] Re: 1.8.5 release schedule? — Yukihiro Matsumoto <matz@...> 2006/06/19

まつもと ゆきひろです

[#28753] Re: 1.8.5 release schedule? — URABE Shyouhei <root@...> 2006/06/19

卜部です。

[#28754] Re: 1.8.5 release schedule? — Yukihiro Matsumoto <matz@...> 2006/06/19

まつもと ゆきひろです

[#28813] Re: 1.8.5 release schedule? — URABE Shyouhei <root@...> 2006/06/23

卜部です。

[#28818] ruby 1.8.5 preview1 (Re: Re: 1.8.5 release schedule?) — Yukihiro Matsumoto <matz@...> 2006/06/24

まつもと ゆきひろです

[#28819] Re: ruby 1.8.5 preview1 (Re: Re: 1.8.5 release schedule?) — URABE Shyouhei <root@...> 2006/06/24

卜部です。

[#28820] Re: ruby 1.8.5 preview1 (Re: Re: 1.8.5 release schedule?) — Kouhei Yanagita <yanagi@...> 2006/06/24

柳田です。

[#28821] udp test with ruby 1.8.5 preview1 on cygwin — Tanaka Akira <akr@...17n.org> 2006/06/24

In article <y7vnup05.wl%yanagi@shakenbu.org>,

[#28823] Re: udp test with ruby 1.8.5 preview1 on cygwin — Kouhei Yanagita <yanagi@...> 2006/06/24

> いちおう問題の切り分けをするために確認したいんですが、その環

[#28824] Re: udp test with ruby 1.8.5 preview1 on cygwin — Tanaka Akira <akr@...17n.org> 2006/06/24

In article <veqrun77.wl%yanagi@shakenbu.org>,

[#28825] Re: udp test with ruby 1.8.5 preview1 on cygwin — Kouhei Yanagita <yanagi@...> 2006/06/24

mswin32 版ではどうなるのだろうと思って

[#28833] Re: udp test with ruby 1.8.5 preview1 on cygwin — info@... 2006/06/24

Cygwin @ WindowsXP SP2 です。

[#28834] Re: udp test with ruby 1.8.5 preview1 on cygwin — Tanaka Akira <akr@...17n.org> 2006/06/24

In article <449D66EC.8050405@cyanet.jp>,

[#29120] Re: 1.8.5 release schedule? — "U.Nakamura" <usa@...> 2006/07/24

こんにちは、なかむら(う)です。

[#29121] Re: 1.8.5 release schedule? — Yukihiro Matsumoto <matz@...> 2006/07/24

まつもと ゆきひろです

[#29128] bugs in ruby_1_8 (Re: 1.8.5 release schedule?) — URABE Shyouhei <root@...> 2006/07/25

卜部です。

[#29133] Re: bugs in ruby_1_8 (Re: 1.8.5 release schedule?) — Yukihiro Matsumoto <matz@...> 2006/07/26

まつもと ゆきひろです

[#29144] Re: bugs in ruby_1_8 (Re: 1.8.5 release schedule?) — URABE Shyouhei <root@...> 2006/07/26

卜部です。

[#29146] Re: bugs in ruby_1_8 (Re: 1.8.5 release schedule?) — Yukihiro Matsumoto <matz@...> 2006/07/26

まつもと ゆきひろです

[#29185] 1.8.5 preview3? — URABE Shyouhei <root@...> 2006/08/04

卜部です。

[#29186] Re: 1.8.5 preview3? — Yukihiro Matsumoto <matz@...> 2006/08/04

まつもと ゆきひろです

[#29225] Re: 1.8.5 preview3? — URABE Shyouhei <root@...> 2006/08/08

卜部です。

[#29226] Re: 1.8.5 preview3? — Yukihiro Matsumoto <matz@...> 2006/08/08

まつもと ゆきひろです

[#29228] Re: 1.8.5 preview3? — Yukihiro Matsumoto <matz@...> 2006/08/08

まつもと ゆきひろです

[#29231] Re: 1.8.5 preview3? — URABE Shyouhei <root@...> 2006/08/08

卜部です。

[#28718] binding の仕様変更? or バグ? — Hidetoshi NAGAI <nagai@...>

永井@知能.九工大です.

15 messages 2006/06/12

[#28744] rational 1.08 — Tadayoshi Funaba <tadf@...>

ふなばです。

27 messages 2006/06/18
[#28773] Re: rational 1.08 — Shin-ichiro HARA <sinara@...> 2006/06/20

原です。

[#28830] Re: rational 1.08 — Tadayoshi Funaba <tadf@...> 2006/06/24

ふなばです。

[ruby-dev:28735] Module#toplevel_eval (Re: binding の仕様変更? or バグ?)

From: Hidetoshi NAGAI <nagai@...>
Date: 2006-06-14 23:35:03 UTC
List: ruby-dev #28735
永井@知能.九工大です.

# 変なことばかりやってるんで全く相手にされてないですね...(;_;)

他に悪影響がでないということを条件に,とりあえず実装してみました.
現状に対して非常に困っておりますし,互換性にも影響がないはず
(だと思います) なので,なんとか採用していただくことはできないでしょうか.
CVS の ruby_1_8 との差分を添付します.

Module#toplevel_eval は module_eval と同様に文字列またはブロックで
コード片を受け取り,評価します.
ただし,評価されるコード片の中では,

 * モジュールで定義されたメソッドを関数型メソッドとして呼び出せる.

 * ::CONST のような定数アクセスは,そのモジュールのコンテキストを
   最優先に行う.見つからなければ本来のトップレベルを検索するが,
   代入の場合はそのモジュール (の特異クラスの) のコンテキストで行われる.

というようになります.
これにより,関数型のメソッドを使って作られたスクリプトを,
モジュールをトップレベルとして load しても動くはずです.
また,::CONST = val の実行などで本来のトップレベルが汚染されることも
避けられると思います.

なお,評価されるコードの中で新たにスレッドを作った場合,
設定はそのスレッドに引き継がれます.
ただし評価されるコード中であっても,requrie (autoload 含む) が
呼ばれた場合には,require が完了するまでこの性質は無効にされます.
# ライブラリでのトラブルを避けるためです.

ちょっと長いですが,module_eval との違いは次のようになります.
======================================================
module M
  HOGE = 111
  def foo(*args)
    p [self, args]
  end
end

class X
end

########################################

begin
  p '-----(1)-----'
  M.module_eval{foo(1,2,3)}
rescue
  p $!
end
#=> #<NoMethodError: undefined method `foo' for M:Module>

begin
  p '-----(2)-----'
  M.toplevel_eval{foo(1,2,3)}
rescue
  p $!
end
#=> [M, [1, 2, 3]]

begin
  p '-----(3)-----'
  M.module_eval{X.new.instance_eval{foo(1,2,3)}}
rescue
  p $!
end
#=> #<NoMethodError: undefined method `foo' for #<X:0x401d1308>>

begin
  p '-----(4)-----'
  M.toplevel_eval{X.new.instance_eval{foo(1,2,3)}}
rescue
  p $!
end
#=> [#<X:0x401d1178>, [1, 2, 3]]

begin
  p '-----(5)-----'
  M.module_eval{Object.new.instance_eval{foo(1,2,3)}}
rescue
  p $!
end
#=> #<NoMethodError: undefined method `foo' for #<Object:0x401d1074>>

begin
  p '-----(6)-----'
  M.toplevel_eval{Object.new.instance_eval{foo(1,2,3)}}
rescue
  p $!
end
#=> [#<Object:0x401d0ed0>, [1, 2, 3]]

begin
  p '-----(9)-----'
  M.module_eval{Object.new.instance_eval{p HOGE}}
rescue
  p $!
end
#=> #<NameError: uninitialized constant HOGE>

begin
  p '-----(10)-----'
  M.toplevel_eval{Object.new.instance_eval{p HOGE}}
rescue
  p $!
end
#=> 111

begin
  p '-----(11)-----'
  M.module_eval{X.new.instance_eval{p HOGE}}
rescue
  p $!
end
#=> #<NameError: uninitialized constant HOGE>

begin
  p '-----(12)-----'
  M.toplevel_eval{X.new.instance_eval{p HOGE}}
rescue
  p $!
end
#=> 111

begin
  p '-----(13)-----'
  M.module_eval{p ::HOGE}
rescue
  p $!
end
#=> #<NameError: uninitialized constant HOGE>

begin
  p '-----(14)-----'
  M.toplevel_eval{p ::HOGE}
rescue
  p $!
end
#=> 111

begin
  p '-----(15)-----'
  M.module_eval{p ::M}
rescue
  p $!
end
#=> M

begin
  p '-----(16)-----'
  M.toplevel_eval{p ::M}
rescue
  p $!
end
#=> M

begin
  p '-----(17)-----'
  M.module_eval{Object.new.instance_eval{p ::HOGE}}
rescue
  p $!
end
#=> #<NameError: uninitialized constant HOGE>

begin
  p '-----(18)-----'
  M.toplevel_eval{Object.new.instance_eval{p ::HOGE}}
rescue
  p $!
end
#=> 111

begin
  p '-----(19)-----'
  M.module_eval{X.new.instance_eval{p ::HOGE}}
rescue
  p $!
end
#=> #<NameError: uninitialized constant HOGE>

begin
  p '-----(20)-----'
  M.toplevel_eval{X.new.instance_eval{p ::HOGE}}
rescue
  p $!
end
#=> 111

begin
  p '-----(21)-----'
  M.module_eval{
    def hoge(*args)
      p [self, args]
    end
    hoge(:a, :b, :c)
    Object.new.instance_eval{hoge(:d, :e, :f)}
  }
rescue
  p $!
end
#=> #<NoMethodError: undefined method `hoge' for M:Module>

begin
  p '-----(22)-----'
  M.toplevel_eval{
    def fuga(*args)
      p [self, args]
    end
    fuga(:a, :b, :c)
    Object.new.instance_eval{fuga(:d, :e, :f)}
  }
rescue
  p $!
end
#=> [M, [:a, :b, :c]]
#=> [#<Object:0x401d04bc>, [:d, :e, :f]]

p '--------------------------'

p m = Module.new   #=> #<Module:0x401d0480>
m.toplevel_eval{
  FOO = :foo
  ::BAR = :bar

  def baz(*args)
    [self, args]
  end

p baz(1, FOO, ::FOO, ::BAR)
                   #=> [#<Module:0x401d0480>, [1, :foo, :foo, :bar]]
p Object.new.instance_eval{baz(2, FOO, ::FOO, ::BAR)}
                   #=> [#<Object:0x401d02dc>, [2, :foo, :foo, :bar]]
}
p m.constants      #=> ["BAR", "FOO"]
======================================================

-- 
                                       永井 秀利 (九工大 知能情報)
                                           nagai@ai.kyutech.ac.jp

Attachments (1)

eval.c.toplevel_eval-diff (10.1 KB, text/x-diff)
Index: eval.c
===================================================================
RCS file: /var/cvs/src/ruby/eval.c,v
retrieving revision 1.616.2.173
diff -u -r1.616.2.173 eval.c
--- eval.c	7 Jun 2006 00:19:11 -0000	1.616.2.173
+++ eval.c	14 Jun 2006 22:46:15 -0000
@@ -469,17 +469,39 @@
     rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, 0, NOEX_UNDEF);
 }
 
+static void current_toplevel_set(VALUE);
+static VALUE current_toplevel_get(void);
+
 static NODE*
 search_method(klass, id, origin)
     VALUE klass, *origin;
     ID id;
 {
     NODE *body;
+    VALUE top;
 
     if (!klass) return 0;
+
+    if (RCLASS(klass)->super == rb_cObject && (top = current_toplevel_get())) {
+        /* search current toplevel module before Object class */
+        if (st_lookup(RCLASS(top)->m_tbl, id, (st_data_t *)&body)) {
+            if (origin) *origin = top;
+            return body;
+        }
+    }
+
     while (!st_lookup(RCLASS(klass)->m_tbl, id, (st_data_t *)&body)) {
 	klass = RCLASS(klass)->super;
 	if (!klass) return 0;
+
+        if (RCLASS(klass)->super == rb_cObject 
+            && (top = current_toplevel_get())) {
+            /* search current toplevel module before Object class */
+            if (st_lookup(RCLASS(top)->m_tbl, id, (st_data_t *)&body)) {
+                klass = top;
+                break;
+            }
+        }
     }
 
     if (origin) *origin = klass;
@@ -1849,6 +1871,24 @@
 #define ruby_cbase (ruby_cref->nd_clss)
 
 static VALUE
+ev_const_defined_at_top(id)
+    ID id;
+{
+    VALUE result;
+    VALUE top = current_toplevel_get();
+
+    if (!top) {
+        return Qfalse;
+    }
+    if (RCLASS(top)->iv_tbl && st_lookup(RCLASS(top)->iv_tbl, id, &result)) {
+        if (result != Qundef) {
+            return Qtrue;
+        }
+    }
+    return Qfalse;
+}
+
+static VALUE
 ev_const_defined(cref, id, self)
     NODE *cref;
     ID id;
@@ -1857,6 +1897,11 @@
     NODE *cbase = cref;
     VALUE result;
 
+    /* if toplevel module is defined, search current toplevel first */
+    if (RTEST(ev_const_defined_at_top(id))) {
+        return Qtrue;
+    }
+
     while (cbase && cbase->nd_next) {
 	struct RClass *klass = RCLASS(cbase->nd_clss);
 
@@ -1881,6 +1926,16 @@
 {
     NODE *cbase = cref;
     VALUE result;
+    VALUE top = current_toplevel_get();
+
+    if (top) {
+        /* if toplevel module is defined, search current toplevel first */
+        if (RCLASS(top)->iv_tbl && st_lookup(RCLASS(top)->iv_tbl, id, &result)) {
+            if (result != Qundef) {
+                return result;
+            }
+        }
+    }
 
     while (cbase && cbase->nd_next) {
 	VALUE klass = cbase->nd_clss;
@@ -2458,9 +2513,14 @@
 	break;
 
       case NODE_COLON3:
-	if (rb_const_defined_from(rb_cObject, node->nd_mid)) {
-	    return "constant";
-	}
+        {
+            if (RTEST(ev_const_defined_at_top(node->nd_mid))) {
+                return "constant";
+            }
+            if (rb_const_defined_from(rb_cObject, node->nd_mid)) {
+                return "constant";
+            }
+        }
 	break;
 
       case NODE_NTH_REF:
@@ -2844,13 +2904,19 @@
 	return c;
     }
     else if (nd_type(cpath) == NODE_COLON2) {
-	return ruby_cbase;
+        return ruby_cbase;
     }
     else if (ruby_wrapper) {
 	return ruby_wrapper;
     }
     else {
-	return rb_cObject;
+        VALUE top = current_toplevel_get();
+        if (top) {
+            return top;
+        }
+        else {
+            return rb_cObject;
+        }
     }
 }
 
@@ -3643,7 +3709,13 @@
 	    rb_const_set(class_prefix(self, node->nd_else), node->nd_else->nd_mid, result);
 	}
 	else {
-	    rb_const_set(ruby_cbase, node->nd_vid, result);
+            VALUE top = current_toplevel_get();
+            if (top) {
+                rb_const_set(top, node->nd_vid, result);
+            }
+            else {
+                rb_const_set(ruby_cbase, node->nd_vid, result);
+            }
 	}
 	break;
 
@@ -3723,7 +3795,14 @@
 	break;
 
       case NODE_COLON3:
-	result = rb_const_get_from(rb_cObject, node->nd_mid);
+        {
+            if (RTEST(ev_const_defined_at_top(node->nd_mid))) {
+                result = rb_const_get_from(current_toplevel_get(), node->nd_mid);
+            }
+            else {
+                result = rb_const_get_from(rb_cObject, node->nd_mid);
+            }
+        }
 	break;
 
       case NODE_NTH_REF:
@@ -5187,7 +5266,13 @@
 	    rb_const_set(class_prefix(self, lhs->nd_else), lhs->nd_else->nd_mid, val);
 	}
 	else {
-	    rb_const_set(ruby_cbase, lhs->nd_vid, val);
+            VALUE top = current_toplevel_get();
+            if (top) {
+                rb_const_set(top, lhs->nd_vid, val);
+            }
+            else {
+                rb_const_set(ruby_cbase, lhs->nd_vid, val);
+            }
 	}
 	break;
 
@@ -6718,6 +6803,90 @@
     return specific_eval(argc, argv, mod, mod);
 }
 
+
+struct mod_toplevel_eval_arg {
+    int argc;
+    VALUE *argv;
+    VALUE mod;
+    VALUE orig_top;
+};
+
+VALUE
+mod_toplevel_eval_call(arg)
+    struct mod_toplevel_eval_arg *arg;
+{
+    current_toplevel_set(arg->mod);
+    return specific_eval(arg->argc, arg->argv, arg->mod, arg->mod);
+}
+
+VALUE
+mod_toplevel_eval_ensure(arg)
+    struct mod_toplevel_eval_arg *arg;
+{
+    RCLASS(arg->mod)->iv_tbl = 0;
+    RCLASS(arg->mod)->m_tbl = 0;
+
+    current_toplevel_set(arg->orig_top);
+}
+
+/*
+ *  call-seq:
+ *     mod.toplevel_eval(string [, filename [, lineno]] )   => obj
+ *     mod.toplevel_eval{| | block }                        => obj
+ *  
+ *  Evaluates the string or block in the context of _mod_, as if 
+ *  the context is the toplevel context. <code>toplevel_eval</code> 
+ *  returns the result of evaluating its argument.
+ *  In evaluating the argument, methods defined in _mod_ are regarded 
+ *  as toplevel functions. Constants in _mod_ are valid in evaluating. 
+ *  And when access <code>::CONST</code>, search in _mod_ first.
+ *  Even if at calling this method, the setting is ignored during
+ *  <code>require file</code> (or autoload file) to prevent troubles
+ *  on libraries.
+ *  Threads derived from the code inherit the context.
+ *     
+ *     p m = Module.new    #=> #<Module:0x401d0480>
+ *     m.toplevel_eval{
+ *       FOO = :foo
+ *       ::BAR = :bar
+ *       def baz(*args)
+ *         [self, args]
+ *       end
+ *       p baz(1, FOO, ::FOO, ::BAR)
+ *                         #=> [#<Module:0x401d0480>, [1, :foo, :foo, :bar]]
+ *       p Object.new.instance_eval{baz(2, FOO, ::BAR)}
+ *                         #=> [#<Object:0x401d02dc>, [2, :foo, :foo, :bar]]
+ *     }
+ *     p m.constants       #=> ["BAR", "FOO"]
+ *
+ */
+VALUE
+rb_mod_toplevel_eval(argc, argv, mod)
+    int argc;
+    VALUE *argv;
+    VALUE mod;
+{
+    volatile VALUE curr_top = current_toplevel_get();
+    struct mod_toplevel_eval_arg arg;
+
+    NEWOBJ(klass, struct RClass);
+    /* OBJSETUP(klass, RBASIC(mod)->klass, T_ICLASS);*/
+    OBJSETUP(klass, rb_cClass, T_ICLASS);
+
+    RCLASS(klass)->super = mod;
+    RCLASS(klass)->iv_tbl = RCLASS(mod)->iv_tbl;
+    RCLASS(klass)->m_tbl = RCLASS(mod)->m_tbl;
+
+    arg.argc = argc;
+    arg.argv = argv;
+    arg.mod  = (VALUE)klass;
+    arg.orig_top = curr_top;
+
+    rb_ensure(mod_toplevel_eval_call, (VALUE)&arg, 
+              mod_toplevel_eval_ensure, (VALUE)&arg);
+}
+
+
 VALUE rb_load_path;
 
 NORETURN(static void load_failed _((VALUE)));
@@ -7075,6 +7244,7 @@
 {
     VALUE result = Qnil;
     volatile VALUE errinfo = ruby_errinfo;
+    volatile VALUE orig_top = current_toplevel_get();
     int state;
     struct {
 	NODE *node;
@@ -7092,6 +7262,7 @@
     saved.node = ruby_current_node;
     saved.func = ruby_frame->last_func;
     saved.safe = ruby_safe_level;
+    current_toplevel_set((VALUE)0); /* ignore current_toplevel at require */
     PUSH_TAG(PROT_NONE);
     if ((state = EXEC_TAG()) == 0) {
 	VALUE feature, path;
@@ -7134,6 +7305,7 @@
 	}
     }
     POP_TAG();
+    current_toplevel_set(orig_top);
     ruby_current_node = saved.node;
     ruby_set_current_source();
     ruby_frame->last_func = saved.func;
@@ -7904,6 +8076,8 @@
     rb_define_method(rb_cModule, "module_eval", rb_mod_module_eval, -1);
     rb_define_method(rb_cModule, "class_eval", rb_mod_module_eval, -1);
 
+    rb_define_method(rb_cModule, "toplevel_eval", rb_mod_toplevel_eval, -1);
+
     rb_undef_method(rb_cClass, "module_function");
 
     rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, -1);
@@ -9763,6 +9937,7 @@
     struct BLOCK *block;
     struct iter *iter;
     struct tag *tag;
+    VALUE toplevel;
     VALUE klass;
     VALUE wrapper;
     NODE *cref;
@@ -9798,6 +9973,20 @@
     VALUE thread;
 };
 
+static void
+current_toplevel_set(top)
+    VALUE top;
+{
+    curr_thread->toplevel = top;
+}
+
+static VALUE
+current_toplevel_get(void)
+{
+    return curr_thread->toplevel;
+}
+
+
 #define THREAD_RAISED 0x200	 /* temporary flag */
 #define THREAD_TERMINATING 0x400 /* persistent flag */
 #define THREAD_FLAGS_MASK  0x400 /* mask for persistent flags */
@@ -9987,6 +10176,7 @@
 
     rb_gc_mark(th->klass);
     rb_gc_mark(th->wrapper);
+    rb_gc_mark(th->toplevel);
     rb_gc_mark((VALUE)th->cref);
 
     rb_gc_mark((VALUE)th->scope);
@@ -10343,6 +10533,7 @@
 rb_thread_die(th)
     rb_thread_t th;
 {
+    th->toplevel = 0;
     th->thgroup = 0;
     th->status = THREAD_KILLED;
     if (th->stk_ptr) free(th->stk_ptr);
@@ -11566,6 +11757,7 @@
     th->scope = 0;\
     th->klass = 0;\
     th->wrapper = 0;\
+    th->toplevel = 0;\
     th->cref = ruby_cref;\
     th->dyna_vars = ruby_dyna_vars;\
     th->block = 0;\
@@ -11744,6 +11936,7 @@
 	curr_thread->next->prev = th;
 	th->next = curr_thread->next;
 	curr_thread->next = th;
+	th->toplevel = curr_thread->toplevel;
 	th->priority = curr_thread->priority;
 	th->thgroup = curr_thread->thgroup;
     }
@@ -12079,6 +12272,7 @@
 	if (th->status != THREAD_KILLED) {
 	    rb_thread_ready(th);
 	    if (th != main_thread) {
+		th->toplevel = 0;
 		th->thgroup = 0;
 		th->priority = 0;
 		th->status = THREAD_TO_KILL;
@@ -12554,6 +12748,7 @@
 	scope_dup(tag->scope);
     }
     th->thread = curr_thread->thread;
+    th->toplevel = curr_thread->toplevel;
     th->thgroup = cont_protect;
 
     for (vars = ruby_dyna_vars; vars; vars = vars->next) {

In This Thread