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.