openlogic-rdf 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|