require 'digest' require 'set' module RDF # Represents an RDF property. # If an optional subject is provided on instatiation, provides access to values of this property belonging to the # associated subject. Property objects are +Enumerable+. Values are returned as copies with no order garunteed # and may be accessed individually by key. # # == Usage # age = RDF::Property.new('http://activerdf.org/test/age') # age.domain => [#] # age.range => [#] # age.type => [#] # age.to_a => ActiveRdfError: http://activerdf.org/test/age: no associated subject # # email = RDF::Property.new('http://activerdf.org/test/email', 'http://activerdf.org/test/eyal') # email.replace("eyal@cs.cu.nl") # replace any existing values # email.add("eyal.oren@deri.com") # add new value to this property # email += ("eyal.oren@deri.net") # alternative way to add new value # email.clear # delete any existing values # email.add(["eyal@cs.cu.nl","eyal.oren@deri.com"]) # add array containing values # email["eyal.oren@deri.com"] = "eyal.oren@deri.net" # replace existing value # email[p.index("eyal.oren@deri.net")] = "eyal.oren@deri.org" # replace existing value by key # email.include?("eyal.oren@deri.org") => true # check for existing value # email == ["eyal.oren@deri.org","eyal@cs.cu.nl"] => true # compare value(s) to array (order is ignored) # email.delete("eyal@cs.cu.nl") # delete specific value # email == "eyal.oren@deri.org" => true # compare value(s) to single value # email.collect!{|val| val.gsub(/@/,' at ').gsub(/\./,' dot ')} # update value(s) with result of block class Property < RDFS::Resource attr_reader :subject def initialize(property, subject = nil) super(property) @subject = subject @lang = nil @exact_lang = true @datatype = nil @context = nil if @subject class<" end # Returns a new array populated with the keys to the values def keys collect{|value| get_key(value)} end # Returns the language tag and the match settings for the property if tag is nil. # Returns a new RDF::Property object with the @lang value set if tag is provided # see also #context, #datatype def lang(tag = nil, exact = true) if tag.nil? [@lang,@exact_lang] else property_with_lang = RDF::Property.new(self, @subject) property_with_lang.lang = tag, exact property_with_lang end end # Sets lang and match settings def lang=(*args) args.flatten! @lang = args[0].sub(/^@/,'') @exact_lang = truefalse(args[1],true) end # Returns the number of values assigned to this property for this @subject def length to_a.length end alias :size :length # Ensure the return of only one value assigned to this property for this @subject. # If more than 1 value is found, ActiveRdfError is thrown. def only entries = self.entries raise ActiveRDF::ActiveRdfError if entries.size > 1 entries[0] end # Equivalent to Property#delete_if, but returns nil if no changes were made def reject!(&block) # :yields: key, value change = false each_pair do |key, value| if yield(key, value) delete(value) change = true end end self if change end # Value replacement. Replaces all current value(s) with the new value def replace(new) clear add(new) self end alias :size :length # Allow this Property to be automatically converted to array alias :to_ary :to_a # Returns a hash of copies of all values with indexes. # Changes to this hash will not effect the underlying values. Use #add or #replace to persist changes. # See also #each_pair def to_h hash = {} to_a.each do |value| hash[get_key(value)] = value end hash end # Return an array containing the values for the given keys. def values_at(*args) args.collect{|md5| self[md5]} end private def get_key(value) Digest::MD5.hexdigest(value.to_s) end end end