This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
module Hashery
|
||||
|
||||
# TODO: Should associations be singleton?
|
||||
#
|
||||
# TODO: Is it really wise to keep a table of all associations?
|
||||
|
||||
# Association is a general binary association that allows one
|
||||
# object to be associated with another. It has a variety of uses,
|
||||
# such as linked-lists, simple ordered maps and mixed collections,
|
||||
# among them.
|
||||
#
|
||||
# NOTE: This class is still fairly experimental. And it is not
|
||||
# loaded along with the other Hashery libraries when using
|
||||
# `require 'hashery'`. It must be required independently.
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# The method :>> is used to construct the association.
|
||||
# It is a rarely used method so it is generally available.
|
||||
# But you can't use it for any of the following classes
|
||||
# becuase they use #>> for other things.
|
||||
#
|
||||
# Bignum
|
||||
# Fixnum
|
||||
# Date
|
||||
# IPAddr
|
||||
# Process::Status
|
||||
#
|
||||
class Association
|
||||
include Comparable
|
||||
|
||||
class << self
|
||||
#
|
||||
# Store association references.
|
||||
#
|
||||
# Returns `Hash` of all associaitons.
|
||||
#
|
||||
def reference
|
||||
@reference ||= Hash.new{ |h,k,v| h[k]=[] }
|
||||
end
|
||||
|
||||
#
|
||||
# Shortcut for #new.
|
||||
#
|
||||
# index - The "index key" of the association.
|
||||
# value - The "value" of the association.
|
||||
#
|
||||
# Returns `Association`.
|
||||
#
|
||||
def [](index, value)
|
||||
new(index, value)
|
||||
end
|
||||
|
||||
#def new(index, value)
|
||||
# lookup[[index, value]] ||= new(index, value)
|
||||
#end
|
||||
|
||||
#def lookup
|
||||
# @lookup ||= {}
|
||||
#end
|
||||
end
|
||||
|
||||
#
|
||||
# The "index key" of the association.
|
||||
#
|
||||
attr_accessor :index
|
||||
|
||||
#
|
||||
# The "value" of the association.
|
||||
#
|
||||
attr_accessor :value
|
||||
|
||||
#
|
||||
# Initialize new Association.
|
||||
#
|
||||
# index - The "index key" of the association.
|
||||
# value - The "value" of the association.
|
||||
#
|
||||
def initialize(index, value=nil)
|
||||
@index = index
|
||||
@value = value
|
||||
|
||||
unless index.associations.include?(value)
|
||||
index.associations << value
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Compare the values of two associations.
|
||||
#
|
||||
# TODO: Comparions with non-associations?
|
||||
#
|
||||
# assoc - The other `Association`.
|
||||
#
|
||||
# Returns [Integer] `1`, `0`, or `-1`.
|
||||
#
|
||||
def <=>(assoc)
|
||||
return -1 if self.value < assoc.value
|
||||
return 1 if self.value > assoc.value
|
||||
return 0 if self.value == assoc.value
|
||||
end
|
||||
|
||||
#
|
||||
# Invert association, making the index the value and vice-versa.
|
||||
#
|
||||
# Returns [Array] with two-elements reversed.
|
||||
#
|
||||
def invert!
|
||||
temp = @index
|
||||
@index = @value
|
||||
@value = temp
|
||||
end
|
||||
|
||||
#
|
||||
# Produce a string representation.
|
||||
#
|
||||
# Returns [String].
|
||||
#
|
||||
def to_s
|
||||
return "#{index} >> #{value}"
|
||||
end
|
||||
|
||||
#
|
||||
# Produce a literal code string for creating an association.
|
||||
#
|
||||
# Returns [String].
|
||||
#
|
||||
def inspect
|
||||
"#{index.inspect} >> #{value.inspect}"
|
||||
end
|
||||
|
||||
#
|
||||
# Convert to two-element associative array.
|
||||
#
|
||||
# Returns [Array] Two-element Array of index and value pair.
|
||||
#
|
||||
def to_ary
|
||||
[index, value]
|
||||
end
|
||||
|
||||
#
|
||||
# Object extensions.
|
||||
#
|
||||
module Kernel
|
||||
|
||||
#
|
||||
# Define an association for +self+.
|
||||
#
|
||||
# to - The value of the association.
|
||||
#
|
||||
# Returns [Association].
|
||||
#
|
||||
def >>(to)
|
||||
Association.new(self, to)
|
||||
end
|
||||
|
||||
#
|
||||
# List of associations for this object.
|
||||
#
|
||||
# Returns an `Array` of `Associations`.
|
||||
#
|
||||
def associations
|
||||
Association.reference[self]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Object #:nodoc:
|
||||
include Hashery::Association::Kernel
|
||||
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
|
||||
#++
|
||||
|
||||
# Copyright (c) 2005 Rubyworks, Thomas Sawyer
|
||||
Reference in New Issue
Block a user