- From: Dan Brickley <danbri@w3.org>
- Date: Sat, 8 Dec 2001 09:07:24 -0500 (EST)
- To: <www-archive+ruby@w3.org>
Ahem, this is the version where both simple queries work! s/fp/bp/
--danbri
---------- Forwarded message ----------
Date: Sat, 8 Dec 2001 14:13:35 GMT
From: danbri@fireball.dyndns.org
To: danbri@W3.org
#!/usr/local/bin/ruby
#
# RDFWeb Ruby RDF stuff
# danbri@w3.org
# Overview:
# we use the classes 'Graph', 'Node', and 'Statement'
#
# todo:
# - associate Nodes with Graphs
# - implement ask(template_statement) method (slog through the variations!)
# - implement ntriples-based i/o
# - use method_missing to catch property queries on nodes
# - figure out how to test this and Perl version at same time
# - document the stuff it doesn't do w.r.t. RDF specs
# - find out about various Ruby features I'm unclear on (see 'todo:' notes)
##############################################################################
#
class Node
@@nodes = {}
attr_accessor :content
# constructor (make this private? use get* instead)
def initialize (content)
@content = content
end
def inspect
"#@content "
end
# Get a Node given its URI, recycling where available
def Node.getResource(content)
return @@nodes[content] if @@nodes[content]
node = Node.new(content)
@@nodes[content]=node
return node
end
# get a fresh blank node
# notes: couldn't see how to have Node.getResource() work
def Node.getBlank()
content = '[' + rand(1000000).to_s() # stopgap: todo, uuid
node = Node.new(content)
@@nodes[content]=node
end
def Node.getLiteral(content)
return @@nodes[content] if @@nodes[content]
node = Node.new("\""+content)
@@nodes["\""+content]=node
return node
end
def to_s
"#@content"
end
def method_missing(methid)
str = methid.id2name
print "Missing method ",str,"\n" # todo: use later for rdf property access
end
end
#############################################################################
#
class Graph
attr_accessor :db, :tell
def initialize( statements )
@db = statements
@fp={}
@bp={}
# print "Initializing a graph with statements ", db
statements.each {|statement| tell(statement) }
end
# tell the graph something
def tell ( statement )
# print "\n\nAdding and indexing statement: ", statement
# store objects under subject+predicate
#
sp_list = @fp["#{statement.subject} | #{statement.predicate}"]
if (sp_list)
# puts "Storing object under EXISTING s/p, statement= #{statement}"
# puts "Inspecting existing sp_list: #{sp_list.inspect} \n"
sp_list.push(statement.object) #todo: we should order this list (and po)
end
if (!sp_list)
# puts "Storing object under NEW s/p, statement = #{statement}"
sp_list = [statement.object]
@fp["#{statement.subject} | #{statement.predicate}"]=sp_list
end
# store subjects under predicate+object
#
po_list = @bp["#{statement.predicate} | #{statement.object}"]
if (po_list)
# puts "Storing subject under EXISTING p/o, statement= #{statement}"
po_list.push(statement.subject)
end # todo: lookup else syntax for Ruby
if (!po_list)
# puts "Storing subject under NEW p/o, statement= #{statement}"
po_list = [statement.subject]
@bp["#{statement.predicate} | #{statement.object}"]=po_list
end
end
def toNtriples()
out = "\nSerializing Graph as Ntriples (vapourware: not NTriples yet!):\n"
# forward pointers -- from subject+predicate to object(s)
@fp.each_key{ |key| out += ("FP entry: \tkey='#{key}' value='#{@fp[key]}' \n") }
out += "Inspecting FP: #{@fp.inspect()}\n\n"
# backward pointers -- from predicate+object to subject(s)
@bp.each_key{ |key| out += ("IP entry: \tkey='#{key}' value='#{@bp[key]}' \n")}
out += "Inspecting BP: #{@bp.inspect()} \n\n"
out += "End Ntriples.\n\n"
return out
end
def ask(query)
# puts "Vapourware ask/query method called, template statement: #{query} "
# ooo
if (query.predicate==nil && query.subject==nil && query.object==nil)
# puts "ooo: dump all triples\n"
end
# xxo
if (query.predicate && query.subject && query.object==nil)
# puts "xxo: get value(s) given sp"
# puts "subject = '#{query.subject}' predicate= '#{query.predicate}' \n"
# puts "Answer lookup: "
return @fp["#{query.subject} | #{query.predicate}"]
end
if (query.predicate && query.subject==nil && query.object)
# puts "oxx: get subjects(s) given po"
return @bp["#{query.predicate} | #{query.object}"]
end
end
end
###########################################################################
#
class Statement
attr_accessor :predicate, :subject, :object
def initialize (subject, predicate, object)
@subject = subject
@predicate = predicate
@object = object
end
def inspect
"<#@subject> <#@predicate> <#@object> "
end
def to_s
"Statement: #@subject> <#@predicate> <#@object>\n"
end
end
############################################################################
#
# Examples and tests
srand() # seed randomizer
FOAF = 'http://xmlns.com/foaf/0.1/'
# Get some initial nodes and properties
# some stuff to represent dan
dbhome = Node.getResource('http://rdfweb.org/people/danbri/')
danbri = Node.getBlank()
dbmail = Node.getResource('mailto:danbri@rdfweb.org')
# Some RDF vocabulary
foaf_mbox = Node.getResource(FOAF+'mbox')
foaf_livesIn = Node.getResource(FOAF+'livesIn')
foaf_homepage = Node.getResource(FOAF+'homepage')
# some more resources we'll be mentioning (no URIs known for these)
bristol=Node.getBlank()
libby = Node.getBlank()
lib2 = Node.getBlank()
damey = Node.getBlank()
s1 = Statement.new(danbri,foaf_homepage,dbhome)
s2 = Statement.new(danbri,foaf_mbox,dbmail)
s3 = Statement.new(danbri, foaf_livesIn, Node.getLiteral("Bristol"))
s4 = Statement.new(damey, foaf_livesIn, Node.getLiteral("Bristol"))
g = Graph.new( [s1, s2, s3, s4] ) # we can initialise a graph with content
g2 = Graph.new([]) # or empty (todo: allow no args constructor)
g.tell( Statement.new(libby, foaf_livesIn, Node.getLiteral("Bristol")))
g.tell(Statement.new(libby, foaf_mbox, Node.getResource('mailto:libby.miller@bristol.ac.uk')))
sl2 = Statement.new(libby, foaf_mbox, Node.getResource('mailto:libby@rdfweb.org'))
g.tell( sl2 )
g.tell(Statement.new(damey, foaf_mbox, Node.getResource('mailto:d.m.steer@lse.ac.uk')))
puts "An RDF Graph: ", g, "\n"
puts g.toNtriples()
## Test our (non-existent) query code
# query 'xxo'
puts "Asking for mailboxes of libby:\n"
t1 = g.ask( Statement.new( libby, foaf_mbox, nil))
puts "Answer was: #{t1} \n"
puts "Asking for occupants of bristol:\n"
t2 = g.ask(Statement.new( nil, foaf_livesIn, Node.getLiteral("Bristol")))
puts "Bris occupants are: #{t2} \n"
puts "Printing mailboxes of people who live in bristol: \n\n"
puts t2.each { |who| puts(g.ask(Statement.new(who,foaf_mbox,nil)))}
# query is 'ooo' (all unknown)
t2 = g.ask (Statement.new(nil,nil,nil))
puts "Tripledump: #t2\n" # todo: no workie yet
Received on Saturday, 8 December 2001 09:07:24 UTC