rdf 3.2.3 → 3.2.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.
@@ -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