module ActiveObject module Associations def self.included(base) base.send :include, HasOneAssociation base.send :include, HasManyAssociation end module HasOneAssociation def self.included(base) base.extend ClassMethods end module ClassMethods # has_one用于指明两个对象之间的关联。 # # 一旦使用has_one,下列方法将被添加: # # [association] # 返回关联对象. 如果没有找到则返回+nil+。 # [association=(associate)] # 对关联对象赋值。 # [association.nil?] # 如果没有关联对象,则返回+true+。 # # (用第一个参数替换+association+,例如: # has_one :manager 将添加 manager.nil?.) # # === 示例 # # Account类定义了has_one :beneficiary,将添加: # * Account#beneficiary # * Account#beneficiary=(beneficiary) # * Account#beneficiary.nil? # # === 选项 # # 通过hash选项指定关联的行为 # # 选项: # [:class_name] # 指定关联的类名。默认情况类名是有关联推断出来的,如果无法推断则需要显性指定。 # # 选项示例: # has_one :icon,:class_name=>"Photo" # def has_one(association, options = {}) class_name = options.delete(:class_name) || association.to_s.camelize write_inheritable_attribute "#{association}_class",class_name # 保存关联的类名 attr_accessor "#{association}" merge_attributes "#{association}_id" # 将关联id作为持久化属性 define_method("#{association}_id") do self.instance_variable_get("@#{association}") ? self.instance_variable_get("@#{association}").id : nil end define_method("#{association}_id=") do |value| self.instance_variable_set("@#{association}",self.class.read_inheritable_attribute("#{association}_class").constantize.find(value)) end end end end module HasManyAssociation def self.included(base) base.extend ClassMethods end class Collection def initialize() @objects = [] end # 遍历关联对象集合 def each @objects.each do |object| yield object end end def each_with_index @objects.each_with_index do |object,index| yield object,index end end # 添加一个关联对象 def append(object) @objects << object end # 插入一个关联对象 def insert(index,object) @objects.insert(index,object) end # 删除一个关联对象 def delete(object) @objects.delete(object) end def size @objects.size end def clear @objects.clear end def empty? @objects.empty? end def object_ids @objects.collect{|object| object.id} end def objects @objects end end module ClassMethods # has_many用于指明两个对象之间的关联。 # # 一旦使用has_many,下列方法将被添加: # [associations.each] # 遍历对象集合 # [associations] # 返回关联的对象集合. 如果没有找到则返回空数组。 # [associations.append(object)] # 添加一个关联对象。 # [associations.insert(object,index)] # 插入一个关联对象。 # [associations.delete(object)] # 删除一个关联对象。 # [associations.clear] # 清除所有关联对象。 # [associations.size] # 关联对象的数量。 # [association.empty?] # 如果没有关联对象,则返回+true+。 # # (用第一个参数替换+associations+,例如: # has_many :managers 将添加 managers.empty?.) # # === 示例 # # Account类定义了has_many :friends,将添加: # * Account#friends # * Account#friends.append(user) # * Account#friends.delete(user) # * Account#friends.clear # * Account#friends.size # * Account#friends.empty? # # === 选项 # # 通过hash选项指定关联的行为 # # 选项: # [:class_name] # 指定关联的类名。默认情况类名是有关联推断出来的,如果无法推断则需要显性指定。 # # 选项示例: # has_many :friends,:class_name=>"User" # def has_many(associations, options = {}) class_name = options.delete(:class_name) || associations.to_s.singularize.camelize write_inheritable_attribute "#{associations}_class",class_name # 保存关联的类名 merge_attributes "#{associations}_ids" # 将关联ids作为持久化属性 define_method("#{associations}_ids") do self.instance_variable_get("@#{associations}") ? self.instance_variable_get("@#{associations}").object_ids : [] end define_method("#{associations}_ids=") do |value| self.instance_variable_set("@#{associations}",Collection.new) value.each do |object_id| self.instance_variable_get("@#{associations}").append(self.class.read_inheritable_attribute("#{associations}_class").constantize.find(object_id)) end end define_method("#{associations}") do self.instance_variable_set("@#{associations}",Collection.new) unless self.instance_variable_get("@#{associations}") self.instance_variable_get("@#{associations}") end end end end end end