rdf 1.0.10.2 → 1.1.0.p0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +8 -8
  2. data/CREDITS +0 -2
  3. data/README +67 -20
  4. data/VERSION +1 -1
  5. data/etc/doap.nt +75 -75
  6. data/lib/rdf.rb +15 -64
  7. data/lib/rdf/format.rb +11 -20
  8. data/lib/rdf/mixin/countable.rb +4 -11
  9. data/lib/rdf/mixin/enumerable.rb +4 -8
  10. data/lib/rdf/mixin/mutable.rb +1 -4
  11. data/lib/rdf/mixin/queryable.rb +13 -60
  12. data/lib/rdf/model/graph.rb +46 -22
  13. data/lib/rdf/model/list.rb +27 -102
  14. data/lib/rdf/model/literal.rb +48 -100
  15. data/lib/rdf/model/literal/date.rb +1 -1
  16. data/lib/rdf/model/literal/datetime.rb +1 -35
  17. data/lib/rdf/model/literal/decimal.rb +0 -30
  18. data/lib/rdf/model/literal/double.rb +6 -14
  19. data/lib/rdf/model/literal/integer.rb +3 -11
  20. data/lib/rdf/model/literal/numeric.rb +0 -40
  21. data/lib/rdf/model/literal/time.rb +4 -3
  22. data/lib/rdf/model/node.rb +1 -3
  23. data/lib/rdf/model/statement.rb +7 -47
  24. data/lib/rdf/model/term.rb +9 -0
  25. data/lib/rdf/model/uri.rb +28 -68
  26. data/lib/rdf/model/value.rb +1 -31
  27. data/lib/rdf/nquads.rb +4 -7
  28. data/lib/rdf/ntriples.rb +2 -2
  29. data/lib/rdf/ntriples/format.rb +1 -2
  30. data/lib/rdf/ntriples/reader.rb +15 -68
  31. data/lib/rdf/ntriples/writer.rb +13 -53
  32. data/lib/rdf/query.rb +1 -8
  33. data/lib/rdf/query/pattern.rb +25 -7
  34. data/lib/rdf/query/solution.rb +3 -19
  35. data/lib/rdf/query/solutions.rb +4 -22
  36. data/lib/rdf/query/variable.rb +1 -3
  37. data/lib/rdf/reader.rb +8 -22
  38. data/lib/rdf/repository.rb +23 -5
  39. data/lib/rdf/transaction.rb +19 -8
  40. data/lib/rdf/util/aliasing.rb +3 -13
  41. data/lib/rdf/util/cache.rb +2 -3
  42. data/lib/rdf/util/file.rb +5 -15
  43. data/lib/rdf/vocab.rb +19 -20
  44. data/lib/rdf/writer.rb +5 -44
  45. metadata +12 -27
  46. data/lib/rdf/vocab/schema.rb +0 -652
@@ -1,20 +1,14 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module RDF
3
2
  ##
4
3
  # An RDF literal.
5
4
  #
6
- # Subclasses of {RDF::Literal} should define DATATYPE and GRAMMAR constants, which are used
7
- # for identifying the appropriate class to use for a datatype URI and to perform lexical
8
- # matching on the value.
5
+ # Subclasses of {RDF::Literal} should define DATATYPE and GRAMMAR constants, which are used for identifying the appropriate class to use for a datatype URI and to perform lexical matching on the value.
9
6
  #
10
- # Literal comparison with other {RDF::Value} instances call {RDF::Value#type_error},
11
- # which, returns false. Implementations wishing to have {RDF::TypeError} raised
12
- # should mix-in {RDF::TypeCheck}. This is required for strict SPARQL conformance.
7
+ # Literal comparison with other {RDF::Value} instances call {RDF::Value#type_error}, which, returns false. Implementations wishing to have {RDF::TypeError} raised should mix-in {RDF::TypeCheck}. This is required for strict SPARQL conformance.
13
8
  #
