activerdf_net7 1.6.11
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 +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
|