Skip to main content
Linked Open Data for Rubyists


    What the Semantic Web brings to Ruby

               Gregg Kellogg
              gregg@greggkellogg.net
                Twitter: @gkellogg
                 G+: greggkellogg
Why RDF for Ruby?


   ✤ Major creative force in Web 2.0
   ✤ Rich eco-system (Gems/Rails/…)
   ✤ Fair support for XML (Nokogiri, anyway)
   ✤ Great environment for prototyping and getting
     stuff done.
   ✤ RDF is relatively virgin territory in Ruby



6 Dec 2012                  Ruby SemWeb              2
Ruby RDF
 ❖ RDF.rb/linkeddata                  ❖ Storage
 ❖ Readers/Writers                          ➡ Cassandra

       ➡ RDF/XML                            ➡ SQL(RDF::DO)

       ➡ N3/Turtle/NTriples                 ➡ MongoDB

       ➡ NQuads/TriX                        ➡ Redstore

       ➡ RDFa/Microdata                     ➡ Sesame

       ➡ JSON-LD/RDF-JSON                   ➡ AlegroGraph

       ➡ Raptor bridge                      ➡ Talis
                                            ➡ 4store
 ❖ Query
       ➡ SPARQL/SSE
       ➡ SPARQL::Client


6 Dec 2012                    Ruby SemWeb                    3
Core Classes
 ❖ RDF::Term                                  ❖ Serializations
       ➡ RDF::Literal                               ➡ RDF::Format
             ➡ XSD subtypes                         ➡ RDF::Reader
       ➡ RDF::Resource                              ➡ RDF::Writer
             ➡ RDF::Node                      ❖ Storage
             ➡ RDF::URI                             ➡ RDF::Repository
             ➡ RDF::List
                                              ❖ Query
             ➡ RDF::Graph
                                                    ➡ RDF::Query
 ❖ RDF::Statement                                   ➡ RDF::Query::Pattern
 ❖ RDF::Vocabulary                                  ➡ RDF::Query::Solution
       ➡ With definitions for common                 ➡ RDF::Query::Variable
         vocabularies

6 Dec 2012                            Ruby SemWeb                            4
Simple Graph Manipulation
require 'rdf'

include RDF
g = Graph.new
g << Statement.new(
  RDF::URI.new("https://github.com/gkellogg/rdf"),
  RDF::URI.new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
  RDF::URI.new("http://usefulinc.com/ns/doap#GitRepository"))

# Using common vocabularies
proj = Node.new
g << Statement.new(proj, RDF.type, DOAP.Project)
g << Statement.new(proj, DOAP.repository,
  RDF::URI.new("https://github.com/gkellogg/rdf"))

puts g.dump(:ntriples)




6 Dec 2012                     Ruby SemWeb                           5
Serializing with Writers
   ✤ Graphs can be serialized with available Writers

require 'rdf/ntriples'
require 'rdf/turtle'

puts NTriples::Writer.buffer {|writer| writer << g}

# Also, you can include other formats
Turtle::Writer.buffer {|writer| writer << g}

# Use Graph.dump or Writer.open to save to a file
puts g.dump(:ttl, :standard_prefixes => true)

Turtle::Writer.open('example2.ttl') {|w| w << g}
puts File.read('example2.ttl')




6 Dec 2012                     Ruby SemWeb             6
RDFa Serialization with Haml

   ✤ RDFa writer uses Haml templates write a graph to
     HTML
         ➡   Define your own templates
         ➡   Other examples from Structured Data Linter:
             ➡   http://linter.structured-data.org
             ➡   https://github.com/structured-data/linter/blob/master/lib/rdf/linter/
                 rdfa_template.rb

   ✤ In principle, this can be used to write any XML-
     based format by defining an appropriate template
   ✤ More information in RDFa gem

6 Dec 2012                                 Ruby SemWeb                                   7
Finding Formats
   ✤ Find a format for reading or writing
require 'rdf/rdfa'
require 'rdf/rdfxml'

Writer.for(:ttl)
Writer.for(:content_type => "text/html")
Reader.for('example2.ttl')

# List available formats
RDF::Format.to_a.map(&:to_sym)

