Project

rdf-mapper

0.01
No commit activity in last 3 years
No release in over 3 years
RDFMapper is a lightweight Ruby ORM that works with RDF data in a Rails-like fashion. Is supports XML, N-Triples, JSON formats, SPARQL and ActiveRecord as data sources.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 1.3.0

Runtime

>= 0.4.6
>= 0.1.1
>= 0.0.2
>= 0.0.3
 Project Readme

RDFMapper – Object-relation mapping for RDF data¶ ↑

RDFMapper is an ORM written in Ruby that is designed to play nicely with RDF data.

Features¶ ↑

  • 100% Ruby code based on a slim & smart RDF.rb library

  • All the usual Rails methods: find, create, belongs_to, has_many – you name it

  • Built with performance in mind: all objects are lazy-loaded by default

  • Supports REST, SPARQL and ActiveRecord as RDF data sources

  • Supports XML, N-Triples and JSON out of the box

Installation¶ ↑

The prefered method of installing RDFMapper is through its gem file (requires RubyGems):

% [sudo] gem install rdf-mapper

The latest version of RDFMapper can be found at

Contribute¶ ↑

Please note that RDFMapper in under heavy development right now, it’s not yet suitable for production environment. Any contribution (bug tickets, code patches) is more than welcome. Email us at team@42cities.com or submit a ticket on GitHub.

5-minute crash course¶ ↑

Idea behind RDF models¶ ↑

Models in RDFMapper are essentially RDF nodes that have an ID and at least one triple with an rdf:type predicate. Consider the following example:

<http://example.org/people/237643>   rdf:type       <http://www.example.org/schema#Person>
<http://example.org/people/237643>   example:name   "John Smith"
<http://example.org/people/237643>   example:age    "27"^^xsd:integer

This set of triples defines a node (with an ID of <example.org/people/237643>) that has three ‘attributes’: ‘example:name`, `example:age`, and `rdf:type`. Now `rdf:type` predicate tells us that there’s a class (<www.example.org/schema#Person>) with more or less predefined behavior. And our node (<example.org/people/237643>) is an instance of that class. We could replicate the same logic in Ruby:

class Person
  attr_accessor :id
  attr_accessor :name
  attr_accessor :age
end

person = Person.new
person.id = "http://example.org/people/237643"
person.name = "John Smith"
person.age = 27

That’s essentially what RDFMapper does. It accepts RDF triples (XML or N-triples), creates instances, assigns attributes and binds models together (via Rails-like belongs_to and has_many associations).

Defining a model¶ ↑

Before you start working with RDFMapper, you need to define at least one model. The only required setting is its namespace (think XML namespace) or type (think rdf:type). If you specify the namespace, it will be used by the model itself (to figure out its rdf:type) and by its attributes (to figure out RDF predicates).

class Person < RDFMapper::Model
  namespace "http://example.org/#"
  attribute :name,     :type => :text
  attribute :homepage, :type => :uri, :predicate => 'http://xmlns.com/foaf/0.1/homepage'
end

Person.namespace        #=> #<RDF::Vocabulary(http://example.org/#)>
Person.type             #=> #<RDF::URI(http://example.org/#Person)>

Person.name.type        #=> #<RDF::URI(http://example.org/#name")>
Person.homepage.type    #=> #<RDF::URI(http://xmlns.com/foaf/0.1/homepage)>

For more information on RDF::URI, RDF::Vocabulary and other classes within RDF namespace, refer to RDF.rb documentation.

Defining the data source¶ ↑

By this moment you can work with RDFMapper models with no additional settings. However, if you want to load, save and search for your objects, you need to specify their data source. RDFMapper comes with 3 different flavors of data sources: REST, SPARQL and Rails.

  • SPARQL [read-only] – the standard for RDF data. RDFMapper will query specified SPARQL server over HTTP using standard SPARQL syntax. Currently it supports only a few functions (no subqueries, updates, aggregates, etc.)

  • REST [read-only] – good old HTTP-based data storage. It assumes that an object’s ID (which is an URI) is the place to look when you want to get object’s properties. For example, if an object has an ID ‘example.org/people/237643`, RDFMapper will download data from this address and parse any RDF triples it finds along the way.

  • Rails [read/write] – gets the data from an ActiveRecord model (that is Rails model). This adapter assumes an RDFMapper model has a ‘mirror’ ActiveRecord model with the same attributes and associations.

Assigning data source to a model is easy:

class Person < RDFMapper::Model
  adapter :rails   # There should be a `Person` class that subclasses ActiveRecord::Base
end

class Person < RDFMapper
  adapter :rails, :class_name => 'Employee'   # ActiveRecord::Base model is called `Employee`
end

class Person < RDFMapper
  adapter :sparql, {

:server => ‘some-sparql-server.com’ :headers => { ‘API-Key’ => ‘89d7sfd9sfs’ } }

end

Searching¶ ↑

If you search objects by an ID, it’s up to the adapter (REST, SPARQL, or Rails) to decide what type of ID it requires (an URI, a database column or something else). Check out the documentation for each adapter to see how works.

Person.all                                              #=> #<PersonCollection:23784623>
Person.find('132987')                                   #=> #<Person:217132856>
Person.find(:all, :conditions => { :name => 'John' })   #=> #<PersonCollection:32462387>

Note, the objects above are not loaded. RDFMapper will load them once you access an attribute of a collection or an object. The following 3 objects are loaded instantly, since RDFMapper needs to figure out what their attributes are (in this case ‘nil?`, `name` and `length`).

Person.find('132987').nil?                                     #=> false
Person.find('132987').name                                     #=> "John"
Person.find(:all, :conditions => { :name => 'John' }).length   #=> 3

You should take extra care when dealing with lazy-loaded models, since exceptions may occur when a model is not found:

Person.find('132987')         #=> #<Person:217132856>
Person.find('132987').name    #=> NoMethodError: undefined method `name' for nil:NilClass

Instead, you should first check if a model exists:

@person = Person.find('132987')
@person.name unless @person.nil?

Working with attributes¶ ↑

Attributes in RDFMapper work just as you would expect them to work with just one small exception. Since any attribute of a model is essentially an RDF triple, you can access attributes by their predicates as well:

class Person < RDFMapper::Model
  namespace "http://example.org/#"
  attribute :name, :type => :text
  attribute :homepage, :type => :uri, :predicate => 'http://xmlns.com/foaf/0.1/homepage'
end

instance = Person.new
instance.name                                   #=> "John Smith"
instance[:name]                                 #=> "John Smith"
instance['http://example.org/#name']            #=> "John Smith"
instance.homepage                               #=> #<RDF::URI(http://johnsmith.com/")>
instance['http://xmlns.com/foaf/0.1/homepage']  #=> #<RDF::URI(http://johnsmith.com/")>

That’s pretty much all you need to know. Go try and let us know what you think!

License¶ ↑

RDFMapper is free and unencumbered public domain software. For more information, see unlicense.org or the accompanying UNLICENSE file.

Roadmap¶ ↑

Several important features are not yet implemented. Here’s a rough list of what is still to be done:

  • Test coverage is extremely low (~10%)

  • Documentation coverage is mediocre

  • REST adapter is missing

  • SPARQL adapter supports only simple ‘DESCRIBE` queries. At later stages it will most likely use sparql-client library.

  • JSON support is missing. Will use rdf-json library.

  • ‘has_one` and `has_and_belongs_to_many` are missing