[#38323] [1.8.7][1.9.1][tk] 自前実装の拡張 widget を使いたい場合 — oshida@...

押田です。

22 messages 2009/04/24
[#38331] Re: [1.8.7][1.9.1][tk] 自前実装の拡張 widget を使いたい場合 — Hidetoshi NAGAI <nagai@...> 2009/04/26

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

[#38339] Re: [1.8.7][1.9.1][tk] 自前実装の拡張 widget を使いたい場合 — oshida@... 2009/04/27

押田です。

[#38340] Re: [1.8.7][1.9.1][tk] 自前実装の拡張 widget を使いたい場合 — Hidetoshi NAGAI <nagai@...> 2009/04/27

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

[#38697] Re: [1.8.7][1.9.1][tk] 自前実装の拡張 widget を使いたい場合 — Hidetoshi NAGAI <nagai@...> 2009/06/21

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

[#38711] Re: [1.8.7][1.9.1][tk] 自前実装の拡張 widget を使いたい場合 — oshida@... 2009/06/24

押田です。

[#38723] Re: [1.8.7][1.9.1][tk] 自前実装の拡張 widget を使いたい場合 — Hidetoshi NAGAI <nagai@...> 2009/07/01

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

[#38743] Re: [1.8.7][1.9.1][tk] 自前実装の拡張 widget を使いたい場合 — oshida@... 2009/07/07

押田です。

[#38747] Re: [1.8.7][1.9.1][tk] 自前実装の拡張 widget を使いたい場合 — Hidetoshi NAGAI <nagai@...> 2009/07/08

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

[#38748] Re: [1.8.7][1.9.1][tk] 自前実装の拡張 widget を使いたい場合 — oshida@... 2009/07/08

押田です。

[#38749] Re: [1.8.7][1.9.1][tk] 自前実装の拡張 widget を使いたい場合 — Hidetoshi NAGAI <nagai@...> 2009/07/08

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

[ruby-dev:38233] Re: rinda/eval.rb

From: Tanaka Akira <akr@...>
Date: 2009-04-01 09:13:27 UTC
List: ruby-dev #38233
In article <20090401095853.B00A.C613B076@garbagecollect.jp>,
  "U.Nakamura" <usa@garbagecollect.jp> writes:

>> forkする前にforkできないかどうか、知ることはできますか?
>
> できません。
> # この辺をどうにかできないかという話が以前あったような...

以前 [ruby-dev:34707] で書きましたが、NotImplementedError に
なるだけのメソッドは責務を果たしているとはいえないので、
respond_to? で偽を返すのがいいと思います。

これがあれば、Process.respond_to?(:fork) で fork できるかど
うか判断できるようになります。

しかも、単純にメソッドをなくすのと異なり、呼ぶと
NotImplementedError を発生するのは変わらないので、
NotImplementedError を rescue するという用法は変えずに済み、
また、NoMethodError/NameError を rescue するという剣呑なこと
を勧めてしまうこともありません。

せっかくなのでアップデートしたパッチをつけておきます。

% svn diff --diff-cmd diff -x '-u -p'
Index: include/ruby/intern.h
===================================================================
--- include/ruby/intern.h	(revision 23107)
+++ include/ruby/intern.h	(working copy)
@@ -273,6 +273,8 @@ int rb_method_basic_definition_p(VALUE, 
 VALUE rb_eval_cmd(VALUE, VALUE, int);
 int rb_obj_respond_to(VALUE, ID, int);
 int rb_respond_to(VALUE, ID);
+void rb_define_notimplement_method_id(VALUE mod, ID id, int noex);
+VALUE rb_f_notimplement(int argc, VALUE *argv, VALUE obj);
 void rb_interrupt(void);
 VALUE rb_apply(VALUE, ID, VALUE);
 void rb_backtrace(void);
Index: proc.c
===================================================================
--- proc.c	(revision 23107)
+++ proc.c	(working copy)
@@ -1041,6 +1041,15 @@ method_owner(VALUE obj)
     return data->oclass;
 }
 
+static VALUE
+method_notimplemented_p(VALUE obj)
+{
+    struct METHOD *data;
+
+    Data_Get_Struct(obj, struct METHOD, data);
+    return rb_notimplement_body_p(data->body) ? Qtrue : Qfalse;
+}
+
 /*
  *  call-seq:
  *     obj.method(sym)    => method
@@ -1616,6 +1625,9 @@ method_inspect(VALUE method)
     }
     rb_str_buf_cat2(str, sharp);
     rb_str_append(str, rb_id2str(data->oid));
+    if (rb_notimplement_body_p(data->body)) {
+        rb_str_buf_cat2(str, " (notimplemented)");
+    }
     rb_str_buf_cat2(str, ">");
 
     return str;
@@ -1934,6 +1946,7 @@ Init_Proc(void)
     rb_define_method(rb_cMethod, "name", method_name, 0);
     rb_define_method(rb_cMethod, "owner", method_owner, 0);
     rb_define_method(rb_cMethod, "unbind", method_unbind, 0);
+    rb_define_method(rb_cMethod, "notimplemented?", method_notimplemented_p, 0);
     rb_define_method(rb_cMethod, "source_location", rb_method_location, 0);
     rb_define_method(rb_cMethod, "parameters", rb_method_parameters, 0);
     rb_define_method(rb_mKernel, "method", rb_obj_method, 1);
@@ -1953,6 +1966,7 @@ Init_Proc(void)
     rb_define_method(rb_cUnboundMethod, "name", method_name, 0);
     rb_define_method(rb_cUnboundMethod, "owner", method_owner, 0);
     rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1);
+    rb_define_method(rb_cUnboundMethod, "notimplemented?", method_notimplemented_p, 0);
     rb_define_method(rb_cUnboundMethod, "source_location", rb_method_location, 0);
     rb_define_method(rb_cUnboundMethod, "parameters", rb_method_parameters, 0);
 
Index: vm_method.c
===================================================================
--- vm_method.c	(revision 23107)
+++ vm_method.c	(working copy)
@@ -24,6 +24,8 @@ static struct cache_entry cache[CACHE_SI
 #define ruby_running (GET_VM()->running)
 /* int ruby_running = 0; */
 
+static NODE *notimplement_body = 0;
+
 void
 rb_clear_cache(void)
 {
@@ -414,6 +416,12 @@ rb_export_method(VALUE klass, ID name, I
 }
 
 int
+rb_notimplement_body_p(NODE *method)
+{
+    return method == notimplement_body ? Qtrue : Qfalse;
+}
+
+int
 rb_method_boundp(VALUE klass, ID id, int ex)
 {
     NODE *method;
@@ -422,6 +430,8 @@ rb_method_boundp(VALUE klass, ID id, int
 	if (ex && (method->nd_noex & NOEX_PRIVATE)) {
 	    return Qfalse;
 	}
+        if (rb_notimplement_body_p(method->nd_body))
+           return Qfalse;
 	return Qtrue;
     }
     return Qfalse;
@@ -811,6 +821,42 @@ rb_mod_alias_method(VALUE mod, VALUE new
     return mod;
 }
 
+VALUE
+rb_f_notimplement(int argc, VALUE *argv, VALUE obj)
+{
+    rb_notimplement();
+}
+
+void
+rb_define_notimplement_method_id(VALUE mod, ID id, int noex)
+{
+    rb_add_method(mod, id, notimplement_body, noex);
+}
+
+static VALUE
+rb_mod_notimplemented_method(int argc, VALUE *argv, VALUE mod)
+{
+    int i;
+    if (rb_vm_cbase() == rb_cObject && mod == rb_cObject) {
+        rb_secure(4);
+    }
+
+    for (i = 0; i < argc; i++) {
+        ID id = rb_to_id(argv[i]);
+
+        if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(mod)) {
+            rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'",
+                     rb_id2name(id));
+        }
+        rb_frozen_class_p(mod);
+        if (id == object_id || id == id__send__ || id == idInitialize) {
+            rb_warn("notimplementing `%s' may cause serious problem", rb_id2name(id));
+        }
+       rb_define_notimplement_method_id(mod, id, NOEX_PUBLIC);
+    }
+    return mod;
+}
+
 static void
 secure_visibility(VALUE self)
 {
@@ -1137,5 +1183,9 @@ Init_eval_method(void)
     singleton_removed = rb_intern("singleton_method_removed");
     undefined = rb_intern("method_undefined");
     singleton_undefined = rb_intern("singleton_method_undefined");
+
+    rb_global_variable(&notimplement_body);
+    notimplement_body = NEW_CFUNC(rb_f_notimplement, -1);
+    rb_define_private_method(rb_cModule, "notimplemented_method", rb_mod_notimplemented_method, -1);
 }
 
Index: class.c
===================================================================
--- class.c	(revision 23107)
+++ class.c	(working copy)
@@ -807,25 +807,36 @@ rb_obj_singleton_methods(int argc, VALUE
 void
 rb_define_method_id(VALUE klass, ID name, VALUE (*func)(ANYARGS), int argc)
 {
-    rb_add_method(klass, name, NEW_CFUNC(func,argc), NOEX_PUBLIC);
+    if (func == rb_f_notimplement)
+        rb_define_notimplement_method_id(klass, name, NOEX_PUBLIC);
+    else
+        rb_add_method(klass, name, NEW_CFUNC(func,argc), NOEX_PUBLIC);
 }
 
 void
 rb_define_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc)
 {
-    rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PUBLIC);
+    rb_define_method_id(klass, rb_intern(name), func, argc);
 }
 
 void
 rb_define_protected_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc)
 {
-    rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PROTECTED);
+    ID id = rb_intern(name);
+    if (func == rb_f_notimplement)
+        rb_define_notimplement_method_id(klass, id, NOEX_PROTECTED);
+    else
+        rb_add_method(klass, id, NEW_CFUNC(func, argc), NOEX_PROTECTED);
 }
 
 void
 rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc)
 {
-    rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PRIVATE);
+    ID id = rb_intern(name);
+    if (func == rb_f_notimplement)
+        rb_define_notimplement_method_id(klass, id, NOEX_PRIVATE);
+    else
+        rb_add_method(klass, id, NEW_CFUNC(func, argc), NOEX_PRIVATE);
 }
 
 void
Index: process.c
===================================================================
--- process.c	(revision 23107)
+++ process.c	(working copy)
@@ -2601,10 +2601,10 @@ rb_fork(int *status, int (*chfunc)(void*
  *  fork doesn't copy other threads.
  */
 
+#if defined(HAVE_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
 static VALUE
 rb_f_fork(VALUE obj)
 {
-#if defined(HAVE_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
     rb_pid_t pid;
 
     rb_secure(2);
@@ -2630,11 +2630,10 @@ rb_f_fork(VALUE obj)
       default:
 	return PIDT2NUM(pid);
     }
+}
 #else
-    rb_notimplement();
+#define rb_f_fork rb_f_notimplement
 #endif
-}
-
 
 /*
  *  call-seq:
Index: test/ruby/test_notimp.rb
===================================================================
--- test/ruby/test_notimp.rb	(revision 0)
+++ test/ruby/test_notimp.rb	(revision 0)
@@ -0,0 +1,33 @@
+require 'test/unit'
+
+class TestNotImplement < Test::Unit::TestCase
+  class C
+    notimplemented_method :n
+    def x() end
+  end
+
+  def test_respond_to
+    assert_equal(false, C.new.respond_to?(:n))
+    assert_equal(true, C.new.respond_to?(:x))
+  end
+
+  def test_call
+    assert_raise(NotImplementedError) { C.new.n }
+    assert_nothing_raised { C.new.x }
+  end
+
+  def test_method
+    m = C.new.method(:n)
+    assert(m.notimplemented?)
+    m = C.new.method(:x)
+    assert(!m.notimplemented?)
+  end
+
+  def test_umethod
+    m = C.instance_method(:n)
+    assert(m.notimplemented?)
+    m = C.instance_method(:x)
+    assert(!m.notimplemented?)
+  end
+
+end
Index: file.c
===================================================================
--- file.c	(revision 23107)
+++ file.c	(working copy)
@@ -1926,12 +1926,7 @@ rb_file_s_lchmod(int argc, VALUE *argv)
     return LONG2FIX(n);
 }
 #else
-static VALUE
-rb_file_s_lchmod(int argc, VALUE *argv)
-{
-    rb_notimplement();
-    return Qnil;		/* not reached */
-}
+#define rb_file_s_lchmod rb_f_notimplement
 #endif
 
 struct chown_args {
-- 
[田中 哲][たなか あきら][Tanaka Akira]

In This Thread