activerdf_net7 1.6.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (190) hide show
  1. data/CHANGELOG +79 -0
  2. data/LICENSE +504 -0
  3. data/README.rdoc +34 -0
  4. data/activerdf-jena/CHANGELOG +14 -0
  5. data/activerdf-jena/LICENSE +504 -0
  6. data/activerdf-jena/README +57 -0
  7. data/activerdf-jena/Rakefile +87 -0
  8. data/activerdf-jena/TODO +18 -0
  9. data/activerdf-jena/VERSION +1 -0
  10. data/activerdf-jena/ext/antlr-2.7.5.jar +0 -0
  11. data/activerdf-jena/ext/arq-extra.jar +0 -0
  12. data/activerdf-jena/ext/arq.jar +0 -0
  13. data/activerdf-jena/ext/aterm-java-1.6.jar +0 -0
  14. data/activerdf-jena/ext/commons-logging-1.1.jar +0 -0
  15. data/activerdf-jena/ext/concurrent.jar +0 -0
  16. data/activerdf-jena/ext/icu4j_3_4.jar +0 -0
  17. data/activerdf-jena/ext/iri.jar +0 -0
  18. data/activerdf-jena/ext/jena.jar +0 -0
  19. data/activerdf-jena/ext/jenatest.jar +0 -0
  20. data/activerdf-jena/ext/json.jar +0 -0
  21. data/activerdf-jena/ext/junit.jar +0 -0
  22. data/activerdf-jena/ext/log4j-1.2.12.jar +0 -0
  23. data/activerdf-jena/ext/lucene-core-2.0.0.jar +0 -0
  24. data/activerdf-jena/ext/ng4j.jar +0 -0
  25. data/activerdf-jena/ext/pellet.jar +0 -0
  26. data/activerdf-jena/ext/relaxngDatatype.jar +0 -0
  27. data/activerdf-jena/ext/stax-api-1.0.jar +0 -0
  28. data/activerdf-jena/ext/wstx-asl-3.0.0.jar +0 -0
  29. data/activerdf-jena/ext/xercesImpl.jar +0 -0
  30. data/activerdf-jena/ext/xml-apis.jar +0 -0
  31. data/activerdf-jena/ext/xsdlib.jar +0 -0
  32. data/activerdf-jena/lib/activerdf_jena/init.rb +26 -0
  33. data/activerdf-jena/lib/activerdf_jena/jena.rb +59 -0
  34. data/activerdf-jena/lib/activerdf_jena/jena_adapter.rb +515 -0
  35. data/activerdf-jena/lib/activerdf_jena/lucene.rb +22 -0
  36. data/activerdf-jena/lib/activerdf_jena/ng4j.rb +50 -0
  37. data/activerdf-jena/lib/activerdf_jena/ng4j_adapter.rb +379 -0
  38. data/activerdf-jena/lib/activerdf_jena/pellet.rb +25 -0
  39. data/activerdf-jena/test/bnode_org_rss.rdf +793 -0
  40. data/activerdf-jena/test/eyal-foaf.nt +39 -0
  41. data/activerdf-jena/test/fun_with_bnodes.nt +2 -0
  42. data/activerdf-jena/test/s1.n3 +18 -0
  43. data/activerdf-jena/test/test_data.nt +32 -0
  44. data/activerdf-jena/test/test_jena_adapter.rb +451 -0
  45. data/activerdf-jena/test/test_ng4j_adapter.rb +354 -0
  46. data/activerdf-rdflite/CHANGELOG +31 -0
  47. data/activerdf-rdflite/LICENSE +504 -0
  48. data/activerdf-rdflite/README +16 -0
  49. data/activerdf-rdflite/Rakefile +73 -0
  50. data/activerdf-rdflite/VERSION +1 -0
  51. data/activerdf-rdflite/lib/activerdf_rdflite/fetching.rb +34 -0
  52. data/activerdf-rdflite/lib/activerdf_rdflite/init.rb +13 -0
  53. data/activerdf-rdflite/lib/activerdf_rdflite/rdflite.rb +582 -0
  54. data/activerdf-rdflite/lib/activerdf_rdflite/suggesting.rb +87 -0
  55. data/activerdf-rdflite/test/test_bnode_data.nt +5 -0
  56. data/activerdf-rdflite/test/test_data.nt +32 -0
  57. data/activerdf-rdflite/test/test_escaped_data.nt +2 -0
  58. data/activerdf-rdflite/test/test_fetching.rb +33 -0
  59. data/activerdf-rdflite/test/test_rdflite.rb +277 -0
  60. data/activerdf-redland/CHANGELOG +12 -0
  61. data/activerdf-redland/LICENSE +504 -0
  62. data/activerdf-redland/README +9 -0
  63. data/activerdf-redland/Rakefile +72 -0
  64. data/activerdf-redland/VERSION +1 -0
  65. data/activerdf-redland/lib/activerdf_redland/init.rb +10 -0
  66. data/activerdf-redland/lib/activerdf_redland/redland.rb +362 -0
  67. data/activerdf-redland/test/test_person_data.nt +42 -0
  68. data/activerdf-redland/test/test_redland_adapter.rb +242 -0
  69. data/activerdf-sesame/CHANGELOG +6 -0
  70. data/activerdf-sesame/LICENSE +10 -0
  71. data/activerdf-sesame/LICENSE-aduna +10 -0
  72. data/activerdf-sesame/LICENSE-lgpl +504 -0
  73. data/activerdf-sesame/README +33 -0
  74. data/activerdf-sesame/Rakefile +77 -0
  75. data/activerdf-sesame/VERSION +1 -0
  76. data/activerdf-sesame/ext/commons-codec-1.3.jar +0 -0
  77. data/activerdf-sesame/ext/commons-dbcp-1.2.2.jar +0 -0
  78. data/activerdf-sesame/ext/commons-httpclient-3.1.jar +0 -0
  79. data/activerdf-sesame/ext/commons-logging-1.1.1.jar +0 -0
  80. data/activerdf-sesame/ext/commons-pool-1.3.jar +0 -0
  81. data/activerdf-sesame/ext/commons-pool-1.5.2.jar +0 -0
  82. data/activerdf-sesame/ext/junit-3.8.2.jar +0 -0
  83. data/activerdf-sesame/ext/openrdf-sesame-2.0-onejar.jar +0 -0
  84. data/activerdf-sesame/ext/openrdf-sesame-2.3-pr1-onejar.jar +0 -0
  85. data/activerdf-sesame/ext/slf4j-api-1.4.3.jar +0 -0
  86. data/activerdf-sesame/ext/slf4j-nop-1.4.3.jar +0 -0
  87. data/activerdf-sesame/ext/wrapper-sesame2.jar +0 -0
  88. data/activerdf-sesame/java/build.number +3 -0
  89. data/activerdf-sesame/java/build.xml +313 -0
  90. data/activerdf-sesame/java/javadoc/allclasses-frame.html +31 -0
  91. data/activerdf-sesame/java/javadoc/allclasses-noframe.html +31 -0
  92. data/activerdf-sesame/java/javadoc/constant-values.html +146 -0
  93. data/activerdf-sesame/java/javadoc/deprecated-list.html +146 -0
  94. data/activerdf-sesame/java/javadoc/help-doc.html +223 -0
  95. data/activerdf-sesame/java/javadoc/index-files/index-1.html +150 -0
  96. data/activerdf-sesame/java/javadoc/index-files/index-10.html +145 -0
  97. data/activerdf-sesame/java/javadoc/index-files/index-2.html +157 -0
  98. data/activerdf-sesame/java/javadoc/index-files/index-3.html +146 -0
  99. data/activerdf-sesame/java/javadoc/index-files/index-4.html +145 -0
  100. data/activerdf-sesame/java/javadoc/index-files/index-5.html +145 -0
  101. data/activerdf-sesame/java/javadoc/index-files/index-6.html +142 -0
  102. data/activerdf-sesame/java/javadoc/index-files/index-7.html +145 -0
  103. data/activerdf-sesame/java/javadoc/index-files/index-8.html +152 -0
  104. data/activerdf-sesame/java/javadoc/index-files/index-9.html +146 -0
  105. data/activerdf-sesame/java/javadoc/index.html +36 -0
  106. data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/WrapperForSesame2.html +665 -0
  107. data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/class-use/WrapperForSesame2.html +144 -0
  108. data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-frame.html +32 -0
  109. data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-summary.html +157 -0
  110. data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-tree.html +150 -0
  111. data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-use.html +144 -0
  112. data/activerdf-sesame/java/javadoc/overview-summary.html +156 -0
  113. data/activerdf-sesame/java/javadoc/overview-tree.html +152 -0
  114. data/activerdf-sesame/java/javadoc/package-list +1 -0
  115. data/activerdf-sesame/java/javadoc/resources/inherit.gif +0 -0
  116. data/activerdf-sesame/java/javadoc/stylesheet.css +29 -0
  117. data/activerdf-sesame/java/lib/commons-codec-1.3.jar +0 -0
  118. data/activerdf-sesame/java/lib/commons-dbcp-1.2.2.jar +0 -0
  119. data/activerdf-sesame/java/lib/commons-httpclient-3.1.jar +0 -0
  120. data/activerdf-sesame/java/lib/commons-logging-1.1.1.jar +0 -0
  121. data/activerdf-sesame/java/lib/commons-pool-1.3.jar +0 -0
  122. data/activerdf-sesame/java/lib/commons-pool-1.5.2.jar +0 -0
  123. data/activerdf-sesame/java/lib/junit-3.8.2.jar +0 -0
  124. data/activerdf-sesame/java/lib/openrdf-sesame-2.0-onejar.jar +0 -0
  125. data/activerdf-sesame/java/lib/openrdf-sesame-2.3-pr1-onejar.jar +0 -0
  126. data/activerdf-sesame/java/lib/slf4j-api-1.4.3.jar +0 -0
  127. data/activerdf-sesame/java/lib/slf4j-nop-1.4.3.jar +0 -0
  128. data/activerdf-sesame/java/manifest.mf +3 -0
  129. data/activerdf-sesame/java/settings.xml +135 -0
  130. data/activerdf-sesame/java/src/org/activerdf/wrapper/sesame2/WrapperForSesame2.java +145 -0
  131. data/activerdf-sesame/java/test-src/org/activerdf/wrapper/sesame2/TestWrapperForSesame2.java +41 -0
  132. data/activerdf-sesame/lib/activerdf_sesame/init.rb +11 -0
  133. data/activerdf-sesame/lib/activerdf_sesame/sesame.rb +400 -0
  134. data/activerdf-sesame/test/eyal-foaf.nt +39 -0
  135. data/activerdf-sesame/test/eyal-foaf.rdf +65 -0
  136. data/activerdf-sesame/test/test_sesame_adapter.rb +341 -0
  137. data/activerdf-sparql/CHANGELOG +35 -0
  138. data/activerdf-sparql/LICENSE +504 -0
  139. data/activerdf-sparql/README +10 -0
  140. data/activerdf-sparql/Rakefile +78 -0
  141. data/activerdf-sparql/VERSION +1 -0
  142. data/activerdf-sparql/lib/activerdf_sparql/init.rb +10 -0
  143. data/activerdf-sparql/lib/activerdf_sparql/sparql.rb +212 -0
  144. data/activerdf-sparql/lib/activerdf_sparql/sparql_result_parser.rb +55 -0
  145. data/activerdf-sparql/test/test_sparql_adapter.rb +108 -0
  146. data/activerdf-yars/LICENSE +504 -0
  147. data/activerdf-yars/README +10 -0
  148. data/activerdf-yars/Rakefile +38 -0
  149. data/activerdf-yars/lib/activerdf_yars/init.rb +10 -0
  150. data/activerdf-yars/lib/activerdf_yars/jars2.rb +119 -0
  151. data/lib/active_rdf.rb +85 -0
  152. data/lib/active_rdf/directaccess/direct_access.rb +49 -0
  153. data/lib/active_rdf/federation/active_rdf_adapter.rb +47 -0
  154. data/lib/active_rdf/federation/connection_pool.rb +156 -0
  155. data/lib/active_rdf/federation/federation_manager.rb +112 -0
  156. data/lib/active_rdf/instance_exec.rb +13 -0
  157. data/lib/active_rdf/objectmanager/bnode.rb +7 -0
  158. data/lib/active_rdf/objectmanager/literal.rb +71 -0
  159. data/lib/active_rdf/objectmanager/namespace.rb +106 -0
  160. data/lib/active_rdf/objectmanager/object_manager.rb +119 -0
  161. data/lib/active_rdf/objectmanager/ordered_set.rb +116 -0
  162. data/lib/active_rdf/objectmanager/property_list.rb +76 -0
  163. data/lib/active_rdf/objectmanager/resource.rb +609 -0
  164. data/lib/active_rdf/objectmanager/resource_like.rb +28 -0
  165. data/lib/active_rdf/queryengine/ntriples_parser.rb +90 -0
  166. data/lib/active_rdf/queryengine/query.rb +245 -0
  167. data/lib/active_rdf/queryengine/query2jars2.rb +22 -0
  168. data/lib/active_rdf/queryengine/query2sparql.rb +139 -0
  169. data/lib/active_rdf_helpers.rb +30 -0
  170. data/lib/active_rdf_log.rb +100 -0
  171. data/test/common.rb +119 -0
  172. data/test/directaccess/test_direct_access.rb +64 -0
  173. data/test/federation/test_connection_pool.rb +86 -0
  174. data/test/federation/test_federation_manager.rb +145 -0
  175. data/test/objectmanager/test_literal.rb +52 -0
  176. data/test/objectmanager/test_namespace.rb +83 -0
  177. data/test/objectmanager/test_object_manager.rb +96 -0
  178. data/test/objectmanager/test_ordered_set.rb +110 -0
  179. data/test/objectmanager/test_resource_reading.rb +150 -0
  180. data/test/objectmanager/test_resource_writing.rb +39 -0
  181. data/test/objectmanager/test_talia_syntax.rb +68 -0
  182. data/test/queryengine/my_external_resource.rb +24 -0
  183. data/test/queryengine/test_external_resource_class.rb +49 -0
  184. data/test/queryengine/test_ntriples_parser.rb +71 -0
  185. data/test/queryengine/test_query.rb +55 -0
  186. data/test/queryengine/test_query2jars2.rb +51 -0
  187. data/test/queryengine/test_query2sparql.rb +76 -0
  188. data/test/queryengine/test_query_engine.rb +52 -0
  189. data/test/test_adapters.rb +58 -0
  190. 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