Trans
3/20/2006 3:44:00 PM
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