Last Update: 2016-03-09
Table of Contents
The following defines terminology used in the document to ensure common understanding.
- rdf-statement
- defines a triple in the form
<subject><predicate><object>where<subject>and<predicate>are both URIs and<object>can be a URI or literal - subject-uri
- the uri in the
<subject>position of a triple - predicate-uri
- the uri in the
<predicate>position of a triple - object-value
- the value in the
<object>position of a triple, which can be a URI or literal - rdf-source
- an instance of a class that includes ActiveTriples::RDFSource and defines properties for predicates which become rdf-statements in the datastore/repository
- subject-source
- when speaking of two rdf-sources in relationship to each other, this is the rdf-source serving the role of
<subject>in the rdf-statement. It is the rdf-source that is defining the predicate through a property definition that will hold the link to the other rdf-source that is the<object>of the statement. - object-source
- a rdf-source that is the value of a predicate in a subject-source
- property-definition
- defines rdf-statements by providing a name to use as an accessor for the object-value(s) and the predicate to use for the rdf-statement(s)
- property-name
- Through reflection, this becomes the methods for accessing the object-value of the rdf-statement generated for this property. For example a property defined with name :has_body will have methods has_body and has_body= defined to get and set the value for has_body, respectively.
- property-predicate
- defines the URI to use as the predicate-uri for the rdf-statement generated for this property
- class_name
- defines the class of the object-source that will be the object-value of the rdf-statement generated for this property. See Explicitly defining a link to another rdf-source section for more information.
A property-definition includes a name for accessor methods and predicate to use as the predicate-uri in the generated rdf-statement(s). It can also have a :classname parameter.
- :classname
- Specifies the class name of another rdf-source. The object-value of this property should be a rdf-source of this class. By setting the :classname, you are explicitly defining the link between the two rdf-sources in the graph. This link is unidirectional from the subject-source to the object-source. To have a bidirectional link, the object-source would need a similar property definition leading back to the original subject-source.
- subject-source
-
- the set of rdf-statements may include an rdf-statement defining the object-source's type (e.g.
<object-source-uri><type-predicate-uri><type-uri>')
- the set of rdf-statements may include an rdf-statement defining the object-source's type (e.g.
- persist
-
- rdf-statements for the subject-source are persisted
- an additional triple with the object-source's rdf-statement for its type will also be persisted
- all rdf-statements are persisted according to the persistence strategy defined on the subject-source
- resume
-
- resuming an subject-source is performed by creating a new instance of the rdf-source class and passing in the URI that is the subject-uri (e.g.
anno1 = AnnotationResource.new('http://www.example.com/anno1')) - initial read of the subject-source from the datastore/repository will include all rdf-statements that match predicates in property-definitions of the subject-source
- initial read of the subject-source from the datastore/repository will NOT include the extra object-source's type rdf-statement
- once the accessor for the object-source property is referenced, the subject-source will have the extra object-source's type rdf-statement
- all other aspects of resuming happen in accordance with the persistence strategy of the subject-source
- resuming an subject-source is performed by creating a new instance of the rdf-source class and passing in the URI that is the subject-uri (e.g.
- destroy
-
- removes all rdf-statements of the subject-source in accordance with the persistence strategy defined on the subject-source
- has no impact on object-sources of the subject-source
When the :classname is defined, and the property is referenced
An implicit definition of a link to another rdf-source occurs when the property is defined without a :classname AND the object-value of the rdf-statement is a URI. That object-value will be
require 'active_triples'
require 'linkeddata'
ActiveTriples::Repositories.add_repository :default, RDF::Repository.new
r = ActiveTriples::Repositories.repositories[:default]
class DummyAuthor
include ActiveTriples::RDFSource
configure repository: :default, type: RDF::URI('http://www.example.com/type/Author')
property :name, predicate: RDF::URI('http://www.example.com/ontology/name')
end
class DummyPage
include ActiveTriples::RDFSource
configure repository: :default, type: RDF::URI('http://www.example.com/type/Page')
property :page_number, predicate: RDF::URI('http://www.example.com/ontology/pageNumber')
end
class DummyChapter
include ActiveTriples::RDFSource
configure repository: :default, type: RDF::URI('http://www.example.com/type/Chapter')
property :title, predicate: RDF::URI('http://www.example.com/ontology/title')
property :has_page, predicate: RDF::URI('http://www.example.com/ontology/hasPage'), class_name: DummyPage # Explicit Link
end
class DummyBook
include ActiveTriples::RDFSource
configure repository: :default, type: RDF::URI('http://www.example.com/type/Book')
property :title, predicate: RDF::URI('http://www.example.com/ontology/title')
property :has_chapter, predicate: RDF::URI('http://www.example.com/ontology/hasChapter'), class_name: DummyChapter # is Explicit Link
property :author, predicate: RDF::URI('http://www.example.com/ontology/author') # can be Implicit Link
endbk1 = DummyBook.new('http://www.example.com/book1')
bk1.title = 'Learning about Explicit Links in ActiveTriples'
ch1 = DummyChapter.new('http://www.example.com/chapter1',bk1)
ch1.title = 'Defining a source with an Explicit Link'
ch2 = DummyChapter.new('http://www.example.com/chapter2',bk1)
ch2.title = 'Persisting a source with Explicit Links'
pgs = []
1.upto(4) do |pgnum|
pg = DummyPage.new("http://www.example.com/page#{pgnum}",bk1)
pg.page_number = pgnum
ch1.has_page << pg if pgnum.between?(1,2) # set explicit link via class_name
ch2.has_page << pg if pgnum.between?(3,4) # set explicit link via class_name
end
au1 = DummyAuthor.new('http://www.example.com/book1/author1',bk1)
au1.name = 'Chad T. Nuga'
bk1.has_chapter = [ch1,ch2] # set explicit link via class_name
bk1.author = au1 # set implicit link
# Persists all objects using ParentStrategy because all objects except bk1 were created with bk1 as the parent.
# This is a convenience. All objects could have been persisted individually with RepositoryStrategy. This is
# not a requirement of using class_name.
bk1.persist!
puts r.dump :ttl
# <http://www.example.com/book1> a <http://www.example.com/type/Book>;
# <http://www.example.com/ontology/author> <http://www.example.com/book1/author1>;
# <http://www.example.com/ontology/hasChapter> <http://www.example.com/chapter1>,
# <http://www.example.com/chapter2>;
# <http://www.example.com/ontology/title> "Learning about Explicit Links in ActiveTriples" .
#
# <http://www.example.com/book1/author1> a <http://www.example.com/type/Author>;
# <http://www.example.com/ontology/name> "Chad T. Nuga" .
#
# <http://www.example.com/chapter1> a <http://www.example.com/type/Chapter>;
# <http://www.example.com/ontology/hasPage> <http://www.example.com/page1>,
# <http://www.example.com/page2>;
# <http://www.example.com/ontology/title> "Defining a source with an Explicit Link" .
#
# <http://www.example.com/chapter2> a <http://www.example.com/type/Chapter>;
# <http://www.example.com/ontology/hasPage> <http://www.example.com/page3>,
# <http://www.example.com/page4>;
# <http://www.example.com/ontology/title> "Persisting a source with Explicit Links" .
#
# <http://www.example.com/page1> a <http://www.example.com/type/Page>;
# <http://www.example.com/ontology/pageNumber> 1 .
#
# <http://www.example.com/page2> a <http://www.example.com/type/Page>;
# <http://www.example.com/ontology/pageNumber> 2 .
#
# <http://www.example.com/page3> a <http://www.example.com/type/Page>;
# <http://www.example.com/ontology/pageNumber> 3 .
#
# <http://www.example.com/page4> a <http://www.example.com/type/Page>;
# <http://www.example.com/ontology/pageNumber> 4 .bk1r = DummyBook.new('http://www.example.com/book1')
bk1r.class # => DummyBook
bk1r.title # => "Learning about Explicit Links in ActiveTriples"
bk1r.persistence_strategy # => ActiveTriples::RepositoryStrategy
puts bk1r.dump :ttl
# <http://www.example.com/book1> a <http://www.example.com/type/Book>;
# <http://www.example.com/ontology/author> <http://www.example.com/book1/author1>;
# <http://www.example.com/ontology/hasChapter> <http://www.example.com/chapter1>,
# <http://www.example.com/chapter2>;
# <http://www.example.com/ontology/title> "Learning about Explicit Links in ActiveTriples" . NOTE: There aren't any triples with the chapters, pages, or author as subject. |
ch1r = bk1r.has_chapter.first
ch1r.class # => DummyChapter
ch1r.title # => "Defining a source with an Explicit Link"
ch1r.persistence_strategy # => ActiveTriples::ParentingStrategy
puts ch1r.dump :ttl
# <http://www.example.com/chapter1> a <http://www.example.com/type/Chapter>;
# <http://www.example.com/ontology/hasPage> <http://www.example.com/page1>,
# <http://www.example.com/page2>;
# <http://www.example.com/ontology/title> "Defining a source with an Explicit Link" .puts bk1r.dump :ttl
# <http://www.example.com/book1> a <http://www.example.com/type/Book>;
# <http://www.example.com/ontology/author> <http://www.example.com/book1/author1>;
# <http://www.example.com/ontology/hasChapter> <http://www.example.com/chapter1>,
# <http://www.example.com/chapter2>;
# <http://www.example.com/ontology/title> "Learning about Explicit Links in ActiveTriples" .
#
# <http://www.example.com/chapter1> a <http://www.example.com/type/Chapter>;
# <http://www.example.com/ontology/hasPage> <http://www.example.com/page1>,
# <http://www.example.com/page2>;
# <http://www.example.com/ontology/title> "Defining a source with an Explicit Link" .
#
# <http://www.example.com/chapter2> a <http://www.example.com/type/Chapter>;
# <http://www.example.com/ontology/hasPage> <http://www.example.com/page3>,
# <http://www.example.com/page4>;
# <http://www.example.com/ontology/title> "Persisting a source with Explicit Links" .au1r = bk1r.author.first
au1r.class # => ActiveTriples::Resource
au1r.name # NoMethodError: undefined method `name' for #<ActiveTriples::Resource:0x00...>
au1r.persistence_strategy # => ActiveTriples::ParentingStrategy
puts au1r.dump :ttl # => nil NOTE: Even though au1r has ParentingStrategy, it will not lazy load the author triples because it does not know what class to use for the author property. |
au1r = DummyAuthor.new(bk1r.author.first.rdf_subject)
au1r.class # => DummyAuthor
au1r.name # => 'Chad T. Nuga'
au1r.persistence_strategy # => ActiveTriples::RepositoryStrategy
puts au1r.dump :ttl
# <http://www.example.com/book1/author1> a <http://www.example.com/type/Author>;
# <http://www.example.com/ontology/name> "Chad T. Nuga" . NOTE: Reading directly from the repository reads in all triples for author1 and sets the persistence_strategy to RepositoryStrategy. |
require 'active_triples'
require 'linkeddata'
ActiveTriples::Repositories.add_repository :default, RDF::Repository.new
r = ActiveTriples::Repositories.repositories[:default]
class DummyAuthor
include ActiveTriples::RDFSource
configure repository: :default, type: RDF::URI('http://www.example.com/type/Author')
property :name, predicate: RDF::URI('http://www.example.com/ontology/name')
end
class DummyPage
include ActiveTriples::RDFSource
configure repository: :default, type: RDF::URI('http://www.example.com/type/Page')
property :page_number, predicate: RDF::URI('http://www.example.com/ontology/pageNumber')
end
class DummyChapter
include ActiveTriples::RDFSource
configure repository: :default, type: RDF::URI('http://www.example.com/type/Chapter')
property :title, predicate: RDF::URI('http://www.example.com/ontology/title')
property :has_page, predicate: RDF::URI('http://www.example.com/ontology/hasPage'), class_name: DummyPage, cast: true # Explicit Link
end
class DummyBook
include ActiveTriples::RDFSource
configure repository: :default, type: RDF::URI('http://www.example.com/type/Book')
property :title, predicate: RDF::URI('http://www.example.com/ontology/title')
property :has_chapter, predicate: RDF::URI('http://www.example.com/ontology/hasChapter'), class_name: DummyChapter # Explicit Link
property :author, predicate: RDF::URI('http://www.example.com/ontology/author') # can be Implicit Link
end
bk1 = DummyBook.new('http://www.example.com/book1')
bk1.title = 'Learning about Explicit Links in ActiveTriples'
ch1 = DummyChapter.new('http://www.example.com/book1/chapter1',bk1)
ch1.title = 'Defining a source with an Explicit Link'
ch2 = DummyChapter.new('http://www.example.com/book1/chapter2',bk1)
ch2.title = 'Persisting a source with Explicit Links'
ch3 = DummyChapter.new('http://www.example.com/book1/chapter3',bk1)
ch3.title = 'Resuming a source with Explicit Links'
ch4 = DummyChapter.new('http://www.example.com/book1/chapter4',bk1)
ch4.title = 'Destroying a source with Explicit Links'
ch5 = DummyChapter.new('http://www.example.com/book1/chapter5',bk1)
ch5.title = 'Navigating an Explicit Link'
1.upto(15) do |pgnum|
pg = DummyPage.new("http://www.example.com/book1/page#{pgnum}",bk1)
pg.page_number = pgnum
ch1.has_page << pg if pgnum.between?(1,3)
ch2.has_page << pg if pgnum.between?(4,6)
ch3.has_page << pg if pgnum.between?(7,9)
ch4.has_page << pg if pgnum.between?(10,12)
ch5.has_page << pg if pgnum.between?(13,15)
end
au1 = DummyAuthor.new('http://www.example.com/book1/author1',bk1)
au1.name = 'Chad T. Nuga'
bk1.has_chapter = [ch1,ch2,ch3,ch4,ch5]
bk1.author = au1
bk1.persist!
bk2 = DummyBook.new('http://www.example.com/book2')
bk2.title = 'Learning about Implicit Links in ActiveTriples'
ch1 = DummyChapter.new('http://www.example.com/book2/chapter1',bk2)
ch1.title = 'Defining a source with an Implicit Link'
ch2 = DummyChapter.new('http://www.example.com/book2/chapter2',bk2)
ch2.title = 'Persisting a source with Implicit Links'
ch3 = DummyChapter.new('http://www.example.com/book2/chapter3',bk2)
ch3.title = 'Resuming a source with Implicit Links'
ch4 = DummyChapter.new('http://www.example.com/book2/chapter4',bk2)
ch4.title = 'Destroying a source with Implicit Links'
ch5 = DummyChapter.new('http://www.example.com/book2/chapter5',bk2)
ch5.title = 'Navigating an Implicit Link'
1.upto(15).each do |pgnum|
pg = DummyPage.new("http://www.example.com/book2/page#{pgnum}",bk2)
pg.page_number = pgnum
ch1.has_page << pg if pgnum.between?(1,3)
ch2.has_page << pg if pgnum.between?(4,6)
ch3.has_page << pg if pgnum.between?(7,9)
ch4.has_page << pg if pgnum.between?(10,12)
ch5.has_page << pg if pgnum.between?(13,15)
end
bk2.has_chapter = [ch1,ch2,ch3,ch4,ch5]
bk2.author = 'Della Wear'
bk2.persist!
puts r.dump :ttl# while all objects are still in memory
ch1 = bk1.has_chapter.first
puts ch1.class
puts ch1.rdf_subject
puts ch1.persistence_strategy
puts ch1.dump :ttl
pg1 = ch1.has_page.first
puts pg1.class
puts pg1.rdf_subject
puts pg1.persistence_strategy
puts pg1.dump :ttl
# after resuming book1
bk1r = DummyBook.new('http://www.example.com/book1')
ch1r = bk1r.has_chapter.first
puts ch1r.class
puts ch1r.rdf_subject
puts ch1r.persistence_strategy
puts ch1r.dump :ttl
ch1r.reload
puts ch1r.dump :ttl
ch1r = DummyChapter.new(ch1r.rdf_subject)
puts pg1.persistence_strategy
puts ch1r.dump :ttl
pg1r = ch1r.has_page.first
puts pg1r.class
puts pg1r.rdf_subject
puts pg1.persistence_strategy
puts pg1r.dump :ttl
pg1r = DummyPage.new(pg1r.rdf_subject)
puts pg1.persistence_strategy
puts pg1r.dump :ttl# while all objects are still in memory
au1 = bk1.author.first
puts au1.class
puts au1r.rdf_subject
puts au1.persistence_strategy
puts au1.dump :ttl
# after resuming book1
bk1r = DummyBook.new('http://www.example.com/book1')
au1r = bk1r.author.first
puts au1r.class
puts au1r.rdf_subject
puts au1r.persistence_strategy
puts au1r.dump :ttl
au1r = DummyAuthor.new(au1r.rdf_subject)
puts au1r.class
puts au1r.rdf_subject
puts au1r.persistence_strategy
puts au1r.dump :ttl