14
- # Specific typed literals may have behavior different from the default implementation. See
15
- # the following defined sub-classes for specific documentation. Additional sub-classes may
16
- # be defined, and will interoperate by defining `DATATYPE` and `GRAMMAR` constants, in addition
17
- # other required overrides of RDF::Literal behavior.
9
+ # Specific typed literals may have behavior different from the default implementation. See the following defined sub-classes for specific documentation. Additional sub-classes may be defined, and will interoperate by defining `DATATYPE` and `GRAMMAR` constants, in addition other required overrides of RDF::Literal behavior.
10
+ #
11
+ # In RDF 1.1, all literals are typed, including plain literals and language tagged literals. Internally, plain literals are given the `xsd:string` datatype and language tagged literals are given the `rdf:langString` datatype. Creating a plain literal, without a datatype or language, will automatically provide the `xsd:string` datatype; similar for language tagged literals. Note that most serialization formats will remove this datatype. Code which depends on a literal having the `xsd:string` datatype being different from a plain literal (formally, without a datatype) may break. However note that the `#has\_datatype?` will continue to return `false` for plain or language-tagged literals.
18
12
  #
19
13
  # * {RDF::Literal::Boolean}
20
14
  # * {RDF::Literal::Date}
@@ -54,24 +48,22 @@ module RDF
54
48
  # RDF::Literal.new(123).datatype #=> XSD.integer
55
49
  # RDF::Literal.new(9223372036854775807).datatype #=> XSD.integer
56
50
  # RDF::Literal.new(3.1415).datatype #=> XSD.double
57
- # RDF::Literal.new(Time.now).datatype #=> XSD.time
51
+ # RDF::Literal.new(Time.now).datatype #=> XSD.dateTime
58
52
  # RDF::Literal.new(Date.new(2010)).datatype #=> XSD.date
59
53
  # RDF::Literal.new(DateTime.new(2010)).datatype #=> XSD.dateTime
60
54
  #
61
- # @see http://www.w3.org/TR/rdf-concepts/#section-Literals
62
- # @see http://www.w3.org/TR/rdf-concepts/#section-Datatypes-intro
55
+ # @see http://www.w3.org/TR/rdf11-concepts/#section-Graph-Literal
56
+ # @see http://www.w3.org/TR/rdf11-concepts/#section-Datatypes
63
57
  class Literal
64
58
 
65
59
  private
66
60
  @@subclasses = [] # @private
67
- @@datatype_map = nil # @private
68
61
 
69
62
  ##
70
63
  # @private
71
64
  # @return [void]
72
65
  def self.inherited(child)
73
66
  @@subclasses << child
74
- @@datatype_map = nil
75
67
  super
76
68
  end
77
69
 
@@ -90,33 +82,20 @@ module RDF
90
82
 
91
83
  include RDF::Term
92
84
 
93
- ##
94
- # @private
95
- # Return Hash mapping from datatype URI to class
96
- def self.datatype_map
97
- @@datatype_map ||= Hash[
98
- @@subclasses
99
- .select {|klass| klass.const_defined?(:DATATYPE)}
100
- .map {|klass| [klass.const_get(:DATATYPE).to_s, klass]}
101
- ]
102
- end
103
-
104
85
  ##
105
86
  # @private
106
87
  # Return datatype class for uri, or nil if none is found
107
88
  def self.datatyped_class(uri)
108
- datatype_map[uri]
89
+ @@subclasses.detect {|klass| klass.const_defined?(:DATATYPE) && klass.const_get(:DATATYPE) == uri}
109
90
  end
110
91
 
111
92
  ##
112
93
  # @private
113
94
  def self.new(value, options = {})
114
- raise ArgumentError, "datatype with language" if options[:language] && (options[:datatype] || RDF.langString).to_s != RDF.langString.to_s
115
-
116
95
  klass = case
117
96
  when !self.equal?(RDF::Literal)
118
97
  self # subclasses can be directly constructed without type dispatch
119
- when typed_literal = datatyped_class(options[:datatype].to_s)
98
+ when typed_literal = datatyped_class(RDF::URI(options[:datatype]))
120
99
  typed_literal
121
100
  else case value
