rdf-xsd 3.2.0 → 3.2.1
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 +19 -15
- data/VERSION +1 -1
- data/lib/rdf/xsd/date.rb +6 -6
- data/lib/rdf/xsd/duration.rb +341 -114
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a344fd7adc4bd8ca84e939dcf26daf656c19e5f60d04b2026ed18393b07a6d9
|
4
|
+
data.tar.gz: fd035fb32fb4719ebcc72f7a133d64c690d20c9f8a8276b18d801625317119b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 303a3003b754327c637caf02ca34c27fc52e50b25302dee1f2cf0d2f820d61e431814c92a5e6af4b9af8511de699f5f841c789a1719dbbe0f36a1a3c96db29ce
|
7
|
+
data.tar.gz: 63cf8178d9118864fc09b26539e95a33062309e10de38eed5b1f0c769d7bd6be47eca8a51d77e77d2faf2545bcd7e032f020a6e326400c804941d0ebc7b0f34f
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# Extended XSD Datatypes for RDF.rb
|
1
|
+
# Extended XSD Datatypes and XQuery functions for RDF.rb
|
2
2
|
|
3
|
-
This gem adds additional RDF::Literal subclasses for extended [XSD datatypes][]
|
3
|
+
This gem adds additional RDF::Literal subclasses for extended [XSD datatypes][] along with methods implementing many [XPath and XQuery Functions][]
|
4
4
|
|
5
5
|
[](https://badge.fury.io/rb/rdf-xsd)
|
6
6
|
[](https://github.com/ruby-rdf/rdf-xsd/actions?query=workflow%3ACI)
|
@@ -11,10 +11,10 @@ This gem adds additional RDF::Literal subclasses for extended [XSD datatypes][]
|
|
11
11
|
|
12
12
|
* Additional xsd:integer subtypes
|
13
13
|
* xsd:float based on xsd:double
|
14
|
-
* xsd:duration
|
14
|
+
* xsd:duration, xsd:yearMonthDuration, and xsd:dayTimeDuration.
|
15
15
|
* rdf:XMLLiteral
|
16
16
|
* XML Exclusive Canonicalization (Nokogiri & REXML)
|
17
|
-
* XML Literal
|
17
|
+
* XML Literal comparisons (EquivalentXml, ActiveSupport or String)
|
18
18
|
|
19
19
|
## Examples
|
20
20
|
|
@@ -29,25 +29,27 @@ This gem adds additional RDF::Literal subclasses for extended [XSD datatypes][]
|
|
29
29
|
* Soft dependency on [ActiveSupport](https://rubygems.org/gems/activesupport) (~> 6.2)
|
30
30
|
|
31
31
|
## Documentation
|
32
|
-
Full documentation available on [
|
32
|
+
Full documentation available on [GitHub][XSD doc]
|
33
33
|
|
34
34
|
### Principle Classes
|
35
35
|
* {RDF::Literal::Base64Binary}
|
36
36
|
* {RDF::Literal::Duration}
|
37
|
+
* {RDF::Literal::YearMonthDuration}
|
38
|
+
* {RDF::Literal::DayTimeDuration}
|
37
39
|
* {RDF::Literal::Float}
|
38
40
|
* {RDF::Literal::HexBinary}
|
39
41
|
* {RDF::Literal::NonPositiveInteger}
|
40
|
-
|
42
|
+
* {RDF::Literal::NegativeInteger}
|
41
43
|
* {RDF::Literal::Long}
|
42
|
-
|
43
|
-
|
44
|
-
|
44
|
+
* {RDF::Literal::Int}
|
45
|
+
* {RDF::Literal::Short}
|
46
|
+
* {RDF::Literal::Byte}
|
45
47
|
* {RDF::Literal::NonNegativeInteger}
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
* {RDF::Literal::PositiveInteger}
|
49
|
+
* {RDF::Literal::UnsignedLong}
|
50
|
+
* {RDF::Literal::UnsignedInt}
|
51
|
+
* {RDF::Literal::UnsignedShort}
|
52
|
+
* {RDF::Literal::UnsignedByte}
|
51
53
|
* {RDF::Literal::YearMonth}
|
52
54
|
* {RDF::Literal::Year}
|
53
55
|
* {RDF::Literal::MonthDay}
|
@@ -100,4 +102,6 @@ Portions of tests are derived from [W3C DAWG tests](https://www.w3.org/2001/sw/D
|
|
100
102
|
[YARD-GS]: https://rubydoc.info/docs/yard/file/docs/GettingStarted.md
|
101
103
|
[PDD]: https://unlicense.org/#unlicensing-contributions
|
102
104
|
[Backports]: https://rubygems.org/gems/backports
|
103
|
-
[XSD Datatypes]: https://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#built-in-datatypes
|
105
|
+
[XSD Datatypes]: https://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#built-in-datatypes
|
106
|
+
[XPath and XQuery Functions]: https://www.w3.org/TR/xpath-functions/
|
107
|
+
[XSD Doc]: https://ruby-rdf.github.io/rdf-xsd
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.2.
|
1
|
+
3.2.1
|
data/lib/rdf/xsd/date.rb
CHANGED
@@ -11,7 +11,7 @@ module RDF; class Literal
|
|
11
11
|
class DateTimeStamp < RDF::Literal::DateTime
|
12
12
|
DATATYPE = RDF::XSD.dateTimeStamp
|
13
13
|
GRAMMAR = %r(\A(-?\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?)((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)\Z).freeze
|
14
|
-
FORMAT = '%Y-%m-%dT%H:%M:%
|
14
|
+
FORMAT = '%Y-%m-%dT%H:%M:%S'.freeze
|
15
15
|
end
|
16
16
|
|
17
17
|
##
|
@@ -24,7 +24,7 @@ module RDF; class Literal
|
|
24
24
|
class YearMonth < RDF::Literal::Date
|
25
25
|
DATATYPE = RDF::XSD.gYearMonth
|
26
26
|
GRAMMAR = %r(\A(-?\d{4,}-\d{2})((?:[\+\-]\d{2}:\d{2})|UTC|Z)?\Z).freeze
|
27
|
-
FORMAT = '%Y-%m
|
27
|
+
FORMAT = '%Y-%m'.freeze
|
28
28
|
|
29
29
|
def initialize(value, datatype: nil, lexical: nil, **options)
|
30
30
|
@string = lexical || value.to_s
|
@@ -42,7 +42,7 @@ module RDF; class Literal
|
|
42
42
|
class Year < RDF::Literal::Date
|
43
43
|
DATATYPE = RDF::XSD.gYear
|
44
44
|
GRAMMAR = %r(\A(-?\d{4,})((?:[\+\-]\d{2}:\d{2})|UTC|Z)?\Z).freeze
|
45
|
-
FORMAT = '%Y
|
45
|
+
FORMAT = '%Y'.freeze
|
46
46
|
|
47
47
|
def initialize(value, datatype: nil, lexical: nil, **options)
|
48
48
|
@string = lexical || value.to_s
|
@@ -60,7 +60,7 @@ module RDF; class Literal
|
|
60
60
|
class MonthDay < RDF::Literal::Date
|
61
61
|
DATATYPE = RDF::XSD.gMonthDay
|
62
62
|
GRAMMAR = %r(\A--(\d{2}-\d{2})((?:[\+\-]\d{2}:\d{2})|UTC|Z)?\Z).freeze
|
63
|
-
FORMAT = '%m-%d
|
63
|
+
FORMAT = '%m-%d'.freeze
|
64
64
|
|
65
65
|
def initialize(value, datatype: nil, lexical: nil, **options)
|
66
66
|
@string = lexical || value.to_s
|
@@ -78,7 +78,7 @@ module RDF; class Literal
|
|
78
78
|
class Day < RDF::Literal::Date
|
79
79
|
DATATYPE = RDF::XSD.gDay
|
80
80
|
GRAMMAR = %r(\A---(\d{2})((?:[\+\-]\d{2}:\d{2})|UTC|Z)?\Z).freeze
|
81
|
-
FORMAT = '%d
|
81
|
+
FORMAT = '%d'.freeze
|
82
82
|
|
83
83
|
def initialize(value, datatype: nil, lexical: nil, **options)
|
84
84
|
@string = lexical || value.to_s
|
@@ -95,7 +95,7 @@ module RDF; class Literal
|
|
95
95
|
class Month < RDF::Literal::Date
|
96
96
|
DATATYPE = RDF::XSD.gMonth
|
97
97
|
GRAMMAR = %r(\A--(\d{2})((?:[\+\-]\d{2}:\d{2})|UTC|Z)?\Z).freeze
|
98
|
-
FORMAT = '%m
|
98
|
+
FORMAT = '%m'.freeze
|
99
99
|
|
100
100
|
def initialize(value, datatype: nil, lexical: nil, **options)
|
101
101
|
@string = lexical || value.to_s
|
data/lib/rdf/xsd/duration.rb
CHANGED
@@ -5,6 +5,8 @@ module RDF; class Literal
|
|
5
5
|
##
|
6
6
|
# A duration literal.
|
7
7
|
#
|
8
|
+
# `duration` is a datatype that represents durations of time. The concept of duration being captured is drawn from those of [ISO 8601](https://www.w3.org/TR/xmlschema11-2/#ISO8601), specifically durations without fixed endpoints.
|
9
|
+
#
|
8
10
|
# @see https://www.w3.org/TR/xmlschema11-2/#duration
|
9
11
|
class Duration < Literal
|
10
12
|
DATATYPE = RDF::XSD.duration
|
@@ -14,12 +16,12 @@ module RDF; class Literal
|
|
14
16
|
| (?:(?:(?<mo>\d+)M)(?:(?<da>\d+)D)?)
|
15
17
|
| (?:(?<da>\d+)D)
|
16
18
|
)
|
17
|
-
(?:T(?:(?:(?:(?<hr>\d+)H)(?:(?<mi>\d+)M)?(?<se>\d+(?:\.\d+)?S)?)
|
19
|
+
(?:T(?:(?:(?:(?<hr>\d+)H)(?:(?<mi>\d+)M)?(?:(?<se>\d+(?:\.\d+)?)S)?)
|
18
20
|
| (?:(?:(?<mi>\d+)M)(?:(?<se>\d+(?:\.\d+)?)S)?)
|
19
21
|
| (?:(?<se>\d+(?:\.\d+)?)S)
|
20
22
|
)
|
21
23
|
)?
|
22
|
-
|(?:T(?:(?:(?:(?<hr>\d+)H)(?:(?<mi>\d+)M)?(?<se>\d+(?:\.\d+)?S)?)
|
24
|
+
|(?:T(?:(?:(?:(?<hr>\d+)H)(?:(?<mi>\d+)M)?(?:(?<se>\d+(?:\.\d+)?)S)?)
|
23
25
|
| (?:(?:(?<mi>\d+)M)(?:(?<se>\d+(?:\.\d+)?)S)?)
|
24
26
|
| (?:(?<se>\d+(?:\.\d+)?)S)
|
25
27
|
)
|
@@ -28,66 +30,59 @@ module RDF; class Literal
|
|
28
30
|
\z)x.freeze
|
29
31
|
|
30
32
|
##
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# *
|
34
|
-
#
|
35
|
-
#
|
33
|
+
# Creates a new Duration instance.
|
34
|
+
#
|
35
|
+
# * Given a `String`, parse as `xsd:duration` into months and seconds
|
36
|
+
# * Given a `Hash` containing any of `:yr`, `:mo`, :da`, `:hr`, `:mi` and `:si`, it is transformed into months and seconds
|
37
|
+
# * Given a Rational, the result is interpreted as days, hours, minutes, and seconds.
|
38
|
+
# * Given an Integer, the result is interpreted as years and months.
|
39
|
+
# * Object representation is the `Array(months, seconds)`
|
40
|
+
#
|
41
|
+
# @param [Literal::Duration, Hash, Array, Literal::Numeric, #to_s] value
|
42
|
+
# If provided an Array, it is the same as the object form of this literal, an array of two integers, the first of which may be negative.
|
43
|
+
# @param [String] lexical (nil)
|
44
|
+
# Supplied lexical representation of this literal,
|
45
|
+
# otherwise it comes from transforming `value` to a string form..
|
46
|
+
# @param [URI] datatype (nil)
|
47
|
+
# @param [Hash{Symbol => Object}] options other options passed to `RDF::Literal#initialize`.
|
48
|
+
# @option options [Boolean] :validate (false)
|
49
|
+
# @option options [Boolean] :canonicalize (false)
|
36
50
|
def initialize(value, datatype: nil, lexical: nil, **options)
|
37
51
|
super
|
38
52
|
@object = case value
|
39
53
|
when Hash
|
40
|
-
|
41
|
-
value[:
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
months = value[:yr].to_i * 12 + value[:mo].to_i
|
55
|
+
seconds = value[:da].to_i * 3600 * 24 +
|
56
|
+
value[:hr].to_i * 3600 +
|
57
|
+
value[:mi].to_i * 60 +
|
58
|
+
value[:se].to_f
|
59
|
+
|
60
|
+
if value[:si]
|
61
|
+
if months != 0
|
62
|
+
months = -months
|
63
|
+
else
|
64
|
+
seconds = -seconds
|
65
|
+
end
|
66
|
+
end
|
67
|
+
[months, seconds]
|
68
|
+
when Rational
|
69
|
+
[0, value * 24 * 3600]
|
70
|
+
when Integer, ::Integer
|
71
|
+
[value.to_i, 0]
|
72
|
+
when Literal::Duration then value.object
|
73
|
+
when Array then value
|
74
|
+
else parse(value.to_s)
|
53
75
|
end
|
54
76
|
end
|
55
77
|
|
56
78
|
##
|
57
79
|
# Converts this literal into its canonical lexical representation.
|
58
80
|
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
# @return [RDF::Literal] `self`
|
81
|
+
# @return [Literal] `self`
|
62
82
|
# @see https://www.w3.org/TR/xmlschema11-2/#dateTime
|
63
83
|
def canonicalize!
|
64
|
-
@string = @humanize = nil
|
65
|
-
|
66
|
-
m_r = (@object[:se].to_f / 60) - 1
|
67
|
-
@object[:se] -= m_r * 60
|
68
|
-
@object[:mi] = @object[:mi].to_i + m_r
|
69
|
-
end
|
70
|
-
if @object[:mi].to_i > 60
|
71
|
-
h_r = (@object[:mi].to_i / 60) - 1
|
72
|
-
@object[:mi] -= h_r * 60
|
73
|
-
@object[:hr] = @object[:hr].to_i + h_r
|
74
|
-
end
|
75
|
-
if @object[:hr].to_i > 24
|
76
|
-
d_r = (@object[:hr].to_i / 24) - 1
|
77
|
-
@object[:hr] -= d_r * 24
|
78
|
-
@object[:da] = @object[:da].to_i + d_r
|
79
|
-
end
|
80
|
-
if @object[:da].to_i > 30
|
81
|
-
m_r = (@object[:da].to_i / 30) - 1
|
82
|
-
@object[:da] -= m_r * 30
|
83
|
-
@object[:mo] = @object[:mo].to_i + m_r
|
84
|
-
end
|
85
|
-
if @object[:mo].to_i > 12
|
86
|
-
y_r = (@object[:mo].to_i / 12) - 1
|
87
|
-
@object[:mo] -= y_r * 12
|
88
|
-
@object[:yr] = @object[:yr].to_i + y_r
|
89
|
-
end
|
90
|
-
@object.to_s # side-effect
|
84
|
+
@string = @humanize = @hash = nil
|
85
|
+
self.to_s # side-effect
|
91
86
|
self
|
92
87
|
end
|
93
88
|
|
@@ -99,7 +94,23 @@ module RDF; class Literal
|
|
99
94
|
#
|
100
95
|
# @return [Boolean]
|
101
96
|
def valid?
|
102
|
-
!!(
|
97
|
+
!!value.match?(self.class.const_get(:GRAMMAR))
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# Returns a hash representation.
|
102
|
+
#
|
103
|
+
# @return [Hash]
|
104
|
+
def to_h
|
105
|
+
@hash ||= {
|
106
|
+
si: ('-' if (@object.first == 0 ? @object.last : @object.first) < 0),
|
107
|
+
yr: (@object.first.abs / 12),
|
108
|
+
mo: (@object.first.abs % 12),
|
109
|
+
da: (@object.last.abs.to_i / (3600 * 24)),
|
110
|
+
hr: ((@object.last.abs.to_i / 3600) % 24),
|
111
|
+
mi: ((@object.last.abs.to_i / 60) % 60),
|
112
|
+
se: sec_str.to_f
|
113
|
+
}
|
103
114
|
end
|
104
115
|
|
105
116
|
##
|
@@ -108,14 +119,22 @@ module RDF; class Literal
|
|
108
119
|
# @return [String]
|
109
120
|
def to_s
|
110
121
|
@string ||= begin
|
111
|
-
|
112
|
-
str
|
113
|
-
|
114
|
-
str << "%
|
115
|
-
str << "
|
116
|
-
str << "%
|
117
|
-
str << "
|
118
|
-
str << "
|
122
|
+
hash = to_h
|
123
|
+
str = (@object.first == 0 ? @object.last : @object.first) < 0 ? '-P' : 'P'
|
124
|
+
hash = to_h
|
125
|
+
str << "%dY" % hash[:yr] if hash[:yr] > 0
|
126
|
+
str << "%dM" % hash[:mo] if hash[:mo] > 0
|
127
|
+
str << "%dD" % hash[:da] if hash[:da] > 0
|
128
|
+
str << "T" if (hash[:hr] + hash[:mi] + hash[:se]) > 0
|
129
|
+
str << "%dH" % hash[:hr] if hash[:hr] > 0
|
130
|
+
str << "%dM" % hash[:mi] if hash[:mi] > 0
|
131
|
+
str << sec_str + 'S' if hash[:se] > 0
|
132
|
+
# Ensure some legal representation
|
133
|
+
if str.end_with?('P')
|
134
|
+
is_a?(Literal::YearMonthDuration) ? 'P0M' : 'PT0S'
|
135
|
+
else
|
136
|
+
str
|
137
|
+
end
|
119
138
|
end
|
120
139
|
end
|
121
140
|
|
@@ -129,57 +148,85 @@ module RDF; class Literal
|
|
129
148
|
@humanize ||= {}
|
130
149
|
@humanize[lang] ||= begin
|
131
150
|
# Just english, for now
|
151
|
+
return "Invalid duration #{value.to_s.inspect}" unless valid?
|
152
|
+
|
153
|
+
md = value.match(GRAMMAR)
|
132
154
|
ar = []
|
133
|
-
ar << plural(
|
134
|
-
ar << plural(
|
135
|
-
ar << plural(
|
136
|
-
ar << plural(
|
137
|
-
ar << plural(
|
138
|
-
ar << plural(
|
139
|
-
ar = ar.compact
|
155
|
+
ar << plural(md[:yr], "year") if md[:yr]
|
156
|
+
ar << plural(md[:mo], "month") if md[:mo]
|
157
|
+
ar << plural(md[:da], "day") if md[:da]
|
158
|
+
ar << plural(md[:hr], "hour") if md[:hr]
|
159
|
+
ar << plural(md[:mi], "minute") if md[:mi]
|
160
|
+
ar << plural(md[:se], "second") if md[:se]
|
140
161
|
last = ar.pop
|
141
162
|
first = ar.join(" ")
|
142
163
|
res = first.empty? ? last : "#{first} and #{last}"
|
143
|
-
|
164
|
+
md[:si] == '-' ? "#{res} ago" : res
|
144
165
|
end
|
145
166
|
end
|
146
167
|
|
147
168
|
##
|
148
|
-
#
|
169
|
+
# Returns `true` if `self` and `other` are durations of the same length.
|
170
|
+
#
|
171
|
+
# From the XQuery function [op:duration-equal](https://www.w3.org/TR/xpath-functions/#func-duration-equal).
|
172
|
+
#
|
173
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-duration-equal
|
149
174
|
def ==(other)
|
150
175
|
# If lexically invalid, use regular literal testing
|
151
176
|
return super unless self.valid?
|
152
177
|
|
153
|
-
|
154
|
-
when Duration
|
155
|
-
return super unless other.valid?
|
156
|
-
self.to_f == other.to_f
|
157
|
-
when String
|
158
|
-
self.to_s(:xml) == other
|
159
|
-
when Numeric
|
160
|
-
self.to_f == other
|
161
|
-
when Literal::DateTime, Literal::Time, Literal::Date
|
162
|
-
false
|
163
|
-
else
|
164
|
-
super
|
165
|
-
end
|
178
|
+
other.is_a?(Literal::Duration) && other.valid? ? @object == other.object : super
|
166
179
|
end
|
167
180
|
|
168
|
-
#
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
@object[:se].to_f
|
176
|
-
) * (@object[:si] == '-' ? -1 : 1)
|
177
|
-
end
|
181
|
+
# Years
|
182
|
+
#
|
183
|
+
# From the XQuery function [fn:years-from-duration](https://www.w3.org/TR/xpath-functions/#func-years-from-duration).
|
184
|
+
#
|
185
|
+
# @return [Integer]
|
186
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-years-from-duration
|
187
|
+
def years; Integer.new(to_h[:yr] * (to_h[:si] ? -1 : 1)); end
|
178
188
|
|
189
|
+
# Months
|
190
|
+
#
|
191
|
+
# From the XQuery function [fn:months-from-duration](https://www.w3.org/TR/xpath-functions/#func-months-from-duration).
|
192
|
+
#
|
179
193
|
# @return [Integer]
|
180
|
-
|
181
|
-
|
182
|
-
|
194
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-months-from-duration
|
195
|
+
def months; Integer.new(to_h[:mo] * (to_h[:si] ? -1 : 1)); end
|
196
|
+
|
197
|
+
# Days
|
198
|
+
#
|
199
|
+
# From the XQuery function [fn:days-from-duration](https://www.w3.org/TR/xpath-functions/#func-days-from-duration).
|
200
|
+
#
|
201
|
+
# @return [Integer]
|
202
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-days-from-duration
|
203
|
+
def days; Integer.new(to_h[:da] * (to_h[:si] ? -1 : 1)); end
|
204
|
+
|
205
|
+
# Hours
|
206
|
+
#
|
207
|
+
# From the XQuery function [fn:hours-from-duration](https://www.w3.org/TR/xpath-functions/#func-hours-from-duration).
|
208
|
+
#
|
209
|
+
# @return [Integer]
|
210
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-hours-from-duration
|
211
|
+
def hours; Integer.new(to_h[:hr] * (to_h[:si] ? -1 : 1)); end
|
212
|
+
|
213
|
+
# Minutes
|
214
|
+
#
|
215
|
+
# From the XQuery function [fn:minutes-from-duration](https://www.w3.org/TR/xpath-functions/#func-minutes-from-duration).
|
216
|
+
#
|
217
|
+
# @return [Integer]
|
218
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-minutes-from-duration
|
219
|
+
def minutes; Integer.new(to_h[:mi] * (to_h[:si] ? -1 : 1)); end
|
220
|
+
|
221
|
+
# Seconds
|
222
|
+
#
|
223
|
+
# From the XQuery function [fn:seconds-from-duration](https://www.w3.org/TR/xpath-functions/#func-seconds-from-duration).
|
224
|
+
#
|
225
|
+
# @return [Decimal]
|
226
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-seconds-from-duration
|
227
|
+
def seconds; Decimal.new(to_h[:se] * (to_h[:si] ? -1 : 1)); end
|
228
|
+
|
229
|
+
private
|
183
230
|
# Reverse convert from XSD version of duration
|
184
231
|
# XSD allows -P1111Y22M33DT44H55M66.666S with any combination in regular order
|
185
232
|
# We assume 1M == 30D, but are out of spec in this regard
|
@@ -188,22 +235,137 @@ module RDF; class Literal
|
|
188
235
|
# @param [String] value XSD formatted duration
|
189
236
|
# @return [Duration]
|
190
237
|
def parse(value)
|
191
|
-
value.to_s.match(GRAMMAR)
|
238
|
+
return [0, 0] unless md = value.to_s.match(GRAMMAR)
|
239
|
+
|
240
|
+
months = md[:yr].to_i * 12 + md[:mo].to_i
|
241
|
+
seconds = md[:da].to_i * 3600 * 24 +
|
242
|
+
md[:hr].to_i * 3600 +
|
243
|
+
md[:mi].to_i * 60 +
|
244
|
+
md[:se].to_f
|
245
|
+
|
246
|
+
if md[:si]
|
247
|
+
if months != 0
|
248
|
+
months = -months
|
249
|
+
else
|
250
|
+
seconds = -seconds
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
[months, seconds]
|
192
255
|
end
|
193
256
|
|
194
257
|
def sec_str
|
195
|
-
sec = @object
|
258
|
+
sec = @object.last.abs % 60
|
196
259
|
((sec.truncate == sec ? "%d" : "%2.3f") % sec).sub(/(\.[1-9]+)0+$/, '\1')
|
197
260
|
end
|
198
261
|
end # Duration
|
199
262
|
|
263
|
+
##
|
264
|
+
# A `YearMonthDuration` literal.
|
265
|
+
#
|
266
|
+
# `yearMonthDuration` is a datatype ·derived· from `xsd:duration` by restricting its ·lexical representations· to instances of `yearMonthDurationLexicalRep`. The ·value space· of `yearMonthDuration` is therefore that of `duration` restricted to those whose ·seconds· property is 0. This results in a `duration` datatype which is totally ordered.
|
267
|
+
#
|
268
|
+
# @see https://www.w3.org/TR/xmlschema11-2/#yearMonthDuration
|
269
|
+
class YearMonthDuration < Duration
|
270
|
+
DATATYPE = RDF::XSD.yearMonthDuration
|
271
|
+
GRAMMAR = %r(\A
|
272
|
+
(?<si>-)?
|
273
|
+
P(?:(?:(?:(?:(?<yr>\d+)Y)(?:(?<mo>\d+)M)?)
|
274
|
+
| (?:(?:(?<mo>\d+)M))
|
275
|
+
)
|
276
|
+
)
|
277
|
+
\z)x.freeze
|
278
|
+
|
279
|
+
##
|
280
|
+
# Returns the sum of two xs:yearMonthDuration values.
|
281
|
+
#
|
282
|
+
# From the XQuery function [op:add-yearMonthDurations](https://www.w3.org/TR/xpath-functions/#func-add-yearMonthDurations).
|
283
|
+
#
|
284
|
+
# @param [YearMonthDuration] other
|
285
|
+
# @return [YearMonthDuration]
|
286
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-add-yearMonthDurations
|
287
|
+
def +(other)
|
288
|
+
return type_error("#{other.inspect} is not a valid YearMonthDuration") unless other.is_a?(Literal::YearMonthDuration) && other.valid?
|
289
|
+
self.class.new([object.first + other.object.first, 0])
|
290
|
+
end
|
291
|
+
|
292
|
+
##
|
293
|
+
# Returns the result of subtracting one xs:yearMonthDuration value from another.
|
294
|
+
#
|
295
|
+
# From the XQuery function [op:subtract-yearMonthDurations](https://www.w3.org/TR/xpath-functions/#func-subtract-yearMonthDurations).
|
296
|
+
#
|
297
|
+
# @param [YearMonthDuration] other
|
298
|
+
# @return [YearMonthDuration]
|
299
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-subtract-yearMonthDurations
|
300
|
+
def -(other)
|
301
|
+
return type_error("#{other.inspect} is not a valid YearMonthDuration") unless other.is_a?(Literal::YearMonthDuration) && other.valid?
|
302
|
+
self.class.new([object.first - other.object.first, 0])
|
303
|
+
end
|
304
|
+
|
305
|
+
##
|
306
|
+
# Returns the result of multiplying the value of self by `other`. The result is rounded to the nearest month.
|
307
|
+
#
|
308
|
+
# From the XQuery function [op:multiply-yearMonthDuration](https://www.w3.org/TR/xpath-functions/#func-multiply-yearMonthDuration).
|
309
|
+
#
|
310
|
+
# @param [Literal::Numeric, ::Numeric, DayTimeDuration] other
|
311
|
+
# @return [YearMonthDuration]
|
312
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-multiply-yearMonthDuration
|
313
|
+
def *(other)
|
314
|
+
return type_error("#{other.inspect} is not a valid Numeric") unless (other.is_a?(::Numeric) || other.is_a?(Literal::Numeric))
|
315
|
+
self.class.new([(object.first * other.to_f).round, 0])
|
316
|
+
end
|
317
|
+
|
318
|
+
##
|
319
|
+
# Returns the result of dividing the value of self by `other`. The result is rounded to the nearest month.
|
320
|
+
#
|
321
|
+
# From the XQuery functions [op:divide-yearMonthDuration](https://www.w3.org/TR/xpath-functions/#func-divide-yearMonthDuration) and [op:divide-yearMonthDuration-by-yearMonthDuration](https://www.w3.org/TR/xpath-functions/#func-divide-yearMonthDuration-by-yearMonthDuration).
|
322
|
+
#
|
323
|
+
# @param [Literal::Numeric, ::Numeric, YearMonthDuration] other
|
324
|
+
# @return [YearMonthDuration, Decimal]
|
325
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-divide-yearMonthDuration
|
326
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-divide-yearMonthDuration-by-yearMonthDuration
|
327
|
+
def /(other)
|
328
|
+
case other
|
329
|
+
when Literal::YearMonthDuration
|
330
|
+
return type_error("#{other.inspect} is not a valid YearMonthDuration or Numeric") unless other.valid?
|
331
|
+
Decimal.new(object.first / other.object.first.to_f)
|
332
|
+
when Literal::Numeric, ::Numeric
|
333
|
+
self.class.new([(object.first / other.to_f).round, 0])
|
334
|
+
else
|
335
|
+
type_error("#{other.inspect} is not a valid YearMonthDuration or Numeric")
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
##
|
340
|
+
# Compares this literal to `other` for sorting purposes.
|
341
|
+
#
|
342
|
+
# From the XQuery function [op:yearMonthDuration-greater-than](https://www.w3.org/TR/xpath-functions/#func-yearMonthDuration-less-than).
|
343
|
+
#
|
344
|
+
# @param [Literal::YearMonthDuration] other
|
345
|
+
# @return [Boolean] `true` if less than other for defined datatypes
|
346
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-yearMonthDuration-less-than
|
347
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-yearMonthDuration-greater-than
|
348
|
+
def <=>(other)
|
349
|
+
return type_error("#{other.inspect} is not a valid YearMonthDuration") unless other.is_a?(Literal::YearMonthDuration) && other.valid?
|
350
|
+
@object.first <=> other.object.first
|
351
|
+
end
|
352
|
+
|
353
|
+
##
|
354
|
+
# Converts the dayTimeDuration into rational seconds.
|
355
|
+
#
|
356
|
+
# @return [Rational]
|
357
|
+
def to_i
|
358
|
+
object.first.to_i
|
359
|
+
end
|
360
|
+
end # YearMonthDuration
|
361
|
+
|
200
362
|
##
|
201
363
|
# A DayTimeDuration literal.
|
202
364
|
#
|
203
|
-
# dayTimeDuration is a datatype ·derived· from duration by restricting its ·lexical representations· to instances of dayTimeDurationLexicalRep
|
365
|
+
# `dayTimeDuration` is a datatype ·derived· from `duration` by restricting its ·lexical representations· to instances of `dayTimeDurationLexicalRep`. The ·value space· of `dayTimeDuration` is therefore that of `duration` restricted to those whose ·months· property is 0. This results in a duration datatype which is totally ordered.
|
204
366
|
#
|
205
367
|
# @see https://www.w3.org/TR/xmlschema11-2/#dayTimeDuration
|
206
|
-
class DayTimeDuration <
|
368
|
+
class DayTimeDuration < Duration
|
207
369
|
DATATYPE = RDF::XSD.dayTimeDuration
|
208
370
|
GRAMMAR = %r(\A
|
209
371
|
(?<si>-)?
|
@@ -221,22 +383,87 @@ module RDF; class Literal
|
|
221
383
|
)
|
222
384
|
)
|
223
385
|
\z)x.freeze
|
224
|
-
end # DayTimeDuration
|
225
386
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
(
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
387
|
+
##
|
388
|
+
# Returns the sum of two xs:dayTimeDuration values.
|
389
|
+
#
|
390
|
+
# From the XQuery function [op:add-dayTimeDurations](https://www.w3.org/TR/xpath-functions/#func-add-dayTimeDurations).
|
391
|
+
#
|
392
|
+
# @param [DayTimeDuration] other
|
393
|
+
# @return [DayTimeDuration]
|
394
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-add-dayTimeDurations
|
395
|
+
def +(other)
|
396
|
+
return type_error("#{other.inspect} is not a valid DayTimeDuration") unless other.is_a?(Literal::DayTimeDuration) && other.valid?
|
397
|
+
self.class.new([0, object.last + other.object.last])
|
398
|
+
end
|
399
|
+
|
400
|
+
##
|
401
|
+
# Returns the result of subtracting one xs:dayTimeDuration value from another.
|
402
|
+
#
|
403
|
+
# From the XQuery function [op:subtract-dayTimeDurationss](https://www.w3.org/TR/xpath-functions/#func-subtract-dayTimeDurations).
|
404
|
+
#
|
405
|
+
# @param [DayTimeDuration] other
|
406
|
+
# @return [DayTimeDuration]
|
407
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-subtract-dayTimeDurations
|
408
|
+
def -(other)
|
409
|
+
return type_error("#{other.inspect} is not a valid DayTimeDuration") unless other.is_a?(Literal::DayTimeDuration) && other.valid?
|
410
|
+
self.class.new([0, object.last - other.object.last])
|
411
|
+
end
|
412
|
+
|
413
|
+
##
|
414
|
+
# Returns the result of multiplying the value of self by `other`. The result is rounded to the nearest month.
|
415
|
+
#
|
416
|
+
# From the XQuery function [op:multiply-dayTimeDuration](https://www.w3.org/TR/xpath-functions/#func-multiply-dayTimeDuration).
|
417
|
+
#
|
418
|
+
# @param [Literal::Numeric, ::Numeric] other
|
419
|
+
# @return [DayTimeDuration]
|
420
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-multiply-dayTimeDuration
|
421
|
+
def *(other)
|
422
|
+
return type_error("#{other.inspect} is not a valid Numeric") unless (other.is_a?(::Numeric) || other.is_a?(Literal::Numeric))
|
423
|
+
self.class.new([0, object.last * other.to_f])
|
424
|
+
end
|
425
|
+
|
426
|
+
##
|
427
|
+
# Returns the result of dividing the value of self by `other`. The result is rounded to the nearest month.
|
428
|
+
#
|
429
|
+
# From the XQuery functions [op:divide-yearMonthDuration](https://www.w3.org/TR/xpath-functions/#func-divide-dayTimeDuration) and [op:divide-yearMonthDuration-by-yearMonthDuration](https://www.w3.org/TR/xpath-functions/#func-divide-dayTimeDuration-by-dayTimeDuration).
|
430
|
+
#
|
431
|
+
# @param [Literal::Numeric, ::Numeric, DayTimeDuration] other
|
432
|
+
# @return [DayTimeDuration, Decimal]
|
433
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-divide-dayTimeDuration
|
434
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-divide-dayTimeDuration-by-dayTimeDuration
|
435
|
+
def /(other)
|
436
|
+
case other
|
437
|
+
when DayTimeDuration
|
438
|
+
return type_error("#{other.inspect} is not a valid DayTimeDuration or Numeric") unless other.valid?
|
439
|
+
Decimal.new(object.last / other.object.last.to_f)
|
440
|
+
when Literal::Numeric, ::Numeric
|
441
|
+
self.class.new([0, object.last / other.to_f])
|
442
|
+
else
|
443
|
+
type_error("#{other.inspect} is not a valid DayTimeDuration or Numeric")
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
##
|
448
|
+
# Compares this literal to `other` for sorting purposes.
|
449
|
+
#
|
450
|
+
# From the XQuery function [op:dayTimeDuration-less-than](https://www.w3.org/TR/xpath-functions/#func-dayTimeDuration-less-than).
|
451
|
+
#
|
452
|
+
# @param [DayTimeDuration] other
|
453
|
+
# @return [Boolean] `true` if less than other for defined datatypes
|
454
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-dayTimeDuration-less-than
|
455
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-dayTimeDuration-greater-than
|
456
|
+
def <=>(other)
|
457
|
+
return type_error("#{other.inspect} is not a valid DayTimeDuration") unless other.is_a?(Literal::DayTimeDuration) && other.valid?
|
458
|
+
@object.last <=> other.object.last
|
459
|
+
end
|
460
|
+
|
461
|
+
##
|
462
|
+
# Converts the dayTimeDuration into rational seconds.
|
463
|
+
#
|
464
|
+
# @return [Rational]
|
465
|
+
def to_r
|
466
|
+
Rational(object.last) / (24 * 3600)
|
467
|
+
end
|
241
468
|
end # DayTimeDuration
|
242
469
|
end; end # RDF::Literal
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rdf-xsd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gregg
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-02-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rdf
|
@@ -109,7 +109,8 @@ dependencies:
|
|
109
109
|
- - "~>"
|
110
110
|
- !ruby/object:Gem::Version
|
111
111
|
version: '0.9'
|
112
|
-
description: Adds RDF::Literal subclasses for extended XSD datatypes
|
112
|
+
description: Adds RDF::Literal subclasses for extended XSD datatypes with methods
|
113
|
+
for many XPath and XQuery functions.
|
113
114
|
email: public-rdf-ruby@w3.org
|
114
115
|
executables: []
|
115
116
|
extensions: []
|
@@ -132,7 +133,12 @@ files:
|
|
132
133
|
homepage: https://github.com/ruby-rdf/rdf-xsd
|
133
134
|
licenses:
|
134
135
|
- Unlicense
|
135
|
-
metadata:
|
136
|
+
metadata:
|
137
|
+
documentation_uri: https://ruby-rdf.github.io/rdf-xsd
|
138
|
+
bug_tracker_uri: https://github.com/ruby-rdf/rdf-xsd/issues
|
139
|
+
homepage_uri: https://github.com/ruby-rdf/rdf-xsd
|
140
|
+
mailing_list_uri: https://lists.w3.org/Archives/Public/public-rdf-ruby/
|
141
|
+
source_code_uri: https://github.com/ruby-rdf/rdf-xsd
|
136
142
|
post_install_message: |2
|
137
143
|
|
138
144
|
For best results, use nokogiri and equivalent-xml gems as well.
|
@@ -154,5 +160,5 @@ requirements: []
|
|
154
160
|
rubygems_version: 3.3.3
|
155
161
|
signing_key:
|
156
162
|
specification_version: 4
|
157
|
-
summary: Extended XSD Datatypes for RDF.rb.
|
163
|
+
summary: Extended XSD Datatypes and XPath and XQuery functions for RDF.rb.
|
158
164
|
test_files: []
|