# = class_extension.rb # # == Copyright (c) 2006 Daniel Schierbeck # # Ruby License # # This module is free software. You may use, modify, and/or redistribute this # software under the same terms as Ruby. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. # # == Special Thanks # # Thanks to Trans, Nobu and Ulysses for their original on this concept. # # == Authors and Contributors # # * Daniel Schierbeck # * Thomas Sawyer # * Nobu Nakada # * Ulysses # Author:: Daniel Schierbeck # Copyright:: Copyright (c) 2006 Daniel Schierbeck # License:: Ruby License # class Module alias_method :append_features_without_class_extension, :append_features # = class_extension # # Normally when including modules, class/module methods are not # extended. To achieve this behavior requires some clever # Ruby Karate. Instead class_extension provides an easy to use # and clean solution. Simply place the extending class methods # in a block of the special module method #class_extension. # # module Mix # def inst_meth # puts 'inst_meth' # end # # class_extension do # def class_meth # "Class Method!" # end # end # end # # class X # include Mix # end # # X.class_meth #=> "Class Method!" # def class_extension(&block) @class_extension ||= Module.new do def self.append_features(mod) append_features_without_class_extension(mod) end end @class_extension.module_eval(&block) if block_given? @class_extension end private :class_extension def append_features(mod) append_features_without_class_extension(mod) mod.extend(class_extension) if mod.instance_of? Module mod.__send__(:class_extension).__send__(:include, class_extension) end end end class Class undef_method :class_extension end # _____ _ # |_ _|__ ___| |_ # | |/ _ \/ __| __| # | | __/\__ \ |_ # |_|\___||___/\__| # =begin test require 'test/unit' class TC_ClassMethods < Test::Unit::TestCase # fixture module N class_extension do def n ; 43 ; end def s ; self ; end end extend class_extension end class X include N def n ; 11 ; end end module K include N class_extension do def n ; super + 1 ; end end end class Z include K end # tests def test_01 assert_equal( 43, N.n ) assert_equal( N, N.s ) end def test_02 assert_equal( 43, X.n ) assert_equal( X, X.s ) end def test_03 assert_equal( 11, X.new.n ) end def test_04 assert_equal( 43, K.n ) #notic the difference! assert_equal( K, K.s ) end def test_05 assert_equal( 44, Z.n ) assert_equal( Z, Z.s ) end end =end