From: Trans Date: 2006-03-21T00:48:50+09:00 Subject: Re: once again looking for my module methods Actually, I have developed what is probably the most complete solution out there. Check out Calibre's require 'calibre/classinherit' Even so, any solution is still an ugly hack and imperfect to the real solution. Hint. Hint. ---- classinherit.rb #:title: ClassInherit # # This framework provides a very convenient way to have modules # pass along class methods in the inheritance chain. # # Presently in Ruby the class/module methods of a module # are not inherited when a module is included --contrary to # the behavior of classes themselves when they are subclassed. # To achieve the same behavior with modules requires some clever # Ruby karate. ClassInherit provides a nice solution. # Simply place the class inheritable methods in the block # parameter of the special module method ClassInherit. # # module Mix # def inst_meth # puts 'inst_meth' # end # # ClassInherit do # def class_meth # "Class Method!" # end # end # end # # class X # include Mix # end # # X.class_meth #=> "Class Method!" # # ClassInherit is a capitalized method. This is used because it # indeed creates (or reopens) a ClassInherit module in which # the given block is evaluated, then the ClassInherit module # is extended against the current module. # # The above is actually equivalent to putting the class/module # methods in a nested ClassInherit module and extending the # module _manually_, eg. # # module Mix # def inst_meth # puts 'inst_meth' # end # # module ClassInherit # def class_meth # "Class Method!" # end # end # # extend ClassInherit # end # # class X # include Mix # end # # X.class_meth #=> "Class Method!" # # Lastly, #class_inherit is an available alias for #ClassInherit # if you prefer only lowercase methods. # # == Notes # # Just a quick comment on the need for this behavior. # # A module is an encapsulation of code, hence when a module is included # (or extends), the module itself should have discretion over how it # effects the receiving class/module. That is the very embodiment of # encapsulation. Having it otherwise, as Ruby now does, stymies the # practice --and we end up with "hacks" like this to compensate. # # Ruby would be much improved by making this bevaivor standard. # And making non-inheritance the exception, which is alwasy easy # enough to achieve: just put the code in a separate # (and thus uninherited) module. # # == Author(s) # # * Thomas Sawyer # * Nobu Nakada # * Ulysses # class Module alias_method :append_features_without_classinherit, :append_features def append_features( base ) result = append_features_without_classinherit( base ) if const_defined?( :ClassInherit ) base.extend( self::ClassInherit ) unless base.is_a?( Class ) unless base.const_defined?( :ClassInherit ) base.const_set( :ClassInherit, Module.new ) end my = self base::ClassInherit.class_eval do include my::ClassInherit end end end result end def ClassInherit( &yld ) if const_defined?( :ClassInherit ) self::ClassInherit.class_eval( &yld ) else self.const_set( :ClassInherit, Module.new( &yld ) ) end extend( self::ClassInherit ) self::ClassInherit end # For compatibility with old rendition alias_method :class_inherit, :ClassInherit end class Class undef_method :ClassInherit undef_method :class_inherit end