#--
# WontoMedia - a wontology web application
# Copyright (C) 2011 - Glen E. Ivey
# www.wontology.com
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License version
# 3 as published by the Free Software Foundation.
#
# 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. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program in the file COPYING and/or LICENSE. If not,
# see .
#++
# This module provides a container for methods that manipulate or
# transform Connection objects.
module ConnectionHelper
# This method renders a multi-line string in the 'n3' format (aka
# 'Notation3' standardized by the W3C, see
# http://en.wikipedia.org/wiki/Notation3 for an introduction) from
# an array of Connection models.
#
# This is currently a trivial but correct implementation. It supports
# our current data model, but will need a significant upgrade when
# WontoMedia begins to support reiffied edges (blank nodes), etc.
def self.connection_array_to_n3(connections)
result = ""
connections.each do |connection|
result << "<##{connection.subject.name}> <##{connection.predicate.name}> "
if connection.kind_of_obj == Connection::OBJECT_KIND_ITEM
result << "<##{connection.obj.name}> .\n"
else
result << "\"#{connection.scalar_obj}\" .\n"
end
end
result
end
# An operator usable for sorting, returns 0 for a==b, <0 for a [
"subject_id = ? AND predicate_id = ?", a.predicate_id,
Item.find_by_name('has_scalar_object') ])
b_kind = Connection.first( :conditions => [
"subject_id = ? AND predicate_id = ?", b.predicate_id,
Item.find_by_name('has_scalar_object') ])
if a_kind != b_kind
return a_kind.nil? ? 1 : -1
end
end
# relationships w/ predicates constrained by max_uses_per_item:
# sort lower maximums closer to top of list. Sort unconstrained
# predicates as "infinite maximum"
max_uses = Item.find_by_name('max_uses_per_item')
a_max = Connection.first( :conditions => [
"subject_id = ? AND predicate_id = ?", a.predicate_id, max_uses.id ])
unless a_max.nil?
a_max = a_max.scalar_obj.nil? ? nil : a_max.scalar_obj.to_i
end
b_max = Connection.first( :conditions => [
"subject_id = ? AND predicate_id = ?", b.predicate_id, max_uses.id ])
unless b_max.nil?
b_max = b_max.scalar_obj.nil? ? nil : b_max.scalar_obj.to_i
end
unless a_max == b_max
return -1 if b_max.nil?
return 1 if a_max.nil?
return a_max - b_max
end
a_id = a.predicate_id
b_id = b.predicate_id
# sort by "predicate external factor" hash, higher numbers better
# (this is intended to support, among other things, sorting based
# on the number of times the same predicate is used in the list of
# connections being sorted. Requires caller to make a counting
# pass over the sort set first to build the hash
a_count = factor_hash[a_id].nil? ? 0 : factor_hash[a_id]
b_count = factor_hash[b_id].nil? ? 0 : factor_hash[b_id]
return b_count - a_count if a_count != b_count
# sort by property ID order (this is essentially arbitrary, but
# ensures the sort order is stable and that subsequent factors
# only affect sorting within groups of connections all referencing
# the same property item)
return a_id - b_id if a_id != b_id
# sort connections with missing objects (e.g. "add here"
# place-holders) below others
a_blank = a.kind_of_obj.nil? ||
(a.kind_of_obj == Connection::OBJECT_KIND_ITEM ?
a.obj : a.scalar_obj ) == nil
b_blank = b.kind_of_obj.nil? ||
(b.kind_of_obj == Connection::OBJECT_KIND_ITEM ?
b.obj : b.scalar_obj ) == nil
return a_blank ? 1 : -1 if a_blank != b_blank
# sort connections whose objects are built-in below others
aflag = a.obj.nil? ? 0 : a.obj.flags & Item::DATA_IS_UNALTERABLE
bflag = b.obj.nil? ? 0 : b.obj.flags & Item::DATA_IS_UNALTERABLE
return aflag - bflag
end
end