module RTM::AR module TraverseAssociations def define_association(prop, options={}) r = options[:rule] module_eval(<<-EOS, "(__AR_DELEGATOR_DEFINE_ASSOCIATION__)", 1) def direct_#{prop}_roles # prefetch typing topics rtype = @ips_#{prop}_rtype ||= self.topic_map.get("#{r[:role_type]}") atype = @ips_#{prop}_atype ||= self.topic_map.get("#{r[:association_type]}") otype = @ips_#{prop}_otype ||= self.topic_map.get("#{r[:other_role_type]}") # return nothing if any of the typing topics does not exist return [] unless rtype && atype && otype # we do that only here and not earlier because some might me nil rtype = rtype.id atype = atype.id otype = otype.id self.__getobj__.roles.map{|r| r.ttype_id != nil && r.ttype_id == rtype && r.parent.roles.size == #{r[:association_arity]} && r.parent != nil && r.parent.ttype_id == atype && (r2 = r.parent.roles.select{|r2| r2.ttype_id != nil && r2.ttype_id == otype}.first) && r2}.select{|r2| r2}.map{|r2| AssociationRole.wrap(r2)} end def direct_#{prop} direct_#{prop}_roles.map{|r2| r2.player}.uniq end EOS if r[:transitive] module_eval(<<-EOS, "(__AR_DELEGATOR_DEFINE_ASSOCIATION2__)", 1) def #{prop} d = todo = self.direct_#{prop} while todo.size > 0 todo = todo.map{|dt| dt.direct_#{prop}}.flatten.uniq - d d += todo end d #d2 = self.direct_#{prop}.map {|dt| dt.#{prop}}.flatten #(d+d2).uniq end EOS else if r[:infer] && r[:infer_other] # this part is not testet at all! module_eval(<<-EOS, "(__AR_DELEGATOR_DEFINE_ASSOCIATION3a__)", 1) def #{prop} dps = (self + self.#{r[:infer]}).flatten.uniq dcps = dps.map{|d2| d2.direct_#{prop}} (dcps + dcps.map{|d2| d2.#{r[:infer_other]}}).flatten.uniq end EOS elsif r[:infer] module_eval(<<-EOS, "(__AR_DELEGATOR_DEFINE_ASSOCIATION3__)", 1) def #{prop} (self.direct_#{prop} + self.#{r[:infer]}.map{|d2| d2.direct_#{prop}}).flatten.uniq end EOS elsif r[:infer_other] module_eval(<<-EOS, "(__AR_DELEGATOR_DEFINE_ASSOCIATION4__)", 1) def #{prop} d = self.direct_#{prop} (d + d.map{|d2| d2.#{r[:infer_other]}}).flatten.uniq end EOS end end if r[:add] module_eval(<<-EOS, "(__AR_DELEGATOR_DEFINE_ASSOCIATION_ADD_REMOVE__)", 1) def add_#{r[:add]}(t) a = self.topic_map.create_association("#{r[:association_type]}") a.create_role self, "#{r[:role_type]}" a.create_role t, "#{r[:other_role_type]}" a # TODO add_x in define_association needs to trigger reload of the topics somewhere end def remove_#{r[:add]}(t) direct_#{prop}_roles.select{|r| r.player == t}.each{|r| r.parent.remove} # TODO remove_x in define_association needs to trigger reload of the topics somewhere end EOS end end end end