# = inheritor.rb # # == Copyright (c) 2005 Thomas Sawyer # # 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. # # == Author(s) # # * Thomas Sawyer # Author:: Thomas Sawyer # Copyright:: Copyright (c) 2006 Thomas Sawyer # License:: Ruby License require 'facets/core/module/class_extension' # = Inheritor # # Inheritor providse a means to store and inherit data via # the class heirarchy. An inheritor creates two methods # one named after the key that provides a reader. And one # named after key! which provides the writer. (Because of # the unique nature of inheritor the reader and writer # can't be the same method.) # # class X # inheritor :foo, [], :+ # end # # class Y < X # end # # X.x! << :a # X.x => [:a] # Y.x => [:a] # # Y.x! << :b # X.x => [:a] # Y.x => [:a, :b] # # It is interesting to note that the only reason inheritor is needed at all # is becuase Ruby does not allow modules to be inherited at the class-level, or # conversely that the "class-levels" of classes are not modules instead. class Object # Create an inheritor "class attribute". def inheritor( key, obj, op=nil ) # inhertiance operator op = op ? op.to_sym : :add # inheritor store a this level instance_variable_set("@#{key}", obj) #base = self deflambda = lambda do define_method( key ) do defined?(super) ? super.__send__(op,obj) : obj.dup end define_method( "#{key}!" ) do instance_variable_get("@#{key}") || inheritor( key, obj.class.new, op ) #if instance_variables.include?("@#{key}") # instance_variable_get("@#{key}") #else # if self != base # inheritor( key, obj.class.new, op ) # end #end end end # TODO This is an issue if you try to include a module # into Module or Class itself. How to fix? # if the object is a module (not a class or other object) if self == Class or self == Module class_eval &deflambda elsif is_a?(Class) (class << self; self; end).class_eval &deflambda elsif is_a?(Module) #class_inherit &deflambda extend class_extension( &deflambda ) else # other Object (class << self; self; end).class_eval &deflambda end obj end end # _____ _ # |_ _|__ ___| |_ # | |/ _ \/ __| __| # | | __/\__ \ |_ # |_|\___||___/\__| # =begin testing require 'test/unit' #class TC01 < Test::Unit::TestCase # def setup # @a = [1] # @i = Inheritor.new( @a, [2], :+ ) # end # def test_01_001 # assert_equal([2],@i) # end # def test_01_002 # assert_equal([1,2],@i.inheritance) # end #end class TC02 < Test::Unit::TestCase class C inheritor :koko, [1], :+ end class D < C inheritor :koko, [2], :+ end def test_02_001 assert_equal( [1], C.koko! ) end def test_02_002 assert_equal( [1], C.koko ) end def test_02_003 assert_equal( [2], D.koko! ) end def test_02_004 assert_equal( [1,2], D.koko ) end end class TC03 < Test::Unit::TestCase class C inheritor :koko, [1], :+ end class D < C end def test_03_001 assert_equal( [1], C.koko! ) end def test_03_002 assert_equal( [1], C.koko ) end def test_03_003 assert_equal( [], D.koko! ) end def test_03_004 assert_equal( [1], D.koko ) end end class TC04 < Test::Unit::TestCase class X inheritor :x, {:a=>1}, :merge end module M inheritor :x, {:b=>2}, :merge end class Y < X include M inheritor :x, {:c=>3}, :merge end def test_04_001 assert_equal( {:a=>1}, X.x ) end def test_04_002 assert_equal( 2, M.x[:b] ) end def test_04_003 assert_equal( {:a=>1,:b=>2,:c=>3}, Y.x ) end def test_04_004 assert_equal( 1, X.x[:a] ) assert_equal( nil, X.x[:b] ) assert_equal( nil, X.x[:c] ) end def test_04_005 ; assert_equal( 1, Y.x[:a] ) ; end def test_04_006 ; assert_equal( 2, Y.x[:b] ) ; end def test_04_007 ; assert_equal( 3, Y.x[:c] ) ; end def test_04_008 Y.x![:d] = 4 assert_equal( 4, Y.x[:d] ) end end class TC05 < Test::Unit::TestCase class C inheritor :relations, [], :concat end class D < C #inheritor :relations, [], :concat end C.relations! << 1 C.relations! << 2 D.relations! << 3 def test_05_001 assert_equal( [1,2], C.relations ) assert_equal( [1,2,3], D.relations ) end end class TC06 < Test::Unit::TestCase module MM inheritor :koko, [], :+ koko! << 1 end class CC1 include MM #inheritor :koko, [], :+ koko! << 2 koko! << 3 end class CC2 include MM #inheritor :koko, [], :+ koko! << 4 end def test_06_001 assert_equal( [1], MM.koko ) end def test_06_002 assert_equal( [1,2,3], CC1.koko ) end def test_06_003 assert_equal( [1,4], CC2.koko ) end end =end