122
101
  when ::TrueClass then RDF::Literal::Boolean
@@ -138,9 +117,9 @@ module RDF
138
117
  literal
139
118
  end
140
119
 
141
- TRUE = RDF::Literal.new(true)
142
- FALSE = RDF::Literal.new(false)
143
- ZERO = RDF::Literal.new(0)
120
+ TRUE = RDF::Literal.new(true).freeze
121
+ FALSE = RDF::Literal.new(false).freeze
122
+ ZERO = RDF::Literal.new(0).freeze
144
123
 
145
124
  # @return [Symbol] The language tag (optional).
146
125
  attr_accessor :language
@@ -149,32 +128,25 @@ module RDF
149
128
  attr_accessor :datatype
150
129
 
151
130
  ##
131
+ # Literals without a datatype are given either xsd:string or rdf:langString
132
+ # depending on if there is language
133
+ #
152
134
  # @param [Object] value
153
- # @option options [Symbol] :language (nil)
154
- # @option options [String] :lexical (nil)
155
- # Supplied lexical representation of this literal,
156
- # otherwise it comes from transforming `value` to a string form
157
- # See {#to_s}.
158
- # @option options [URI] :datatype (nil)
159
- # @option options [Boolean] :validate (false)
160
- # @option options [Boolean] :canonicalize (false)
135
+ # @option options [Symbol] :language (nil)
136
+ # @option options [URI] :datatype (nil)
161
137
  # @raise [ArgumentError]
162
138
  # if there is a language and datatype is no rdf:langString
163
- # or datatype is rdf:langString and there is no language
164
139
  # @see http://www.w3.org/TR/rdf11-concepts/#section-Graph-Literal
165
140
  # @see http://www.w3.org/TR/rdf11-concepts/#section-Datatypes
166
141
  def initialize(value, options = {})
167
142
  @object = value
168
143
  @string = options[:lexical] if options[:lexical]
169
144
  @string = value if !defined?(@string) && value.is_a?(String)
170
- @string = @string.encode(Encoding::UTF_8) if @string && @string.respond_to?(:encode)
171
- @object = @string if @string && @object.is_a?(String)
172
145
  @language = options[:language].to_s.to_sym if options[:language]
173
146
  @datatype = RDF::URI(options[:datatype]) if options[:datatype]
174
147
  @datatype ||= self.class.const_get(:DATATYPE) if self.class.const_defined?(:DATATYPE)
175
-
176
- # Ignore rdf:langString if there is a language
177
- @datatype = nil if @language && @datatype == RDF.langString
148
+ @datatype ||= @language ? RDF.langString : RDF::XSD.string
149
+ raise ArgumentError, "datatype with language must be rdf:langString" if @language && @datatype != RDF::langString
178
150
  raise ArgumentError, "datatype of rdf:langString requires a language" if !@language && @datatype == RDF::langString
179
151
  end
180
152
 
@@ -213,24 +185,7 @@ module RDF
213
185
  #
214
186
  # @return [Fixnum]
215
187
  def hash
216
- @hash ||= to_s.hash
217
- end
218
-
219
-
220
- ##
221
- # Returns a hash code for the value.
222
- #
223
- # @return [Fixnum]
224
- def value_hash
225
- @value_hash ||= value.hash
226
- end
227
-
228
- ##
229
- # @private
230
- def freeze
231
- hash.freeze
232
- value_hash.freeze
233
- super
188
+ to_s.hash
234
189
  end
235
190
 
236
191
  ##
@@ -268,46 +223,32 @@ module RDF
268
223
  true
269
224
  when self.has_language? && self.language.to_s.downcase == other.language.to_s.downcase
270
225
  # Literals with languages can compare if languages are identical
271
- self.value_hash == other.value_hash && self.value == other.value
272
- when (self.simple? || self.datatype == XSD.string) && (other.simple? || other.datatype == XSD.string)
273
- self.value_hash == other.value_hash && self.value == other.value
226
+ self.value == other.value
227
+ when self.simple? && other.simple?
228
+ self.value == other.value
274
229
  when other.comperable_datatype?(self) || self.comperable_datatype?(other)
