# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig. # License: Apache License, Version 2.0 module RTM::AR class Topic < Construct include RTM::Topic wrapper_cache # parent :topic_map alias :parent :topic_map property_set :subject_identifiers, :aka => [:si,:sid], :type => :SubjectIdentifier, :wrap => true, #:create => :subject_identifier, :create_aka => [:csi,:csid], #:create_args => [{:name => :reference, :type => :String}] :add => :subject_identifier, :remove => :subject_identifier alias :getSubjectIdentifiers :subject_identifiers property_set :subject_locators, :aka => [:sl,:slo], :type => :SubjectLocator, :wrap => true, #:create => :subject_locator, :create_aka => [:csl, :cslo], #:create_args => [{:name => :reference, :type => :String}] :add => :subject_locator, :remove => :subject_locator alias :getSubjectLocators :subject_locators property :reified, :computable => true, :type => :Reifiable, :wrap => true property_set :names, :aka => [:n, :topic_names], :type => :Name, :wrap => true, :create => :name_internal, # :create_aka => [:create_topic_name, :cn], :create_args => [ {:name => :value, :type => :String}, {:name => :type, :type => :Topic, :optional => true}, {:name => :scope, :type => :Collection} ] alias :names_by :names # intermediate solution, check real TMAPI usage def create_name(arg1,arg2 = :nothing, arg3 = :nothing) if (arg2 == :nothing) && (arg3 == :nothing) #arg1 = value raise "create_name(value): value must be a String" unless arg1.is_a?(String) return create_name_internal(:value => arg1, :type => self.parent._topic_by_locator!(RTM::PSI[:name_type])) end if (arg3 == :nothing) if arg2.is_a?(Array) #arg1 = value, arg2 = scope raise "create_name(value, scope): value must be a String" unless arg1.is_a?(String) arg2.each do |theme| raise "create_name(value, scope): scope must be an Array of Topics/Topic-References" unless (theme.is_a?(String) || theme.is_a?(RTM::Topic) || theme.is_a?(RTM::Locator)) end return arg2.empty? ? create_name_internal(:value => arg1) : create_name_internal(:value => arg1, :scope => self.parent._topic_by_locator!(arg2)) elsif arg2.is_a?(String) #arg1 = type, arg2 = value raise "create_name(type, value): type must be a Topic/Topic-Reference" unless (arg1.is_a?(String) || arg1.is_a?(RTM::Topic) || arg1.is_a?(RTM::Locator)) return create_name_internal(:type => self.parent._topic_by_locator!(arg1), :value => arg2) else raise "create_name(?,?): arguments don't match" end end #arg1 = type, arg2 = value, arg3 = scope raise "create_name(type, value, scope): type must be a Topic/Topic-Reference" unless (arg1.is_a?(String) || arg1.is_a?(RTM::Topic) || arg1.is_a?(RTM::Locator)) raise "create_name(type, value, scope): value must be a String" unless arg2.is_a?(String) raise "create_name(type, value, scope): scope must be an Array" unless arg3.is_a?(Array) arg3.each do |theme| raise "create_name(type, value, scope): scope must be an Array of Topics/Topic-References" unless (theme.is_a?(String) || theme.is_a?(RTM::Topic) || theme.is_a?(RTM::Locator)) end return create_name_internal(:type => self.parent._topic_by_locator!(arg1), :value => arg2, :scope => self.parent._topic_by_locator!(arg3)) end alias :cn :create_name alias :create_topic_name :create_name property_set :occurrences, :aka => :o, :type => :Occurrence, :wrap => true, :create => :occurrence_internal, :create_aka => :co, :create_args => [ {:name => :type, :type => :Topic}, {:name => :value, :type => [:String, :Locator]}, {:name => :scope, :type => :Collection} ] alias :occurrences_by :occurrences # intermediate solution, check real TMAPI usage def create_occurrence(type,value,params={}) if params[:scope] if value.is_a?(RTM::Locator) return create_occurrence_internal(topic_map.get!(type),value,topic_map._topic_by_locator!(params[:scope]), :datatype => RTM::PSI[:IRI]) elsif !params[:datatype] return create_occurrence_internal(topic_map.get!(type),value,topic_map._topic_by_locator!(params[:scope])) else # datatype given, no locator return create_occurrence_internal(topic_map.get!(type),value,topic_map.create_locator(params[:datatype]),topic_map._topic_by_locator!(params[:scope])) end else #no scope if value.is_a?(RTM::Locator) return create_occurrence_internal(topic_map.get!(type),value, :datatype => RTM::PSI[:IRI]) elsif !params[:datatype] return create_occurrence_internal(topic_map.get!(type),value, params) else #datatype given, no locator return create_occurrence_internal(topic_map.get!(type),value,topic_map.create_locator(params[:datatype])) end end end def characteristics(*args) names(*args).to_a + occurrences(*args).to_a end alias :children :characteristics alias :characteristics_by :characteristics # intermediate solution, check real TMAPI usage property_set :roles, :aka => [:r, :roles_played, :association_roles], :computable => true, :type => :Role, :wrap => true def filter_roles(*args) puts puts "topic filter roles:" puts args.inspect if args.size == 1 a1 = args.shift # if a1 == :any # a1 = nil # end role_type = topic_map.get(a1) return self.roles unless role_type if role_type.respond_to?(:each) query_conditions = (["ttype_id = ?"] * role_type.size).join(" OR ") puts puts "qq:" puts query_conditions puts role_type.map{|rt| rt.id} puts return self.roles.find(:all,:conditions => [query_conditions, role_type.map{|rt| rt.id}]) else return self.roles.find(:all,:conditions => ["ttype_id = ?", role_type.id]) end elsif args.size == 2 role_type = args.shift # if role_type == :any # role_type = nil # end role_type = topic_map.get(role_type) assoc_type = args.shift # if assoc_type == :any # assoc_type = nil # end assoc_type = topic_map.get(assoc_type) if role_type && assoc_type puts "trying to return topic.roles for #{role_type.inspect} and #{assoc_type.inspect}" res = self.roles.find(:all, :conditions => ["roles.ttype_id = ? and associations.ttype_id = ?", role_type.id, assoc_type.id]) puts res.inspect return res elsif assoc_type return self.roles.find(:all, :conditions => ["associations.ttype_id = ?", assoc_type.id]) elsif role_type return self.roles.find(:all,:conditions => ["ttype_id = ?", role_type.id]) else warn("Topic#roles got 2 arguments but doesn't know how to handle (or referenced topics where not found)") end end false end property_set :associations, :aka => [:a, :associations_played], :type => :Association, :wrap => true property_set :scoped, :aka => :scoped_objects, :type => :Construct, :wrap => true property_set :scoped_associations, :type => :Association, :wrap => true property_set :scoped_names, :aka => :scoped_topic_names, :type => :Name, :wrap => true property_set :scoped_variants, :type => :Variant, :wrap => true property_set :scoped_occurrences, :type => :Occurrence, :wrap => true property_set :typed, :aka => :typed_objects, :type => :Construct, :wrap => true property_set :typed_associations, :aka => [:ta,:associations_typed,:at], :type => :Association, :wrap => true property_set :typed_roles, :aka => [:rt,:roles_typed,:association_roles_typed,:art,:rt], :type => :Role, :wrap => true property_set :typed_names, :aka => [:nt,:names_typed,:topic_names_typed,:tnt,:nt], :type => :Name, :wrap => true property_set :typed_occurrences, :aka => [:to,:occurrences_typed,:ot], :type => :Occurrence, :wrap => true def id __getobj__.id end # class:Topic equality, http://www.isotopicmaps.org/sam/sam-model/#d0e1029 # # This method is all crap. These ActiveRecord Arrays can't be intersected, # so I map the identifiers to their reference which seems long winded. # Still I find it better than using their ID in the long. # def ==(o) return false unless o return false unless o.respond_to?(:subject_identifiers) return false unless o.respond_to?(:subject_locators) return false unless o.respond_to?(:names) # Two topic items are equal if they have: # * at least one equal string in their [subject identifiers] properties, # -> test if intersection are > 0 my_si = self.subject_identifiers.map{|si| si.reference} ot_si = o.subject_identifiers.map{|si| si.reference} return true if ( my_si & ot_si).size > 0 # * at least one equal string in their [item identifiers] properties, my_ii = self.item_identifiers.map{|ii| ii.reference} ot_ii = o.item_identifiers.map{|ii| ii.reference} return true if (my_ii & ot_ii).size > 0 # * at least one equal string in their [subject locators] properties, my_sl = self.subject_locators.map{|sl| sl.reference} ot_sl = o.subject_locators.map{|sl| sl.reference} return true if (my_sl & ot_sl).size > 0 # * an equal string in the [subject identifiers] property of the one topic item and the [item identifiers] property of the other, or return true if (my_si & ot_ii).size > 0 return true if (my_ii & ot_si).size > 0 # * the same information item in their [reified] properties. return true if self.reified != nil && o.reified != nil && (self.reified == o.reified) # ... otherwise false end end end