Skip to content

Commit cd1da2f

Browse files
committed
Refectore bulk of Date, and DateTime into new Temporal class, and use to re-implement Time as well.
1 parent 7acc71d commit cd1da2f

10 files changed

Lines changed: 552 additions & 640 deletions

File tree

lib/rdf/model/literal.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def self.inherited(child)
7777
require 'rdf/model/literal/decimal'
7878
require 'rdf/model/literal/integer'
7979
require 'rdf/model/literal/double'
80+
require 'rdf/model/literal/temporal'
8081
require 'rdf/model/literal/date'
8182
require 'rdf/model/literal/datetime'
8283
require 'rdf/model/literal/time'

lib/rdf/model/literal/date.rb

Lines changed: 1 addition & 197 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module RDF; class Literal
44
#
55
# @see http://www.w3.org/TR/xmlschema11-2/#date
66
# @since 0.2.1
7-
class Date < Literal
7+
class Date < Temporal
88
DATATYPE = RDF::URI("http://www.w3.org/2001/XMLSchema#date")
99
GRAMMAR = %r(\A(-?\d{4}-\d{2}-\d{2})((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z).freeze
1010
FORMAT = '%Y-%m-%d'.freeze
@@ -41,42 +41,6 @@ def initialize(value, datatype: nil, lexical: nil, **options)
4141
end rescue ::DateTime.new
4242
end
4343

44-
##
45-
# Converts this literal into its canonical lexical representation.
46-
#
47-
# Note that the timezone is recoverable for xsd:date, where it is not for xsd:dateTime and xsd:time, which are both transformed relative to Z, if a timezone is provided.
48-
#
49-
# @return [RDF::Literal] `self`
50-
# @see http://www.w3.org/TR/xmlschema11-2/#date
51-
def canonicalize!
52-
if self.valid? && @zone && @zone != '+00:00'
53-
adjust_to_timezone!
54-
else
55-
@string = nil
56-
end
57-
self
58-
end
59-
60-
##
61-
# Returns `true` if the value adheres to the defined grammar of the
62-
# datatype.
63-
#
64-
# Special case for date and dateTime, for which '0000' is not a valid year
65-
#
66-
# @return [Boolean]
67-
# @since 0.2.1
68-
def valid?
69-
super && object && value !~ %r(\A0000)
70-
end
71-
72-
##
73-
# Returns the value as a string.
74-
#
75-
# @return [String]
76-
def to_s
77-
@string || (@object.strftime(FORMAT) + self.tz)
78-
end
79-
8044
##
8145
# Returns a human-readable value for the literal
8246
#
@@ -93,165 +57,5 @@ def humanize(lang = :en)
9357
end
9458
d
9559
end
96-
97-
##
98-
# Does the literal representation include a timezone? Note that this is only possible if initialized using a string, or `:lexical` option.
99-
#
100-
# @return [Boolean]
101-
# @since 1.1.6
102-
def timezone?
103-
!@zone.nil?
104-
end
105-
alias_method :tz?, :timezone?
106-
alias_method :has_tz?, :timezone?
107-
alias_method :has_timezone?, :timezone?
108-
109-
##
110-
# Adjust the timezone.
111-
#
112-
# From [fn:adjust-date-to-timezone](https://www.w3.org/TR/xpath-functions/#func-adjust-date-to-timezone)
113-
#
114-
# @overload adjust_to_timezone!
115-
# Adjusts the timezone to UTC.
116-
#
117-
# @return [Date] `self`
118-
# @raise [RangeError] if `zone < -14*60` or `zone > 14*60`
119-
# @overload adjust_to_timezone!(zone)
120-
# If `zone` is nil, then the timzeone component is removed.
121-
#
122-
# Otherwise, the timezone is set based on the difference between the current timezone offset (if any) and `zone`.
123-
#
124-
# @param [String] zone (nil) In the form of {ZONE_FORMAT}
125-
# @return [Date] `self`
126-
# @raise [RangeError] if `zone < -14*60` or `zone > 14*60`
127-
# @see https://www.w3.org/TR/xpath-functions/#func-adjust-date-to-timezone
128-
def adjust_to_timezone!(*args)
129-
zone = args.empty? ? '+00:00' : args.first
130-
if zone.nil?
131-
# Remove timezone component
132-
@object = ::DateTime.parse(@object.strftime('%F'))
133-
@zone = nil
134-
else
135-
md = zone.match(Literal::DateTime::ZONE_GRAMMAR) if zone
136-
raise ArgumentError,
137-
"expected #{zone.inspect} to be a xsd:dayTimeDuration or +/-HH:MM" unless md
138-
# Adjust to zone
139-
si, hr, mi = md[:si], md[:hr], md[:mi]
140-
si ||= '+'
141-
offset = hr.to_i * 60 + mi.to_i
142-
raise ArgumentError,
143-
"Zone adjustment of #{zone} out of range" if
144-
md.nil? || offset > 14*60
145-
146-
new_zone = "%s%.2d:%.2d" % [si, hr.to_i, mi.to_i]
147-
dt = @zone.nil? ? @object : @object.new_offset(new_zone)
148-
@object = ::DateTime.parse(dt.strftime("%FT00:00:00#{new_zone}"))
149-
@zone = new_zone
150-
end
151-
@string = nil
152-
self
153-
end
154-
155-
##
156-
# Functional version of `#adjust_to_timezone!`.
157-
#
158-
# @overload adjust_to_timezone
159-
# @param (see #adjust_to_timezone!)
160-
# @return [Date]
161-
# @raise (see #adjust_to_timezone!)
162-
# @overload adjust_to_timezone(zone) (see #adjust_to_timezone!)
163-
# @return [Date]
164-
# @raise (see #adjust_to_timezone!)
165-
def adjust_to_timezone(*args)
166-
self.dup.adjust_to_timezone!(*args)
167-
end
168-
169-
##
170-
# Returns the timezone part of arg as a simple literal. Returns the empty string if there is no timezone.
171-
#
172-
# @return [RDF::Literal]
173-
# @since 1.1.6
174-
def tz
175-
RDF::Literal(@zone == "+00:00" ? 'Z' : @zone)
176-
end
177-
178-
##
179-
# Returns the timezone part of arg as an xsd:dayTimeDuration, or `nil`
180-
# if lexical form of literal does not include a timezone.
181-
#
182-
# From [fn:timezone-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-timezone-from-dateTime).
183-
#
184-
# @return [RDF::Literal]
185-
# @see https://www.w3.org/TR/xpath-functions/#func-timezone-from-dateTime
186-
def timezone
187-
if @zone
188-
md = @zone.match(Literal::DateTime::ZONE_GRAMMAR)
189-
si, hr, mi = md[:si], md[:hr].to_i, md[:mi].to_i
190-
si = nil unless si == "-"
191-
res = "#{si}PT#{hr}H#{"#{mi}M" if mi > 0}"
192-
RDF::Literal(res, datatype: RDF::URI("http://www.w3.org/2001/XMLSchema#dayTimeDuration"))
193-
end
194-
end
195-
196-
##
197-
# Updates the date to a new timezone, or no timezone.
198-
##
199-
# Equal compares as Date objects
200-
#
201-
# From the XQuery function [op:date-equal](https://www.w3.org/TR/xpath-functions/#func-date-equal).
202-
#
203-
# @param [Date, Literal] other
204-
# @return [Boolean]
205-
# @see https://www.w3.org/TR/xpath-functions/#func-date-equal
206-
def ==(other)
207-
# If lexically invalid, use regular literal testing
208-
return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?)
209-
210-
case other
211-
when Literal::Date
212-
return super unless other.valid?
213-
self.object == other.object
214-
when Literal::Time, Literal::DateTime
215-
false
216-
else
217-
super
218-
end
219-
end
220-
221-
##
222-
# Compares `self` to `other` for sorting purposes (with type check).
223-
#
224-
# @param [Object] other
225-
# @return [Integer] `-1`, `0`, or `1`
226-
def <=>(other)
227-
# If lexically invalid, use regular literal testing
228-
return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?)
229-
return super unless other.is_a?(Date)
230-
@object <=> other.object
231-
end
232-
233-
# Years
234-
#
235-
# From the XQuery function [fn:year-from-date](https://www.w3.org/TR/xpath-functions/#func-year-from-date).
236-
#
237-
# @return [Integer]
238-
# @see https://www.w3.org/TR/xpath-functions/#func-year-from-date
239-
def year; Integer.new(object.year); end
240-
241-
# Months
242-
#
243-
# From the XQuery function [fn:month-from-date](https://www.w3.org/TR/xpath-functions/#func-month-from-date).
244-
#
245-
# @return [Integer]
246-
# @see https://www.w3.org/TR/xpath-functions/#func-month-from-date
247-
def month; Integer.new(object.month); end
248-
249-
# Days
250-
#
251-
# From the XQuery function [fn:day-from-date](https://www.w3.org/TR/xpath-functions/#func-day-from-date).
252-
#
253-
# @return [Integer]
254-
# @see https://www.w3.org/TR/xpath-functions/#func-day-from-date
255-
def day; Integer.new(object.day); end
25660
end # Date
25761
end; end # RDF::Literal

0 commit comments

Comments
 (0)