activesesame 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.txt +0 -0
- data/README.txt +25 -0
- data/Rakefile +3 -0
- data/init.rb +0 -0
- data/install.rb +0 -0
- data/lib/active_sesame/active_sesame.rb +7 -0
- data/lib/active_sesame/base.rb +235 -0
- data/lib/active_sesame/behaviors.rb +38 -0
- data/lib/active_sesame/general.rb +25 -0
- data/lib/active_sesame/monkey_patches.rb +15 -0
- data/lib/active_sesame/ontology.rb +93 -0
- data/lib/active_sesame/owl_thing.rb +92 -0
- data/lib/active_sesame/rdf_class.rb +46 -0
- data/lib/active_sesame/rdf_constants.rb +55 -0
- data/lib/active_sesame/rdf_property.rb +7 -0
- data/lib/active_sesame/repository.rb +103 -0
- data/lib/active_sesame/result_parser.rb +67 -0
- data/lib/active_sesame/support.rb +114 -0
- data/lib/active_sesame/testing.rb +107 -0
- data/lib/active_sesame/transaction_builder.rb +28 -0
- data/lib/active_sesame/version.rb +9 -0
- data/lib/activesesame.rb +1 -0
- data/spec/spec_active_sesame.rb +131 -0
- data/spec/spec_helpers.rb +49 -0
- data/tasks/default.rake +0 -0
- metadata +79 -0
@@ -0,0 +1,92 @@
|
|
1
|
+
class ActiveSesame::OwlThing
|
2
|
+
require 'digest/sha1'
|
3
|
+
include ActiveSesame::Support
|
4
|
+
#class methods for building the definition of the class
|
5
|
+
# - The most basic definition should (when inheriting from OwlThing create the subClassOf triple
|
6
|
+
# - The init method is the same for all even owl thing
|
7
|
+
#init for creating a new instance of the thing
|
8
|
+
# - A method to create a uri for the thing
|
9
|
+
# - - This could be <blank> as well
|
10
|
+
|
11
|
+
# OwlThing.new creates a new term that is a rdf:type of owl:Thing
|
12
|
+
# when a class is created that inherits from OwlThing the definition for the class term is yet another instantiation of owl thing that can be placed in a class attribute
|
13
|
+
# new results in rdf:type relationship, inherited results in rdfs:subClassOf relationship
|
14
|
+
|
15
|
+
# Use class attribute term as the place for keeping
|
16
|
+
# Pass in the uri and object through the new() when inherited as called
|
17
|
+
# Questions to be answered:
|
18
|
+
# -Does self.add_triple/term.add_relationships overwrite relationships or always add to unsaved_triples?
|
19
|
+
|
20
|
+
|
21
|
+
# TODO:
|
22
|
+
# -Be sure that if the term exists that it will populate relationships and what not appropriately
|
23
|
+
# -Be sure the "unsaved triples" are not added when the triple already exists
|
24
|
+
# -Add find methods:
|
25
|
+
# --Find for uri (id equivalent)
|
26
|
+
# --find(:all)
|
27
|
+
# --find(:all/:first, :conditions => "?self rdf:type #{self.class.term.term} . user input" (made with sparql query object?)
|
28
|
+
|
29
|
+
class << self
|
30
|
+
attr_accessor :repository, :term, :uri
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_accessor :uri, :term
|
34
|
+
|
35
|
+
def self.inherited(klass)
|
36
|
+
klass.term.add_triple({:subject => "base:#{klass}", :predicate => "rdfs:subClassOf", :object => "owl:Thing"})
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.repository
|
40
|
+
@repository ||= self.repository = ActiveSesame::Repository.new #Setting default repository
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.set_repository(repo)
|
44
|
+
self.repository = repo
|
45
|
+
self.reset_term
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.uri
|
49
|
+
@uri ||= "base:" + self.to_s.split("::").last
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.set_uri(uri)
|
53
|
+
self.uri = uri
|
54
|
+
self.reset_term
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.term
|
58
|
+
@term ||= ActiveSesame::Ontology::Term.new(uri, self.repository)
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.reset_term
|
62
|
+
@term = ActiveSesame::Ontology::Term.new(uri, self.repository)
|
63
|
+
@term.add_triple({:subject => "base:#{self}", :predicate => "rdfs:subClassOf", :object => "owl:Thing"})
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def self.method_missing(method, *args, &block)
|
68
|
+
self.term.send(method, *args, &block)
|
69
|
+
end
|
70
|
+
|
71
|
+
def method_missing(method, *args, &block)
|
72
|
+
self.term.send(method, *args, &block)
|
73
|
+
end
|
74
|
+
|
75
|
+
def initialize(options={})
|
76
|
+
@uri = options[:uri] if options[:uri]
|
77
|
+
@uri ||= self.generate_uri
|
78
|
+
@term = ActiveSesame::Ontology::Term.new(@uri, self.class.repository)
|
79
|
+
self.add_triple({:subject => @uri, :predicate => "rdf:type", :object => self.class.uri}) if @term.relationships.size == 0
|
80
|
+
end
|
81
|
+
|
82
|
+
def repository
|
83
|
+
self.class.repository
|
84
|
+
end
|
85
|
+
|
86
|
+
def generate_uri
|
87
|
+
self.repository.base_uri + "#" + Digest::SHA1.hexdigest(Time.now.to_s + self.object_id.to_s)
|
88
|
+
end
|
89
|
+
|
90
|
+
@uri = "owl:Thing" #Set the default URI to the correct owl term
|
91
|
+
|
92
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ActiveSesame
|
2
|
+
#
|
3
|
+
# The represenation and means of exploring RDF Classes
|
4
|
+
#
|
5
|
+
class RDFClass
|
6
|
+
|
7
|
+
attr_reader :name, :properties, :subclasses, :superclass
|
8
|
+
|
9
|
+
def self.find(klass, options={})
|
10
|
+
@@connection ||= Repository.new
|
11
|
+
class_types.inject([]) {|memo, type| ResultParser.singular_values(@@connection.find_by_sparql("SELECT ?klass WHERE { ?klass rdf:type #{type} }")) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.class_types
|
15
|
+
["rdf:Class", "owl:Class", "owl:Thing"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(name)
|
19
|
+
self.name = name
|
20
|
+
self.properties = find_properties
|
21
|
+
self.sublcasses = find_subclasses
|
22
|
+
self.superclass = find_superclass
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_properties
|
26
|
+
ResultParser.singular_values(@@connection.find_by_sparql("SELECT ?property WHERE { #{self.name} rdf:property ?property }"))
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_subclasses
|
30
|
+
ResultParser.singular_values(@@connection.find_by_sparql("SELECT ?subClasses WHERE { #{self.name} rdf:subClassOf ?subClasses }"))
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_superclass
|
34
|
+
ResultParser.singular_values(@@connection.find_by_sparql("SELECT ?super WHERE { ?super rdfs:subClassOf #{self.name} }"))
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_triple(*args)
|
38
|
+
if args.size == 3
|
39
|
+
Repository.save_triple(args[0], args[1], args[3])
|
40
|
+
elsif args.size == 1 and (args[0].class == Triple or args[0].class == Hash)
|
41
|
+
Repository.save_triple(args[0][:subject], args[0][:predicate], args[0][:object])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ActiveSesame::RDFConstants
|
2
|
+
def self.literal_to_proc_hash
|
3
|
+
{
|
4
|
+
"http://www.w3.org/2001/XMLSchema#string" => :to_s,
|
5
|
+
"http://www.w3.org/2001/XMLSchema#dateTime" => :to_time,
|
6
|
+
"http://www.w3.org/2001/XMLSchema#int" => :to_i
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.literals
|
11
|
+
[
|
12
|
+
"http://www.w3.org/2001/XMLSchema#string",
|
13
|
+
"http://www.w3.org/2001/XMLSchema#int",
|
14
|
+
"http://www.w3.org/2001/XMLSchema#dateTime",
|
15
|
+
]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.class_to_match_hash
|
19
|
+
{
|
20
|
+
String => "xsd:string",
|
21
|
+
Time => "xsd:dateTime",
|
22
|
+
Date => "xsd:date",
|
23
|
+
Fixnum => "xsd:integer"
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.class_to_literal
|
28
|
+
{
|
29
|
+
String => "http://www.w3.org/2001/XMLSchema#string",
|
30
|
+
Time => "http://www.w3.org/2001/XMLSchema#dateTime",
|
31
|
+
Date => "http://www.w3.org/2001/XMLSchema#date",
|
32
|
+
Fixnum => "http://www.w3.org/2001/XMLSchema#int"
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.prefixes
|
37
|
+
{
|
38
|
+
:xsd => "http://www.w3.org/2001/XMLSchema",
|
39
|
+
:owl => "http://www.w3.org/2002/07/owl",
|
40
|
+
:rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns",
|
41
|
+
:rdfs => "http://www.w3.org/2000/01/rdf-schema",
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.uri_to_prefix(uri, additional_uris={})
|
46
|
+
uri_prefix, term = uri.split("#","")
|
47
|
+
uri_prefixes = self.prefixes.merge(additional_uris)
|
48
|
+
if term and uri_prefixes.has_key?(uri_without_pound)
|
49
|
+
uri_prefixes[uri_without_pound] + ":" + term
|
50
|
+
else
|
51
|
+
uri
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module ActiveSesame
|
2
|
+
class Repository
|
3
|
+
|
4
|
+
@@prefixes = {"xsd" => "http://www.w3.org/2001/XMLSchema#",
|
5
|
+
"ss" => "http://study-stash.radiology.umm.edu/ontologies/study-stash.owl",
|
6
|
+
"owl" => "http://www.w3.org/2002/07/owl",
|
7
|
+
"rdf" => "http://www.w3.org/1999/02/22-rdf-syntax-ns",
|
8
|
+
"rdfs" => "http://www.w3.org/2000/01/rdf-schema"}
|
9
|
+
|
10
|
+
attr_accessor :triple_store_id, :repository_uri, :repository_location, :base_uri, :connector, :prefixes
|
11
|
+
|
12
|
+
def initialize(repository_type=SesameProtocol, options={})
|
13
|
+
self.send(:extend, repository_type)
|
14
|
+
options = default_options.merge(options)
|
15
|
+
options.each {|key,value| send("#{key}=".to_sym, value) if respond_to?(key) }
|
16
|
+
self.prefixes = @@prefixes
|
17
|
+
end
|
18
|
+
|
19
|
+
def find_by_sparql(query, include_prefixes=true)
|
20
|
+
query_dispatch("", :method => :get, :body => {:query => self.sparql_base + " " + self.prefixes_to_sparql + " " + query, :queryLn => "SPARQL"})
|
21
|
+
end
|
22
|
+
|
23
|
+
def find(query, include_prefixes=true)
|
24
|
+
ActiveSesame::ResultParser.tableize(find_by_sparql(query, include_prefixes))
|
25
|
+
end
|
26
|
+
|
27
|
+
def group_save(xml)
|
28
|
+
query_dispatch("statements", {:method => :post, "content-type" => "application/x-rdftransaction", :body => xml})
|
29
|
+
end
|
30
|
+
|
31
|
+
def save_triple(subject, predicate, object)
|
32
|
+
query_dispatch("statements", {:method => :put, :body => {:subj => subject, :pred => predicate, :obj => object}})
|
33
|
+
end
|
34
|
+
|
35
|
+
def delete_by_pattern(subject, predicate, object)
|
36
|
+
query_dispatch("statements", {:method => :delete, :body => {:subj => subject, :pred => predicate, :obj => object}})
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_prefix(prefix, uri)
|
40
|
+
self.prefixes = self.prefixes.merge({prefix => uri})
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_prefixes(prefix_hash)
|
44
|
+
self.prefixes = self.prefixes.merge(prefix_hash)
|
45
|
+
end
|
46
|
+
|
47
|
+
def sparql_base
|
48
|
+
"BASE <#{base_uri}>"
|
49
|
+
end
|
50
|
+
|
51
|
+
def prefixes_to_sparql
|
52
|
+
self.prefixes.keys.inject("") {|sparql,key| sparql += "PREFIX #{key}: <#{self.prefixes[key]}> " }
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
module SesameProtocol
|
58
|
+
require 'rest-open-uri'
|
59
|
+
require 'uri'
|
60
|
+
|
61
|
+
def self.extended(klass)
|
62
|
+
simple_rest_methods :size, :contexts, :namespaces
|
63
|
+
end
|
64
|
+
|
65
|
+
def query_dispatch(method_name, args={})
|
66
|
+
args[:body][:query] = encode_sparql(args[:body][:query]) if args[:body][:query] if args[:body]
|
67
|
+
args[:body][:subj] = encode_sparql(args[:body][:subj]) if args[:body][:subj] if args[:body]
|
68
|
+
args[:body][:pred] = encode_sparql(args[:body][:pred]) if args[:body][:pred] if args[:body]
|
69
|
+
args[:body][:obj] = encode_sparql(args[:body][:obj]) if args[:body][:obj] if args[:body]
|
70
|
+
[:get, :put, :delete].include?(args[:method]) ? vars_if_get = hash_to_get(args[:body]) : vars_if_get = ""
|
71
|
+
method_name == "" ? slash = "" : slash = "/"
|
72
|
+
return open(self.repository_uri + "/" + self.triple_store_id + slash + method_name.to_s + vars_if_get, args).read
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.simple_rest_methods(*method_names)
|
76
|
+
method_names.each do |name|
|
77
|
+
new_name = name.to_s
|
78
|
+
define_method(new_name) { return query_dispatch(name) }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
def encode_sparql(query)
|
84
|
+
URI.encode(query).gsub("?","%3f").gsub("/","%2f").gsub(":","%3a").gsub("\\","5C")
|
85
|
+
end
|
86
|
+
|
87
|
+
def hash_to_get(hash)
|
88
|
+
(hash.inject("?") {|total,tuple| total += "#{tuple[0]}=#{tuple[1]}&"}).chop
|
89
|
+
end
|
90
|
+
|
91
|
+
def default_options
|
92
|
+
{
|
93
|
+
:repository_uri => "http://localhost:8111/sesame/repositories",
|
94
|
+
:triple_store_id => "test",
|
95
|
+
:location => "http://localhost:8111/sesame/repositories/test",
|
96
|
+
:query_language => "SPARQL",
|
97
|
+
:base_uri => "http://www.fakeontology.org/ontology.owl"
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ActiveSesame
|
2
|
+
module ResultParser
|
3
|
+
require 'libxml'
|
4
|
+
#def ResultParser.append_features(someClass)
|
5
|
+
def self.tableize(xml_document)
|
6
|
+
xml_document = self.to_document(xml_document)
|
7
|
+
rows = []
|
8
|
+
xml_document.find("/sparql/results/result").each do |result|
|
9
|
+
hash = {}
|
10
|
+
result.each_element do |binding|
|
11
|
+
key = binding.attributes.to_h["name"]
|
12
|
+
hash[key] = value_from_binding(binding)
|
13
|
+
end
|
14
|
+
rows << hash
|
15
|
+
end
|
16
|
+
return rows
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.singular_values(xml_document)
|
20
|
+
xml_document = self.to_document(xml_document)
|
21
|
+
values = []
|
22
|
+
xml_document.find("/sparql/results/result/binding").each {|binding| values << self.value_from_binding(binding) }
|
23
|
+
return values
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.hash_values(xml_document)
|
27
|
+
xml_document = REXML::Document.new(xml_document) if xml_document.class == String
|
28
|
+
keys = []
|
29
|
+
xml_document.elements.each("/sparql/head/variable") do |variable|
|
30
|
+
keys << variable.attributes["name"]
|
31
|
+
end
|
32
|
+
xml_document = REXML::Document.new(xml_document) if xml_document.class == String
|
33
|
+
hash = {}
|
34
|
+
xml_document.elements.each("/sparql/results/result") do |result|
|
35
|
+
hash[result.elements["binding[@name='#{keys[0]}']/uri|literal"].text] = result.elements["binding[@name='#{keys[1]}']/uri|literal"].text
|
36
|
+
end
|
37
|
+
return hash
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.value_from_binding(binding)
|
41
|
+
literal = binding.find_first("literal")
|
42
|
+
uri = binding.find_first("uri")
|
43
|
+
if uri
|
44
|
+
uri.content
|
45
|
+
elsif literal
|
46
|
+
type_cast_literal(literal)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.type_cast_literal(literal_element)
|
51
|
+
#puts literal_element.attributes["datatype"] #Use when Exception thrown "nil is not a Symbol"
|
52
|
+
return literal_element.content.send(RDFConstants.literal_to_proc_hash[literal_element.attributes.to_h["datatype"]]) if literal_element.attributes.to_h["datatype"]
|
53
|
+
return literal_element.text
|
54
|
+
end
|
55
|
+
#end
|
56
|
+
|
57
|
+
private
|
58
|
+
def self.to_document(string_or_doc)
|
59
|
+
if string_or_doc.class == String
|
60
|
+
string_or_doc.sub!("xmlns=\"http://www.w3.org/2005/sparql-results#\"","")
|
61
|
+
LibXML::XML::Document.string(string_or_doc)
|
62
|
+
else
|
63
|
+
string_or_doc
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module ActiveSesame
|
2
|
+
module Support
|
3
|
+
|
4
|
+
#Think about changing to a uri class rather than manipulating strings...
|
5
|
+
def self.property_to_constant(prop)
|
6
|
+
prop = prop.to_s
|
7
|
+
prop = ResultParser.uri_to_sym(prop) if prop.match(/#/)
|
8
|
+
prop.first.upcase + prop.slice(1,prop.length)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.uri_to_sym(uri)
|
12
|
+
uri.split("#")[1].to_sym
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.encode_whitespace(string)
|
16
|
+
string.gsub(" ","%20")
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.uncode_whitespace(string)
|
20
|
+
return string.class == String ? string.gsub("%20"," ") : string
|
21
|
+
end
|
22
|
+
|
23
|
+
def is_uri?(string)
|
24
|
+
if string.class == String
|
25
|
+
string =~ /^http:\/\//
|
26
|
+
else
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def uri_to_prefix(uri, additional_uris={})
|
32
|
+
uri_prefix, term = uri.split("#")
|
33
|
+
uri_prefixes = ActiveSesame::RDFConstants.prefixes.merge(additional_uris)
|
34
|
+
uri_prefixes = uri_prefixes.keys.inject(Hash.new) {|hash,key| hash[uri_prefixes[key]] = key; hash} #reverse key and value
|
35
|
+
#puts "\n" + uri_prefixes.inspect + "\n"
|
36
|
+
if uri_prefixes.has_key?(uri_prefix)
|
37
|
+
uri_prefixes[uri_prefix]
|
38
|
+
else
|
39
|
+
uri_prefix
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def method_from_uri(uri, additional_uris={})
|
44
|
+
#puts "uris for doober: #{additional_uris.inspect}"
|
45
|
+
#puts "uri to be transformed to method #{uri}"
|
46
|
+
#puts "method generated: #{self.uri_to_prefix(uri, additional_uris)}"
|
47
|
+
uri_prefix = self.uri_to_prefix(uri, additional_uris)
|
48
|
+
bogus, term = uri.split("#")
|
49
|
+
term ? "#{uri_prefix}_#{term}" : uri_prefix
|
50
|
+
end
|
51
|
+
|
52
|
+
def expand_triples(triple_list, additional_uris={})
|
53
|
+
#puts "\n#{additional_uris.inspect}\n"
|
54
|
+
triple_list.collect {|triple| expand_triple(triple, additional_uris) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def expand_triple(triple, additional_uris={})
|
58
|
+
#puts "\n#{additional_uris.inspect}\n"
|
59
|
+
triple.keys.inject(Hash.new) {|hash,key| hash[key] = expand_term(triple[key], additional_uris); hash }
|
60
|
+
end
|
61
|
+
|
62
|
+
def expand_terms(term_list, additional_uris={})
|
63
|
+
#puts "\n#{additional_uris.inspect}\n"
|
64
|
+
term_list.collect {|term| self.expand_term(term) }
|
65
|
+
end
|
66
|
+
|
67
|
+
def expand_term(full_term, additional_uris={})
|
68
|
+
#puts "\n#{additional_uris.inspect}\n"
|
69
|
+
prefix, term = full_term.split(":")
|
70
|
+
(term != nil and not is_uri?(full_term)) ? expand_prefix(prefix, additional_uris) + "#" + term : full_term
|
71
|
+
end
|
72
|
+
|
73
|
+
def expand_prefix(prefix, additional_uris={})
|
74
|
+
#puts "\n#{additional_uris.inspect}\n"
|
75
|
+
if additional_uris.has_key?(prefix)
|
76
|
+
additional_uris[prefix]
|
77
|
+
else
|
78
|
+
throw "Invalid Prefix: the prefix \"#{prefix}\" was not found in #{additional_uris.inspect}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
class Triple
|
85
|
+
attr_accessor :hash
|
86
|
+
|
87
|
+
def self.triple_components
|
88
|
+
[:subject, :object, :predicate]
|
89
|
+
end
|
90
|
+
|
91
|
+
def method_missing(method, *args, &block)
|
92
|
+
if self.hash.has_key?(method)
|
93
|
+
self.hash[method]
|
94
|
+
else
|
95
|
+
super(method, *args, &block)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def initialize(real_hash={})
|
100
|
+
self.hash = real_hash.keys.inject(Hash.new) {|hash,key| hash[key.to_sym] = real_hash[key] if self.class.triple_components.include?(key.to_sym); hash }
|
101
|
+
unless self.hash.has_key?(:subject) and self.hash.has_key?(:object) and self.hash.has_key?(:predicate)
|
102
|
+
raise "Not a valid triple: missing subject, object, or predicate"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_hash
|
107
|
+
self.hash
|
108
|
+
end
|
109
|
+
|
110
|
+
def to_triple
|
111
|
+
self
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|