rdf 3.2.2 → 3.2.5
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.
- checksums.yaml +4 -4
- data/README.md +37 -37
- data/VERSION +1 -1
- data/lib/rdf/mixin/countable.rb +5 -1
- data/lib/rdf/mixin/enumerable.rb +13 -1
- data/lib/rdf/mixin/queryable.rb +13 -1
- data/lib/rdf/model/list.rb +1 -1
- data/lib/rdf/model/literal/date.rb +27 -82
- data/lib/rdf/model/literal/datetime.rb +22 -122
- data/lib/rdf/model/literal/decimal.rb +12 -0
- data/lib/rdf/model/literal/double.rb +20 -0
- data/lib/rdf/model/literal/integer.rb +6 -0
- data/lib/rdf/model/literal/numeric.rb +154 -4
- data/lib/rdf/model/literal/temporal.rb +310 -0
- data/lib/rdf/model/literal/time.rb +26 -98
- data/lib/rdf/model/literal.rb +2 -1
- data/lib/rdf/model/statement.rb +3 -1
- data/lib/rdf/model/uri.rb +24 -3
- data/lib/rdf/ntriples/reader.rb +1 -1
- data/lib/rdf/vocab/owl.rb +450 -445
- data/lib/rdf/vocab/rdfs.rb +89 -88
- data/lib/rdf/vocab/writer.rb +84 -51
- data/lib/rdf/vocab/xsd.rb +249 -249
- data/lib/rdf/vocabulary.rb +142 -132
- data/lib/rdf.rb +0 -3
- metadata +11 -5
- data/lib/rdf/mixin/enumerator.rb +0 -40
@@ -9,91 +9,41 @@ 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 <
|
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
|
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.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
+
hr = "%.2i" % (hr.to_i % 24) if hr.to_i > 23
|
43
|
+
value = "#{hr}:#{mi}:#{se}"
|
44
|
+
# Normalize to 1972-12-31 dateTime base
|
45
|
+
::DateTime.parse("1972-12-31T#{hr}:#{mi}:#{se}#{@zone}")
|
46
|
+
end rescue ::DateTime.new
|
97
47
|
end
|
98
48
|
|
99
49
|
##
|
@@ -104,32 +54,10 @@ module RDF; class Literal
|
|
104
54
|
def humanize(lang = :en)
|
105
55
|
t = object.strftime("%r")
|
106
56
|
if timezone?
|
107
|
-
|
108
|
-
|
109
|
-
else
|
110
|
-
" #{self.tz}"
|
111
|
-
end
|
57
|
+
z = @zone == '+00:00' ? "UTC" : @zone
|
58
|
+
t += " #{z}"
|
112
59
|
end
|
113
60
|
t
|
114
61
|
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
62
|
end # Time
|
135
63
|
end; end # RDF::Literal
|
data/lib/rdf/model/literal.rb
CHANGED
@@ -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
|
-
#
|
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
|
data/lib/rdf/model/statement.rb
CHANGED
@@ -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
|
-
|
214
|
+
!!@options[:quoted]
|
213
215
|
end
|
214
216
|
|
215
217
|
##
|
data/lib/rdf/model/uri.rb
CHANGED
@@ -111,6 +111,11 @@ module RDF
|
|
111
111
|
tag tel turn turns tv urn javascript
|
112
112
|
).freeze
|
113
113
|
|
114
|
+
# Characters in a PName which must be escaped
|
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
|
118
|
+
|
114
119
|
##
|
115
120
|
# Cache size may be set through {RDF.config} using `uri_cache_size`.
|
116
121
|
#
|
@@ -627,10 +632,14 @@ module RDF
|
|
627
632
|
# RDF::URI('http://www.w3.org/2000/01/rdf-schema#').qname #=> [:rdfs, nil]
|
628
633
|
# RDF::URI('http://www.w3.org/2000/01/rdf-schema#label').qname #=> [:rdfs, :label]
|
629
634
|
# RDF::RDFS.label.qname #=> [:rdfs, :label]
|
635
|
+
# RDF::Vocab::DC.title.qname(
|
636
|
+
# prefixes: {dcterms: 'http://purl.org/dc/terms/'}) #=> [:dcterms, :title]
|
637
|
+
#
|
638
|
+
# @note within this software, the term QName is used to describe the tuple of prefix and suffix for a given IRI, where the prefix identifies some defined vocabulary. This somewhat contrasts with the notion of a [Qualified Name](https://www.w3.org/TR/2006/REC-xml-names11-20060816/#ns-qualnames) from XML, which are a subset of Prefixed Names.
|
630
639
|
#
|
631
640
|
# @param [Hash{Symbol => String}] prefixes
|
632
641
|
# Explicit set of prefixes to look for matches, defaults to loaded vocabularies.
|
633
|
-
# @return [Array(Symbol, Symbol)] or `nil` if no QName found
|
642
|
+
# @return [Array(Symbol, Symbol)] or `nil` if no QName found. The suffix component will not have [reserved characters](https://www.w3.org/TR/turtle/#reserved) escaped.
|
634
643
|
def qname(prefixes: nil)
|
635
644
|
if prefixes
|
636
645
|
prefixes.each do |prefix, uri|
|
@@ -659,13 +668,25 @@ module RDF
|
|
659
668
|
end
|
660
669
|
|
661
670
|
##
|
662
|
-
# Returns a
|
671
|
+
# Returns a Prefixed Name (PName) or the full IRI with any [reserved characters](https://www.w3.org/TR/turtle/#reserved) in the suffix escaped.
|
672
|
+
#
|
673
|
+
# @example Using a custom prefix for creating a PNname.
|
674
|
+
# RDF::URI('http://purl.org/dc/terms/creator').
|
675
|
+
# pname(prefixes: {dcterms: 'http://purl.org/dc/terms/'})
|
676
|
+
# #=> "dcterms:creator"
|
663
677
|
#
|
664
678
|
# @param [Hash{Symbol => String}] prefixes
|
665
679
|
# Explicit set of prefixes to look for matches, defaults to loaded vocabularies.
|
666
680
|
# @return [String] or `nil`
|
681
|
+
# @see #qname
|
682
|
+
# @see https://www.w3.org/TR/rdf-sparql-query/#prefNames
|
667
683
|
def pname(prefixes: nil)
|
668
|
-
|
684
|
+
q = self.qname(prefixes: prefixes)
|
685
|
+
return self.to_s unless q
|
686
|
+
prefix, suffix = q
|
687
|
+
suffix = suffix.to_s.gsub(PN_ESCAPE_CHARS) {|c| "\\#{c}"} if
|
688
|
+
suffix.to_s.match?(PN_ESCAPE_CHARS)
|
689
|
+
[prefix, suffix].join(":")
|
669
690
|
end
|
670
691
|
|
671
692
|
##
|
data/lib/rdf/ntriples/reader.rb
CHANGED
@@ -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
|
|