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.
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