activerdf_net7 1.6.11
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +79 -0
- data/LICENSE +504 -0
- data/README.rdoc +34 -0
- data/activerdf-jena/CHANGELOG +14 -0
- data/activerdf-jena/LICENSE +504 -0
- data/activerdf-jena/README +57 -0
- data/activerdf-jena/Rakefile +87 -0
- data/activerdf-jena/TODO +18 -0
- data/activerdf-jena/VERSION +1 -0
- data/activerdf-jena/ext/antlr-2.7.5.jar +0 -0
- data/activerdf-jena/ext/arq-extra.jar +0 -0
- data/activerdf-jena/ext/arq.jar +0 -0
- data/activerdf-jena/ext/aterm-java-1.6.jar +0 -0
- data/activerdf-jena/ext/commons-logging-1.1.jar +0 -0
- data/activerdf-jena/ext/concurrent.jar +0 -0
- data/activerdf-jena/ext/icu4j_3_4.jar +0 -0
- data/activerdf-jena/ext/iri.jar +0 -0
- data/activerdf-jena/ext/jena.jar +0 -0
- data/activerdf-jena/ext/jenatest.jar +0 -0
- data/activerdf-jena/ext/json.jar +0 -0
- data/activerdf-jena/ext/junit.jar +0 -0
- data/activerdf-jena/ext/log4j-1.2.12.jar +0 -0
- data/activerdf-jena/ext/lucene-core-2.0.0.jar +0 -0
- data/activerdf-jena/ext/ng4j.jar +0 -0
- data/activerdf-jena/ext/pellet.jar +0 -0
- data/activerdf-jena/ext/relaxngDatatype.jar +0 -0
- data/activerdf-jena/ext/stax-api-1.0.jar +0 -0
- data/activerdf-jena/ext/wstx-asl-3.0.0.jar +0 -0
- data/activerdf-jena/ext/xercesImpl.jar +0 -0
- data/activerdf-jena/ext/xml-apis.jar +0 -0
- data/activerdf-jena/ext/xsdlib.jar +0 -0
- data/activerdf-jena/lib/activerdf_jena/init.rb +26 -0
- data/activerdf-jena/lib/activerdf_jena/jena.rb +59 -0
- data/activerdf-jena/lib/activerdf_jena/jena_adapter.rb +515 -0
- data/activerdf-jena/lib/activerdf_jena/lucene.rb +22 -0
- data/activerdf-jena/lib/activerdf_jena/ng4j.rb +50 -0
- data/activerdf-jena/lib/activerdf_jena/ng4j_adapter.rb +379 -0
- data/activerdf-jena/lib/activerdf_jena/pellet.rb +25 -0
- data/activerdf-jena/test/bnode_org_rss.rdf +793 -0
- data/activerdf-jena/test/eyal-foaf.nt +39 -0
- data/activerdf-jena/test/fun_with_bnodes.nt +2 -0
- data/activerdf-jena/test/s1.n3 +18 -0
- data/activerdf-jena/test/test_data.nt +32 -0
- data/activerdf-jena/test/test_jena_adapter.rb +451 -0
- data/activerdf-jena/test/test_ng4j_adapter.rb +354 -0
- data/activerdf-rdflite/CHANGELOG +31 -0
- data/activerdf-rdflite/LICENSE +504 -0
- data/activerdf-rdflite/README +16 -0
- data/activerdf-rdflite/Rakefile +73 -0
- data/activerdf-rdflite/VERSION +1 -0
- data/activerdf-rdflite/lib/activerdf_rdflite/fetching.rb +34 -0
- data/activerdf-rdflite/lib/activerdf_rdflite/init.rb +13 -0
- data/activerdf-rdflite/lib/activerdf_rdflite/rdflite.rb +582 -0
- data/activerdf-rdflite/lib/activerdf_rdflite/suggesting.rb +87 -0
- data/activerdf-rdflite/test/test_bnode_data.nt +5 -0
- data/activerdf-rdflite/test/test_data.nt +32 -0
- data/activerdf-rdflite/test/test_escaped_data.nt +2 -0
- data/activerdf-rdflite/test/test_fetching.rb +33 -0
- data/activerdf-rdflite/test/test_rdflite.rb +277 -0
- data/activerdf-redland/CHANGELOG +12 -0
- data/activerdf-redland/LICENSE +504 -0
- data/activerdf-redland/README +9 -0
- data/activerdf-redland/Rakefile +72 -0
- data/activerdf-redland/VERSION +1 -0
- data/activerdf-redland/lib/activerdf_redland/init.rb +10 -0
- data/activerdf-redland/lib/activerdf_redland/redland.rb +362 -0
- data/activerdf-redland/test/test_person_data.nt +42 -0
- data/activerdf-redland/test/test_redland_adapter.rb +242 -0
- data/activerdf-sesame/CHANGELOG +6 -0
- data/activerdf-sesame/LICENSE +10 -0
- data/activerdf-sesame/LICENSE-aduna +10 -0
- data/activerdf-sesame/LICENSE-lgpl +504 -0
- data/activerdf-sesame/README +33 -0
- data/activerdf-sesame/Rakefile +77 -0
- data/activerdf-sesame/VERSION +1 -0
- data/activerdf-sesame/ext/commons-codec-1.3.jar +0 -0
- data/activerdf-sesame/ext/commons-dbcp-1.2.2.jar +0 -0
- data/activerdf-sesame/ext/commons-httpclient-3.1.jar +0 -0
- data/activerdf-sesame/ext/commons-logging-1.1.1.jar +0 -0
- data/activerdf-sesame/ext/commons-pool-1.3.jar +0 -0
- data/activerdf-sesame/ext/commons-pool-1.5.2.jar +0 -0
- data/activerdf-sesame/ext/junit-3.8.2.jar +0 -0
- data/activerdf-sesame/ext/openrdf-sesame-2.0-onejar.jar +0 -0
- data/activerdf-sesame/ext/openrdf-sesame-2.3-pr1-onejar.jar +0 -0
- data/activerdf-sesame/ext/slf4j-api-1.4.3.jar +0 -0
- data/activerdf-sesame/ext/slf4j-nop-1.4.3.jar +0 -0
- data/activerdf-sesame/ext/wrapper-sesame2.jar +0 -0
- data/activerdf-sesame/java/build.number +3 -0
- data/activerdf-sesame/java/build.xml +313 -0
- data/activerdf-sesame/java/javadoc/allclasses-frame.html +31 -0
- data/activerdf-sesame/java/javadoc/allclasses-noframe.html +31 -0
- data/activerdf-sesame/java/javadoc/constant-values.html +146 -0
- data/activerdf-sesame/java/javadoc/deprecated-list.html +146 -0
- data/activerdf-sesame/java/javadoc/help-doc.html +223 -0
- data/activerdf-sesame/java/javadoc/index-files/index-1.html +150 -0
- data/activerdf-sesame/java/javadoc/index-files/index-10.html +145 -0
- data/activerdf-sesame/java/javadoc/index-files/index-2.html +157 -0
- data/activerdf-sesame/java/javadoc/index-files/index-3.html +146 -0
- data/activerdf-sesame/java/javadoc/index-files/index-4.html +145 -0
- data/activerdf-sesame/java/javadoc/index-files/index-5.html +145 -0
- data/activerdf-sesame/java/javadoc/index-files/index-6.html +142 -0
- data/activerdf-sesame/java/javadoc/index-files/index-7.html +145 -0
- data/activerdf-sesame/java/javadoc/index-files/index-8.html +152 -0
- data/activerdf-sesame/java/javadoc/index-files/index-9.html +146 -0
- data/activerdf-sesame/java/javadoc/index.html +36 -0
- data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/WrapperForSesame2.html +665 -0
- data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/class-use/WrapperForSesame2.html +144 -0
- data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-frame.html +32 -0
- data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-summary.html +157 -0
- data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-tree.html +150 -0
- data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-use.html +144 -0
- data/activerdf-sesame/java/javadoc/overview-summary.html +156 -0
- data/activerdf-sesame/java/javadoc/overview-tree.html +152 -0
- data/activerdf-sesame/java/javadoc/package-list +1 -0
- data/activerdf-sesame/java/javadoc/resources/inherit.gif +0 -0
- data/activerdf-sesame/java/javadoc/stylesheet.css +29 -0
- data/activerdf-sesame/java/lib/commons-codec-1.3.jar +0 -0
- data/activerdf-sesame/java/lib/commons-dbcp-1.2.2.jar +0 -0
- data/activerdf-sesame/java/lib/commons-httpclient-3.1.jar +0 -0
- data/activerdf-sesame/java/lib/commons-logging-1.1.1.jar +0 -0
- data/activerdf-sesame/java/lib/commons-pool-1.3.jar +0 -0
- data/activerdf-sesame/java/lib/commons-pool-1.5.2.jar +0 -0
- data/activerdf-sesame/java/lib/junit-3.8.2.jar +0 -0
- data/activerdf-sesame/java/lib/openrdf-sesame-2.0-onejar.jar +0 -0
- data/activerdf-sesame/java/lib/openrdf-sesame-2.3-pr1-onejar.jar +0 -0
- data/activerdf-sesame/java/lib/slf4j-api-1.4.3.jar +0 -0
- data/activerdf-sesame/java/lib/slf4j-nop-1.4.3.jar +0 -0
- data/activerdf-sesame/java/manifest.mf +3 -0
- data/activerdf-sesame/java/settings.xml +135 -0
- data/activerdf-sesame/java/src/org/activerdf/wrapper/sesame2/WrapperForSesame2.java +145 -0
- data/activerdf-sesame/java/test-src/org/activerdf/wrapper/sesame2/TestWrapperForSesame2.java +41 -0
- data/activerdf-sesame/lib/activerdf_sesame/init.rb +11 -0
- data/activerdf-sesame/lib/activerdf_sesame/sesame.rb +400 -0
- data/activerdf-sesame/test/eyal-foaf.nt +39 -0
- data/activerdf-sesame/test/eyal-foaf.rdf +65 -0
- data/activerdf-sesame/test/test_sesame_adapter.rb +341 -0
- data/activerdf-sparql/CHANGELOG +35 -0
- data/activerdf-sparql/LICENSE +504 -0
- data/activerdf-sparql/README +10 -0
- data/activerdf-sparql/Rakefile +78 -0
- data/activerdf-sparql/VERSION +1 -0
- data/activerdf-sparql/lib/activerdf_sparql/init.rb +10 -0
- data/activerdf-sparql/lib/activerdf_sparql/sparql.rb +212 -0
- data/activerdf-sparql/lib/activerdf_sparql/sparql_result_parser.rb +55 -0
- data/activerdf-sparql/test/test_sparql_adapter.rb +108 -0
- data/activerdf-yars/LICENSE +504 -0
- data/activerdf-yars/README +10 -0
- data/activerdf-yars/Rakefile +38 -0
- data/activerdf-yars/lib/activerdf_yars/init.rb +10 -0
- data/activerdf-yars/lib/activerdf_yars/jars2.rb +119 -0
- data/lib/active_rdf.rb +85 -0
- data/lib/active_rdf/directaccess/direct_access.rb +49 -0
- data/lib/active_rdf/federation/active_rdf_adapter.rb +47 -0
- data/lib/active_rdf/federation/connection_pool.rb +156 -0
- data/lib/active_rdf/federation/federation_manager.rb +112 -0
- data/lib/active_rdf/instance_exec.rb +13 -0
- data/lib/active_rdf/objectmanager/bnode.rb +7 -0
- data/lib/active_rdf/objectmanager/literal.rb +71 -0
- data/lib/active_rdf/objectmanager/namespace.rb +106 -0
- data/lib/active_rdf/objectmanager/object_manager.rb +119 -0
- data/lib/active_rdf/objectmanager/ordered_set.rb +116 -0
- data/lib/active_rdf/objectmanager/property_list.rb +76 -0
- data/lib/active_rdf/objectmanager/resource.rb +609 -0
- data/lib/active_rdf/objectmanager/resource_like.rb +28 -0
- data/lib/active_rdf/queryengine/ntriples_parser.rb +90 -0
- data/lib/active_rdf/queryengine/query.rb +245 -0
- data/lib/active_rdf/queryengine/query2jars2.rb +22 -0
- data/lib/active_rdf/queryengine/query2sparql.rb +139 -0
- data/lib/active_rdf_helpers.rb +30 -0
- data/lib/active_rdf_log.rb +100 -0
- data/test/common.rb +119 -0
- data/test/directaccess/test_direct_access.rb +64 -0
- data/test/federation/test_connection_pool.rb +86 -0
- data/test/federation/test_federation_manager.rb +145 -0
- data/test/objectmanager/test_literal.rb +52 -0
- data/test/objectmanager/test_namespace.rb +83 -0
- data/test/objectmanager/test_object_manager.rb +96 -0
- data/test/objectmanager/test_ordered_set.rb +110 -0
- data/test/objectmanager/test_resource_reading.rb +150 -0
- data/test/objectmanager/test_resource_writing.rb +39 -0
- data/test/objectmanager/test_talia_syntax.rb +68 -0
- data/test/queryengine/my_external_resource.rb +24 -0
- data/test/queryengine/test_external_resource_class.rb +49 -0
- data/test/queryengine/test_ntriples_parser.rb +71 -0
- data/test/queryengine/test_query.rb +55 -0
- data/test/queryengine/test_query2jars2.rb +51 -0
- data/test/queryengine/test_query2sparql.rb +76 -0
- data/test/queryengine/test_query_engine.rb +52 -0
- data/test/test_adapters.rb +58 -0
- metadata +266 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
# Simple class which will contain all values of a specified property related to a subject.
|
2
|
+
# It provides some useful shortcut methods to work with properties and related values.
|
3
|
+
|
4
|
+
class PropertyList < Array
|
5
|
+
|
6
|
+
# Add reader accessor
|
7
|
+
attr_reader :s, :p
|
8
|
+
attr_accessor :writeable
|
9
|
+
|
10
|
+
# Initialize a new list of properties' values
|
11
|
+
# * p the original property
|
12
|
+
# * pv_list the list of properties' values
|
13
|
+
# * s the sobject which property is related to
|
14
|
+
# * writeable if set to false, the list will be write-protected
|
15
|
+
def initialize(p, pv_list, s, writeable = true)
|
16
|
+
super pv_list
|
17
|
+
@s, @p = s, p
|
18
|
+
@writeable = writeable
|
19
|
+
end
|
20
|
+
|
21
|
+
# add a new property value realated to @p property and @s subject
|
22
|
+
alias :add :<<
|
23
|
+
def <<(pv)
|
24
|
+
check_writeable!
|
25
|
+
# update the array list
|
26
|
+
add pv
|
27
|
+
|
28
|
+
# insert the new statment into the store
|
29
|
+
FederationManager.add(@s, @p, pv)
|
30
|
+
end
|
31
|
+
|
32
|
+
# delete a statment which contains old_p_value
|
33
|
+
# and insert a new statment (@s, @p, new_p_value)
|
34
|
+
def replace(old_p_value, new_p_value)
|
35
|
+
check_writeable!
|
36
|
+
# delete the old statment
|
37
|
+
self.delete(old_p_value)
|
38
|
+
FederationManager.delete(@s, @p, old_p_value)
|
39
|
+
|
40
|
+
# insert the new statment
|
41
|
+
self << new_p_value
|
42
|
+
end
|
43
|
+
|
44
|
+
# if no papameters will be specified, delete every
|
45
|
+
# triple related to :s and p: otherwise delete the
|
46
|
+
# triples whose values are specified by params
|
47
|
+
def remove(*params)
|
48
|
+
check_writeable!
|
49
|
+
if params.length >= 1
|
50
|
+
# delete only triples whose values is specified by parameters
|
51
|
+
params.each{|param|
|
52
|
+
if self.delete(param)
|
53
|
+
return FederationManager.delete(@s, @p, param)
|
54
|
+
end
|
55
|
+
}
|
56
|
+
else
|
57
|
+
# delete every triple related to :s and :p whose values is contained by self...
|
58
|
+
self.each{|value|
|
59
|
+
if FederationManager.delete(@s, @p, value) == false
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
}
|
63
|
+
# ...and clear the array Poperty_list array
|
64
|
+
self.clear
|
65
|
+
return true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
# Checks if the list is writeable, raise an error otherwise
|
72
|
+
def check_writeable!
|
73
|
+
raise(RuntimeError, "List is not writeable!") unless(@writeable)
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,609 @@
|
|
1
|
+
# require 'active_rdf'
|
2
|
+
require 'objectmanager/object_manager'
|
3
|
+
require 'objectmanager/namespace'
|
4
|
+
require 'objectmanager/property_list'
|
5
|
+
require 'instance_exec'
|
6
|
+
|
7
|
+
module RDFS
|
8
|
+
# Represents an RDF resource and manages manipulations of that resource,
|
9
|
+
# including data lookup (e.g. eyal.age), data updates (e.g. eyal.age=20),
|
10
|
+
# class-level lookup (Person.find_by_name 'eyal'), and class-membership
|
11
|
+
# (eyal.class ...Person).
|
12
|
+
|
13
|
+
class Resource
|
14
|
+
|
15
|
+
include ResourceLike
|
16
|
+
|
17
|
+
# adding accessor to the class uri:
|
18
|
+
# the uri of the rdf resource being represented by this class
|
19
|
+
class << self
|
20
|
+
attr_accessor :class_uri
|
21
|
+
end
|
22
|
+
|
23
|
+
# uri of the resource (for instances of this class: rdf resources)
|
24
|
+
attr_reader :uri
|
25
|
+
|
26
|
+
# creates new resource representing an RDF resource
|
27
|
+
def initialize uri
|
28
|
+
@uri = case uri
|
29
|
+
# allow Resource.new(other_resource)
|
30
|
+
when RDFS::Resource
|
31
|
+
uri.uri
|
32
|
+
# allow Resource.new('<uri>') by stripping out <>
|
33
|
+
when /^<([^>]*)>$/
|
34
|
+
$1
|
35
|
+
# allow Resource.new('uri')
|
36
|
+
when String
|
37
|
+
uri
|
38
|
+
else
|
39
|
+
raise ActiveRdfError, "cannot create resource <#{uri}>"
|
40
|
+
end
|
41
|
+
@predicates = Hash.new
|
42
|
+
end
|
43
|
+
|
44
|
+
# setting our own class uri to rdfs:resource
|
45
|
+
# (has to be done after defining our RDFS::Resource.new
|
46
|
+
# because it cannot be found in Namespace.lookup otherwise)
|
47
|
+
self.class_uri = Namespace.lookup(:rdfs, :Resource)
|
48
|
+
|
49
|
+
def self.uri; class_uri.uri; end
|
50
|
+
def self.==(other)
|
51
|
+
other.respond_to?(:uri) ? other.uri == self.uri : false
|
52
|
+
end
|
53
|
+
def self.localname; Namespace.localname(self); end
|
54
|
+
|
55
|
+
##### ######
|
56
|
+
##### start of instance-level code
|
57
|
+
##### ######
|
58
|
+
|
59
|
+
def abbreviation; [Namespace.prefix(uri).to_s, localname]; end
|
60
|
+
# a resource is same as another if they both represent the same uri
|
61
|
+
def ==(other);
|
62
|
+
other.respond_to?(:uri) ? other.uri == self.uri : false
|
63
|
+
end
|
64
|
+
alias_method 'eql?','=='
|
65
|
+
|
66
|
+
# overriding hash to use uri.hash
|
67
|
+
# needed for array.uniq
|
68
|
+
def hash; uri.hash; end
|
69
|
+
|
70
|
+
def self.to_ntriple; "<#{class_uri.uri}>"; end
|
71
|
+
|
72
|
+
def to_xml
|
73
|
+
base = Namespace.expand(Namespace.prefix(self),'').chop
|
74
|
+
|
75
|
+
xml = "<?xml version=\"1.0\"?>\n"
|
76
|
+
xml += "<rdf:RDF xmlns=\"#{base}\#\"\n"
|
77
|
+
Namespace.abbreviations.each { |p| uri = Namespace.expand(p,''); xml += " xmlns:#{p.to_s}=\"#{uri}\"\n" if uri != base + '#' }
|
78
|
+
xml += " xml:base=\"#{base}\">\n"
|
79
|
+
|
80
|
+
xml += "<rdf:Description rdf:about=\"\##{localname}\">\n"
|
81
|
+
direct_predicates.each do |p|
|
82
|
+
objects = Query.new.distinct(:o).where(self, p, :o).execute
|
83
|
+
objects.each do |obj|
|
84
|
+
prefix, localname = Namespace.prefix(p), Namespace.localname(p)
|
85
|
+
pred_xml = if prefix
|
86
|
+
"%s:%s" % [prefix, localname]
|
87
|
+
else
|
88
|
+
p.uri
|
89
|
+
end
|
90
|
+
|
91
|
+
case obj
|
92
|
+
when RDFS::Resource
|
93
|
+
xml += " <#{pred_xml} rdf:resource=\"#{obj.uri}\"/>\n"
|
94
|
+
when LocalizedString
|
95
|
+
xml += " <#{pred_xml} xml:lang=\"#{obj.lang}\">#{obj}</#{pred_xml}>\n"
|
96
|
+
else
|
97
|
+
xml += " <#{pred_xml} rdf:datatype=\"#{obj.xsd_type.uri}\">#{obj}</#{pred_xml}>\n"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
xml += "</rdf:Description>\n"
|
102
|
+
xml += "</rdf:RDF>"
|
103
|
+
end
|
104
|
+
|
105
|
+
##### #####
|
106
|
+
##### class level methods #####
|
107
|
+
##### #####
|
108
|
+
|
109
|
+
# returns the predicates that have this resource as their domain (applicable
|
110
|
+
# predicates for this resource)
|
111
|
+
def Resource.predicates
|
112
|
+
domain = Namespace.lookup(:rdfs, :domain)
|
113
|
+
Query.new.distinct(:p).where(:p, domain, class_uri).execute || []
|
114
|
+
end
|
115
|
+
|
116
|
+
# quick fix for "direct" getting of a property
|
117
|
+
# return a PropertyCollection (see PropertyCollection class)
|
118
|
+
def [](property)
|
119
|
+
if !property.instance_of?(RDFS::Resource)
|
120
|
+
property = RDFS::Resource.new(property)
|
121
|
+
end
|
122
|
+
|
123
|
+
plv = Query.new.distinct(:o).where(self, property, :o).execute
|
124
|
+
|
125
|
+
# make and return new propertis collection
|
126
|
+
PropertyList.new(property, plv, self)
|
127
|
+
end
|
128
|
+
|
129
|
+
# manages invocations such as Person.find_by_name,
|
130
|
+
# Person.find_by_foaf::name, Person.find_by_foaf::name_and_foaf::knows, etc.
|
131
|
+
def Resource.method_missing(method, *args)
|
132
|
+
if /find_by_(.+)/.match(method.to_s)
|
133
|
+
ActiveRdfLogger::log_debug "Constructing dynamic finder for #{method}", self
|
134
|
+
|
135
|
+
# construct proxy to handle delayed lookups
|
136
|
+
# (find_by_foaf::name_and_foaf::age)
|
137
|
+
proxy = DynamicFinderProxy.new($1, nil, *args)
|
138
|
+
|
139
|
+
# if proxy already found a value (find_by_name) we will not get a more
|
140
|
+
# complex query, so return the value. Otherwise, return the proxy so that
|
141
|
+
# subsequent lookups are handled
|
142
|
+
return proxy.value || proxy
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# returns array of all instances of this class (e.g. Person.find_all)
|
147
|
+
# (always returns collection)
|
148
|
+
def Resource.find_all(*args)
|
149
|
+
find(:all, *args)
|
150
|
+
end
|
151
|
+
|
152
|
+
def Resource.find(*args)
|
153
|
+
class_uri.find(*args)
|
154
|
+
end
|
155
|
+
|
156
|
+
##### #####
|
157
|
+
##### instance level methods #####
|
158
|
+
##### #####
|
159
|
+
def find(*args)
|
160
|
+
# extract sort options from args
|
161
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
162
|
+
|
163
|
+
query = Query.new.distinct(:s)
|
164
|
+
query.where(:s, Namespace.lookup(:rdf,:type), self)
|
165
|
+
|
166
|
+
if options.include? :order
|
167
|
+
sort_predicate = options[:order]
|
168
|
+
query.sort(:sort_value)
|
169
|
+
query.where(:s, sort_predicate, :sort_value)
|
170
|
+
end
|
171
|
+
|
172
|
+
if options.include? :reverse_order
|
173
|
+
sort_predicate = options[:reverse_order]
|
174
|
+
query.reverse_sort(:sort_value)
|
175
|
+
query.where(:s, sort_predicate, :sort_value)
|
176
|
+
end
|
177
|
+
|
178
|
+
if options.include? :where
|
179
|
+
raise ActiveRdfError, "where clause should be hash of predicate => object" unless options[:where].is_a? Hash
|
180
|
+
options[:where].each do |p,o|
|
181
|
+
if options.include? :context
|
182
|
+
query.where(:s, p, o, options[:context])
|
183
|
+
else
|
184
|
+
query.where(:s, p, o)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
else
|
188
|
+
if options[:context]
|
189
|
+
query.where(:s, :p, :o, options[:context])
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
query.limit(options[:limit]) if options[:limit]
|
194
|
+
query.offset(options[:offset]) if options[:offset]
|
195
|
+
|
196
|
+
if block_given?
|
197
|
+
query.execute do |resource|
|
198
|
+
yield resource
|
199
|
+
end
|
200
|
+
else
|
201
|
+
query.execute(:flatten => false)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def localname
|
206
|
+
Namespace.localname(self)
|
207
|
+
end
|
208
|
+
|
209
|
+
# Simple query shortcut which return a special object created on-the-fly by which is
|
210
|
+
# possible to directly obtain every distinct resources where:
|
211
|
+
# property ==> specified by the user by [] operator
|
212
|
+
# object ==> current Ruby object representing an RDF resource
|
213
|
+
def inverse
|
214
|
+
inverseobj = Object.new
|
215
|
+
inverseobj.instance_variable_set(:@obj_uri, self)
|
216
|
+
|
217
|
+
class <<inverseobj
|
218
|
+
|
219
|
+
def [](property_uri)
|
220
|
+
property = RDFS::Resource.new(property_uri)
|
221
|
+
Query.new.distinct(:s).where(:s, property, @obj_uri).execute
|
222
|
+
end
|
223
|
+
private(:type)
|
224
|
+
end
|
225
|
+
|
226
|
+
return inverseobj
|
227
|
+
end
|
228
|
+
|
229
|
+
# manages invocations such as eyal.age
|
230
|
+
def method_missing(method, *args,&block)
|
231
|
+
# possibilities:
|
232
|
+
# 1. eyal.age is a property of eyal (triple exists <eyal> <age> "30")
|
233
|
+
# evidence: eyal age ?a, ?a is not nil (only if value exists)
|
234
|
+
# action: return ?a
|
235
|
+
#
|
236
|
+
# 2. eyal's class is in domain of age, but does not have value for eyal
|
237
|
+
# explain: eyal is a person and some other person (not eyal) has an age
|
238
|
+
# evidence: eyal type ?c, age domain ?c
|
239
|
+
# action: return nil
|
240
|
+
#
|
241
|
+
# 3. eyal.age = 30 (setting a value for a property)
|
242
|
+
# explain: eyal has (or could have) a value for age, and we update that value
|
243
|
+
# complication: we need to find the full URI for age (by looking at
|
244
|
+
# possible predicates to use
|
245
|
+
# evidence: eyal age ?o (eyal has a value for age now, we're updating it)
|
246
|
+
# evidence: eyal type ?c, age domain ?c (eyal could have a value for age, we're setting it)
|
247
|
+
# action: add triple (eyal, age, 30), return 30
|
248
|
+
#
|
249
|
+
# 4. eyal.age is a custom-written method in class Person
|
250
|
+
# evidence: eyal type ?c, ?c.methods includes age
|
251
|
+
# action: inject age into eyal and invoke
|
252
|
+
#
|
253
|
+
# 5. eyal.age is registered abbreviation
|
254
|
+
# evidence: age in @predicates
|
255
|
+
# action: return object from triple (eyal, @predicates[age], ?o)
|
256
|
+
#
|
257
|
+
# 6. eyal.foaf::name, where foaf is a registered abbreviation
|
258
|
+
# evidence: foaf in Namespace.
|
259
|
+
# action: return namespace proxy that handles 'name' invocation, by
|
260
|
+
# rewriting into predicate lookup (similar to case (5)
|
261
|
+
|
262
|
+
ActiveRdfLogger.log_debug(self) { "Method_missing: #{method}" }
|
263
|
+
|
264
|
+
# are we doing an update or not?
|
265
|
+
# checking if method ends with '='
|
266
|
+
|
267
|
+
update = method.to_s[-1..-1] == '='
|
268
|
+
methodname = if update
|
269
|
+
method.to_s[0..-2]
|
270
|
+
else
|
271
|
+
method.to_s
|
272
|
+
end
|
273
|
+
|
274
|
+
# extract single values from array unless user asked for eyal.all_age
|
275
|
+
flatten = true
|
276
|
+
if method.to_s[0..3] == 'all_'
|
277
|
+
flatten = false
|
278
|
+
methodname = methodname[4..-1]
|
279
|
+
end
|
280
|
+
|
281
|
+
# check possibility (5)
|
282
|
+
if @predicates.include?(methodname)
|
283
|
+
if update
|
284
|
+
return set_predicate(@predicates[methodname], args)
|
285
|
+
else
|
286
|
+
return get_predicate(@predicates[methodname], false, &block)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# check possibility (6)
|
291
|
+
if Namespace.abbreviations.include?(methodname.to_sym)
|
292
|
+
namespace = Object.new
|
293
|
+
namespace.instance_variable_set(:@uri, methodname)
|
294
|
+
namespace.instance_variable_set(:@subject, self)
|
295
|
+
namespace.instance_variable_set(:@flatten, flatten)
|
296
|
+
|
297
|
+
# catch the invocation on the namespace
|
298
|
+
class <<namespace
|
299
|
+
def method_missing(localname, *values, &block)
|
300
|
+
update = localname.to_s[-1..-1] == '='
|
301
|
+
predicate = if update
|
302
|
+
Namespace.lookup(@uri, localname.to_s[0..-2])
|
303
|
+
else
|
304
|
+
Namespace.lookup(@uri, localname)
|
305
|
+
end
|
306
|
+
|
307
|
+
if update
|
308
|
+
@subject.set_predicate(predicate, values)
|
309
|
+
else
|
310
|
+
@subject.get_predicate(predicate, @flatten, &block)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
private(:type)
|
314
|
+
end
|
315
|
+
return namespace
|
316
|
+
end
|
317
|
+
|
318
|
+
candidates = if update
|
319
|
+
(class_level_predicates + direct_predicates).compact.uniq
|
320
|
+
else
|
321
|
+
direct_predicates
|
322
|
+
end
|
323
|
+
|
324
|
+
# checking possibility (1) and (3)
|
325
|
+
candidates.each do |pred|
|
326
|
+
if Namespace.localname(pred) == methodname
|
327
|
+
if update
|
328
|
+
return set_predicate(pred, args)
|
329
|
+
else
|
330
|
+
return get_predicate(pred, flatten, &block)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
raise ActiveRdfError, "Could not set #{methodname} to #{args}: no suitable predicate found. Maybe you are missing some schema information?" if update
|
336
|
+
|
337
|
+
# get/set attribute value did not succeed, so checking option (2) and (4)
|
338
|
+
|
339
|
+
# checking possibility (2), it is not handled correctly above since we use
|
340
|
+
# direct_predicates instead of class_level_predicates. If we didn't find
|
341
|
+
# anything with direct_predicates, we need to try the
|
342
|
+
# class_level_predicates. Only if we don't find either, we
|
343
|
+
# throw "method_missing"
|
344
|
+
candidates = class_level_predicates
|
345
|
+
|
346
|
+
# if any of the class_level candidates fits the sought method, then we
|
347
|
+
# found situation (2), so we return nil or [] depending on the {:array =>
|
348
|
+
# true} value
|
349
|
+
if candidates.any?{ |c| Namespace.localname(c) == methodname }
|
350
|
+
return_ary = args[0][:array] if args[0].is_a? Hash
|
351
|
+
if return_ary
|
352
|
+
return []
|
353
|
+
else
|
354
|
+
return nil
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
# checking possibility (4)
|
359
|
+
# TODO: implement search strategy to select in which class to invoke
|
360
|
+
# e.g. if to_s defined in Resource and in Person we should use Person
|
361
|
+
ActiveRdfLogger::log_debug(self){ "RDFS::Resource: method_missing option 4: custom class method" }
|
362
|
+
self.type.each do |klass|
|
363
|
+
if klass.instance_methods.include?(method.to_s)
|
364
|
+
_dup = klass.new(uri)
|
365
|
+
return _dup.send(method,*args)
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
# if none of the three possibilities work out, we don't know this method
|
370
|
+
# invocation, but we don't want to throw NoMethodError, instead we return
|
371
|
+
# nil, so that eyal.age does not raise error, but returns nil. (in RDFS,
|
372
|
+
# we are never sure that eyal cannot have an age, we just dont know the
|
373
|
+
# age right now)
|
374
|
+
nil
|
375
|
+
end
|
376
|
+
|
377
|
+
# saves instance into datastore
|
378
|
+
def save
|
379
|
+
db = ConnectionPool.write_adapter
|
380
|
+
rdftype = Namespace.lookup(:rdf, :type)
|
381
|
+
types.each do |t|
|
382
|
+
db.add(self, rdftype, t)
|
383
|
+
end
|
384
|
+
|
385
|
+
Query.new.distinct(:p,:o).where(self, :p, :o).execute do |p, o|
|
386
|
+
db.add(self, p, o)
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
# returns all rdf:type of this instance, e.g. [RDFS::Resource,
|
391
|
+
# FOAF::Person]
|
392
|
+
#
|
393
|
+
# Note: this method performs a database lookup for { self rdf:type ?o }. For
|
394
|
+
# simple type-checking (to know if you are handling an ActiveRDF object, use
|
395
|
+
# self.class, which does not do a database query, but simply returns
|
396
|
+
# RDFS::Resource.
|
397
|
+
def type
|
398
|
+
types.collect do |type|
|
399
|
+
ObjectManager.construct_class(type)
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
# define a localname for a predicate URI
|
404
|
+
#
|
405
|
+
# localname should be a Symbol or String, fulluri a Resource or String, e.g.
|
406
|
+
# add_predicate(:name, FOAF::lastName)
|
407
|
+
def add_predicate localname, fulluri
|
408
|
+
localname = localname.to_s
|
409
|
+
fulluri = RDFS::Resource.new(fulluri) if fulluri.is_a? String
|
410
|
+
|
411
|
+
# predicates is a hash from abbreviation string to full uri resource
|
412
|
+
@predicates[localname] = fulluri
|
413
|
+
end
|
414
|
+
|
415
|
+
|
416
|
+
# overrides built-in instance_of? to use rdf:type definitions
|
417
|
+
def instance_of?(klass)
|
418
|
+
self.type.include?(klass)
|
419
|
+
end
|
420
|
+
|
421
|
+
# returns all predicates that fall into the domain of the rdf:type of this
|
422
|
+
# resource
|
423
|
+
def class_level_predicates
|
424
|
+
type = Namespace.lookup(:rdf, 'type')
|
425
|
+
domain = Namespace.lookup(:rdfs, 'domain')
|
426
|
+
Query.new.distinct(:p).where(self,type,:t).where(:p, domain, :t).execute || []
|
427
|
+
end
|
428
|
+
|
429
|
+
# returns all predicates that are directly defined for this resource
|
430
|
+
def direct_predicates(distinct = true)
|
431
|
+
if distinct
|
432
|
+
Query.new.distinct(:p).where(self, :p, :o).execute
|
433
|
+
else
|
434
|
+
Query.new.select(:p).where(self, :p, :o).execute
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
def property_accessors
|
439
|
+
direct_predicates.collect {|pred| Namespace.localname(pred) }
|
440
|
+
end
|
441
|
+
|
442
|
+
# alias include? to ==, so that you can do paper.creator.include?(eyal)
|
443
|
+
# without worrying whether paper.creator is single- or multi-valued
|
444
|
+
alias include? ==
|
445
|
+
|
446
|
+
def set_predicate(predicate, values)
|
447
|
+
FederationManager.delete(self, predicate, nil)
|
448
|
+
values.flatten.each {|v| FederationManager.add(self, predicate, v) }
|
449
|
+
values
|
450
|
+
end
|
451
|
+
|
452
|
+
def get_predicate(predicate, flatten=false,&block)
|
453
|
+
query = Query.new.distinct(:o).where(self, predicate, :o)
|
454
|
+
if block_given?
|
455
|
+
yield query, :o
|
456
|
+
end
|
457
|
+
values = query.execute(:flatten => flatten)
|
458
|
+
|
459
|
+
# TODO: fix '<<' for Fixnum values etc (we cannot use values.instance_eval
|
460
|
+
# because Fixnum cannot do instace_eval, they're not normal classes)
|
461
|
+
if values.is_a?(RDFS::Resource) and !values.nil?
|
462
|
+
# prepare returned values for accepting << later, eg. in
|
463
|
+
# eyal.foaf::knows << knud
|
464
|
+
#
|
465
|
+
# store @subject, @predicate in returned values
|
466
|
+
values.instance_exec(self, predicate) do |s,p|
|
467
|
+
@subj = s
|
468
|
+
@pred = p
|
469
|
+
end
|
470
|
+
|
471
|
+
# overwrite << to add triple to db
|
472
|
+
values.instance_eval do
|
473
|
+
def <<(value)
|
474
|
+
FederationManager.add(@subj, @pred, value)
|
475
|
+
end
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
values
|
480
|
+
end
|
481
|
+
|
482
|
+
private
|
483
|
+
# def ancestors(predicate)
|
484
|
+
# subproperty = Namespace.lookup(:rdfs,:subPropertyOf)
|
485
|
+
# Query.new.distinct(:p).where(predicate, subproperty, :p).execute
|
486
|
+
# end
|
487
|
+
|
488
|
+
|
489
|
+
# returns all rdf:types of this resource but without a conversion to
|
490
|
+
# Ruby classes (it returns an array of RDFS::Resources)
|
491
|
+
def types
|
492
|
+
type = Namespace.lookup(:rdf, :type)
|
493
|
+
|
494
|
+
# we lookup the type in the database
|
495
|
+
types = Query.new.distinct(:t).where(self,type,:t).execute
|
496
|
+
|
497
|
+
# we are also always of type rdfs:resource and of our own class (e.g. foaf:Person)
|
498
|
+
defaults = []
|
499
|
+
defaults << Namespace.lookup(:rdfs,:Resource)
|
500
|
+
defaults << self.class.class_uri
|
501
|
+
|
502
|
+
(types + defaults).uniq
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
# proxy to manage find_by_ invocations
|
508
|
+
class DynamicFinderProxy
|
509
|
+
@ns = nil
|
510
|
+
@where = nil
|
511
|
+
@value = nil
|
512
|
+
attr_reader :value
|
513
|
+
private(:type)
|
514
|
+
|
515
|
+
# construct proxy from find_by text
|
516
|
+
# foaf::name
|
517
|
+
def initialize(find_string, where, *args)
|
518
|
+
@where = where || []
|
519
|
+
parse_attributes(find_string, *args)
|
520
|
+
end
|
521
|
+
|
522
|
+
def method_missing(method, *args)
|
523
|
+
# we store the ns:name for later (we need to wait until we have the
|
524
|
+
# arguments before actually constructing the where clause): now we just
|
525
|
+
# store that a where clause should appear about foaf:name
|
526
|
+
|
527
|
+
# if this method is called name_and_foaf::age we add ourself to the query
|
528
|
+
# otherwise, the query is built: we execute it and return the results
|
529
|
+
if method.to_s.include?('_and_')
|
530
|
+
parse_attributes(method.to_s, *args)
|
531
|
+
else
|
532
|
+
@where << Namespace.lookup(@ns, method.to_s)
|
533
|
+
query(*args)
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
private
|
538
|
+
# split find_string by occurrences of _and_
|
539
|
+
def parse_attributes string, *args
|
540
|
+
attributes = string.split('_and_')
|
541
|
+
attributes.each do |atr|
|
542
|
+
# attribute can be:
|
543
|
+
# - a namespace prefix (foaf): store prefix in @ns to prepare for method_missing
|
544
|
+
# - name (attribute name): store in where to prepare for method_missing
|
545
|
+
if Namespace.abbreviations.include?(atr.to_sym)
|
546
|
+
@ns = atr.to_s.downcase.to_sym
|
547
|
+
else
|
548
|
+
# found simple attribute label, e.g. 'name'
|
549
|
+
# find out candidate (full) predicate for this localname: investigate
|
550
|
+
# all possible predicates and select first one with matching localname
|
551
|
+
candidates = Query.new.distinct(:p).where(:s,:p,:o).execute
|
552
|
+
@where << candidates.select {|cand| Namespace.localname(cand) == atr}.first
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
# if the last attribute was a prefix, return this dynamic finder (we'll
|
557
|
+
# catch the following method_missing and construct the real query then)
|
558
|
+
# if the last attribute was a localname, construct the query now and return
|
559
|
+
# the results
|
560
|
+
if Namespace.abbreviations.include?(attributes.last.to_sym)
|
561
|
+
return self
|
562
|
+
else
|
563
|
+
return query(*args)
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
# construct and execute finder query
|
568
|
+
def query(*args)
|
569
|
+
# extract options from args or use an empty hash (no options given)
|
570
|
+
options = args.last.is_a?(Hash) ? args.last : {}
|
571
|
+
|
572
|
+
# build query
|
573
|
+
query = Query.new.distinct(:s)
|
574
|
+
@where.each_with_index do |predicate, i|
|
575
|
+
# specify where clauses, use context if given
|
576
|
+
if options[:context]
|
577
|
+
query.where(:s, predicate, args[i], options[:context])
|
578
|
+
else
|
579
|
+
query.where(:s, predicate, args[i])
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
# use sort order if given
|
584
|
+
if options.include? :order
|
585
|
+
sort_predicate = options[:order]
|
586
|
+
query.sort(:sort_value)
|
587
|
+
# add sort predicate where clause unless we have it already
|
588
|
+
query.where(:s, sort_predicate, :sort_value) unless @where.include? sort_predicate
|
589
|
+
end
|
590
|
+
|
591
|
+
if options.include? :reverse_order
|
592
|
+
sort_predicate = options[:reverse_order]
|
593
|
+
query.reverse_sort(:sort_value)
|
594
|
+
query.where(:s, sort_predicate, :sort_value) unless @where.include? sort_predicate
|
595
|
+
end
|
596
|
+
|
597
|
+
query.limit(options[:limit]) if options[:limit]
|
598
|
+
query.offset(options[:offset]) if options[:offset]
|
599
|
+
|
600
|
+
ActiveRdfLogger::log_debug(self) { "Executing dynamic finder: #{query.to_sp}" }
|
601
|
+
|
602
|
+
# store the query results so that caller (Resource.method_missing) can
|
603
|
+
# retrieve them (we cannot return them here, since we were invoked from
|
604
|
+
# the initialize method so all return values are ignored, instead the proxy
|
605
|
+
# itself is returned)
|
606
|
+
@value = query.execute
|
607
|
+
return @value
|
608
|
+
end
|
609
|
+
end
|