ActiveModel-style Ruby ORM for RDF Linked Data. Works with SPARQL 1.1 HTTP endpoints.

Quick start, for using in a rails app.

  1. Add it to your Gemfile and bundle

    gem tripod
  2. Configure it (in application.rb, or development.rb/production.rb/test.rb)

    # (values shown are the defaults)
    Tripod.configure do |config|
      config.update_endpoint = ''
      config.query_endpoint = ''
      config.timeout_seconds = 30
  3. Include it in your model classes.

    class Person
      include Tripod::Resource
      # these are the default rdf-type and graph for resources of this class
      rdf_type ''
      graph_uri ''
      field :name, ''
      field :knows, '', :multivalued => true
      field :aliases, '', :multivalued => true
      field :age, '', :datatype => RDF::XSD.integer
      field :important_dates, '', :datatype =>, :multivalued => true
    # Note: Active Model validations are supported
  4. Use it

    uri = ''
    p = = 'Ric'
    p.age = 31
    p.aliases = ['Rich', 'Richard']
    p.important_dates = [,1,1)]!
    people = Person.all.resources #=> returns all people as an array
    ric = Person.find('') #=> returns a single Person object.


Tripod doesn't supply a database. You need to install one. I recommend Fuseki, which runs on port 3030 by default.

Some Other interesting features

 Eager Loading

    asa = Person.find('')
    ric = Person.find('')
    ric.knows = asa.uri

    ric.eager_load_predicate_triples! #does a big DESCRIBE statement behind the scenes
    knows = ric.get_related_resource('', Resource)
    knows.label # this won't cause another database lookup

    ric.eager_load_object_triples! #does a big DESCRIBE statement behind the scenes
    asa = ric.get_related_resource('', Person) # returns a fully hydrated Person object for asa, without an extra lookup

 Defining a graph at instantiation-time

    class Resource
      include Tripod::Resource
      field :label, RDF::RDFS.label

      # notice also that you don't need to supply an rdf type or graph here!

    r ='', '')
    r.label = "example"

    # Note: Tripod assumes you want to store all resources in named graphs.
    # So if you don't supply a graph at any point (i.e. class or instance level),
    # you will get an error when you try to persist the resource.

Reading and writing arbitrary predicates

    r.write_predicate(RDF.type, '')
    r.read_predicate(RDF.type) #=> ["")]

Finders and criteria

    # A Tripod::Criteria object defines a set of constraints for a SPARQL query.
    # It doesn't actually do anything against the DB until you run resources, first, or count on it.
    # (from Tripod::CriteriaExecution)

    Person.all #=> returns a Tripod::Criteria object which selects all resources of rdf_type, in the graph

    Resource.all #=> returns a criteria object to return resources in the database (as no rdf_type or graph_uri specified at class level)

    Person.all.resources #=> returns all the actual resources for the criteria object, as an array

    Person.first #=> returns the first person (by crafting a sparql query under the covers that only returns 1 result)

    Person.count  #=> returns the count of all people (by crafting a count query under the covers that only returns a count)

    # note that you need to use ?uri as the variable for the subject.
    Person.where("?uri <> 'Joe'") #=> returns a Tripod::Criteria object

    Resource.graph("") #=> Retruns a criteria object with a graph restriction (note: if graph_uri set on the class, it will default to using this)

    Resource.find_by_sparql('SELECT ?uri ?graph WHERE { GRAPH ?graph { ?uri ?p ?o } }') #=> allows arbitrary sparql. Again, use ?uri for the variable of the subjects (and ?graph for the graph).

Chainable criteria

    Person.all.where("?uri <> 'Ric'").where("?uri <> <>).first

    Person.where("?uri <> ?name").limit(1).offset(0).order("DESC(?name)")

Full Documentation

Copyright (c) 2012 Swirrl IT Limited. Released under MIT License