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,373 @@
|
|
1
|
+
module RDF
|
2
|
+
##
|
3
|
+
# An RDF literal.
|
4
|
+
#
|
5
|
+
# Subclasses of {RDF::Literal} should define DATATYPE and GRAMMAR constants, which are used
|
6
|
+
# for identifying the appropriate class to use for a datatype URI and to perform lexical
|
7
|
+
# matching on the value.
|
8
|
+
#
|
9
|
+
# Literal comparison with other {RDF::Value} instances call {RDF::Value#type_error},
|
10
|
+
# which, returns false. Implementations wishing to have {RDF::TypeError} raised
|
11
|
+
# should mix-in {RDF::TypeCheck}. This is required for strict SPARQL conformance.
|
12
|
+
#
|
13
|
+
# Specific typed literals may have behavior different from the default implementation. See
|
14
|
+
# the following defined sub-classes for specific documentation. Additional sub-classes may
|
15
|
+
# be defined, and will interoperate by defining `DATATYPE` and `GRAMMAR` constants, in addition
|
16
|
+
# other required overrides of RDF::Literal behavior.
|
17
|
+
#
|
18
|
+
# * {RDF::Literal::Boolean}
|
19
|
+
# * {RDF::Literal::Date}
|
20
|
+
# * {RDF::Literal::DateTime}
|
21
|
+
# * {RDF::Literal::Decimal}
|
22
|
+
# * {RDF::Literal::Double}
|
23
|
+
# * {RDF::Literal::Integer}
|
24
|
+
# * {RDF::Literal::Time}
|
25
|
+
#
|
26
|
+
# @example Creating a plain literal
|
27
|
+
# value = RDF::Literal.new("Hello, world!")
|
28
|
+
# value.plain? #=> true`
|
29
|
+
#
|
30
|
+
# @example Creating a language-tagged literal (1)
|
31
|
+
# value = RDF::Literal.new("Hello!", :language => :en)
|
32
|
+
# value.has_language? #=> true
|
33
|
+
# value.language #=> :en
|
34
|
+
#
|
35
|
+
# @example Creating a language-tagged literal (2)
|
36
|
+
# RDF::Literal.new("Wazup?", :language => :"en-US")
|
37
|
+
# RDF::Literal.new("Hej!", :language => :sv)
|
38
|
+
# RDF::Literal.new("¡Hola!", :language => :es)
|
39
|
+
#
|
40
|
+
# @example Creating an explicitly datatyped literal
|
41
|
+
# value = RDF::Literal.new("2009-12-31", :datatype => RDF::XSD.date)
|
42
|
+
# value.has_datatype? #=> true
|
43
|
+
# value.datatype #=> RDF::XSD.date
|
44
|
+
#
|
45
|
+
# @example Creating an implicitly datatyped literal
|
46
|
+
# value = RDF::Literal.new(Date.today)
|
47
|
+
# value.has_datatype? #=> true
|
48
|
+
# value.datatype #=> RDF::XSD.date
|
49
|
+
#
|
50
|
+
# @example Creating implicitly datatyped literals
|
51
|
+
# RDF::Literal.new(false).datatype #=> XSD.boolean
|
52
|
+
# RDF::Literal.new(true).datatype #=> XSD.boolean
|
53
|
+
# RDF::Literal.new(123).datatype #=> XSD.integer
|
54
|
+
# RDF::Literal.new(9223372036854775807).datatype #=> XSD.integer
|
55
|
+
# RDF::Literal.new(3.1415).datatype #=> XSD.double
|
56
|
+
# RDF::Literal.new(Time.now).datatype #=> XSD.dateTime
|
57
|
+
# RDF::Literal.new(Date.new(2010)).datatype #=> XSD.date
|
58
|
+
# RDF::Literal.new(DateTime.new(2010)).datatype #=> XSD.dateTime
|
59
|
+
#
|
60
|
+
# @see http://www.w3.org/TR/rdf-concepts/#section-Literals
|
61
|
+
# @see http://www.w3.org/TR/rdf-concepts/#section-Datatypes-intro
|
62
|
+
class Literal
|
63
|
+
|
64
|
+
private
|
65
|
+
@@subclasses = [] # @private
|
66
|
+
|
67
|
+
##
|
68
|
+
# @private
|
69
|
+
# @return [void]
|
70
|
+
def self.inherited(child)
|
71
|
+
@@subclasses << child
|
72
|
+
super
|
73
|
+
end
|
74
|
+
|
75
|
+
public
|
76
|
+
|
77
|
+
require 'rdf/model/literal/numeric'
|
78
|
+
require 'rdf/model/literal/boolean'
|
79
|
+
require 'rdf/model/literal/decimal'
|
80
|
+
require 'rdf/model/literal/integer'
|
81
|
+
require 'rdf/model/literal/double'
|
82
|
+
require 'rdf/model/literal/date'
|
83
|
+
require 'rdf/model/literal/datetime'
|
84
|
+
require 'rdf/model/literal/time'
|
85
|
+
require 'rdf/model/literal/token'
|
86
|
+
require 'rdf/model/literal/xml'
|
87
|
+
|
88
|
+
include RDF::Term
|
89
|
+
|
90
|
+
##
|
91
|
+
# @private
|
92
|
+
# Return datatype class for uri, or nil if none is found
|
93
|
+
def self.datatyped_class(uri)
|
94
|
+
@@subclasses.detect {|klass| klass.const_defined?(:DATATYPE) && klass.const_get(:DATATYPE) == uri}
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# @private
|
99
|
+
def self.new(value, options = {})
|
100
|
+
klass = case
|
101
|
+
when !self.equal?(RDF::Literal)
|
102
|
+
self # subclasses can be directly constructed without type dispatch
|
103
|
+
when typed_literal = datatyped_class(RDF::URI(options[:datatype]))
|
104
|
+
typed_literal
|
105
|
+
else case value
|
106
|
+
when ::TrueClass then RDF::Literal::Boolean
|
107
|
+
when ::FalseClass then RDF::Literal::Boolean
|
108
|
+
when ::Integer then RDF::Literal::Integer
|
109
|
+
when ::Float then RDF::Literal::Double
|
110
|
+
when ::BigDecimal then RDF::Literal::Decimal
|
111
|
+
when ::DateTime then RDF::Literal::DateTime
|
112
|
+
when ::Date then RDF::Literal::Date
|
113
|
+
when ::Time then RDF::Literal::Time # FIXME: Ruby's Time class can represent datetimes as well
|
114
|
+
when ::Symbol then RDF::Literal::Token
|
115
|
+
else self
|
116
|
+
end
|
117
|
+
end
|
118
|
+
literal = klass.allocate
|
119
|
+
literal.send(:initialize, value, options)
|
120
|
+
literal.validate! if options[:validate]
|
121
|
+
literal.canonicalize! if options[:canonicalize]
|
122
|
+
literal
|
123
|
+
end
|
124
|
+
|
125
|
+
TRUE = RDF::Literal.new(true).freeze
|
126
|
+
FALSE = RDF::Literal.new(false).freeze
|
127
|
+
ZERO = RDF::Literal.new(0).freeze
|
128
|
+
|
129
|
+
# @return [Symbol] The language tag (optional).
|
130
|
+
attr_accessor :language
|
131
|
+
|
132
|
+
# @return [URI] The XML Schema datatype URI (optional).
|
133
|
+
attr_accessor :datatype
|
134
|
+
|
135
|
+
##
|
136
|
+
# @param [Object] value
|
137
|
+
# @option options [Symbol] :language (nil)
|
138
|
+
# @option options [URI] :datatype (nil)
|
139
|
+
def initialize(value, options = {})
|
140
|
+
@object = value
|
141
|
+
@string = options[:lexical] if options[:lexical]
|
142
|
+
@string = value if !defined?(@string) && value.is_a?(String)
|
143
|
+
@language = options[:language].to_s.to_sym if options[:language]
|
144
|
+
@datatype = RDF::URI(options[:datatype]) if options[:datatype]
|
145
|
+
@datatype ||= self.class.const_get(:DATATYPE) if self.class.const_defined?(:DATATYPE)
|
146
|
+
end
|
147
|
+
|
148
|
+
##
|
149
|
+
# Returns the value as a string.
|
150
|
+
#
|
151
|
+
# @return [String]
|
152
|
+
def value
|
153
|
+
@string || to_s
|
154
|
+
end
|
155
|
+
|
156
|
+
##
|
157
|
+
# @return [Object]
|
158
|
+
def object
|
159
|
+
defined?(@object) ? @object : value
|
160
|
+
end
|
161
|
+
|
162
|
+
##
|
163
|
+
# Returns `true`.
|
164
|
+
#
|
165
|
+
# @return [Boolean] `true` or `false`
|
166
|
+
def literal?
|
167
|
+
true
|
168
|
+
end
|
169
|
+
|
170
|
+
##
|
171
|
+
# Returns `false`.
|
172
|
+
#
|
173
|
+
# @return [Boolean] `true` or `false`
|
174
|
+
def anonymous?
|
175
|
+
false
|
176
|
+
end
|
177
|
+
|
178
|
+
##
|
179
|
+
# Returns a hash code for this literal.
|
180
|
+
#
|
181
|
+
# @return [Fixnum]
|
182
|
+
def hash
|
183
|
+
to_s.hash
|
184
|
+
end
|
185
|
+
|
186
|
+
##
|
187
|
+
# Determins if `self` is the same term as `other`.
|
188
|
+
#
|
189
|
+
# @example
|
190
|
+
# RDF::Literal(1).eql?(RDF::Literal(1.0)) #=> false
|
191
|
+
#
|
192
|
+
# @param [Object] other
|
193
|
+
# @return [Boolean] `true` or `false`
|
194
|
+
def eql?(other)
|
195
|
+
self.equal?(other) ||
|
196
|
+
(self.class.eql?(other.class) &&
|
197
|
+
self.value.eql?(other.value) &&
|
198
|
+
self.language.to_s.downcase.eql?(other.language.to_s.downcase) &&
|
199
|
+
self.datatype.eql?(other.datatype))
|
200
|
+
end
|
201
|
+
|
202
|
+
##
|
203
|
+
# Returns `true` if this literal is equivalent to `other` (with type check).
|
204
|
+
#
|
205
|
+
# @example
|
206
|
+
# RDF::Literal(1) == RDF::Literal(1.0) #=> true
|
207
|
+
#
|
208
|
+
# @param [Object] other
|
209
|
+
# @return [Boolean] `true` or `false`
|
210
|
+
#
|
211
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#func-RDFterm-equal
|
212
|
+
# @see http://www.w3.org/TR/rdf-concepts/#section-Literal-Equality
|
213
|
+
def ==(other)
|
214
|
+
case other
|
215
|
+
when Literal
|
216
|
+
case
|
217
|
+
when self.eql?(other)
|
218
|
+
true
|
219
|
+
when self.has_language? && self.language.to_s.downcase == other.language.to_s.downcase
|
220
|
+
# Literals with languages can compare if languages are identical
|
221
|
+
self.value == other.value
|
222
|
+
when (self.simple? || self.datatype == XSD.string) && (other.simple? || other.datatype == XSD.string)
|
223
|
+
self.value == other.value
|
224
|
+
when other.comperable_datatype?(self) || self.comperable_datatype?(other)
|
225
|
+
# Comoparing plain with undefined datatypes does not generate an error, but returns false
|
226
|
+
# From data-r2/expr-equal/eq-2-2.
|
227
|
+
false
|
228
|
+
else
|
229
|
+
type_error("unable to determine whether #{self.inspect} and #{other.inspect} are equivalent")
|
230
|
+
end
|
231
|
+
when String
|
232
|
+
self.plain? && self.value.eql?(other)
|
233
|
+
else false
|
234
|
+
end
|
235
|
+
end
|
236
|
+
alias_method :===, :==
|
237
|
+
|
238
|
+
##
|
239
|
+
# Returns `true` if this is a plain literal.
|
240
|
+
#
|
241
|
+
# @return [Boolean] `true` or `false`
|
242
|
+
# @see http://www.w3.org/TR/rdf-concepts/#dfn-plain-literal
|
243
|
+
def plain?
|
244
|
+
language.nil? && datatype.nil?
|
245
|
+
end
|
246
|
+
alias_method :simple?, :plain?
|
247
|
+
|
248
|
+
##
|
249
|
+
# Returns `true` if this is a language-tagged literal.
|
250
|
+
#
|
251
|
+
# @return [Boolean] `true` or `false`
|
252
|
+
# @see http://www.w3.org/TR/rdf-concepts/#dfn-plain-literal
|
253
|
+
def has_language?
|
254
|
+
!language.nil?
|
255
|
+
end
|
256
|
+
alias_method :language?, :has_language?
|
257
|
+
|
258
|
+
##
|
259
|
+
# Returns `true` if this is a datatyped literal.
|
260
|
+
#
|
261
|
+
# @return [Boolean] `true` or `false`
|
262
|
+
# @see http://www.w3.org/TR/rdf-concepts/#dfn-typed-literal
|
263
|
+
def has_datatype?
|
264
|
+
!datatype.nil?
|
265
|
+
end
|
266
|
+
alias_method :datatype?, :has_datatype?
|
267
|
+
alias_method :typed?, :has_datatype?
|
268
|
+
alias_method :datatyped?, :has_datatype?
|
269
|
+
|
270
|
+
##
|
271
|
+
# Returns `true` if the value adheres to the defined grammar of the
|
272
|
+
# datatype.
|
273
|
+
#
|
274
|
+
# @return [Boolean] `true` or `false`
|
275
|
+
# @since 0.2.1
|
276
|
+
def valid?
|
277
|
+
grammar = self.class.const_get(:GRAMMAR) rescue nil
|
278
|
+
grammar.nil? || !!(value =~ grammar)
|
279
|
+
end
|
280
|
+
|
281
|
+
##
|
282
|
+
# Returns `true` if the value does not adhere to the defined grammar of
|
283
|
+
# the datatype.
|
284
|
+
#
|
285
|
+
# @return [Boolean] `true` or `false`
|
286
|
+
# @since 0.2.1
|
287
|
+
def invalid?
|
288
|
+
!valid?
|
289
|
+
end
|
290
|
+
|
291
|
+
##
|
292
|
+
# Returns `true` if the literal has a datatype and the comparison should
|
293
|
+
# return false instead of raise a type error.
|
294
|
+
#
|
295
|
+
# This behavior is intuited from SPARQL data-r2/expr-equal/eq-2-2
|
296
|
+
# @return [Boolean]
|
297
|
+
def comperable_datatype?(other)
|
298
|
+
return false unless self.plain? || self.has_language?
|
299
|
+
|
300
|
+
case other
|
301
|
+
when RDF::Literal::Numeric, RDF::Literal::Boolean,
|
302
|
+
RDF::Literal::Date, RDF::Literal::Time, RDF::Literal::DateTime
|
303
|
+
# Invald types can be compared without raising a TypeError if literal has a language (open-eq-08)
|
304
|
+
!other.valid? && self.has_language?
|
305
|
+
else
|
306
|
+
case other.datatype
|
307
|
+
when XSD.string
|
308
|
+
true
|
309
|
+
when nil
|
310
|
+
# A different language will not generate a type error
|
311
|
+
other.has_language?
|
312
|
+
else
|
313
|
+
# An unknown datatype may not be used for comparison, unless it has a language? (open-eq-8)
|
314
|
+
self.has_language?
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
##
|
320
|
+
# Validates the value using {#valid?}, raising an error if the value is
|
321
|
+
# invalid.
|
322
|
+
#
|
323
|
+
# @return [RDF::Literal] `self`
|
324
|
+
# @raise [ArgumentError] if the value is invalid
|
325
|
+
# @since 0.2.1
|
326
|
+
def validate!
|
327
|
+
raise ArgumentError, "#{to_s.inspect} is not a valid <#{datatype.to_s}> literal" if invalid?
|
328
|
+
self
|
329
|
+
end
|
330
|
+
alias_method :validate, :validate!
|
331
|
+
|
332
|
+
##
|
333
|
+
# Returns a copy of this literal converted into its canonical lexical
|
334
|
+
# representation.
|
335
|
+
#
|
336
|
+
# Subclasses should override `#canonicalize!` as needed and appropriate,
|
337
|
+
# not this method.
|
338
|
+
#
|
339
|
+
# @return [RDF::Literal]
|
340
|
+
# @since 0.2.1
|
341
|
+
def canonicalize
|
342
|
+
self.dup.canonicalize!
|
343
|
+
end
|
344
|
+
|
345
|
+
##
|
346
|
+
# Converts this literal into its canonical lexical representation.
|
347
|
+
#
|
348
|
+
# Subclasses should override this as needed and appropriate.
|
349
|
+
#
|
350
|
+
# @return [RDF::Literal] `self`
|
351
|
+
# @since 0.3.0
|
352
|
+
def canonicalize!
|
353
|
+
@language = @language.to_s.downcase.to_sym if @language
|
354
|
+
self
|
355
|
+
end
|
356
|
+
|
357
|
+
##
|
358
|
+
# Returns the value as a string.
|
359
|
+
#
|
360
|
+
# @return [String]
|
361
|
+
def to_s
|
362
|
+
@object.to_s
|
363
|
+
end
|
364
|
+
|
365
|
+
##
|
366
|
+
# Returns a developer-friendly representation of `self`.
|
367
|
+
#
|
368
|
+
# @return [String]
|
369
|
+
def inspect
|
370
|
+
sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, RDF::NTriples.serialize(self))
|
371
|
+
end
|
372
|
+
end # Literal
|
373
|
+
end # RDF
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module RDF
|
2
|
+
##
|
3
|
+
# An RDF blank node, also known as an anonymous or unlabeled node.
|
4
|
+
#
|
5
|
+
# @example Creating a blank node with an implicit identifier
|
6
|
+
# bnode = RDF::Node.new
|
7
|
+
#
|
8
|
+
# @example Creating a blank node with an UUID identifier
|
9
|
+
# bnode = RDF::Node.uuid
|
10
|
+
# bnode.to_s #=> "_:504c0a30-0d11-012d-3f50-001b63cac539"
|
11
|
+
#
|
12
|
+
class Node
|
13
|
+
include RDF::Resource
|
14
|
+
|
15
|
+
##
|
16
|
+
# Returns a blank node with a random UUID-based identifier.
|
17
|
+
#
|
18
|
+
# @param [Hash{Symbol => Object}] options
|
19
|
+
# @option options [Regexp] :grammar (nil)
|
20
|
+
# a grammar specification that the generated UUID must match
|
21
|
+
# @return [RDF::Node]
|
22
|
+
def self.uuid(options = {})
|
23
|
+
case
|
24
|
+
when options[:grammar]
|
25
|
+
# The UUID is generated such that its initial part is guaranteed
|
26
|
+
# to match the given `grammar`, e.g. `/^[A-Za-z][A-Za-z0-9]*/`.
|
27
|
+
# Some RDF storage systems (e.g. AllegroGraph) require this.
|
28
|
+
# @see http://github.com/bendiken/rdf/pull/43
|
29
|
+
uuid = RDF::Util::UUID.generate(options) until uuid =~ options[:grammar]
|
30
|
+
else
|
31
|
+
uuid = RDF::Util::UUID.generate(options)
|
32
|
+
end
|
33
|
+
self.new(uuid)
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Alias for `RDF::Node.new`, at the moment.
|
38
|
+
#
|
39
|
+
# @private
|
40
|
+
# @param [#to_s] id
|
41
|
+
# @return [RDF::Node]
|
42
|
+
# @since 0.2.0
|
43
|
+
def self.intern(id)
|
44
|
+
self.new(id)
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Override #dup to remember original object.
|
49
|
+
# This allows .eql? to determine that two nodes
|
50
|
+
# are the same thing, and not different nodes
|
51
|
+
# instantiated with the same identifier.
|
52
|
+
# @return [RDF::Node]
|
53
|
+
def dup
|
54
|
+
node = super
|
55
|
+
node.original = self.original || self
|
56
|
+
node
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Originally instantiated node, if any
|
61
|
+
# @return [RDF::Node]
|
62
|
+
attr_accessor :original
|
63
|
+
|
64
|
+
# @return [String]
|
65
|
+
attr_accessor :id
|
66
|
+
|
67
|
+
##
|
68
|
+
# @param [#to_s] id
|
69
|
+
def initialize(id = nil)
|
70
|
+
@id = (id || "g#{__id__.to_i.abs}").to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Returns `true`.
|
75
|
+
#
|
76
|
+
# @return [Boolean]
|
77
|
+
def node?
|
78
|
+
true
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Returns `true`.
|
83
|
+
#
|
84
|
+
# @return [Boolean]
|
85
|
+
def anonymous?
|
86
|
+
true
|
87
|
+
end
|
88
|
+
|
89
|
+
alias_method :unlabeled?, :anonymous?
|
90
|
+
|
91
|
+
##
|
92
|
+
# Returns `false`.
|
93
|
+
#
|
94
|
+
# @return [Boolean]
|
95
|
+
def labeled?
|
96
|
+
!unlabeled?
|
97
|
+
end
|
98
|
+
|
99
|
+
##
|
100
|
+
# Returns a hash code for this blank node.
|
101
|
+
#
|
102
|
+
# @return [Fixnum]
|
103
|
+
def hash
|
104
|
+
@id.hash
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Determins if `self` is the same term as `other`.
|
109
|
+
#
|
110
|
+
# In this case, nodes must be the same object
|
111
|
+
#
|
112
|
+
# @param [Node] other
|
113
|
+
# @return [Boolean]
|
114
|
+
def eql?(other)
|
115
|
+
other.is_a?(RDF::Node) && (self.original || self).equal?(other.original || other)
|
116
|
+
end
|
117
|
+
|
118
|
+
##
|
119
|
+
# Checks whether this blank node is equal to `other` (type checking).
|
120
|
+
#
|
121
|
+
# In this case, different nodes having the same id are considered the same.
|
122
|
+
#
|
123
|
+
# Per SPARQL data-r2/expr-equal/eq-2-2, numeric can't be compared with other types
|
124
|
+
#
|
125
|
+
# @param [Object] other
|
126
|
+
# @return [Boolean]
|
127
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#func-RDFterm-equal
|
128
|
+
def ==(other)
|
129
|
+
case other
|
130
|
+
when Literal
|
131
|
+
# If other is a Literal, reverse test to consolodate complex type checking logic
|
132
|
+
other == self
|
133
|
+
else
|
134
|
+
other.respond_to?(:node?) && other.node? && other.respond_to?(:id) && @id == other.id
|
135
|
+
end
|
136
|
+
end
|
137
|
+
alias_method :===, :==
|
138
|
+
|
139
|
+
##
|
140
|
+
# Returns a string representation of this blank node.
|
141
|
+
#
|
142
|
+
# @return [String]
|
143
|
+
def to_s
|
144
|
+
"_:%s" % @id.to_s
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Returns a symbol representation of this blank node.
|
149
|
+
#
|
150
|
+
# @return [Symbol]
|
151
|
+
# @since 0.2.0
|
152
|
+
def to_sym
|
153
|
+
@id.to_s.to_sym
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module RDF
|
2
|
+
##
|
3
|
+
# An RDF resource.
|
4
|
+
module Resource
|
5
|
+
include RDF::Term
|
6
|
+
|
7
|
+
##
|
8
|
+
# Instantiates an {RDF::Node} or an {RDF::URI}, depending on the given
|
9
|
+
# argument.
|
10
|
+
#
|
11
|
+
# @return [RDF::Resource]
|
12
|
+
def self.new(*args, &block)
|
13
|
+
case arg = args.shift
|
14
|
+
when Symbol then Node.intern(arg, *args, &block)
|
15
|
+
when /^_:(.*)$/ then Node.new($1, *args, &block)
|
16
|
+
else URI.new(arg, *args, &block)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Returns `true` to indicate that this value is a resource.
|
22
|
+
#
|
23
|
+
# @return [Boolean]
|
24
|
+
def resource?
|
25
|
+
true
|
26
|
+
end
|
27
|
+
end # Resource
|
28
|
+
end # RDF
|