rb_cObject
An RDF graph class
$Id$
Portions of this file (namely the graph-equivalence stuff) were ported to Ruby from the Test::RDF Perl module written by Michael Hendricks. His copyright is:
Copyright (C) 2006 Michael Hendricks <michael@palmcluster.org> This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Copyright © 2008-2009, Michael Granger All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Return a hash describing all model types supported by the underlying Redland library.
static VALUE rleaf_redleaf_graph_s_model_types( VALUE klass )
Create a new Redleaf::Graph object. If the optional store object is given, it is used as the backing store for the graph. If none is specified a new Redleaf::MemoryHashStore is used.
static VALUE rleaf_redleaf_graph_initialize( int argc, VALUE *argv, VALUE self )
Return a Hash of supported serializers from the underlying Redland library.
Redleaf::Parser.serializers # => { "rss-1.0" => "RSS 1.0", # "rdfxml" => "RDF/XML", # "json-triples" => "RDF/JSON Triples", # "rdfxml-abbrev" => "RDF/XML (Abbreviated)", # "rdfxml-xmp" => "RDF/XML (XMP Profile)", # "turtle" => "Turtle", # "ntriples" => "N-Triples", # "json" => "RDF/JSON Resource-Centric", # "dot" => "GraphViz DOT format", # "atom" => "Atom 1.0" }
static VALUE rleaf_redleaf_graph_s_serializers( VALUE klass )
Returns true if the specified format is supported by the Redland backend.
# File lib/redleaf/graph.rb, line 86 86: def self::valid_format?( format ) 87: Redleaf.logger.debug "Checking validity of format %p" % [ format ] 88: return self.serializers.key?( format ) 89: end
Append statements to the graph, either as Redleaf::Statements, valid triples in Arrays, or a subgraph of nodes expressed in a Hash.
require 'redleaf/constants' incude Redleaf::Constants::CommonNamespaces # (for the FOAF namespace constant) MY_FOAF = Redleaf::Namspace.new( 'http://deveiate.org/foaf.xml#' ) michael = MY_FOAF[:me] graph = Redleaf::Graph.new statement1 = Redleaf::Statement.new( michael, FOAF[:family_name], 'Granger' ) statement2 = [ michael, FOAF[:givenname], 'Michael' ] graph.append( statement1, statement2 ) graph << [ michael, FOAF[:homepage], URI('http://deveiate.org/') ]
static VALUE rleaf_redleaf_graph_append( int argc, VALUE *argv, VALUE self )
Return a string describing the status of contexts in the receiving graph. This will be a count of the contexts if they are enabled, or “contexts not enabled” if they aren’t enabled.
# File lib/redleaf/graph.rb, line 196 196: def context_info 197: if self.contexts_enabled? 198: return "%d contexts" % [ self.contexts.length ] 199: else 200: return "contexts disabled" 201: end 202: end
Returns an Array of URIs describing the contexts in the receiving graph.
static VALUE rleaf_redleaf_graph_contexts( VALUE self )
Duplicate the receiver and return the copy.
static VALUE rleaf_redleaf_graph_dup( VALUE self )
Call block once for each statement in the graph.
static VALUE rleaf_redleaf_graph_each_statement( VALUE self )
Returns true if the graph does not contain any statements.
# File lib/redleaf/graph.rb, line 101 101: def empty? 102: return self.size.zero? 103: end
Run the query in the given query string (qstring) against the graph. The query language specifies the query language, and limit, and offset can be used to limit the results. The #query method is the public interface to this method.
static VALUE rleaf_redleaf_graph_execute_query( int argc, VALUE *argv, VALUE self )
Returns true if the graph has at least one statement with the specified subject and predicate.
static VALUE rleaf_redleaf_graph_has_predicate_about_p( VALUE self, VALUE subject, VALUE predicate )
Returns true if the graph has at least one statement with the specified predicate and object.
static VALUE rleaf_redleaf_graph_has_predicate_entailing_p( VALUE self, VALUE predicate, VALUE object )
Return true if the receiver contains the specified statement, which can be either a Redleaf::Statement object or a valid triple in an Array.
static VALUE rleaf_redleaf_graph_include_p( VALUE self, VALUE statement )
Returns true if the graph contains any statements with the specified object.
static VALUE rleaf_redleaf_graph_include_object_p( VALUE self, VALUE object )
Returns true if the graph contains any statements with the specified subject.
static VALUE rleaf_redleaf_graph_include_subject_p( VALUE self, VALUE subject )
Return a human-readable representation of the object suitable for debugging.
# File lib/redleaf/graph.rb, line 184 184: def inspect 185: return "#<%s:0x%x %d statements, %s>" % [ 186: self.class.name, 187: self.object_id * 2, 188: self.size, 189: self.context_info 190: ] 191: end
call-seq:
graph.is_equivalent_to?( other_graph ) -> true or false graph === other_graph -> true or false
Equivalence method — compare the receiving graph with other_graph according to the graph equivalency rules in:
http://www.w3.org/TR/rdf-concepts/#section-graph-equality
# File lib/redleaf/graph.rb, line 145 145: def is_equivalent_to?( other_graph ) 146: unless other_graph.size == self.size 147: self.log.debug "Graphs differ in size (%d vs. %d)" % [ self.size, other_graph.size ] 148: return false 149: end 150: 151: other = other_graph.dup 152: bnode_map = BnodeMap.new 153: difference = nil 154: 155: difference = self.find do |stmt| 156: # If the copy of the other graph has an equivalent statement, remove it 157: # and move on to the next one. 158: if other.remove_equivalent_statement( stmt, bnode_map ) 159: next 160: 161: # Otherwise, we've found a difference 162: else 163: stmt 164: end 165: end 166: 167: buf = '' 168: PP.pp( bnode_map, buf ) 169: self.log.debug "Bnode map after comparison:\n%s" % [ buf ] 170: 171: if difference 172: self.log.debug "%p is not equivalent to %p because it does not contain %p" % 173: [ self, other_graph, difference ] 174: return false 175: else 176: return true 177: end 178: end
Parse the RDF at the specified uri into the receiving graph. Returns the number of statements added to the graph (if the underlying store supports ).
graph = Redleaf::Graph.new graph.load( "http://bigasterisk.com/foaf.rdf" ) graph.load( "http://www.w3.org/People/Berners-Lee/card.rdf" ) graph.load( "http://danbri.livejournal.com/data/foaf" ) graph.size
static VALUE rleaf_redleaf_graph_load( VALUE self, VALUE uri )
Return one object of a statement with the specified subject and predicate.
static VALUE rleaf_redleaf_graph_object( VALUE self, VALUE subject, VALUE predicate )
Return an Array of object nodes from the graph that have the specified subject and predicate.
static VALUE rleaf_redleaf_graph_objects( VALUE self, VALUE subject, VALUE predicate )
Return one predicate of a statement with the specified subject and object.
static VALUE rleaf_redleaf_graph_predicate( VALUE self, VALUE subject, VALUE object )
Return an Array of predicate nodes from the graph that have the specified subject and object.
static VALUE rleaf_redleaf_graph_predicates( VALUE self, VALUE subject, VALUE object )
Returns an Array of predicates (URI objects) that point from the specified subject.
static VALUE rleaf_redleaf_graph_predicates_about( VALUE self, VALUE subject )
Returns an Array of predicates (URI objects) that point to the specified object.
static VALUE rleaf_redleaf_graph_predicates_entailing( VALUE self, VALUE object )
Run a SPARQL query against the graph. The optional prefixes hash can be used to set up prefixes in the query.
require 'redleaf/constants' include Redleaf::Constants::CommonNamespaces # Declare a custom namespace and create a graph with a node about its title book = Redleaf::Namespace.new( 'http://example.org/book' ) graph = Redleaf::Graph.new graph << [ book[:book1], DC[:title], "SPARQL Tutorial" ] qstring = 'SELECT ?title WHERE { book:book1 dc:title ?title }' res = graph.query( qstring, :book => book, :dc => DC ) # => #<Redleaf::BindingsQueryResult:0x07466b3> res.each do |row| puts row.title end
# File lib/redleaf/graph.rb, line 126 126: def query( querystring, *args ) 127: prefixes = args.last.is_a?( Hash ) ? args.last : {} 128: 129: 130: prelude = prefixes.collect {|prefix, uri| "PREFIX %s: <%s>\n" % [ prefix, uri ] }.join 131: querystring = prelude + querystring 132: self.log.debug "Querystring is: %p" % [ querystring ] 133: 134: return self.execute_query( querystring ) 135: end
Removes one or more statements from the graph that match the specified statement (either a Redleaf::Statement or a valid triple in an Array) and returns any that were removed.
Any nil values in the statement will match any value.
# Set a new home page for the Redleaf project, preserving the old one # as the 'old_homepage' stmt = graph.remove([ :Redleaf, DOAP[:homepage], nil ]) stmt.predicate = DOAP[:old_homepage] graph.append( stmt ) graph.append([ :Redleaf, DOAP[:homepage], URL.parse('http://deveiate.org/projects/Redleaf') ])
static VALUE rleaf_redleaf_graph_remove( VALUE self, VALUE statement )
Search for statements in the graph with the specified subject, predicate, and object and return them. If subject, predicate, or object are nil, they will match any value.
# Match any statements about authors graph.load( 'http://deveiant.livejournal.com/data/foaf' ) # graph[ nil, FOAF[:knows], nil ] # => [...]
static VALUE rleaf_redleaf_graph_search( VALUE self, VALUE subject, VALUE predicate, VALUE object )
Return the graph serialized to a String in the specified format. Valid +format+s are keys of the Hash returned by ::serializers.
The nshash argument can be used to set namespaces in the output (for serializers that support them). It should be of the form:
{ :nsname => <namespace URI> }
Examples:
turtle = graph.serialized_as( 'turtle' ) xml = graph.serialized_as( 'rdfxml-abbrev', :foaf => 'http://xmlns.com/foaf/0.1/' )
static VALUE rleaf_redleaf_graph_serialized_as( int argc, VALUE *argv, VALUE self )
Return the number of statements in the graph. If the underlying store doesn’t support fetching the size of the graph, the return value will be negative.
static VALUE rleaf_redleaf_graph_size( VALUE self )
Return an Array of all the statements in the graph.
static VALUE rleaf_redleaf_graph_statements( VALUE self )
Return the Redleaf::Store associated with the receiver.
static VALUE rleaf_redleaf_graph_store( VALUE self )
Associate the given new_store with the receiver, breaking the association between it and any previous Store.
static VALUE rleaf_redleaf_graph_store_eq( VALUE self, VALUE storeobj )
Return one subject of a statement with the specified predicate and object.
static VALUE rleaf_redleaf_graph_subject( VALUE self, VALUE predicate, VALUE object )
Return an Array of subject nodes from the graph that have the specified predicate and object.
static VALUE rleaf_redleaf_graph_subjects( VALUE self, VALUE predicate, VALUE object )
Returns true if the receiving model supports contexts.
static VALUE rleaf_redleaf_graph_supports_contexts_p( VALUE self )
Synchronise the model to the model implementation.
static VALUE rleaf_redleaf_graph_sync( VALUE self )
Proxy method — handle #to_«format» methods by invoking a serializer for the specified format.
# File lib/redleaf/graph.rb, line 225 225: def method_missing( sym, *args ) 226: super unless sym.to_s =~ /^to_(\w+)$/ 227: 228: format = $1.tr( '_', '-' ) 229: super unless self.class.valid_format?( format ) 230: 231: serializer = lambda { self.serialized_as(format) } 232: 233: # Install the closure as a new method and call it 234: self.class.send( :define_method, sym, &serializer ) 235: return self.method( sym ).call 236: end
Given the specified bnode_map (a BnodeMap object which contains an equivalence mapping between blank nodes in the receiver and statement), remove the given statement from the receiver if an equivalent one exists. If an equivalent exists, return it, otherwise return nil. This was ported from Michael Hendricks’s Test::RDF Perl module. :TODO: Refactor into multiple methods
# File lib/redleaf/graph.rb, line 245 245: def remove_equivalent_statement( statement, bnode_map ) 246: subject = statement.subject 247: predicate = statement.predicate 248: object = statement.object 249: 250: subject_is_floating = false 251: object_is_floating = false 252: 253: # anchor the subject if possible 254: if subject.is_a?( Symbol ) 255: subject_is_floating = true 256: if mapped = bnode_map[ subject ] 257: subject = mapped 258: subject_is_floating = false 259: end 260: end 261: 262: # anchor the object if possible 263: if object.is_a?( Symbol ) 264: object_is_floating = true 265: if mapped = bnode_map[ object ] 266: object = mapped 267: object_is_floating = false 268: end 269: end 270: 271: # If both the subject and object are unmapped bnodes, select the first 272: # triple with the same predicate and unmapped bnode subject and objects 273: if subject_is_floating && object_is_floating 274: self.log.debug "Anchoring a subject (%p) and an object (%p)" % 275: [ subject, object ] 276: equivalent = self[ nil, predicate, nil ].find do |stmt| 277: if stmt.subject.is_a?( Symbol ) && 278: stmt.object.is_a?( Symbol ) && 279: bnode_map.valid?( subject, stmt.subject ) && 280: bnode_map.valid?( object, stmt.object ) 281: 282: bnode_map[ subject ] = stmt.subject 283: bnode_map[ object ] = stmt.object 284: 285: stmt 286: end 287: end 288: 289: # If the subject is an unanchored bnode, select the first 290: # triple with the same predicate and object and an unmapped subject 291: elsif subject_is_floating 292: self.log.debug "Anchoring a subject (%p)" % [ subject ] 293: equivalent = self[ nil, predicate, object ].find do |stmt| 294: if stmt.subject.is_a?( Symbol ) && 295: bnode_map.valid?( subject, stmt.subject ) 296: 297: bnode_map[ subject ] = stmt.subject 298: stmt 299: end 300: end 301: 302: # Do the same for an unanchored object 303: elsif object_is_floating 304: self.log.debug "Anchoring an object (%p)" % [ object ] 305: equivalent = self[ subject, predicate, nil ].find do |stmt| 306: if stmt.object.is_a?( Symbol ) && 307: bnode_map.valid?( object, stmt.object ) 308: 309: bnode_map[ object ] = stmt.object 310: stmt 311: end 312: end 313: 314: # If the statement's nodes are all either mapped or not bnodes, just 315: # search for an equivalent 316: else 317: self.log.debug "Searching for an anchored statement {%p, %p, %p}" % 318: [ subject, predicate, object ] 319: equivalent = self[ subject, predicate, object ].first 320: end 321: 322: self.log.debug "Equivalent is: %p" % [ equivalent ] 323: 324: return self.remove( equivalent ).first if equivalent 325: return nil 326: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.