Hi,

At Mon, 6 Dec 2004 09:39:43 +0900,
Peter wrote in [ruby-talk:122619]:
> At https://developer.berlios.de/project/showfiles.php?group_id=1216&release_id=4105 
> you can find a patch that implements the idea but returns an UnboundMethod 
> instead of a symbol (or a Method when defining a singleton method). It 
> extends Module#public/private/protected to take a single (Unbound)?Method 
> as parameter. The patch is against the source of Ruby 1.8.2.

I wonder if this might cause confution.

  class Foo
    public def foo
    end
  end
  class Bar
    private Foo.instance_method(:foo)
  end

Aren't Method#public etc. superfluous?


Index: eval.c =================================================================== RCS file: /cvs/ruby/src/ruby/eval.c,v retrieving revision 1.742 diff -U2 -p -d -r1.742 eval.c --- eval.c 3 Dec 2004 04:56:24 -0000 1.742 +++ eval.c 6 Dec 2004 02:50:59 -0000 @@ -147,4 +147,7 @@ static VALUE rb_mod_define_method _((int NORETURN(static void rb_raise_jump _((VALUE))); static VALUE rb_make_exception _((int argc, VALUE *argv)); +static VALUE um_new _((VALUE klass, NODE *body, ID id)); +static VALUE m_new _((VALUE klass, VALUE recv, NODE *body, ID id)); +static ID check_method_id _((VALUE obj, VALUE mod)); static int scope_vmode; @@ -315,5 +318,5 @@ static ID added, singleton_added; static ID __id__, __send__, respond_to; -void +NODE * rb_add_method(klass, mid, node, noex) VALUE klass; @@ -351,4 +354,5 @@ rb_add_method(klass, mid, node, noex) } } + return node; } @@ -3671,10 +3675,10 @@ rb_eval(self, n) defn = copy_node_scope(node->nd_defn, ruby_cref); - rb_add_method(ruby_class, node->nd_mid, defn, noex); + body = rb_add_method(ruby_class, node->nd_mid, defn, noex); if (scope_vmode == SCOPE_MODFUNC) { rb_add_method(rb_singleton_class(ruby_class), node->nd_mid, defn, NOEX_PUBLIC); } - result = Qnil; + result = um_new(ruby_class, body, node->nd_mid); } break; @@ -3707,7 +3711,7 @@ rb_eval(self, n) } defn = copy_node_scope(node->nd_defn, ruby_cref); - rb_add_method(klass, node->nd_mid, defn, + body = rb_add_method(klass, node->nd_mid, defn, NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0)); - result = Qnil; + result = m_new(klass, recv, body, node->nd_mid); } break; @@ -6926,8 +6930,13 @@ set_method_visibility(self, argc, argv, { int i; + VALUE m; + ID id; secure_visibility(self); for (i=0; i<argc; i++) { - rb_export_method(self, rb_to_id(argv[i]), ex); + m = argv[i]; + id = check_method_id(m, self); + if (!id) id = rb_to_id(m); + rb_export_method(self, id, ex); } rb_clear_cache_by_class(self); @@ -7148,20 +7157,22 @@ rb_mod_modfunc(argc, argv, module) set_method_visibility(module, argc, argv, NOEX_PRIVATE); for (i=0; i<argc; i++) { - VALUE m = module; + if (!(id = check_method_id(argv[i], module))) { + VALUE m = module; - id = rb_to_id(argv[i]); - for (;;) { - body = search_method(m, id, &m); - if (body == 0) { - body = search_method(rb_cObject, id, &m); - } - if (body == 0 || body->nd_body == 0) { - rb_bug("undefined method `%s'; can't happen", rb_id2name(id)); - } - if (nd_type(body->nd_body) != NODE_ZSUPER) { - break; /* normal case: need not to follow 'super' link */ + id = rb_to_id(argv[i]); + for (;;) { + body = search_method(m, id, &m); + if (body == 0) { + body = search_method(rb_cObject, id, &m); + } + if (body == 0 || body->nd_body == 0) { + rb_bug("undefined method `%s'; can't happen", rb_id2name(id)); + } + if (nd_type(body->nd_body) != NODE_ZSUPER) { + break; /* normal case: need not to follow 'super' link */ + } + m = RCLASS(m)->super; + if (!m) break; } - m = RCLASS(m)->super; - if (!m) break; } rb_add_method(rb_singleton_class(module), id, body->nd_body, NOEX_PUBLIC); @@ -8635,5 +8646,5 @@ mnew(klass, obj, id, mklass) } if (TYPE(klass) == T_ICLASS) klass = RBASIC(klass)->klass; - method = Data_Make_Struct(mklass, struct METHOD, bm_mark, free, data); + method = Data_Make_Struct(mklass, struct METHOD, bm_mark, -1, data); data->klass = klass; data->recv = obj; @@ -8647,4 +8658,79 @@ mnew(klass, obj, id, mklass) } +static VALUE +um_new(klass, body, id) + VALUE klass; + ID id; + NODE *body; +{ + VALUE method; + struct METHOD *data; + + method = Data_Make_Struct(rb_cUnboundMethod, struct METHOD, bm_mark, -1, data); + data->klass = klass; + data->recv = Qundef; + data->id = id; + data->body = body; + data->rklass = klass; + data->oid = id; + OBJ_INFECT(method, klass); + + return method; +} + +static VALUE +m_new(klass, recv, body, id) + VALUE klass, recv; + ID id; + NODE *body; +{ + VALUE method; + struct METHOD *data; + + method = Data_Make_Struct(rb_cMethod, struct METHOD, bm_mark, -1, data); + data->klass = klass; + data->recv = recv; + data->id = id; + data->body = body; + data->rklass = klass; + data->oid = id; + OBJ_INFECT(method, klass); + + return method; +} + +static ID +check_method_id(obj, mod) + VALUE obj, mod; +{ + struct METHOD *data; + VALUE klass; + ID id; + ID noex; + NODE *body; + + if (TYPE(obj) != T_DATA || RDATA(obj)->dmark != bm_mark) + return 0; + data = (struct METHOD *)RDATA(obj)->data; + if (data->rklass != mod) { + rb_raise(rb_eTypeError, "%s mismatch - %s for %s", + (TYPE(mod) == T_CLASS ? "class" : "module"), + rb_obj_as_string(data->rklass), rb_obj_as_string(mod)); + } + for (klass = data->rklass, id = data->oid;; klass = RCLASS(klass)->super) { + if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) { + rb_raise(rb_eTypeError, "method %s in %s disappeared", + rb_id2name(data->oid), rb_class2name(data->rklass)); + } + + if (nd_type(body) != NODE_ZSUPER) break; + } + + if (body != data->body) { + rb_raise(rb_eTypeError, "method %s in %s changed", + rb_id2name(data->oid), rb_class2name(data->rklass)); + } + return data->oid; +} /**********************************************************************
-- Nobu Nakada