Hyperextended #
As you well know, mixins only copy plain instance methods into the target class. And may I ask what world-class solutions we have if you need to copy class methods? Um, you can’t copy the metaclass (which includes class methods.)
>> class GiftedClass
>> def self.capabilities
>> [:swimming, :diving, :chess, :valour]
>> end
>> end
>> class LesserClass
>> extend (class << GiftedClass; self; end)
>> end
TypeError: wrong argument type Class (expected Module)
from (irb):8:in `extend'
from (irb):8
I’ve been trying to write a hyperextend method that will take a class and mixin instance and class methods alike, but no.
Nobu’s three-year-old solution is to put all your class methods in a nested module, then alter append_features to allow the mixin to copy the nested module functions into the metaclass. And don’t forget to extend the original module, to make sure the nested module functions are still usable as class (module) methods in the original module.
module Mix
def inst_meth
puts 'inst_meth'
end
module ClassMethods
def class_meth
puts 'class_meth'
end
end
extend ClassMethods
def self.append_features(klass)
super
klass.extend(ClassMethods)
end
end
class LesserClass
include Mix
end
While the behind-the-scenes is a bit wordy, it’s excellent that you can still use include and get the class methods to come through. (Unearthed from ruby-talk:35979.)


Cat-herder
I’ve tried to coax append_features into auto-extending with ClassMethods when present, but singleton methods defy wrapping. It is written.
Tim
Rails uses this extensively. It doesn’t have the module extend its own ClassMethods though, because they’re not intended to be used independently.
Thomas
Very cool :
) I tried to this myself some days ago and failed. Next time, I will search ruby-talk first ;)Ulysses
Hey, _why. The nice thing about the internal ClassMethods pattern is that it can be automated:
class Module alias :append_features_no_classmethods \ :append_features def append_features(base) append_features_no_classmethods(base) begin clsm = self::ClassMethods rescue NameError clsm = nil end base.extend(clsm) if clsm end endSomewhat ironic is that if you try to use a module to extend append_features (and thus avoid alias) it doesn’t work.
module AutoExtendClassMethods def append_features(base) super(base) ... end end class Module include AutoExtendClassMethods endAs an appendum, I should add that it is a good idea to use self::ClassMethods—if you just use ClassMethods, you might inherit ClassMethods from a parent scope, which could lead to some hard to figure out bugs.
(Sorry for rambling on,)
flgr
This ought to be possible with evil-ruby. Just do
class << self; inherit class << GiftedClass; self; end; end—sorry that it looks so complex.clark
you must have eaten all meta kryptonite
why
Wow, yeah. Rails is all over this one. Haroomph.
Comments are closed for this entry.