From: Yehuda Katz Date: 2009-01-18T16:26:19+09:00 Subject: [ruby-core:21399] Proposal: Module#copy_method --000e0cd2557889b8260460bcbd4e Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit I'd like it to be possible to copy methods from one module to another. The rationale is that this feature would make it possible to modify existing methods without being forced to resort to aliasing. Here's an implementation that works on 1.8 and 1.9: static VALUE copy_method(VALUE self, VALUE klass, VALUE symbol) { ID id = rb_to_id(symbol); NODE *node = NULL; st_table *other_method_table = RCLASS(klass)->m_tbl; st_table *method_table = RCLASS(self)->m_tbl; if(st_lookup(other_method_table, id, (void *)&node)) { st_insert(method_table, (st_data_t)id, (st_data_t)node); return (Qtrue); } else { rb_raise(rb_eRuntimeError, "No such method `%s' on %s", rb_id2name(id), STR2CSTR(rb_mod_name(klass))); } } void Init_copy_method() { VALUE c = rb_cObject; c = rb_const_get(c,rb_intern("Module")); rb_define_method(c, "copy_method", copy_method, 2); } And the ruby code: module TrackAddedMethods def method_added(meth) @__added_methods ||= [] @__added_methods << meth end def __added_methods @__added_methods end end class Module def __move_to_module(*meth_names) me = self mod = Module.new do meth_names.each do |name| copy_method me, name end end meth_names.each do |name| remove_method name end include mod end def chain(&blk) mod = Module.new do extend TrackAddedMethods end mod.class_eval(&blk) __move_to_module(*mod.__added_methods) include mod end end It would be used like: class Bar def foo 1 end chain do def foo super + 1 end end end This particular Ruby implementation is just one option, but the point is that having the generic ability to move methods around would be powerful. -- Yehuda Katz Developer | Engine Yard (ph) 718.877.1325 --000e0cd2557889b8260460bcbd4e Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable I'd like it to be possible to copy methods from one module to another. = The rationale is that this feature would make it possible to modify existin= g methods without being forced to resort to aliasing. Here's an impleme= ntation that works on 1.8 and 1.9:

static VALUE copy_method(VALUE self, VALUE klass, VALUE= symbol) {
  ID id =3D rb_to_id(symbol);
&nbs= p; NODE *node =3D NULL;
  st_table *other_method_t= able =3D RCLASS(klass)->m_tbl;
  st_table *method_table =3D RCLASS(self)->m_tbl;

  if(st_lookup(other_method_table, id, (void *)= &node)) {
    st_insert(method_table, (st_data= _t)id, (st_data_t)node);
    return (Qtrue);
  } else {
    rb_raise(rb_eRuntimeError, "No such method `%s'= ; on %s", rb_id2name(id), STR2CSTR(rb_mod_name(klass)));
&nb= sp; }
}

void Init_copy_method() {
  VALUE c =3D rb_cObject= ;
  c =3D rb_const_get(c,rb_intern("Module"))= ;
  rb_define_method(c, "copy_method", copy_m= ethod, 2);
}

And the ruby code:

module Trac= kAddedMethods  
  def method_added(meth)
    @__added_methods ||=3D []
    = @__added_methods << meth
  end
  
  def __added_methods
 = ;   @__added_methods
  end
end

class Module
  def __mo= ve_to_module(*meth_names)
    me =3D self
    mod =3D Module.new do
    =  meth_names.each do |name|
        = ;copy_method me, name
      end
&nb= sp;   end
    meth_names.each do |name|<= /div>
      remove_method name
    end
    include mod
<= div>  end
  
  def chain(= &blk)
    mod =3D Module.new do
&nbs= p;     extend TrackAddedMethods
    = ;end
    mod.class_eval(&blk)
    __move_to_module(*mod.__added_methods)
&n= bsp;   include mod
  end
end
<= div>
It would be used like:

cla= ss Bar
  def foo
    1
  end
    = ;
  chain do
    def foo
=
      super + 1
    end
  end
end

This particular Ruby implementation is just one option, but the point is = that having the generic ability to move methods around would be powerful.

--
Yehuda Katz
Developer | Engine Yard
(ph) 718.877.1325=
--000e0cd2557889b8260460bcbd4e--