rdf 3.2.3 → 3.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,91 +9,44 @@ module RDF; class Literal
9
9
  #
10
10
  # @see http://www.w3.org/TR/xmlschema11-2/#time
11
11
  # @since 0.2.1
12
- class Time < Literal
12
+ class Time < Temporal
13
13
  DATATYPE = RDF::URI("http://www.w3.org/2001/XMLSchema#time")
14
14
  GRAMMAR = %r(\A(\d{2}:\d{2}:\d{2}(?:\.\d+)?)((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z).freeze
15
- FORMAT = '%H:%M:%S.%L%:z'.freeze
15
+ FORMAT = '%H:%M:%S.%L'.freeze
16
16
 
17
17
  ##
18
+ # Internally, a `DateTime` is represented using a native `::DateTime`. If initialized from a `::DateTime`, the timezone is taken from that native object, otherwise, a timezone (or no timezone) is taken from the string representation having a matching `zzzzzz` component.
19
+ #
18
20
  # @param [String, DateTime, #to_datetime] value
19
21
  # @param (see Literal#initialize)
20
22
  def initialize(value, datatype: nil, lexical: nil, **options)
21
23
  @datatype = RDF::URI(datatype || self.class.const_get(:DATATYPE))
22
24
  @string = lexical || (value if value.is_a?(String))
23
25
  @object = case
24
- when value.is_a?(::DateTime) then value
25
- when value.respond_to?(:to_datetime) then value.to_datetime rescue ::DateTime.parse(value.to_s)
26
- else ::DateTime.parse(value.to_s)
27
- end rescue ::DateTime.new
28
- end
29
-
30
- ##
31
- # Converts this literal into its canonical lexical representation.
32
- #
33
- # §3.2.8.2 Canonical representation
34
- #
35
- # The canonical representation for time is defined by prohibiting
36
- # certain options from the Lexical representation (§3.2.8.1).
37
- # Specifically, either the time zone must be omitted or, if present, the
38
- # time zone must be Coordinated Universal Time (UTC) indicated by a "Z".
39
- # Additionally, the canonical representation for midnight is 00:00:00.
40
- #
41
- # @return [RDF::Literal] `self`
42
- # @see http://www.w3.org/TR/xmlschema11-2/#time
43
- def canonicalize!
44
- if self.valid?
45
- @string = if timezone?
46
- @object.new_offset.new_offset.strftime(FORMAT[0..-4] + 'Z').sub('.000', '')
26
+ when value.respond_to?(:to_datetime)
27
+ dt = value.to_datetime
28
+ @zone = dt.zone
29
+ # Normalize to 1972-12-31 dateTime base
30
+ hms = dt.strftime(FORMAT)
31
+ ::DateTime.parse("1972-12-31T#{hms}#{@zone}")
47
32
  else
48
- @object.strftime(FORMAT[0..-4]).sub('.000', '')
49
- end
50
- end
51
- self
52
- end
53
-
54
- ##
55
- # Returns the timezone part of arg as a simple literal. Returns the empty string if there is no timezone.
56
- #
57
- # @return [RDF::Literal]
58
- # @see http://www.w3.org/TR/sparql11-query/#func-tz
59
- def tz
60
- zone = timezone? ? object.zone : ""
61
- zone = "Z" if zone == "+00:00"
62
- RDF::Literal(zone)
63
- end
64
-
65
- ##
66
- # Returns `true` if the value adheres to the defined grammar of the
67
- # datatype.
68
- #
69
- # Special case for date and dateTime, for which '0000' is not a valid year
70
- #
71
- # @return [Boolean]
72
- # @since 0.2.1
73
- def valid?
74
- super && !object.nil?
75
- end
76
-
77
- ##
78
- # Does the literal representation include a timezone? Note that this is only possible if initialized using a string, or `:lexical` option.
79
- #
80
- # @return [Boolean]
81
- # @since 1.1.6
82
- def timezone?
83
- md = self.to_s.match(GRAMMAR)
84
- md && !!md[2]
85
- end
86
- alias_method :tz?, :timezone?
87
- alias_method :has_tz?, :timezone?
88
- alias_method :has_timezone?, :timezone?
89
-
90
- ##
91
- # Returns the value as a string.
92
- # Does not normalize timezone
93
- #
94
- # @return [String]
95
- def to_s
96
- @string || @object.strftime(FORMAT).sub("+00:00", 'Z').sub('.000', '')
33
+ md = value.to_s.match(GRAMMAR)
34
+ _, tm, tz = Array(md)
35
+ if tz
36
+ @zone = tz == 'Z' ? '+00:00' : tz
37
+ else
38
+ @zone = nil # No timezone
39
+ end
40
+ # Normalize 24:00:00 to 00:00:00
41
+ hr, mi, se = tm.split(':')
42
+ if hr.to_i > 23
43
+ hr = "%.2i" % (hr.to_i % 24)
44
+ @string = nil
45
+ end
46
+ value = "#{hr}:#{mi}:#{se}"
47
+ # Normalize to 1972-12-31 dateTime base
48
+ ::DateTime.parse("1972-12-31T#{hr}:#{mi}:#{se}#{@zone}")
49
+ end rescue ::DateTime.new
97
50
  end
98
51
 
99
52
  ##
@@ -104,32 +57,10 @@ module RDF; class Literal
104
57
  def humanize(lang = :en)
105
58
  t = object.strftime("%r")
106
59
  if timezone?
107
- t += if self.tz == 'Z'
108
- " UTC"
109
- else
110
- " #{self.tz}"
111
- end
60
+ z = @zone == '+00:00' ? "UTC" : @zone
61
+ t += " #{z}"
112
62
  end
113
63
  t
114
64
  end
115
-
116
- ##
117
- # Equal compares as Time objects
118
- def ==(other)
119
- # If lexically invalid, use regular literal testing
120
- return super unless self.valid?
121
-
122
- case other
123
- when Literal::Time
124
- return super unless other.valid?
125
- # Compare as strings, as time includes a date portion, and adjusting for UTC
126
- # can create a mismatch in the date portion.
127
- self.object.new_offset.strftime('%H%M%S.%L') == other.object.new_offset.strftime('%H%M%S.%L')
128
- when Literal::DateTime, Literal::Date
129
- false
130
- else
131
- super
132
- end
133
- end
134
65
  end # Time
135
66
  end; end # RDF::Literal
@@ -77,6 +77,7 @@ module RDF
77
77
  require 'rdf/model/literal/decimal'
78
78
  require 'rdf/model/literal/integer'
79
79
  require 'rdf/model/literal/double'
80
+ require 'rdf/model/literal/temporal'
80
81
  require 'rdf/model/literal/date'
81
82
  require 'rdf/model/literal/datetime'
82
83
  require 'rdf/model/literal/time'
@@ -295,7 +296,7 @@ module RDF
295
296
  when self.simple? && other.simple?
296
297
  self.value_hash == other.value_hash && self.value == other.value
297
298
  when other.comperable_datatype?(self) || self.comperable_datatype?(other)
298
- # Comoparing plain with undefined datatypes does not generate an error, but returns false
299
+ # Comparing plain with undefined datatypes does not generate an error, but returns false
299
300
  # From data-r2/expr-equal/eq-2-2.
300
301
  false
301
302
  else
@@ -71,6 +71,7 @@ module RDF
71
71
  # @option options [RDF::Term] :graph_name (nil)
72
72
  # Note, in RDF 1.1, a graph name MUST be an {Resource}.
73
73
  # @option options [Boolean] :inferred used as a marker to record that this statement was inferred based on semantic relationships (T-Box).
74
+ # @option options [Boolean] :quoted used as a marker to record that this statement quoted and appears as the subject or object of another RDF::Statement.
74
75
  # @return [RDF::Statement]
75
76
  #
76
77
  # @overload initialize(subject, predicate, object, **options)
@@ -83,6 +84,7 @@ module RDF
83
84
  # @option options [RDF::Term] :graph_name (nil)
84
85
  # Note, in RDF 1.1, a graph name MUST be an {Resource}.
85
86
  # @option options [Boolean] :inferred used as a marker to record that this statement was inferred based on semantic relationships (T-Box).
87
+ # @option options [Boolean] :quoted used as a marker to record that this statement quoted and appears as the subject or object of another RDF::Statement.
86
88
  # @return [RDF::Statement]
87
89
  def initialize(subject = nil, predicate = nil, object = nil, options = {})
88
90
  if subject.is_a?(Hash)
@@ -209,7 +211,7 @@ module RDF
209
211
  ##
210
212
  # @return [Boolean]
211
213
  def quoted?
212
- false
214
+ !!@options[:quoted]
213
215
  end
214
216
 
215
217
  ##
data/lib/rdf/model/uri.rb CHANGED
@@ -112,8 +112,9 @@ module RDF
112
112
  ).freeze
113
113
 
114
114
  # Characters in a PName which must be escaped
115
- PN_ESCAPE_CHARS = /[~\.\-!\$&'\(\)\*\+,;=\/\?\#@%_]/.freeze
116
- PN_ESCAPES = /\\#{PN_ESCAPE_CHARS}/.freeze
115
+ # Note: not all reserved characters need to be escaped in SPARQL/Turtle, but they must be unescaped when encountered
116
+ PN_ESCAPE_CHARS = /[~\.!\$&'\(\)\*\+,;=\/\?\#@%]/.freeze
117
+ PN_ESCAPES = /\\#{Regexp.union(PN_ESCAPE_CHARS, /[\-_]/)}/.freeze
117
118
 
118
119
  ##
119
120
  # Cache size may be set through {RDF.config} using `uri_cache_size`.
@@ -255,7 +255,7 @@ module RDF::NTriples
255
255
  if !match(ST_END)
256
256
  log_error("Expected end of statement (found: #{current_line.inspect})", lineno: lineno, exception: RDF::ReaderError)
257
257
  end
258
- RDF::Statement.new(subject, predicate, object)
258
+ RDF::Statement.new(subject, predicate, object, quoted: true)
259
259
  end
260
260
  end
261
261
 
@@ -317,13 +317,12 @@ class RDF::Query
317
317
  def hash
318
318
  @bindings.hash
319
319
  end
320
-
320
+
321
321
  ##
322
322
  # Equivalence of solution
323
323
  def eql?(other)
324
324
  other.is_a?(Solution) && @bindings.eql?(other.bindings)
325
325
  end
326
- alias_method :==, :eql?
327
326
 
328
327
  ##
329
328
  # Equals of solution
@@ -77,6 +77,15 @@ module RDF; class Query
77
77
  end
78
78
  end
79
79
 
80
+ ##
81
+ # Sets variable names used in these solutions. If not set, the default is determined by the variables used in each solution.
82
+ #
83
+ # @param [Array<Symbol, RDF::Query::Variable>] vars
84
+ # @return [Array<Symbol>]
85
+ def variable_names=(vars)
86
+ @variable_names = vars.map(&:to_sym)
87
+ end
88
+
80
89
  ##
81
90
  # @overload variable?
82
91
  # Returns `false`.
@@ -294,5 +303,17 @@ module RDF; class Query
294
303
  self
295
304
  end
296
305
  alias_method :limit!, :limit
306
+
307
+ ##
308
+ # Equivalence of solution
309
+ def eql?(other)
310
+ super && (!other.respond_to?(:variable_names) || variable_names.eql?(other.variable_names))
311
+ end
312
+
313
+ ##
314
+ # Equals of solution
315
+ def ==(other)
316
+ super && (!other.respond_to?(:variable_names) || variable_names.eql?(other.variable_names))
317
+ end
297
318
  end # Solutions
298
319
  end; end # RDF::Query