# = association.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. # # == Authors and Contributors # # * Thomas Sawyer # Author:: Thomas Sawyer # Copyright:: Copyright (c) 2005 Thomas Sawyer # License:: Ruby License # = Association # # Gerenal binary association allows one object to be # associated with another. It has a variety of uses, # link-lists, simple ordered maps and mixed collections, # among them. # # == Usage # # Associations can be used to draw simple relationships. # # :Apple >> :Fruit # :Apple >> :Red # # :Apple.associations #=> [ :Fruit, :Red ] # # It can also be used for simple lists of ordered pairs. # # c = [ :a >> 1, :b >> 2 ] # c.each { |k,v| puts "#{k} associated with #{v} } # # produces # # a associated with 1 # b associated with 2 # # == Limitations # # The method :>> is used to construct the association. # It is a rarely used method so it is generally available. # But you can't use an Association while extending # any of the following classes becuase they use #>> for # other things. # # Bignum # Fixnum # Date # IPAddr # Process::Status # class Association include Comparable attr_accessor :index, :value def self.[](*args) new(*args) end def initialize(index, value=nil) @index = index @value = value end def <=>(assoc) return -1 if self.value < assoc.value return 1 if self.value > assoc.value return 0 if self.value == assoc.value end def invert! temp = @index @index = @value @value = temp end def to_s return "#{index.to_s}#{value.to_s}" end def inspect %{#{@index.inspect} >> #{@value.inspect}} end def to_ary [ @index, @value ] end end module Kernel ASSOCIATIONS = Hash.new{ |h,k,v| h[k]=[] } # Define an association with +self+. def >>(to) ASSOCIATIONS[self] << to Association.new(self, to) end def associations ASSOCIATIONS[self] end end #-- # Setup the >> method in classes that use it already. # # This is a bad idea b/c it can cause backward compability issues. # # class Bignum # alias_method( :rshift, :>>) if method_defined?(:>>) # remove_method :>> # end # # class Fixnum # alias_method( :rshift, :>>) if method_defined?(:>>) # remove_method :>> # end # # class Date # alias_method( :months_later, :>>) if method_defined?(:>>) # remove_method :>> # end # # class IPAddr # alias_method( :rshift, :>>) if method_defined?(:>>) # remove_method :>> # end # # class Process::Status # alias_method( :rshift, :>>) if method_defined?(:>>) # remove_method :>> # end #++ # _____ _ # |_ _|__ ___| |_ # | |/ _ \/ __| __| # | | __/\__ \ |_ # |_|\___||___/\__| # =begin test require 'test/unit' class TC01 < Test::Unit::TestCase def setup @complex_hierarchy = [ 'parent' >> 'child', 'childless', 'another_parent' >> [ 'subchildless', 'subparent' >> 'subchild' ] ] end def test_ohash k,v = [],[] ohash = [ 'A' >> '3', 'B' >> '2', 'C' >> '1' ] ohash.each { |e1,e2| k << e1 ; v << e2 } assert_equal( ['A','B','C'], k ) assert_equal( ['3','2','1'], v ) end def test_complex complex = [ 'Drop Menu' >> [ 'Button 1', 'Button 2', 'Button 3' ], 'Help' ] assert_equal( 'Drop Menu', complex[0].index ) end def test_associations complex = [ :a >> :b, :a >> :c ] assert_equal( [ :b, :c ], :a.associations ) end end =end