275
- # Comoparing plain with undefined datatypes does not generate an error, but returns false
230
+ # Comparing plain with undefined datatypes does not generate an error, but returns false
276
231
  # From data-r2/expr-equal/eq-2-2.
277
232
  false
278
233
  else
279
234
  type_error("unable to determine whether #{self.inspect} and #{other.inspect} are equivalent")
280
235
  end
281
236
  when String
282
- self.simple? && self.value.eql?(other)
237
+ self.plain? && self.value.eql?(other)
283
238
  else false
284
239
  end
285
240
  end
286
241
  alias_method :===, :==
287
242
 
288
243
  ##
289
- # Returns `true` if this is a plain literal. A plain literal
290
- # may have a language, but may not have a datatype. For
291
- # all practical purposes, this includes xsd:string literals
292
- # too.
244
+ # Returns `true` if this is a plain literal.
293
245
  #
294
246
  # @return [Boolean] `true` or `false`
295
247
  # @see http://www.w3.org/TR/rdf-concepts/#dfn-plain-literal
296
248
  def plain?
297
- has_language? ?
298
- (datatype || RDF.langString) == RDF.langString :
299
- (datatype || XSD.string) == XSD.string
300
- end
301
-
302
- ##
303
- # Returns `true` if this is a simple literal.
304
- # A simple literal has no datatype or language.
305
- #
306
- # @return [Boolean] `true` or `false`
307
- # @see http://www.w3.org/TR/sparql11-query/#simple_literal
308
- def simple?
309
- !has_language? && !has_datatype?
249
+ datatype == RDF::XSD.string
310
250
  end
251
+ alias_method :simple?, :plain?
311
252
 
312
253
  ##
313
254
  # Returns `true` if this is a language-tagged literal.
@@ -315,17 +256,19 @@ module RDF
315
256
  # @return [Boolean] `true` or `false`
316
257
  # @see http://www.w3.org/TR/rdf-concepts/#dfn-plain-literal
317
258
  def has_language?
318
- !language.nil?
259
+ datatype == RDF.langString
319
260
  end
320
261
  alias_method :language?, :has_language?
321
262
 
322
263
  ##
323
264
  # Returns `true` if this is a datatyped literal.
324
265
  #
266
+ # For historical reasons, this excludes xsd:string and rdf:langString
267
+ #
325
268
  # @return [Boolean] `true` or `false`
326
269
  # @see http://www.w3.org/TR/rdf-concepts/#dfn-typed-literal
327
270
  def has_datatype?
328
- !datatype.nil?
271
+ !plain? && !language?
329
272
  end
330
273
  alias_method :datatype?, :has_datatype?
331
274
  alias_method :typed?, :has_datatype?
@@ -369,19 +312,24 @@ module RDF
369
312
  # Invald types can be compared without raising a TypeError if literal has a language (open-eq-08)
370
313
  !other.valid? && self.has_language?
371
314
  else
372
- case other.datatype
373
- when XSD.string
374
- true
375
- when nil
376
- # A different language will not generate a type error
377
- other.has_language?
378
- else
379
- # An unknown datatype may not be used for comparison, unless it has a language? (open-eq-8)
380
- self.has_language?
381
- end
315
+ # An unknown datatype may not be used for comparison, unless it has a language? (open-eq-8)
316
+ self.has_language?
382
317
  end
383
318
  end
384
319
 
320
+ ##
321
+ # Returns a copy of this literal converted into its canonical lexical
322
+ # representation.
323
+ #
324
+ # Subclasses should override `#canonicalize!` as needed and appropriate,
325
+ # not this method.
326
+ #
327
+ # @return [RDF::Literal]
328
+ # @since 0.2.1
329
+ def canonicalize
330
+ self.dup.canonicalize!
331
+ end
332
+
385
333
  ##
386
334
  # Converts this literal into its canonical lexical representation.
387
335
  #
@@ -18,7 +18,7 @@ module RDF; class Literal
18
18
  @string ||= value if value.is_a?(String)
