openlogic-rdf 0.3.6
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/AUTHORS +3 -0
- data/CREDITS +9 -0
- data/README +361 -0
- data/UNLICENSE +24 -0
- data/VERSION +1 -0
- data/bin/rdf +18 -0
- data/etc/doap.nt +62 -0
- data/lib/df.rb +1 -0
- data/lib/rdf/cli.rb +200 -0
- data/lib/rdf/format.rb +383 -0
- data/lib/rdf/mixin/countable.rb +39 -0
- data/lib/rdf/mixin/durable.rb +31 -0
- data/lib/rdf/mixin/enumerable.rb +637 -0
- data/lib/rdf/mixin/indexable.rb +26 -0
- data/lib/rdf/mixin/inferable.rb +5 -0
- data/lib/rdf/mixin/mutable.rb +191 -0
- data/lib/rdf/mixin/queryable.rb +265 -0
- data/lib/rdf/mixin/readable.rb +15 -0
- data/lib/rdf/mixin/type_check.rb +21 -0
- data/lib/rdf/mixin/writable.rb +152 -0
- data/lib/rdf/model/graph.rb +263 -0
- data/lib/rdf/model/list.rb +731 -0
- data/lib/rdf/model/literal/boolean.rb +121 -0
- data/lib/rdf/model/literal/date.rb +73 -0
- data/lib/rdf/model/literal/datetime.rb +72 -0
- data/lib/rdf/model/literal/decimal.rb +86 -0
- data/lib/rdf/model/literal/double.rb +189 -0
- data/lib/rdf/model/literal/integer.rb +126 -0
- data/lib/rdf/model/literal/numeric.rb +184 -0
- data/lib/rdf/model/literal/time.rb +87 -0
- data/lib/rdf/model/literal/token.rb +47 -0
- data/lib/rdf/model/literal/xml.rb +39 -0
- data/lib/rdf/model/literal.rb +373 -0
- data/lib/rdf/model/node.rb +156 -0
- data/lib/rdf/model/resource.rb +28 -0
- data/lib/rdf/model/statement.rb +296 -0
- data/lib/rdf/model/term.rb +77 -0
- data/lib/rdf/model/uri.rb +570 -0
- data/lib/rdf/model/value.rb +133 -0
- data/lib/rdf/nquads.rb +152 -0
- data/lib/rdf/ntriples/format.rb +48 -0
- data/lib/rdf/ntriples/reader.rb +239 -0
- data/lib/rdf/ntriples/writer.rb +219 -0
- data/lib/rdf/ntriples.rb +104 -0
- data/lib/rdf/query/pattern.rb +329 -0
- data/lib/rdf/query/solution.rb +252 -0
- data/lib/rdf/query/solutions.rb +237 -0
- data/lib/rdf/query/variable.rb +221 -0
- data/lib/rdf/query.rb +404 -0
- data/lib/rdf/reader.rb +511 -0
- data/lib/rdf/repository.rb +389 -0
- data/lib/rdf/transaction.rb +161 -0
- data/lib/rdf/util/aliasing.rb +63 -0
- data/lib/rdf/util/cache.rb +139 -0
- data/lib/rdf/util/file.rb +38 -0
- data/lib/rdf/util/uuid.rb +36 -0
- data/lib/rdf/util.rb +6 -0
- data/lib/rdf/version.rb +19 -0
- data/lib/rdf/vocab/cc.rb +18 -0
- data/lib/rdf/vocab/cert.rb +13 -0
- data/lib/rdf/vocab/dc.rb +63 -0
- data/lib/rdf/vocab/dc11.rb +23 -0
- data/lib/rdf/vocab/doap.rb +45 -0
- data/lib/rdf/vocab/exif.rb +168 -0
- data/lib/rdf/vocab/foaf.rb +69 -0
- data/lib/rdf/vocab/geo.rb +13 -0
- data/lib/rdf/vocab/http.rb +26 -0
- data/lib/rdf/vocab/owl.rb +59 -0
- data/lib/rdf/vocab/rdfs.rb +17 -0
- data/lib/rdf/vocab/rsa.rb +12 -0
- data/lib/rdf/vocab/rss.rb +14 -0
- data/lib/rdf/vocab/sioc.rb +93 -0
- data/lib/rdf/vocab/skos.rb +36 -0
- data/lib/rdf/vocab/wot.rb +21 -0
- data/lib/rdf/vocab/xhtml.rb +9 -0
- data/lib/rdf/vocab/xsd.rb +58 -0
- data/lib/rdf/vocab.rb +215 -0
- data/lib/rdf/writer.rb +475 -0
- data/lib/rdf.rb +192 -0
- metadata +173 -0
@@ -0,0 +1,237 @@
|
|
1
|
+
module RDF; class Query
|
2
|
+
##
|
3
|
+
# An RDF basic graph pattern (BGP) query solution sequence.
|
4
|
+
#
|
5
|
+
# @example Filtering solutions using a hash
|
6
|
+
# solutions.filter(:author => RDF::URI("http://ar.to/#self"))
|
7
|
+
# solutions.filter(:author => "Arto Bendiken")
|
8
|
+
# solutions.filter(:author => [RDF::URI("http://ar.to/#self"), "Arto Bendiken"])
|
9
|
+
# solutions.filter(:updated => RDF::Literal(Date.today))
|
10
|
+
#
|
11
|
+
# @example Filtering solutions using a block
|
12
|
+
# solutions.filter { |solution| solution.author.literal? }
|
13
|
+
# solutions.filter { |solution| solution.title =~ /^SPARQL/ }
|
14
|
+
# solutions.filter { |solution| solution.price < 30.5 }
|
15
|
+
# solutions.filter { |solution| solution.bound?(:date) }
|
16
|
+
# solutions.filter { |solution| solution.age.datatype == RDF::XSD.integer }
|
17
|
+
# solutions.filter { |solution| solution.name.language == :es }
|
18
|
+
#
|
19
|
+
# @example Reordering solutions based on a variable or proc
|
20
|
+
# solutions.order_by(:updated)
|
21
|
+
# solutions.order_by(:updated, :created)
|
22
|
+
# solutions.order_by(:updated, lambda {|a, b| b <=> a})
|
23
|
+
#
|
24
|
+
# @example Selecting/Projecting particular variables only
|
25
|
+
# solutions.select(:title)
|
26
|
+
# solutions.select(:title, :description)
|
27
|
+
# solutions.project(:title)
|
28
|
+
#
|
29
|
+
# @example Eliminating duplicate solutions
|
30
|
+
# solutions.distinct
|
31
|
+
#
|
32
|
+
# @example Limiting the number of solutions
|
33
|
+
# solutions.offset(20).limit(10)
|
34
|
+
#
|
35
|
+
# @example Counting the number of matching solutions
|
36
|
+
# solutions.count
|
37
|
+
# solutions.count { |solution| solution.price < 30.5 }
|
38
|
+
#
|
39
|
+
# @example Iterating over all found solutions
|
40
|
+
# solutions.each { |solution| puts solution.inspect }
|
41
|
+
#
|
42
|
+
# @since 0.3.0
|
43
|
+
class Solutions < Array
|
44
|
+
alias_method :each_solution, :each
|
45
|
+
|
46
|
+
##
|
47
|
+
# Returns the number of matching query solutions.
|
48
|
+
#
|
49
|
+
# @overload count
|
50
|
+
# @return [Integer]
|
51
|
+
#
|
52
|
+
# @overload count { |solution| ... }
|
53
|
+
# @yield [solution]
|
54
|
+
# @yieldparam [RDF::Query::Solution] solution
|
55
|
+
# @yieldreturn [Boolean]
|
56
|
+
# @return [Integer]
|
57
|
+
#
|
58
|
+
# @return [Integer]
|
59
|
+
def count(&block)
|
60
|
+
super
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Returns hash of bindings from each solution. Each bound variable will have
|
65
|
+
# an array of bound values representing those from each solution, where a given
|
66
|
+
# solution will have just a single value for each bound variable
|
67
|
+
# @return [Hash{Symbol => Array<RDF::Term>}]
|
68
|
+
def bindings
|
69
|
+
bindings = {}
|
70
|
+
each do |solution|
|
71
|
+
solution.each do |key, value|
|
72
|
+
bindings[key] ||= []
|
73
|
+
bindings[key] << value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
bindings
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Filters this solution sequence by the given `criteria`.
|
81
|
+
#
|
82
|
+
# @param [Hash{Symbol => Object}] criteria
|
83
|
+
# @yield [solution]
|
84
|
+
# @yieldparam [RDF::Query::Solution] solution
|
85
|
+
# @yieldreturn [Boolean]
|
86
|
+
# @return [void] `self`
|
87
|
+
def filter(criteria = {}, &block)
|
88
|
+
if block_given?
|
89
|
+
self.reject! do |solution|
|
90
|
+
!block.call(solution.is_a?(Solution) ? solution : Solution.new(solution))
|
91
|
+
end
|
92
|
+
else
|
93
|
+
self.reject! do |solution|
|
94
|
+
solution = solution.is_a?(Solution) ? solution : Solution.new(solution)
|
95
|
+
results = criteria.map do |name, value|
|
96
|
+
solution[name] == value
|
97
|
+
end
|
98
|
+
!results.all?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
self
|
102
|
+
end
|
103
|
+
alias_method :filter!, :filter
|
104
|
+
|
105
|
+
##
|
106
|
+
# Reorders this solution sequence by the given `variables`.
|
107
|
+
#
|
108
|
+
# Variables may be symbols or {Query::Variable} instances.
|
109
|
+
# A variable may also be a Procedure/Lambda, compatible with {::Enumerable#sort}.
|
110
|
+
# This takes two arguments (solutions) and returns -1, 0, or 1 equivalently to <=>.
|
111
|
+
#
|
112
|
+
# If called with a block, variables are ignored, and the block is invoked with
|
113
|
+
# pairs of solutions. The block is expected to return -1, 0, or 1 equivalently to <=>.
|
114
|
+
#
|
115
|
+
# @param [Array<Proc, Query::Variable, Symbol, #to_sym>] variables
|
116
|
+
# @yield [solution]
|
117
|
+
# @yieldparam [RDF::Query::Solution] q
|
118
|
+
# @yieldparam [RDF::Query::Solution] b
|
119
|
+
# @yieldreturn [Integer] -1, 0, or 1 depending on value of comparator
|
120
|
+
# @return [void] `self`
|
121
|
+
def order(*variables, &block)
|
122
|
+
if variables.empty? && !block_given?
|
123
|
+
raise ArgumentError, "wrong number of arguments (0 for 1)"
|
124
|
+
else
|
125
|
+
self.sort! do |a, b|
|
126
|
+
if block_given?
|
127
|
+
block.call((a.is_a?(Solution) ? a : Solution.new(a)), (b.is_a?(Solution) ? b : Solution.new(b)))
|
128
|
+
else
|
129
|
+
# Try each variable until a difference is found.
|
130
|
+
variables.inject(nil) do |memo, v|
|
131
|
+
memo || begin
|
132
|
+
comp = v.is_a?(Proc) ? v.call(a, b) : (v = v.to_sym; a[v] <=> b[v])
|
133
|
+
comp == 0 ? false : comp
|
134
|
+
end
|
135
|
+
end || 0
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
self
|
140
|
+
end
|
141
|
+
alias_method :order_by, :order
|
142
|
+
|
143
|
+
##
|
144
|
+
# Restricts this solution sequence to the given `variables` only.
|
145
|
+
#
|
146
|
+
# @param [Array<Symbol, #to_sym>] variables
|
147
|
+
# @return [void] `self`
|
148
|
+
def project(*variables)
|
149
|
+
if variables.empty?
|
150
|
+
raise ArgumentError, "wrong number of arguments (0 for 1)"
|
151
|
+
else
|
152
|
+
variables.map!(&:to_sym)
|
153
|
+
self.each do |solution|
|
154
|
+
solution.bindings.delete_if { |k, v| !variables.include?(k.to_sym) }
|
155
|
+
end
|
156
|
+
end
|
157
|
+
self
|
158
|
+
end
|
159
|
+
alias_method :select, :project
|
160
|
+
|
161
|
+
##
|
162
|
+
# Ensures that the solutions in this solution sequence are unique.
|
163
|
+
#
|
164
|
+
# @return [void] `self`
|
165
|
+
def distinct
|
166
|
+
self.uniq!
|
167
|
+
self
|
168
|
+
end
|
169
|
+
alias_method :distinct!, :distinct
|
170
|
+
alias_method :reduced, :distinct
|
171
|
+
alias_method :reduced!, :distinct
|
172
|
+
|
173
|
+
##
|
174
|
+
# Limits this solution sequence to bindings starting from the `start`
|
175
|
+
# offset in the overall solution sequence.
|
176
|
+
#
|
177
|
+
# @param [Integer, #to_i] start
|
178
|
+
# zero or a positive or negative integer
|
179
|
+
# @return [void] `self`
|
180
|
+
def offset(start)
|
181
|
+
case start = start.to_i
|
182
|
+
when 0 then nil
|
183
|
+
else self.slice!(0...start)
|
184
|
+
end
|
185
|
+
self
|
186
|
+
end
|
187
|
+
alias_method :offset!, :offset
|
188
|
+
|
189
|
+
##
|
190
|
+
# Limits the number of solutions in this solution sequence to a maximum
|
191
|
+
# of `length`.
|
192
|
+
#
|
193
|
+
# @param [Integer, #to_i] length
|
194
|
+
# zero or a positive integer
|
195
|
+
# @return [void] `self`
|
196
|
+
# @raise [ArgumentError] if `length` is negative
|
197
|
+
def limit(length)
|
198
|
+
length = length.to_i
|
199
|
+
raise ArgumentError, "expected zero or a positive integer, got #{length}" if length < 0
|
200
|
+
case length
|
201
|
+
when 0 then self.clear
|
202
|
+
else self.slice!(length..-1) if length < self.size
|
203
|
+
end
|
204
|
+
self
|
205
|
+
end
|
206
|
+
alias_method :limit!, :limit
|
207
|
+
|
208
|
+
##
|
209
|
+
# Returns an array of the distinct variable names used in this solution
|
210
|
+
# sequence.
|
211
|
+
#
|
212
|
+
# @return [Array<Symbol>]
|
213
|
+
def variable_names
|
214
|
+
variables = self.inject({}) do |result, solution|
|
215
|
+
solution.each_name do |name|
|
216
|
+
result[name] ||= true
|
217
|
+
end
|
218
|
+
result
|
219
|
+
end
|
220
|
+
variables.keys
|
221
|
+
end
|
222
|
+
|
223
|
+
##
|
224
|
+
# Returns `true` if this solution sequence contains bindings for any of
|
225
|
+
# the given `variables`.
|
226
|
+
#
|
227
|
+
# @param [Array<Symbol, #to_sym>] variables
|
228
|
+
# an array of variables to check
|
229
|
+
# @return [Boolean] `true` or `false`
|
230
|
+
# @see RDF::Query::Solution#has_variables?
|
231
|
+
# @see RDF::Query#execute
|
232
|
+
def have_variables?(variables)
|
233
|
+
self.any? { |solution| solution.has_variables?(variables) }
|
234
|
+
end
|
235
|
+
alias_method :has_variables?, :have_variables?
|
236
|
+
end # Solutions
|
237
|
+
end; end # RDF::Query
|
@@ -0,0 +1,221 @@
|
|
1
|
+
class RDF::Query
|
2
|
+
##
|
3
|
+
# An RDF query variable.
|
4
|
+
#
|
5
|
+
# @example Creating a named unbound variable
|
6
|
+
# var = RDF::Query::Variable.new(:x)
|
7
|
+
# var.unbound? #=> true
|
8
|
+
# var.value #=> nil
|
9
|
+
#
|
10
|
+
# @example Creating an anonymous unbound variable
|
11
|
+
# var = RDF::Query::Variable.new
|
12
|
+
# var.name #=> :g2166151240
|
13
|
+
#
|
14
|
+
# @example Unbound variables match any value
|
15
|
+
# var === 42 #=> true
|
16
|
+
#
|
17
|
+
# @example Creating a bound variable
|
18
|
+
# var = RDF::Query::Variable.new(:y, 123)
|
19
|
+
# var.bound? #=> true
|
20
|
+
# var.value #=> 123
|
21
|
+
#
|
22
|
+
# @example Bound variables match only their actual value
|
23
|
+
# var === 42 #=> false
|
24
|
+
# var === 123 #=> true
|
25
|
+
#
|
26
|
+
# @example Getting the variable name
|
27
|
+
# var.named? #=> true
|
28
|
+
# var.name #=> :y
|
29
|
+
# var.to_sym #=> :y
|
30
|
+
#
|
31
|
+
# @example Rebinding a variable returns the previous value
|
32
|
+
# var.bind!(456) #=> 123
|
33
|
+
# var.value #=> 456
|
34
|
+
#
|
35
|
+
# @example Unbinding a previously bound variable
|
36
|
+
# var.unbind!
|
37
|
+
# var.unbound? #=> true
|
38
|
+
#
|
39
|
+
# @example Getting the string representation of a variable
|
40
|
+
# var = RDF::Query::Variable.new(:x)
|
41
|
+
# var.to_s #=> "?x"
|
42
|
+
# var = RDF::Query::Variable.new(:y, 123)
|
43
|
+
# var.to_s #=> "?y=123"
|
44
|
+
#
|
45
|
+
class Variable
|
46
|
+
include RDF::Term
|
47
|
+
|
48
|
+
##
|
49
|
+
# The variable's name.
|
50
|
+
#
|
51
|
+
# @return [Symbol]
|
52
|
+
attr_accessor :name
|
53
|
+
alias_method :to_sym, :name
|
54
|
+
|
55
|
+
##
|
56
|
+
# The variable's value.
|
57
|
+
#
|
58
|
+
# @return [RDF::Term]
|
59
|
+
attr_accessor :value
|
60
|
+
|
61
|
+
##
|
62
|
+
# @param [Symbol, #to_sym] name
|
63
|
+
# the variable name
|
64
|
+
# @param [RDF::Term] value
|
65
|
+
# an optional variable value
|
66
|
+
def initialize(name = nil, value = nil)
|
67
|
+
@name = (name || "g#{__id__.to_i.abs}").to_sym
|
68
|
+
@value = value
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Returns `true`.
|
73
|
+
#
|
74
|
+
# @return [Boolean]
|
75
|
+
# @see RDF::Term#variable?
|
76
|
+
# @since 0.1.7
|
77
|
+
def variable?
|
78
|
+
true
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Returns `true` if this variable has a name.
|
83
|
+
#
|
84
|
+
# @return [Boolean]
|
85
|
+
def named?
|
86
|
+
true
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# Returns `true` if this variable is bound.
|
91
|
+
#
|
92
|
+
# @return [Boolean]
|
93
|
+
def bound?
|
94
|
+
!unbound?
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# Returns `true` if this variable is unbound.
|
99
|
+
#
|
100
|
+
# @return [Boolean]
|
101
|
+
def unbound?
|
102
|
+
value.nil?
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# Returns `true` if this variable is distinguished.
|
107
|
+
#
|
108
|
+
# @return [Boolean]
|
109
|
+
def distinguished?
|
110
|
+
@distinguished.nil? || @distinguished
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# Sets if variable is distinguished or non-distinguished.
|
115
|
+
# By default, variables are distinguished
|
116
|
+
#
|
117
|
+
# @return [Boolean]
|
118
|
+
def distinguished=(value)
|
119
|
+
@distinguished = value
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# Rebinds this variable to the given `value`.
|
124
|
+
#
|
125
|
+
# @param [RDF::Term] value
|
126
|
+
# @return [RDF::Term] the previous value, if any.
|
127
|
+
def bind(value)
|
128
|
+
old_value = self.value
|
129
|
+
self.value = value
|
130
|
+
old_value
|
131
|
+
end
|
132
|
+
alias_method :bind!, :bind
|
133
|
+
|
134
|
+
##
|
135
|
+
# Unbinds this variable, discarding any currently bound value.
|
136
|
+
#
|
137
|
+
# @return [RDF::Term] the previous value, if any.
|
138
|
+
def unbind
|
139
|
+
old_value = self.value
|
140
|
+
self.value = nil
|
141
|
+
old_value
|
142
|
+
end
|
143
|
+
alias_method :unbind!, :unbind
|
144
|
+
|
145
|
+
##
|
146
|
+
# Returns this variable as `Hash`.
|
147
|
+
#
|
148
|
+
# @return [Hash{Symbol => RDF::Query::Variable}]
|
149
|
+
def variables
|
150
|
+
{name => self}
|
151
|
+
end
|
152
|
+
alias_method :to_hash, :variables
|
153
|
+
|
154
|
+
##
|
155
|
+
# Returns this variable's bindings (if any) as a `Hash`.
|
156
|
+
#
|
157
|
+
# @return [Hash{Symbol => RDF::Term}]
|
158
|
+
def bindings
|
159
|
+
unbound? ? {} : {name => value}
|
160
|
+
end
|
161
|
+
|
162
|
+
##
|
163
|
+
# Returns a hash code for this variable.
|
164
|
+
#
|
165
|
+
# @return [Fixnum]
|
166
|
+
# @since 0.3.0
|
167
|
+
def hash
|
168
|
+
@name.hash
|
169
|
+
end
|
170
|
+
|
171
|
+
##
|
172
|
+
# Returns `true` if this variable is equivalent to a given `other`
|
173
|
+
# variable. Or, to another Term if bound, or to any other Term
|
174
|
+
#
|
175
|
+
# @param [Object] other
|
176
|
+
# @return [Boolean] `true` or `false`
|
177
|
+
# @since 0.3.0
|
178
|
+
def eql?(other)
|
179
|
+
if unbound?
|
180
|
+
other.is_a?(RDF::Term) # match any Term when unbound
|
181
|
+
elsif other.is_a?(RDF::Query::Variable)
|
182
|
+
@name.eql?(other.name)
|
183
|
+
else
|
184
|
+
value.eql?(other)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
alias_method :==, :eql?
|
188
|
+
|
189
|
+
##
|
190
|
+
# Compares this variable with the given value.
|
191
|
+
#
|
192
|
+
# @param [RDF::Term] other
|
193
|
+
# @return [Boolean]
|
194
|
+
def ===(other)
|
195
|
+
if unbound?
|
196
|
+
other.is_a?(RDF::Term) # match any Term when unbound
|
197
|
+
else
|
198
|
+
value === other
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
##
|
203
|
+
# Returns a string representation of this variable.
|
204
|
+
#
|
205
|
+
# Distinguished variables are indicated with a single `?`.
|
206
|
+
#
|
207
|
+
# Non-distinguished variables are indicated with a double `??`
|
208
|
+
#
|
209
|
+
# @example
|
210
|
+
# v = Variable.new("a")
|
211
|
+
# v.to_s => '?a'
|
212
|
+
# v.distinguished = false
|
213
|
+
# v.to_s => '??a'
|
214
|
+
#
|
215
|
+
# @return [String]
|
216
|
+
def to_s
|
217
|
+
prefix = distinguished? ? '?' : "??"
|
218
|
+
unbound? ? "#{prefix}#{name}" : "#{prefix}#{name}=#{value}"
|
219
|
+
end
|
220
|
+
end # Variable
|
221
|
+
end # RDF::Query
|