POSEIdON_RDF
POSEIdON (short for "Pimp your Objects with SEmantic InformatiON") is a small
library that lets you add RDF information to classes and their instances.
It can also add methods as_rdf
and to_rdf
to those classes and objects that
can be used to retrieve RDF representations in various formats, based on
the functionality provided by the RDF gem.
Notes on v2.0: This is a complete rewrite of the first POSEIdON code,
with a complete redesign of the core functionality. It changes the names
of user methods as well, so you will need to adjust your POSEIdON
definitions in your code (if you used POSEIdON 1.x, that is).
How to use this gem
First, include the main POSEIdON module in classes where you want to use
RDF generation features:
class Foo
include PoseidonRdf::Poseidon
end
Now, your class contains a bunch of high-level class and instance methods for
adding RDF triples. Methods for output and serialisation of the resulting RDF
are also added.
In order to configure your class to use POSEIdON, you call the poseidon
method with a block that contains statements using the POSEIdON DSL:
Example
class Foo
include Poseidon
poseidon do
base 'http://example.org/'
class_uri 'http://example.org/Foo'
same_as 'http://example.org/SomeOtherFoo'
instance_uri_scheme 'http://example.org/Foo/#{id}'
...
end
end
This DSL will be explained step by step in the following sections.
The POSEIdON DSL
Class-related configuration
The DSL is divided into two sections: One that specifies how classes
can be represented as RDF, and another section for the configuration
of their instances. First, I will explain what you can do to
represent classes.
Identifying URIs for classes
Every RDF entity needs an URI to identify itself. In order to define
such an identifier for your class, use the class_uri
method.
In order to reduce the lines in example code, this and the following
examples assume we want to configure a class named Foo
, as in the
first sample above. The following examples show a POSEIdON configuration
along with the resulting snippet of RDF (in Turtle notation).
poseidon do
base 'http://example.org/'
class_uri 'http://example.org/Foo'
end
@base <http://example.org/> .
<Foo> a <owl:Class> .
First, a base URI is defined for the RDF output. In combination
with <Foo>
this results in the URI we gave in the class_uri
configuration statement.
In addition, the RDF generator will automatically add a statement
that gives the type of your Ruby Class as rdfs:Class
or
owl:Class
, depending on the RDF formalism you chose for output
(see below).
In these examples, values are given as strings. It is possible to
use other objects as values (such as accessing class or instance
methods by using symbols). See below for the options.
Relations to other classes
You can declare equivalence relations and subclass relations
for your Ruby class:
poseidon do
base 'http://example.org/'
class_uri 'http://example.org/Foo'
same_as 'http://example.org/SomeOtherFoo'
subclass_of 'http://example.org/AMoreGeneralFoo'
end
@base <http://example.org/> .
<Foo> a <owl:Class> ;
owl:sameAs <http://example.org/SomeOtherFoo> ;
rdfs:subClassOf <http://example.org/AMoreGeneralFoo> .
Instance-related configuration
There are other options to configure how instances of a class
should be exported.
Identifying URIs for classes
First, every instance itself needs an identifier. With
instance_uri_scheme
you can provide a string that can be
evaluated in the context of the instance object. The result
should be an URL-compatible string that is unique for each
instance object. If you have some kind of id attribute, this
is an ideal candidate.
Let us assume that the Foo
class has a numeric identifier
accessible via the instance method id
, and there is one
instance object with the ID 1
. Then, the following
code defines a string scheme for instances:
poseidon do
base 'http://example.org/'
class_uri 'http://example.org/Foo'
instance_uri_scheme 'http://example.org/Foo/#{id}'
end
@base <http://example.org/> .
<Foo> a <owl:Class> .
<Foo/1> a <Foo> .
It is important to use single quotes for the string scheme
in order to avoid the string to be evaluated right away. The
string scheme internally uses the interpolation #{id}
, but
the interpolation will be computed in the context of the
object to be represented, so for our single object, this part
of the string will yield '1'
.
Mapping attributes to RDF statements
You can declare how atomic attributes of an instance shall be
represented in RDF. For this you basically need to provide
information about the URI that shall serve as the RDF
predicate linking the instance (subject) to the attribute
(object).
This can be done with the instance_attributes
method
(assuming that the instance object has an attribute name
set to the value of 'Bar'):
poseidon do
base 'http://example.org/'
class_uri 'http://example.org/Foo'
instance_uri_scheme 'http://example.org/Foo/#{id}'
instance_attributes :name, 'http://example.org/hasName'
end
@base <http://example.org/> .
<Foo> a <owl:Class> .
<Foo/1> a <Foo> ;
<hasName> "Bar" .
You provide a Hash to this method, where the keys are symbols
indicating the method names for your attributes, and the values
are (in the default case) strings indicating the predicate URI.
Note: In the future, it will also be possible to use more
complicated configurations here, e.g., if you need to transform
attribute values first, or if you need to export the value of
an attribute more than one time using different predicates.
You can call instance_attributes
multiple times without
losing information from earlier calls.
Mapping member objects to RDF statements
This method is useful for atomic attributes (such as strings or
numbers). If you need to export more complex objects along with
an instance, you can do so with describe_member
This method
evaluates one or more member objects and
- expresses their membership inside the instance using a given
predicate URI,
- and, optionally, adds their RDF to the output.
In both cases, the class of the member objects needs to be configured
to use POSEIdON, too. However, in the first case, only the instance
URI has to be configured.
Let us assume that our instance of Foo has the following member
objects:
- an
owner
, which is some kind of person or agent for whom
RDF descriptions are already available at some external URL, - and a collection
tidbits
of instances of the Tidbit
class
which we want to describe in RDF inside the main RDF of the
Foo instance itself.
The owner object points to the existing RDF description with an URL
field, and the Foo instance possesses two tidbits, a "gadget" and
a "gimmick".
This can be configured with the following configuration:
poseidon do
...
describe_member :owner, {
membership: 'http://example.org/belongsTo',
with_data: false
}
describe_member :tidbits, {
membership: 'http://example.org/hasTidBit',
with_data: true
}
end
The first configuration gives a membership predicate URI
for the owner relation,
and tells POSEIdON not to export the owner's RDF data
except for its instance URI.
The second configuration gives a membership predicate URI
for the possession of the tidbit, and tells POSEIdON
export the tidbits' RDF along with the Foo RDF:
@base <http://example.org/> .
<Foo/1> a <Foo> ;
<belongsTo> <http://some/external/uri> ;
<hasTidBit> <Tidbit/1>, <Tidbit/2> .
<Tidbit/1> a <Tidbit> ;
<hasName> "gadget" .
<Tidbit/2> a <Tidbit> ;
<hasName> "gimmick" .
We see that POSEIdON checks whether the member object is an enumeration.
If yes, every item in the enumeration will be exported. If not, the
single member will be exported.
The configuration for the owner and for the Tidbit
class is omitted here, but the
example should be clear, anyway.
How to provide values
URIs can be given in the following formats:
- As
RDF::URI
objects. These will be used without change. - As strings. These will be used as-is, and will automatically be
converted to URIs.
- As symbols. These stand for methods that will be called during
RDF generation. Depending on the context, class or instance methods
will be called. Their result will be converted to RDF URIs, if they
are of a different type.
Thus, it is also possible to use predefined or ad-hoc vocabularies from
the Ruby RDF library here, such as
FOAF.surname
, DC.title
, and so on.
The people example contains some of
these predefined vocabularies in action.
Export
When POSEIdON has been mixed in, two methods are provided to classes
and instances that generate and serialise RDF:
poseidon_as_rdf
, which generates the RDF graph,- and
poseidon_to_rdf
, which returns a serialised string of the
RDF in a given format.
poseidon_to_rdf(mode, format)
expects two parameters:
- The mode, which determines what RDF vocabularies to use. At
the moment this defaults to
:owl
, which is also the only option
(but more will follow). - The format, which selects an RDF serialisation format. It
defaults to
:turtle
, other options are :ntriples
or :rdfxml
.
Providing standard as_rdf
and to_rdf
methods
The two methods as_rdf
and to_rdf
are not automatically defined because
they could cause conflicts. If you want them, include the module
PoseidonRdf::StandardMethods
after include PoseidonRdf::Poseidon
.
Now, if you want to change mode or format, you can do so using the
following methods:
@example_class.poseidon_set_standard_mode(:owl)
@example_class.poseidon_set_standard_format(:rdfxml)
While the mode must be adjusted for every class that has POSEIdON mixed in,
the format change is only relevant to classes that act as a starting point
of RDF generation – that is, those that actually call to_rdf
(since the
collection of RDF under the hood only consists of calls to as_rdf
, where
the serialisation format is irrelevant).
Release history:
2.0 (29.05.2014)
Major redesign, improvement of DSL and internal functionality.
Re-release under the available gem name "poseidon_rdf".
1.1.1 (17 July 2013)
- Turtle format
- minor bux fixes
1.0.0 (23 June 2013) initial relase
Plans
(none at the moment.)
Contributing to POSEIdON
- Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
- Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
- Fork the project.
- Start a feature/bugfix branch.
- Commit and push until you are happy with your contribution.
- Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
- Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
Copyright
Copyright (c) 2012–2104 Peter Menke, SFB 673.
Licensed under the GNU LGPL v3. See LICENSE.txt for further details.