19
19
  @object = case
20
20
  when value.is_a?(::Date) then value
21
- when value.respond_to?(:to_date) then value.to_date # Ruby 1.9+
21
+ when value.respond_to?(:to_date) then value.to_date
22
22
  else ::Date.parse(value.to_s)
23
23
  end rescue nil
24
24
  end
@@ -15,12 +15,9 @@ module RDF; class Literal
15
15
  @datatype = RDF::URI(options[:datatype] || self.class.const_get(:DATATYPE))
16
16
  @string = options[:lexical] if options.has_key?(:lexical)
17
17
  @string ||= value if value.is_a?(String)
18
- @has_timezone = @string.nil? || if md = @string.match(GRAMMAR)
19
- !!md[2] # If lexical value contains timezone
20
- end
21
18
  @object = case
22
19
  when value.is_a?(::DateTime) then value
23
- when value.respond_to?(:to_datetime) then value.to_datetime # Ruby 1.9+
20
+ when value.respond_to?(:to_datetime) then value.to_datetime
24
21
  else ::DateTime.parse(value.to_s)
25
22
  end rescue nil
26
23
  end
@@ -36,35 +33,6 @@ module RDF; class Literal
36
33
  self
37
34
  end
38
35
 
39
- ##
40
- # Returns the timezone part of arg as a simple literal. Returns the empty string if there is no timezone.
41
- #
42
- # @return [RDF::Literal]
43
- # @see http://www.w3.org/TR/sparql11-query/#func-tz
44
- def tz
45
- zone = @has_timezone ? object.zone : ""
46
- zone = "Z" if zone == "+00:00"
47
- RDF::Literal(zone)
48
- end
49
-
50
- ##
51
- # Returns the timezone part of arg as an xsd:dayTimeDuration, or `nil`
52
- # if lexical form of literal does not include a timezone.
53
- #
54
- # @return [RDF::Literal]
55
- def timezone
56
- if tz == 'Z'
57
- RDF::Literal("PT0S", :datatype => RDF::XSD.dayTimeDuration)
58
- elsif md = tz.to_s.match(/^([+-])?(\d+):(\d+)?$/)
59
- plus_minus, hour, min = md[1,3]
60
- plus_minus = nil unless plus_minus == "-"
61
- hour = hour.to_i
62
- min = min.to_i
63
- res = "#{plus_minus}PT#{hour}H#{"#{min}M" if min > 0}"
64
- RDF::Literal(res, :datatype => RDF::XSD.dayTimeDuration)
65
- end
66
- end
67
-
68
36
  ##
69
37
  # Returns `true` if the value adheres to the defined grammar of the
70
38
  # datatype.
@@ -77,8 +45,6 @@ module RDF; class Literal
77
45
  super && object && value !~ %r(\A0000)
78
46
  end
79
47
 
80
- ##
81
- # Returns the `timezone` of the literal. If the
82
48
  ##
83
49
  # Returns the value as a string.
84
50
  #
@@ -56,36 +56,6 @@ module RDF; class Literal
56
56
  (d = to_d) && d > 0 ? self : RDF::Literal(d.abs)
57
57
  end
58
58
 
59
- ##
60
- # Returns the number with no fractional part that is closest to the argument. If there are two such numbers, then the one that is closest to positive infinity is returned. An error is raised if arg is not a numeric value.
61
- #
62
- # @return [RDF::Literal]
63
- def round
64
- self.class.new(to_d.round)
65
- end
66
-
67
- ##
68
- # Returns the smallest integer greater than or equal to `self`.
69
- #
70
- # @example
71
- # RDF::Literal(1).ceil #=> RDF::Literal(1)
72
- #
73
- # @return [RDF::Literal]
74
- def ceil
75
- self.class.new(to_d.ceil)
76
- end
77
-
78
- ##
79
- # Returns the largest integer less than or equal to `self`.
80
- #
81
- # @example
82
- # RDF::Literal(1).floor #=> RDF::Literal(1)
83
- #
84
- # @return [RDF::Literal]
85
- def floor
86
- self.class.new(to_d.floor)
87
- end
88
-
89
59
  ##
