Note that this implementation is fairly tailored for the use-case I was
targeting, and as such doesn't COPY the method, but only repoints and
undefines the original one. A more generic implementation would probably be
similar semantically to alias_method. Imagine:
alias_method_to_module :bar, Baz, :bat

-- Yehuda

On Sat, Jan 17, 2009 at 11:27 PM, Yehuda Katz <wycats / gmail.com> wrote:

> 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
>



-- 
Yehuda Katz
Developer | Engine Yard
(ph) 718.877.1325