Picking and renaming methods from included modules---tastes like Eiffel?
Daniel Berger blogged about how to make 'include' a little more flexible by allowing to rename or exclude specific methods.
He proposed the following syntax:
module TFoo def method_a "hello" end def method_b "world" end end module TBar def method_a "goodbye" end def method_b "cruel world" end def method_y "huh?" end end class MyKlass include TFoo, :alias => {:method_a, :method_z}, :exclude => :method_b include TBar end m = MyKlass.new m.method_a # => "goodbye" m.method_b # => "cruel world" m.method_y # => "huh?" m.method_z # => "hello"
Making it happen
Here's my implementation. I think somebody might have posted such a thing to ruby-talk, but anyway this must have been written for the first time by some Japanese Rubyist years ago, so yet another reinvention won't matter nor hurt.
This definition of Class#include should be a fairly safe replacement for the default one since I'm not raising an exception when there's a nameclash (which I rather feel is a bad idea, but I haven't given this much thought), but maybe it could make sense to create a new method with those semantics.
The code:
class Class old_include = instance_method(:include) define_method(:include) do |*args| default = {:alias => {}, :exclude => []} hash_arg = (Hash === args.last) ? default.update(args.pop) : default m = Module.new args.each{|mod| m.module_eval{ include mod } } # ^^^^^^^^^^^^^^^ # check for "method shadowing" here and raise an exception or # something if you feel like it hash_arg[:alias].each_pair do |old, new| m.module_eval{ alias_method(new, old); undef_method(old) } end excluded = (Array === hash_arg[:exclude]) ? hash_arg[:exclude] : [hash_arg[:exclude]] # [*hash_arg[:exclude]] won't work on 1.9 cause there's no Object#to_a excluded.each{|meth| m.module_eval { undef_method(meth) } } old_include.bind(self).call(m) end end
Alternate syntax - lukfugl (2005-12-01 (Thr) 15:40:05)
Read my comments on an alternate syntax with implementation (shamelessly based on yours here) at RedHanded:
http://redhanded.hobix.com/inspect/mixinsButWithTablespoons.html
mfp 2005-12-01 (Thr) 15:48:05
heh just saw your 1st comment on redhanded and was about to implement it but you posted yours faster :)
Facets - Trans (2005-12-01 (Thr) 10:50:02)
Facets has some methods for doing this kind of thing a little more along the lines of how Ruby handles methods:
class MyKlass
integrate TFoo do
rename :method_a, :method_z
remove :method_b
end
include TBar end
mfp 2005-12-01 (Thr) 17:19:17
Is it based on the same fundamental operation (creating a new module and operating on it)?
Nice - Daniel Berger (2005-12-01 (Thr) 06:25:31)
Very nice. I'm still undecided about what should happen with a nameclash, but I'm leaning towards a warning rather than an exception. Just knowing that it's happening (with -w) could help resolve an otherwise hidden bug.
Now, any chance of a patch to class.c? :)
mfp 2005-12-01 (Thr) 08:37:37
Wouldn't it be shot down on first sight if sent to ruby-core? ;-) I don't know if the uebermenschen have an official position on this (remember I wrote it because I was too lazy to search the archives :)
Daniel Berger 2005-12-01 (Thr) 09:26:49
Maybe, maybe not. It has a decent chance of making it into Sydney :)
Mark Hubbart 2005-12-01 (Thr) 20:06:07
I particularly like the ':alias => {:orig => :new}' syntax. I wish alias_method would take a hash; I think it would be much clearer than 'alias_method :new, :old'.
Keyword(s):[blog] [ruby] [module] [include] [snippet]
References:[Ruby]