90
60
  # Returns `true` if the value is zero.
91
61
  #
@@ -50,7 +50,7 @@ module RDF; class Literal
50
50
  i, f, e = ('%.15E' % @object.to_f).split(/[\.E]/)
51
51
  f.sub!(/0*$/, '') # remove any trailing zeroes
52
52
  f = '0' if f.empty? # ...but there must be a digit to the right of the decimal point
53
- e.sub!(/^(?:\+|(\-))?0+(\d+)$/, '\1\2') # remove the optional leading '+' sign and any extra leading zeroes
53
+ e.sub!(/^\+?0+(\d)$/, '\1') # remove the optional leading '+' sign and any extra leading zeroes
54
54
  "#{i}.#{f}E#{e}"
55
55
  end
56
56
  @object = Float(@string) unless @object.nil?
@@ -118,7 +118,7 @@ module RDF; class Literal
118
118
  end
119
119
 
120
120
  ##
121
- # Returns the smallest number greater than or equal to `self`.
121
+ # Returns the smallest integer greater than or equal to `self`.
122
122
  #
123
123
  # @example
124
124
  # RDF::Literal(1.2).ceil #=> RDF::Literal(2)
@@ -129,11 +129,11 @@ module RDF; class Literal
129
129
  # @return [RDF::Literal]
130
130
  # @since 0.2.3
131
131
  def ceil
132
- self.class.new(to_f.ceil)
132
+ RDF::Literal(to_f.ceil)
133
133
  end
134
134
 
135
135
  ##
136
- # Returns the largest number less than or equal to `self`.
136
+ # Returns the largest integer less than or equal to `self`.
137
137
  #
138
138
  # @example
139
139
  # RDF::Literal(1.2).floor #=> RDF::Literal(1)
@@ -144,7 +144,7 @@ module RDF; class Literal
144
144
  # @return [RDF::Literal]
145
145
  # @since 0.2.3
146
146
  def floor
147
- self.class.new(to_f.floor)
147
+ RDF::Literal(to_f.floor)
148
148
  end
149
149
 
150
150
  ##
@@ -153,15 +153,7 @@ module RDF; class Literal
153
153
  # @return [RDF::Literal]
154
154
  # @since 0.2.3
155
155
  def abs
156
- (f = to_f) && f > 0 ? self : self.class.new(f.abs)
157
- end
158
-
159
- ##
160
- # Returns the number with no fractional part that is closest to the argument. If there are two such numbers, then the one that is closest to positive infinity is returned. An error is raised if arg is not a numeric value.
161
- #
162
- # @return [RDF::Literal]
163
- def round
164
- self.class.new(to_f.round)
156
+ (f = to_f) && f > 0 ? self : RDF::Literal(f.abs)
165
157
  end
166
158
 
167
159
  ##
@@ -41,7 +41,7 @@ module RDF; class Literal
41
41
  end
42
42
 
43
43
  ##
44
- # Returns the predecessor value of `self`.
44
+ # Returns the successor value of `self`.
45
45
  #
46
46
  # @return [RDF::Literal]
47
47
  # @since 0.2.3
@@ -50,7 +50,7 @@ module RDF; class Literal
50
50
  end
51
51
 
52
52
  ##
53
- # Returns the successor value of `self`.
53
+ # Returns the predecessor value of `self`.
54
54
  #
55
55
  # @return [RDF::Literal]
56
56
  # @since 0.2.3
@@ -83,15 +83,7 @@ module RDF; class Literal
83
83
  # @return [RDF::Literal]
84
84
  # @since 0.2.3
85
85
  def abs
86
- (n = to_i) && n > 0 ? self : self.class.new(n.abs)
87
- end
88
-
89
- ##
90
- # Returns `self`.
91
- #
92
- # @return [RDF::Literal]
93
- def round
94
- self
86
+ (n = to_i) && n > 0 ? self : RDF::Literal(n.abs)
95
87
  end
96
88
 
97
89
  ##