# Open a URL and use format detection to find a writer
puts Graph.load('http://greggkellogg.net/foaf').
  dump(:ttl, :base_uri => 'http://greggkellogg.net/foaf',
       :standard_prefixes => true)

f = "http://greggkellogg.net/github-lod/doap.ttl"
Turtle::Reader.open(f) do |reader|
  reader.each {|st| puts st.inspect}
end

6 Dec 2012                         Ruby SemWeb              8
BGP Query support
f = "http://greggkellogg.net/github-lod/doap.ttl"
doap = Graph.load(f)
                                                       ✤ Query with
# using RDF::Query
query = Query.new(
                                                         RDF::Query
  :person => {
      RDF.type => FOAF.Person,
      FOAF.name => :name,
      FOAF.mbox => :email,
  })
query.execute(doap).each do |soln|
  puts "name: #{soln.name}, email: #{soln[:email]}"
end; nil

# using Query::Pattern
query = Query.new do
  pattern [:project, DOAP.developer, :person]
  pattern [:person, FOAF.name, :name]
end
query.execute(doap).each do |soln|
  puts "project: #{soln.project} name: #{soln.name}"
end; nil
6 Dec 2012                         Ruby SemWeb                        9
SPARQL
require 'sparql'                                     ❖ SPARQL gem
f = "./dumps/github-lod.nt"                            executes locally
doap = Graph.load(f)
                                                       for against
query = SPARQL.parse(%q(                               RDF::Queryable
  PREFIX doap: <http://usefulinc.com/ns/doap#>
  PREFIX foaf: <http://xmlns.com/foaf/0.1/>            object.
  SELECT ?repo ?name
                                                     ❖ SPARQL::Client
  WHERE {                                              gem executes
    [ a doap:Project;
      doap:name ?repo;
                                                       against a remote
      doap:developer [ a foaf:Person;                  repository
        foaf:name ?name
        ]
                                                       ➡ Best for querying
    ]                                                    large datasets.
  }
  ORDER BY DESC(?repo)
  LIMIT 20
))
query.execute(doap).each do |soln|
   puts "project: #{soln.repo} name: #{soln.name}"
end; nil




                                        10
RDF Behavior
   ✤ Classes can behave like RDF
         ➡   RDF::Countable – #empty?, #count, #size
         ➡   RDF::Durable
         ➡   RDF::Enumerable – must implement #each
             –   #statements, #each, #triples, #quads, ...
         ➡   RDF::Writable – must implement #(insert/delete/each)_statement
             –   #load, #insert, #<<, #update, #delete
         ➡   RDF::Queryable – must implement #each
             ➡   should implement #query_pattern & #query_execute
             –   #query, #first, #first_(subject,predicate,object)
         –   RDF::TypeCheck – raises TypeError on illegal comparison

6 Dec 2012                                 Ruby SemWeb                        11
ActiveRecord with RDF
   ✤ Import #RDF::Enumerable and implement #each
require 'github-api-client'
class GitHub::User
  include RDF::Enumerable
  def each
    u = RDF::URI("http://github.com/#{login}")
    yield RDF::Statement.new(u, RDF::FOAF.name, name)
    yield RDF::Statement.new(u, RDF::mbox, RDF::URI("mailto:#{email}")) unless email.nil?
  end
end

u = GitHub::User.get('gkellogg')
puts u.dump(:ttl, :standard_prefixes => true)




6 Dec 2012                            Ruby SemWeb                               12
Other Resources
   ✤ Spira
         ➡   Get Ruby classes from RDF datastores

   ✤ Distiller
         ➡   Transform between RDF formats, including RDFa generation
         ➡   http://rdf.greggkellogg.net

   ✤ Documentation
         ➡   Comprehensive documentation of Ruby LinkedData related gems available at
             http://rdf.greggkellogg.net/yard/index.html

   ✤ GitHub LOD Demo
         ➡   Examples used in this presentation, along with a demo Sinatra application
             illustrating Ruby RDF usage is available:
             ➡   GitHub project: http://github.com/gkellogg/github-lod (Public Domain)
             ➡   Running demo: http://greggkellogg.net/github-lod
6 Dec 2012                                 Ruby SemWeb                                   13