From 0adae254168950ad80a2366e00794aabca0a7f27 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Sat, 19 Feb 2022 14:01:13 -0800 Subject: [PATCH 1/8] Use markdown in etc/xsd.ttl and regenerate rdf/vocab/xsd.rb. --- etc/xsd.ttl | 342 +++++++++++++++++++++---------------------- lib/rdf/vocab/xsd.rb | 196 ++++++++++++------------- 2 files changed, 269 insertions(+), 269 deletions(-) diff --git a/etc/xsd.ttl b/etc/xsd.ttl index 9f0e7c86..cf5ebda8 100644 --- a/etc/xsd.ttl +++ b/etc/xsd.ttl @@ -16,28 +16,28 @@ xsd:anySimpleType a rdfs:Datatype; rdfs:subClassOf xsd:anyType; rdfs:label "anySimpleType"; rdfs:comment """ - The definition of anySimpleType is a special ·restriction· of anyType. The - ·lexical space· of anySimpleType is the set of all sequences of Unicode - characters, and its ·value space· includes all ·atomic values· and all - finite-length lists of zero or more ·atomic values·. + The definition of `anySimpleType` is a special _restriction_ of `anyType`. The + _lexical space_ of a`nySimpleType` is the set of all sequences of Unicode + characters, and its _value space_ includes all _atomic values_ and all + finite-length lists of zero or more _atomic values_. """ . xsd:anyAtomicType a rdfs:Datatype; rdfs:subClassOf xsd:anyType; rdfs:label "anySimpleType"; rdfs:comment """ - anyAtomicType is a special ·restriction· of anySimpleType. The ·value· and - ·lexical spaces· of anyAtomicType are the unions of the ·value· and - ·lexical spaces· of all the ·primitive· datatypes, and anyAtomicType is - their ·base type·. + `anyAtomicType` is a special _restriction_ of `anySimpleType`. The _value_ and + _lexical spaces_ of `anyAtomicType` are the unions of the _value_ and + _lexical spaces_ of all the _primitive_ datatypes, and `anyAtomicType` is + their _base type_. """ . xsd:anyURI a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "anyURI"; rdfs:comment """ - anyURI represents an Internationalized Resource Identifier Reference - (IRI). An anyURI value can be absolute or relative, and may have an + `anyURI` represents an Internationalized Resource Identifier Reference + (IRI). An `anyURI` value can be absolute or relative, and may have an optional fragment identifier (i.e., it may be an IRI Reference). This type should be used when the value fulfills the role of an IRI, as defined in [RFC 3987] or its successor(s) in the IETF Standards Track. @@ -47,8 +47,8 @@ xsd:base64Binary a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "base64Binary"; rdfs:comment """ - base64Binary represents arbitrary Base64-encoded binary data. For - base64Binary data the entire binary stream is encoded using the Base64 + `base64Binary` represents arbitrary Base64-encoded binary data. For + `base64Binary` data the entire binary stream is encoded using the `Base64` Encoding defined in [RFC 3548], which is derived from the encoding described in [RFC 2045]. """ . @@ -57,15 +57,15 @@ xsd:boolean a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "boolean"; rdfs:comment """ - boolean represents the values of two-valued logic. + `boolean` represents the values of two-valued logic. """ . xsd:date a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "date"; rdfs:comment """ - date represents top-open intervals of exactly one day in length on the - timelines of dateTime, beginning on the beginning moment of each day, up to + `date` represents top-open intervals of exactly one day in length on the + timelines of `dateTime`, beginning on the beginning moment of each day, up to but not including the beginning moment of the next day). For non-timezoned values, the top-open intervals disjointly cover the non-timezoned timeline, one per day. For timezoned values, the intervals begin at every minute and @@ -76,7 +76,7 @@ xsd:dateTime a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "dateTime"; rdfs:comment """ - dateTime represents instants of time, optionally marked with a particular + `dateTime` represents instants of time, optionally marked with a particular time zone offset. Values representing the same instant but having different time zone offsets are equal but not identical. """ . @@ -85,9 +85,9 @@ xsd:dateTimeStamp a rdfs:Datatype; rdfs:subClassOf xsd:dateTime; rdfs:label "dateTimeStamp"; rdfs:comment """ - The dateTimeStamp datatype is ·derived· from dateTime by giving the value - required to its explicitTimezone facet. The result is that all values of - dateTimeStamp are required to have explicit time zone offsets and the + The `dateTimeStamp` datatype is _derived_ from `dateTime` by giving the value + required to its `explicitTimezone` facet. The result is that all values of + `dateTimeStamp` are required to have explicit time zone offsets and the datatype is totally ordered. """ . @@ -95,12 +95,12 @@ xsd:decimal a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "decimal"; rdfs:comment """ - decimal represents a subset of the real numbers, which can be represented - by decimal numerals. The ·value space· of decimal is the set of numbers + `decimal` represents a subset of the real numbers, which can be represented + by decimal numerals. The _value space_ of decimal is the set of numbers that can be obtained by dividing an integer by a non-negative power of ten, - i.e., expressible as i / 10n where i and n are integers and n ≥ 0. - Precision is not reflected in this value space; the number 2.0 is not - distinct from the number 2.00. The order relation on decimal is the order + i.e., expressible as `i / 10n` where `i` and `n` are integers and `n ≥ 0`. + Precision is not reflected in this value space; the number `2.0` is not + distinct from the number `2.00`. The order relation on `decimal` is the order relation on real numbers, restricted to this subset. """ . @@ -108,132 +108,132 @@ xsd:integer a rdfs:Datatype; rdfs:subClassOf xsd:decimal; rdfs:label "integer"; rdfs:comment """ - integer is ·derived· from decimal by fixing the value of ·fractionDigits· - to be 0 and disallowing the trailing decimal point. This results in the - standard mathematical concept of the integer numbers. The ·value space· of - integer is the infinite set {...,-2,-1,0,1,2,...}. The ·base type· of - integer is decimal. + `integer` is _derived_ from `decimal` by fixing the value of `fractionDigits` + to be `0` and disallowing the trailing decimal point. This results in the + standard mathematical concept of the integer numbers. The _value space_ of + `integer` is the infinite set `{...,-2,-1,0,1,2,...}`. The _base type_ of + `integer` is `decimal`. """ . xsd:long a rdfs:Datatype; rdfs:subClassOf xsd:integer; rdfs:label "long"; rdfs:comment """ - long is ·derived· from integer by setting the value of ·maxInclusive· to - be 9223372036854775807 and ·minInclusive· to be -9223372036854775808. The - ·base type· of long is integer. + `long` is _derived_ from `integer` by setting the value of `maxInclusive` to + be `9223372036854775807` and `minInclusive` to be `-9223372036854775808`. The + _base type_ of `long` is `integer`. """ . xsd:int a rdfs:Datatype; rdfs:subClassOf xsd:long; rdfs:label "int"; rdfs:comment """ - int is ·derived· from long by setting the value of ·maxInclusive· to be - 2147483647 and ·minInclusive· to be -2147483648. The ·base type· of int - is long. + `int` is _derived_ from `long` by setting the value of `maxInclusive` to be + `2147483647` and `minInclusive` to be `-2147483648`. The _base type_ of `int` + is `long`. """ . xsd:short a rdfs:Datatype; rdfs:subClassOf xsd:int; rdfs:label "short"; rdfs:comment """ - short is ·derived· from int by setting the value of ·maxInclusive· to be - 32767 and ·minInclusive· to be -32768. The ·base type· of short is int. + `short` is _derived_ from `int` by setting the value of `maxInclusive` to be + `32767` and `minInclusive` to be `-32768`. The _base type_ of `short` is `int`. """ . xsd:byte a rdfs:Datatype; rdfs:subClassOf xsd:short; rdfs:label "byte"; rdfs:comment """ - byte is ·derived· from short by setting the value of ·maxInclusive· to be - 127 and ·minInclusive· to be -128. The ·base type· of byte is short. + `byte` is _derived_ from `short` by setting the value of `maxInclusive` to be + `127` and `minInclusive` to be `-128`. The _base type_ of `byte` is `short`. """ . xsd:nonNegativeInteger a rdfs:Datatype; rdfs:subClassOf xsd:integer; rdfs:label "nonNegativeInteger"; rdfs:comment """ - nonNegativeInteger is ·derived· from integer by setting the value of - ·minInclusive· to be 0. This results in the standard mathematical concept - of the non-negative integers. The ·value space· of nonNegativeInteger is - the infinite set {0,1,2,...}. The ·base type· of nonNegativeInteger is - integer. + `nonNegativeInteger` is _derived_ from `integer` by setting the value of + `minInclusive` to be `0`. This results in the standard mathematical concept + of the non-negative integers. The _value space_ of `nonNegativeInteger` is + the infinite set `{0,1,2,...}`. The _base type_ of `nonNegativeInteger` is + `integer`. """ . xsd:positiveInteger a rdfs:Datatype; rdfs:subClassOf xsd:nonNegativeInteger; rdfs:label "positiveInteger"; rdfs:comment """ - positiveInteger is ·derived· from nonNegativeInteger by setting the value - of ·minInclusive· to be 1. This results in the standard mathematical - concept of the positive integer numbers. The ·value space· of - positiveInteger is the infinite set {1,2,...}. The ·base type· of - positiveInteger is nonNegativeInteger. + `positiveInteger` is _derived_ from `nonNegativeInteger` by setting the value + of `minInclusive` to be `1`. This results in the standard mathematical + concept of the positive integer numbers. The _value space_ of + `positiveInteger` is the infinite set `{1,2,...}`. The _base type_ of + `positiveInteger` is `nonNegativeInteger`. """ . xsd:unsignedLong a rdfs:Datatype; rdfs:subClassOf xsd:nonNegativeInteger; rdfs:label "unsignedLong"; rdfs:comment """ - unsignedLong is ·derived· from nonNegativeInteger by setting the value of - ·maxInclusive· to be 18446744073709551615. The ·base type· of unsignedLong - is nonNegativeInteger. + `unsignedLong` is _derived_ from `nonNegativeInteger` by setting the value of + `maxInclusive` to be `18446744073709551615`. The _base type_ of `unsignedLong` + is `nonNegativeInteger`. """ . xsd:unsignedInt a rdfs:Datatype; rdfs:subClassOf xsd:unsignedLong; rdfs:label "unsignedInt"; rdfs:comment """ - unsignedInt is ·derived· from unsignedLong by setting the value of - ·maxInclusive· to be 4294967295. The ·base type· of unsignedInt is - unsignedLong. + `unsignedInt` is _derived_ from `unsignedLong` by setting the value of + `maxInclusive` to be `4294967295`. The _base type_ of `unsignedInt` is + `unsignedLong`. """ . xsd:unsignedShort a rdfs:Datatype; rdfs:subClassOf xsd:unsignedInt; rdfs:label "unsignedShort"; rdfs:comment """ - unsignedShort is ·derived· from unsignedInt by setting the value of - ·maxInclusive· to be 65535. The ·base type· of unsignedShort is - unsignedInt. + `unsignedShort` is _derived_ from `unsignedInt` by setting the value of + `maxInclusive` to be `65535`. The _base type_ of `unsignedShort` is + `unsignedInt`. """ . xsd:unsignedByte a rdfs:Datatype; rdfs:subClassOf xsd:unsignedShort; rdfs:label "unsignedByte"; rdfs:comment """ - nsignedByte is ·derived· from unsignedShort by setting the value of - ·maxInclusive· to be 255. The ·base type· of unsignedByte is - unsignedShort. + `unsignedByte` is _derived_ from `unsignedShort` by setting the value of + `maxInclusive` to be `255`. The _base type_ of `unsignedByte` is + `unsignedShort`. """ . xsd:nonPositiveInteger a rdfs:Datatype; rdfs:subClassOf xsd:integer; rdfs:label "nonPositiveInteger"; rdfs:comment """ - nonPositiveInteger is ·derived· from integer by setting the value of - ·maxInclusive· to be 0. This results in the standard mathematical concept - of the non-positive integers. The ·value space· of nonPositiveInteger is - the infinite set {...,-2,-1,0}. The ·base type· of nonPositiveInteger is - integer. + `nonPositiveInteger` is _derived_ from `integer` by setting the value of + `maxInclusive` to be `0`. This results in the standard mathematical concept + of the non-positive integers. The _value space_ of `nonPositiveInteger` is + the infinite set `{...,-2,-1,0}`. The _base type_ of `nonPositiveInteger` is + `integer`. """ . xsd:negativeInteger a rdfs:Datatype; rdfs:subClassOf xsd:nonPositiveInteger; rdfs:label "negativeInteger"; rdfs:comment """ - negativeInteger is ·derived· from nonPositiveInteger by setting the value - of ·maxInclusive· to be -1. This results in the standard mathematical - concept of the negative integers. The ·value space· of negativeInteger is - the infinite set {...,-2,-1}. The ·base type· of negativeInteger is - nonPositiveInteger. + `negativeInteger` is _derived_ from `nonPositiveInteger` by setting the value + of `maxInclusive` to be `-1`. This results in the standard mathematical + concept of the negative integers. The _value space_ of `negativeInteger` is + the infinite set `{...,-2,-1}`. The _base type_ of `negativeInteger` is + `nonPositiveInteger`. """ . xsd:double a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "double"; rdfs:comment """ - The double datatype is patterned after the IEEE double-precision 64-bit + The `double` datatype is patterned after the IEEE double-precision 64-bit floating point datatype [IEEE 754-2008]. Each floating point datatype has a value space that is a subset of the rational numbers. Floating point numbers are often used to approximate arbitrary real numbers. @@ -243,26 +243,26 @@ xsd:duration a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "duration"; rdfs:comment """ - duration is a datatype that represents durations of time. The concept of + `duration` is a datatype that represents durations of time. The concept of duration being captured is drawn from those of [ISO 8601], specifically durations without fixed endpoints. For example, "15 days" (whose most - common lexical representation in duration is "'P15D'") is a duration value; + common lexical representation in duration is `"'P15D'"`) is a duration value; "15 days beginning 12 July 1995" and "15 days ending 12 July 1995" are not duration values. duration can provide addition and subtraction operations between duration values and between duration/dateTime value pairs, and can be the result of subtracting dateTime values. However, only addition to - dateTime is required for XML Schema processing and is defined in the - function ·dateTimePlusDuration·. + `dateTime` is required for XML Schema processing and is defined in the + function `dateTimePlusDuration`. """ . xsd:dayTimeDuration a rdfs:Datatype; rdfs:subClassOf xsd:duration; rdfs:label "dayTimeDuration"; rdfs:comment """ - 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 + `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. """ . @@ -270,18 +270,18 @@ xsd:yearMonthDuration a rdfs:Datatype; rdfs:subClassOf xsd:duration; rdfs:label "yearMonthDuration"; rdfs:comment """ - yearMonthDuration is a datatype ·derived· from 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. + `yearMonthDuration` is a datatype _derived_ from `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. """ . xsd:float a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "float"; rdfs:comment """ - The float datatype is patterned after the IEEE single-precision 32-bit + The `float` datatype is patterned after the IEEE single-precision 32-bit floating point datatype [IEEE 754-2008]. Its value space is a subset of the rational numbers. Floating point numbers are often used to approximate arbitrary real numbers. @@ -291,7 +291,7 @@ xsd:gDay a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "gDay"; rdfs:comment """ - gDay represents whole days within an arbitrary month—days that recur at the + `gDay` represents whole days within an arbitrary month—days that recur at the same point in each (Gregorian) month. This datatype is used to represent a specific day of the month. To indicate, for example, that an employee gets a paycheck on the 15th of each month. (Obviously, days beyond 28 cannot @@ -302,10 +302,10 @@ xsd:gMonth a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "gMonth"; rdfs:comment """ - gMonth represents whole (Gregorian) months within an arbitrary year—months + `gMonth` represents whole (Gregorian) months within an arbitrary year—months that recur at the same point in each year. It might be used, for example, to say what month annual Thanksgiving celebrations fall in different - countries (--11 in the United States, --10 in Canada, and possibly other + countries (`--11` in the United States, `--10` in Canada, and possibly other months in other countries). """ . @@ -313,7 +313,7 @@ xsd:gMonthDay a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "gMonthDay"; rdfs:comment """ - gMonthDay represents whole calendar days that recur at the same point in + `gMonthDay` represents whole calendar days that recur at the same point in each calendar year, or that occur in some arbitrary calendar year. (Obviously, days beyond 28 cannot occur in all Februaries; 29 is nonetheless permitted.) @@ -323,157 +323,157 @@ xsd:gYear a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "gYear"; rdfs:comment """ - gYear represents Gregorian calendar years. + `gYear` represents Gregorian calendar years. """ . xsd:gYearMonth a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "gYearMonth"; rdfs:comment """ - gYearMonth represents specific whole Gregorian months in specific Gregorian years. + `gYearMonth` represents specific whole Gregorian months in specific Gregorian years. """ . xsd:hexBinary a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "hexBinary"; rdfs:comment """ - hexBinary represents arbitrary hex-encoded binary data. + hexBinary` represents arbitrary hex-encoded binary data. """ . xsd:NOTATION a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "NOTATION"; rdfs:comment """ - NOTATION represents the NOTATION attribute type from [XML]. The ·value - space· of NOTATION is the set of QNames of notations declared in the - current schema. The ·lexical space· of NOTATION is the set of all names of - notations declared in the current schema (in the form of QNames). + `NOTATION` represents the `NOTATION` attribute type from [XML]. The _value + space_ of `NOTATION` is the set of `QNames` of notations declared in the + current schema. The _lexical space_ of `NOTATION` is the set of all names of + notations declared in the current schema (in the form of `QNames`). """ . xsd:QName a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "QName"; rdfs:comment """ - QName represents XML qualified names. The ·value space· of QName is the set - of tuples {namespace name, local part}, where namespace name is an anyURI - and local part is an NCName. The ·lexical space· of QName is the set of - strings that ·match· the QName production of [Namespaces in XML]. + `QName` represents XML qualified names. The _value space_ of `QName` is the set + of tuples `{namespace name, local part}`, where namespace name is an `anyURI` + and local part is an `NCName`. The _lexical space_ of `QName` is the set of + strings that match the `QName` production of [Namespaces in XML]. """ . xsd:string a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "string"; rdfs:comment """ - The string datatype represents character strings in XML. + The `string` datatype represents character strings in XML. """ . xsd:normalizedString a rdfs:Datatype; rdfs:subClassOf xsd:string; rdfs:label "normalizedString"; rdfs:comment """ - normalizedString represents white space normalized strings. The ·value - space· of normalizedString is the set of strings that do not contain the - carriage return (#xD), line feed (#xA) nor tab (#x9) characters. The - ·lexical space· of normalizedString is the set of strings that do not - contain the carriage return (#xD), line feed (#xA) nor tab (#x9) - characters. The ·base type· of normalizedString is string. + `normalizedString` represents white space normalized strings. The _value + space_ of `normalizedString` is the set of strings that do not contain the + carriage return (`#xD`), line feed (`#xA`) nor tab (`#x9`) characters. The + _lexical space_ of `normalizedString` is the set of strings that do not + contain the carriage return (`#xD`), line feed (`#xA`) nor tab (`#x9`) + characters. The _base type_ of `normalizedString` is `string`. """ . xsd:token a rdfs:Datatype; rdfs:subClassOf xsd:normalizedString; rdfs:label "token"; rdfs:comment """ - token represents tokenized strings. The ·value space· of token is the set - of strings that do not contain the carriage return (#xD), line feed (#xA) - nor tab (#x9) characters, that have no leading or trailing spaces (#x20) - and that have no internal sequences of two or more spaces. The ·lexical - space· of token is the set of strings that do not contain the carriage - return (#xD), line feed (#xA) nor tab (#x9) characters, that have no - leading or trailing spaces (#x20) and that have no internal sequences of - two or more spaces. The ·base type· of token is normalizedString. + `token` represents tokenized strings. The _value space_ of `token` is the set + of strings that do not contain the carriage return (`#xD`), line feed (`#xA`) + nor tab (`#x9`) characters, that have no leading or trailing spaces (`#x20`) + and that have no internal sequences of two or more spaces. The _lexical + space_ of `token` is the set of strings that do not contain the carriage + return (`#xD`), line feed (`#xA`) nor tab (`#x9`) characters, that have no + leading or trailing spaces (`#x20`) and that have no internal sequences of + two or more spaces. The _base type_ of `token` is `normalizedString`. """ . xsd:language a rdfs:Datatype; rdfs:subClassOf xsd:token; rdfs:label "language"; rdfs:comment """ - language represents formal natural language identifiers, as defined by [BCP + `language` represents formal natural language identifiers, as defined by [BCP 47] (currently represented by [RFC 4646] and [RFC 4647]) or its - successor(s). The ·value space· and ·lexical space· of language are the set - of all strings that conform to the pattern [a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})* + successor(s). The _value space_ and _lexical space_ of `language` are the set + of all strings that conform to the pattern `[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*`. """ . xsd:Name a rdfs:Datatype; rdfs:subClassOf xsd:token; rdfs:label "Name"; rdfs:comment """ - Name represents XML Names. The ·value space· of Name is the set of all - strings which ·match· the Name production of [XML]. The ·lexical space· of - Name is the set of all strings which ·match· the Name production of [XML]. - The ·base type· of Name is token. + `Name` represents XML Names. The _value space_ of `Name` is the set of all + strings which match the `Name` production of [XML]. The _lexical space_ of + `Name` is the set of all strings which match the `Name` production of [XML]. + The _base type_ of `Name` is `token`. """ . xsd:NCName a rdfs:Datatype; rdfs:subClassOf xsd:Name; rdfs:label "NCName"; rdfs:comment """ - NCName represents XML "non-colonized" Names. The ·value space· of NCName - is the set of all strings which ·match· the NCName production of - [Namespaces in XML]. The ·lexical space· of NCName is the set of all - strings which ·match· the NCName production of [Namespaces in XML]. The - ·base type· of NCName is Name. + `NCName` represents XML "non-colonized" Names. The _value space_ of `NCName` + is the set of all strings which match the `NCName` production of + [Namespaces in XML]. The _lexical space_ of `NCName` is the set of all + strings which match the `NCName` production of [Namespaces in XML]. The + _base type_ of `NCName` is `Name`. """ . xsd:ENTITY a rdfs:Datatype; rdfs:subClassOf xsd:NCName; rdfs:label "ENTITY"; rdfs:comment """ - ENTITY represents the ENTITY attribute type from [XML]. The ·value space· - of ENTITY is the set of all strings that ·match· the NCName production in + `ENTITY` represents the `ENTITY` attribute type from [XML]. The _value space_ + of `ENTITY` is the set of all strings that match the `NCName` production in [Namespaces in XML] and have been declared as an unparsed entity in a - document type definition. The ·lexical space· of ENTITY is the set of all - strings that ·match· the NCName production in [Namespaces in XML]. The - ·base type· of ENTITY is NCName. + document type definition. The _lexical space_ of ENTITY is the set of all + strings that match the NCName production in [Namespaces in XML]. The + _base type_ of ENTITY is NCName. """ . xsd:ID a rdfs:Datatype; rdfs:subClassOf xsd:NCName; rdfs:label "ID"; rdfs:comment """ - ID represents the ID attribute type from [XML]. The ·value space· of ID is - the set of all strings that ·match· the NCName production in [Namespaces - in XML]. The ·lexical space· of ID is the set of all strings that ·match· - the NCName production in [Namespaces in XML]. The ·base type· of ID is - NCName. + `ID` represents the `ID` attribute type from [XML]. The _value space_ of `ID` is + the set of all strings that match the `NCName` production in [Namespaces + in XML]. The _lexical space_ of `ID` is the set of all strings that match + the `NCName` production in [Namespaces in XML]. The _base type_ of `ID` is + `NCName`. """ . xsd:IDREF a rdfs:Datatype; rdfs:subClassOf xsd:NCName; rdfs:label "IDREF"; rdfs:comment """ - IDREF represents the IDREF attribute type from [XML]. The ·value space· of - IDREF is the set of all strings that ·match· the NCName production in - [Namespaces in XML]. The ·lexical space· of IDREF is the set of strings - that ·match· the NCName production in [Namespaces in XML]. The ·base type· - of IDREF is NCName. + `IDREF` represents the `IDREF` attribute type from [XML]. The _value space_ of + `IDREF` is the set of all strings that match the `NCName` production in + [Namespaces in XML]. The _lexical space_ of `IDREF` is the set of strings + that match the `NCName` production in [Namespaces in XML]. The _base type_ + of `IDREF` is `NCName`. """ . xsd:NMTOKEN a rdfs:Datatype; rdfs:subClassOf xsd:token; rdfs:label "NMTOKEN"; rdfs:comment """ - NMTOKEN represents the NMTOKEN attribute type from [XML]. The ·value - space· of NMTOKEN is the set of tokens that ·match· the Nmtoken production - in [XML]. The ·lexical space· of NMTOKEN is the set of strings that - ·match· the Nmtoken production in [XML]. The ·base type· of NMTOKEN is - token. + `NMTOKEN` represents the `NMTOKEN` attribute type from [XML]. The _value + space_ of `NMTOKEN` is the set of tokens that match the `Nmtoken` production + in [XML]. The _lexical space_ of `NMTOKEN` is the set of strings that + match the Nmtoken production in [XML]. The _base type_ of `NMTOKEN` is + `token`. """ . xsd:time a rdfs:Datatype; rdfs:subClassOf xsd:anyAtomicType; rdfs:label "time"; rdfs:comment """ - time represents instants of time that recur at the same point in each + `time` represents instants of time that recur at the same point in each calendar day, or that occur in some arbitrary calendar day. """ . @@ -481,14 +481,14 @@ xsd:ENTITIES a rdfs:Datatype; rdfs:subClassOf xsd:anySimpleType; rdfs:label "ENTITIES"; rdfs:comment """ - ENTITIES represents the ENTITIES attribute type from [XML]. The ·value - space· of ENTITIES is the set of finite, non-zero-length sequences of - ·ENTITY· values that have been declared as unparsed entities in a document - type definition. The ·lexical space· of ENTITIES is the set of - space-separated lists of tokens, of which each token is in the ·lexical - space· of ENTITY. The ·item type· of ENTITIES is ENTITY. ENTITIES is - derived from ·anySimpleType· in two steps: an anonymous list type is - defined, whose ·item type· is ENTITY; this is the ·base type· of ENTITIES, + `ENTITIES` represents the `ENTITIES` attribute type from [XML]. The _value + space_ of `ENTITIES` is the set of finite, non-zero-length sequences of + `ENTITY` values that have been declared as unparsed entities in a document + type definition. The _lexical space_ of `ENTITIES` is the set of + space-separated lists of tokens, of which each token is in the _lexical + space_ of `ENTITY`. The _item type_ of `ENTITIES` is `ENTITY`. `ENTITIES` is + derived from `anySimpleType` in two steps: an anonymous list type is + defined, whose _item type_ is `ENTITY`; this is the _base type_ of `ENTITIES`, which restricts its value space to lists with at least one item. """ . @@ -496,13 +496,13 @@ xsd:IDREFS a rdfs:Datatype; rdfs:subClassOf xsd:anySimpleType; rdfs:label "IDREFS"; rdfs:comment """ - IDREFS represents the IDREFS attribute type from [XML]. The ·value space· - of IDREFS is the set of finite, non-zero-length sequences of IDREFs. The - ·lexical space· of IDREFS is the set of space-separated lists of tokens, of - which each token is in the ·lexical space· of IDREF. The ·item type· of - IDREFS is IDREF. IDREFS is derived from ·anySimpleType· in two steps: an - anonymous list type is defined, whose ·item type· is IDREF; this is the - ·base type· of IDREFS, which restricts its value space to lists with at + `IDREFS` represents the `IDREFS` attribute type from [XML]. The _value space_ + of `IDREFS` is the set of finite, non-zero-length sequences of `IDREF`s. The + _lexical space_ of `IDREFS` is the set of space-separated lists of tokens, of + which each token is in the _lexical space_ of `IDREF`. The _item type_ of + `IDREFS` is `IDREF`. `IDREFS` is derived from `anySimpleType` in two steps: an + anonymous list type is defined, whose _item type_ is `IDREF`; this is the + _base type_ of `IDREFS`, which restricts its value space to lists with at least one item. """ . @@ -510,12 +510,12 @@ xsd:NMTOKENS a rdfs:Datatype; rdfs:subClassOf xsd:anySimpleType; rdfs:label "NMTOKENS"; rdfs:comment """ - NMTOKENS represents the NMTOKENS attribute type from [XML]. The ·value - space· of NMTOKENS is the set of finite, non-zero-length sequences of - ·NMTOKEN·s. The ·lexical space· of NMTOKENS is the set of space-separated - lists of tokens, of which each token is in the ·lexical space· of NMTOKEN. - The ·item type· of NMTOKENS is NMTOKEN. NMTOKENS is derived from - ·anySimpleType· in two steps: an anonymous list type is defined, whose - ·item type· is NMTOKEN; this is the ·base type· of NMTOKENS, which + `NMTOKENS` represents the `NMTOKENS` attribute type from [XML]. The _value + space_ of `NMTOKENS` is the set of finite, non-zero-length sequences of + `NMTOKEN`s. The _lexical space_ of `NMTOKENS` is the set of space-separated + lists of tokens, of which each token is in the _lexical space_ of `NMTOKEN`. + The _item type_ of `NMTOKENS` is `NMTOKEN`. `NMTOKENS` is derived from + `anySimpleType` in two steps: an anonymous list type is defined, whose + _item type_ is `NMTOKEN`; this is the _base type_ of `NMTOKENS`, which restricts its value space to lists with at least one item. """ . diff --git a/lib/rdf/vocab/xsd.rb b/lib/rdf/vocab/xsd.rb index 6b3073a0..3f4bd28b 100644 --- a/lib/rdf/vocab/xsd.rb +++ b/lib/rdf/vocab/xsd.rb @@ -7,55 +7,55 @@ module RDF # # Vocabulary for # # # class XSD < RDF::Vocabulary - # # ENTITIES represents the ENTITIES attribute type from [XML]. The ·value space· of ENTITIES is the set of finite, non-zero-length sequences of ·ENTITY· values that have been declared as unparsed entities in a document type definition. The ·lexical space· of ENTITIES is the set of space-separated lists of tokens, of which each token is in the ·lexical space· of ENTITY. The ·item type· of ENTITIES is ENTITY. ENTITIES is derived from ·anySimpleType· in two steps: an anonymous list type is defined, whose ·item type· is ENTITY; this is the ·base type· of ENTITIES, which restricts its value space to lists with at least one item. + # # `ENTITIES` represents the `ENTITIES` attribute type from [XML]. The _value space_ of `ENTITIES` is the set of finite, non-zero-length sequences of `ENTITY` values that have been declared as unparsed entities in a document type definition. The _lexical space_ of `ENTITIES` is the set of space-separated lists of tokens, of which each token is in the _lexical space_ of `ENTITY`. The _item type_ of `ENTITIES` is `ENTITY`. `ENTITIES` is derived from `anySimpleType` in two steps: an anonymous list type is defined, whose _item type_ is `ENTITY`; this is the _base type_ of `ENTITIES`, which restricts its value space to lists with at least one item. # # @return [RDF::Vocabulary::Term] # attr_reader :ENTITIES # - # # ENTITY represents the ENTITY attribute type from [XML]. The ·value space· of ENTITY is the set of all strings that ·match· the NCName production in [Namespaces in XML] and have been declared as an unparsed entity in a document type definition. The ·lexical space· of ENTITY is the set of all strings that ·match· the NCName production in [Namespaces in XML]. The ·base type· of ENTITY is NCName. + # # `ENTITY` represents the `ENTITY` attribute type from [XML]. The _value space_ of `ENTITY` is the set of all strings that match the `NCName` production in [Namespaces in XML] and have been declared as an unparsed entity in a document type definition. The _lexical space_ of ENTITY is the set of all strings that match the NCName production in [Namespaces in XML]. The _base type_ of ENTITY is NCName. # # @return [RDF::Vocabulary::Term] # attr_reader :ENTITY # - # # ID represents the ID attribute type from [XML]. The ·value space· of ID is the set of all strings that ·match· the NCName production in [Namespaces in XML]. The ·lexical space· of ID is the set of all strings that ·match· the NCName production in [Namespaces in XML]. The ·base type· of ID is NCName. + # # `ID` represents the `ID` attribute type from [XML]. The _value space_ of `ID` is the set of all strings that match the `NCName` production in [Namespaces in XML]. The _lexical space_ of `ID` is the set of all strings that match the `NCName` production in [Namespaces in XML]. The _base type_ of `ID` is `NCName`. # # @return [RDF::Vocabulary::Term] # attr_reader :ID # - # # IDREF represents the IDREF attribute type from [XML]. The ·value space· of IDREF is the set of all strings that ·match· the NCName production in [Namespaces in XML]. The ·lexical space· of IDREF is the set of strings that ·match· the NCName production in [Namespaces in XML]. The ·base type· of IDREF is NCName. + # # `IDREF` represents the `IDREF` attribute type from [XML]. The _value space_ of `IDREF` is the set of all strings that match the `NCName` production in [Namespaces in XML]. The _lexical space_ of `IDREF` is the set of strings that match the `NCName` production in [Namespaces in XML]. The _base type_ of `IDREF` is `NCName`. # # @return [RDF::Vocabulary::Term] # attr_reader :IDREF # - # # IDREFS represents the IDREFS attribute type from [XML]. The ·value space· of IDREFS is the set of finite, non-zero-length sequences of IDREFs. The ·lexical space· of IDREFS is the set of space-separated lists of tokens, of which each token is in the ·lexical space· of IDREF. The ·item type· of IDREFS is IDREF. IDREFS is derived from ·anySimpleType· in two steps: an anonymous list type is defined, whose ·item type· is IDREF; this is the ·base type· of IDREFS, which restricts its value space to lists with at least one item. + # # `IDREFS` represents the `IDREFS` attribute type from [XML]. The _value space_ of `IDREFS` is the set of finite, non-zero-length sequences of `IDREF`s. The _lexical space_ of `IDREFS` is the set of space-separated lists of tokens, of which each token is in the _lexical space_ of `IDREF`. The _item type_ of `IDREFS` is `IDREF`. `IDREFS` is derived from `anySimpleType` in two steps: an anonymous list type is defined, whose _item type_ is `IDREF`; this is the _base type_ of `IDREFS`, which restricts its value space to lists with at least one item. # # @return [RDF::Vocabulary::Term] # attr_reader :IDREFS # - # # NCName represents XML "non-colonized" Names. The ·value space· of NCName is the set of all strings which ·match· the NCName production of [Namespaces in XML]. The ·lexical space· of NCName is the set of all strings which ·match· the NCName production of [Namespaces in XML]. The ·base type· of NCName is Name. + # # `NCName` represents XML "non-colonized" Names. The _value space_ of `NCName` is the set of all strings which match the `NCName` production of [Namespaces in XML]. The _lexical space_ of `NCName` is the set of all strings which match the `NCName` production of [Namespaces in XML]. The _base type_ of `NCName` is `Name`. # # @return [RDF::Vocabulary::Term] # attr_reader :NCName # - # # NMTOKEN represents the NMTOKEN attribute type from [XML]. The ·value space· of NMTOKEN is the set of tokens that ·match· the Nmtoken production in [XML]. The ·lexical space· of NMTOKEN is the set of strings that ·match· the Nmtoken production in [XML]. The ·base type· of NMTOKEN is token. + # # `NMTOKEN` represents the `NMTOKEN` attribute type from [XML]. The _value space_ of `NMTOKEN` is the set of tokens that match the `Nmtoken` production in [XML]. The _lexical space_ of `NMTOKEN` is the set of strings that match the Nmtoken production in [XML]. The _base type_ of `NMTOKEN` is `token`. # # @return [RDF::Vocabulary::Term] # attr_reader :NMTOKEN # - # # NMTOKENS represents the NMTOKENS attribute type from [XML]. The ·value space· of NMTOKENS is the set of finite, non-zero-length sequences of ·NMTOKEN·s. The ·lexical space· of NMTOKENS is the set of space-separated lists of tokens, of which each token is in the ·lexical space· of NMTOKEN. The ·item type· of NMTOKENS is NMTOKEN. NMTOKENS is derived from ·anySimpleType· in two steps: an anonymous list type is defined, whose ·item type· is NMTOKEN; this is the ·base type· of NMTOKENS, which restricts its value space to lists with at least one item. + # # `NMTOKENS` represents the `NMTOKENS` attribute type from [XML]. The _value space_ of `NMTOKENS` is the set of finite, non-zero-length sequences of `NMTOKEN`s. The _lexical space_ of `NMTOKENS` is the set of space-separated lists of tokens, of which each token is in the _lexical space_ of `NMTOKEN`. The _item type_ of `NMTOKENS` is `NMTOKEN`. `NMTOKENS` is derived from `anySimpleType` in two steps: an anonymous list type is defined, whose _item type_ is `NMTOKEN`; this is the _base type_ of `NMTOKENS`, which restricts its value space to lists with at least one item. # # @return [RDF::Vocabulary::Term] # attr_reader :NMTOKENS # - # # NOTATION represents the NOTATION attribute type from [XML]. The ·value space· of NOTATION is the set of QNames of notations declared in the current schema. The ·lexical space· of NOTATION is the set of all names of notations declared in the current schema (in the form of QNames). + # # `NOTATION` represents the `NOTATION` attribute type from [XML]. The _value space_ of `NOTATION` is the set of `QNames` of notations declared in the current schema. The _lexical space_ of `NOTATION` is the set of all names of notations declared in the current schema (in the form of `QNames`). # # @return [RDF::Vocabulary::Term] # attr_reader :NOTATION # - # # Name represents XML Names. The ·value space· of Name is the set of all strings which ·match· the Name production of [XML]. The ·lexical space· of Name is the set of all strings which ·match· the Name production of [XML]. The ·base type· of Name is token. + # # `Name` represents XML Names. The _value space_ of `Name` is the set of all strings which match the `Name` production of [XML]. The _lexical space_ of `Name` is the set of all strings which match the `Name` production of [XML]. The _base type_ of `Name` is `token`. # # @return [RDF::Vocabulary::Term] # attr_reader :Name # - # # QName represents XML qualified names. The ·value space· of QName is the set of tuples {namespace name, local part}, where namespace name is an anyURI and local part is an NCName. The ·lexical space· of QName is the set of strings that ·match· the QName production of [Namespaces in XML]. + # # `QName` represents XML qualified names. The _value space_ of `QName` is the set of tuples `{namespace name, local part}`, where namespace name is an `anyURI` and local part is an `NCName`. The _lexical space_ of `QName` is the set of strings that match the `QName` production of [Namespaces in XML]. # # @return [RDF::Vocabulary::Term] # attr_reader :QName # - # # anyAtomicType is a special ·restriction· of anySimpleType. The ·value· and ·lexical spaces· of anyAtomicType are the unions of the ·value· and ·lexical spaces· of all the ·primitive· datatypes, and anyAtomicType is their ·base type·. + # # `anyAtomicType` is a special _restriction_ of `anySimpleType`. The _value_ and _lexical spaces_ of `anyAtomicType` are the unions of the _value_ and _lexical spaces_ of all the _primitive_ datatypes, and `anyAtomicType` is their _base type_. # # @return [RDF::Vocabulary::Term] # attr_reader :anyAtomicType # - # # The definition of anySimpleType is a special ·restriction· of anyType. The ·lexical space· of anySimpleType is the set of all sequences of Unicode characters, and its ·value space· includes all ·atomic values· and all finite-length lists of zero or more ·atomic values·. + # # The definition of `anySimpleType` is a special _restriction_ of `anyType`. The _lexical space_ of a`nySimpleType` is the set of all sequences of Unicode characters, and its _value space_ includes all _atomic values_ and all finite-length lists of zero or more _atomic values_. # # @return [RDF::Vocabulary::Term] # attr_reader :anySimpleType # @@ -63,147 +63,147 @@ module RDF # # @return [RDF::Vocabulary::Term] # attr_reader :anyType # - # # anyURI represents an Internationalized Resource Identifier Reference (IRI). An anyURI value can be absolute or relative, and may have an optional fragment identifier (i.e., it may be an IRI Reference). This type should be used when the value fulfills the role of an IRI, as defined in [RFC 3987] or its successor(s) in the IETF Standards Track. + # # `anyURI` represents an Internationalized Resource Identifier Reference (IRI). An `anyURI` value can be absolute or relative, and may have an optional fragment identifier (i.e., it may be an IRI Reference). This type should be used when the value fulfills the role of an IRI, as defined in [RFC 3987] or its successor(s) in the IETF Standards Track. # # @return [RDF::Vocabulary::Term] # attr_reader :anyURI # - # # base64Binary represents arbitrary Base64-encoded binary data. For base64Binary data the entire binary stream is encoded using the Base64 Encoding defined in [RFC 3548], which is derived from the encoding described in [RFC 2045]. + # # `base64Binary` represents arbitrary Base64-encoded binary data. For `base64Binary` data the entire binary stream is encoded using the `Base64` Encoding defined in [RFC 3548], which is derived from the encoding described in [RFC 2045]. # # @return [RDF::Vocabulary::Term] # attr_reader :base64Binary # - # # boolean represents the values of two-valued logic. + # # `boolean` represents the values of two-valued logic. # # @return [RDF::Vocabulary::Term] # attr_reader :boolean # - # # byte is ·derived· from short by setting the value of ·maxInclusive· to be 127 and ·minInclusive· to be -128. The ·base type· of byte is short. + # # `byte` is _derived_ from `short` by setting the value of `maxInclusive` to be `127` and `minInclusive` to be `-128`. The _base type_ of `byte` is `short`. # # @return [RDF::Vocabulary::Term] # attr_reader :byte # - # # date represents top-open intervals of exactly one day in length on the timelines of dateTime, beginning on the beginning moment of each day, up to but not including the beginning moment of the next day). For non-timezoned values, the top-open intervals disjointly cover the non-timezoned timeline, one per day. For timezoned values, the intervals begin at every minute and therefore overlap. + # # `date` represents top-open intervals of exactly one day in length on the timelines of `dateTime`, beginning on the beginning moment of each day, up to but not including the beginning moment of the next day). For non-timezoned values, the top-open intervals disjointly cover the non-timezoned timeline, one per day. For timezoned values, the intervals begin at every minute and therefore overlap. # # @return [RDF::Vocabulary::Term] # attr_reader :date # - # # dateTime represents instants of time, optionally marked with a particular time zone offset. Values representing the same instant but having different time zone offsets are equal but not identical. + # # `dateTime` represents instants of time, optionally marked with a particular time zone offset. Values representing the same instant but having different time zone offsets are equal but not identical. # # @return [RDF::Vocabulary::Term] # attr_reader :dateTime # - # # The dateTimeStamp datatype is ·derived· from dateTime by giving the value required to its explicitTimezone facet. The result is that all values of dateTimeStamp are required to have explicit time zone offsets and the datatype is totally ordered. + # # The `dateTimeStamp` datatype is _derived_ from `dateTime` by giving the value required to its `explicitTimezone` facet. The result is that all values of `dateTimeStamp` are required to have explicit time zone offsets and the datatype is totally ordered. # # @return [RDF::Vocabulary::Term] # attr_reader :dateTimeStamp # - # # 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. + # # `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. # # @return [RDF::Vocabulary::Term] # attr_reader :dayTimeDuration # - # # decimal represents a subset of the real numbers, which can be represented by decimal numerals. The ·value space· of decimal is the set of numbers that can be obtained by dividing an integer by a non-negative power of ten, i.e., expressible as i / 10n where i and n are integers and n ≥ 0. Precision is not reflected in this value space; the number 2.0 is not distinct from the number 2.00. The order relation on decimal is the order relation on real numbers, restricted to this subset. + # # `decimal` represents a subset of the real numbers, which can be represented by decimal numerals. The _value space_ of decimal is the set of numbers that can be obtained by dividing an integer by a non-negative power of ten, i.e., expressible as `i / 10n` where `i` and `n` are integers and `n ≥ 0`. Precision is not reflected in this value space; the number `2.0` is not distinct from the number `2.00`. The order relation on `decimal` is the order relation on real numbers, restricted to this subset. # # @return [RDF::Vocabulary::Term] # attr_reader :decimal # - # # The double datatype is patterned after the IEEE double-precision 64-bit floating point datatype [IEEE 754-2008]. Each floating point datatype has a value space that is a subset of the rational numbers. Floating point numbers are often used to approximate arbitrary real numbers. + # # The `double` datatype is patterned after the IEEE double-precision 64-bit floating point datatype [IEEE 754-2008]. Each floating point datatype has a value space that is a subset of the rational numbers. Floating point numbers are often used to approximate arbitrary real numbers. # # @return [RDF::Vocabulary::Term] # attr_reader :double # - # # duration is a datatype that represents durations of time. The concept of duration being captured is drawn from those of [ISO 8601], specifically durations without fixed endpoints. For example, "15 days" (whose most common lexical representation in duration is "'P15D'") is a duration value; "15 days beginning 12 July 1995" and "15 days ending 12 July 1995" are not duration values. duration can provide addition and subtraction operations between duration values and between duration/dateTime value pairs, and can be the result of subtracting dateTime values. However, only addition to dateTime is required for XML Schema processing and is defined in the function ·dateTimePlusDuration·. + # # `duration` is a datatype that represents durations of time. The concept of duration being captured is drawn from those of [ISO 8601], specifically durations without fixed endpoints. For example, "15 days" (whose most common lexical representation in duration is `"'P15D'"`) is a duration value; "15 days beginning 12 July 1995" and "15 days ending 12 July 1995" are not duration values. duration can provide addition and subtraction operations between duration values and between duration/dateTime value pairs, and can be the result of subtracting dateTime values. However, only addition to `dateTime` is required for XML Schema processing and is defined in the function `dateTimePlusDuration`. # # @return [RDF::Vocabulary::Term] # attr_reader :duration # - # # The float datatype is patterned after the IEEE single-precision 32-bit floating point datatype [IEEE 754-2008]. Its value space is a subset of the rational numbers. Floating point numbers are often used to approximate arbitrary real numbers. + # # The `float` datatype is patterned after the IEEE single-precision 32-bit floating point datatype [IEEE 754-2008]. Its value space is a subset of the rational numbers. Floating point numbers are often used to approximate arbitrary real numbers. # # @return [RDF::Vocabulary::Term] # attr_reader :float # - # # gDay represents whole days within an arbitrary month—days that recur at the same point in each (Gregorian) month. This datatype is used to represent a specific day of the month. To indicate, for example, that an employee gets a paycheck on the 15th of each month. (Obviously, days beyond 28 cannot occur in all months; they are nonetheless permitted, up to 31.) + # # `gDay` represents whole days within an arbitrary month—days that recur at the same point in each (Gregorian) month. This datatype is used to represent a specific day of the month. To indicate, for example, that an employee gets a paycheck on the 15th of each month. (Obviously, days beyond 28 cannot occur in all months; they are nonetheless permitted, up to 31.) # # @return [RDF::Vocabulary::Term] # attr_reader :gDay # - # # gMonth represents whole (Gregorian) months within an arbitrary year—months that recur at the same point in each year. It might be used, for example, to say what month annual Thanksgiving celebrations fall in different countries (--11 in the United States, --10 in Canada, and possibly other months in other countries). + # # `gMonth` represents whole (Gregorian) months within an arbitrary year—months that recur at the same point in each year. It might be used, for example, to say what month annual Thanksgiving celebrations fall in different countries (`--11` in the United States, `--10` in Canada, and possibly other months in other countries). # # @return [RDF::Vocabulary::Term] # attr_reader :gMonth # - # # gMonthDay represents whole calendar days that recur at the same point in each calendar year, or that occur in some arbitrary calendar year. (Obviously, days beyond 28 cannot occur in all Februaries; 29 is nonetheless permitted.) + # # `gMonthDay` represents whole calendar days that recur at the same point in each calendar year, or that occur in some arbitrary calendar year. (Obviously, days beyond 28 cannot occur in all Februaries; 29 is nonetheless permitted.) # # @return [RDF::Vocabulary::Term] # attr_reader :gMonthDay # - # # gYear represents Gregorian calendar years. + # # `gYear` represents Gregorian calendar years. # # @return [RDF::Vocabulary::Term] # attr_reader :gYear # - # # gYearMonth represents specific whole Gregorian months in specific Gregorian years. + # # `gYearMonth` represents specific whole Gregorian months in specific Gregorian years. # # @return [RDF::Vocabulary::Term] # attr_reader :gYearMonth # - # # hexBinary represents arbitrary hex-encoded binary data. + # # hexBinary` represents arbitrary hex-encoded binary data. # # @return [RDF::Vocabulary::Term] # attr_reader :hexBinary # - # # int is ·derived· from long by setting the value of ·maxInclusive· to be 2147483647 and ·minInclusive· to be -2147483648. The ·base type· of int is long. + # # `int` is _derived_ from `long` by setting the value of `maxInclusive` to be `2147483647` and `minInclusive` to be `-2147483648`. The _base type_ of `int` is `long`. # # @return [RDF::Vocabulary::Term] # attr_reader :int # - # # integer is ·derived· from decimal by fixing the value of ·fractionDigits· to be 0 and disallowing the trailing decimal point. This results in the standard mathematical concept of the integer numbers. The ·value space· of integer is the infinite set {...,-2,-1,0,1,2,...}. The ·base type· of integer is decimal. + # # `integer` is _derived_ from `decimal` by fixing the value of `fractionDigits` to be `0` and disallowing the trailing decimal point. This results in the standard mathematical concept of the integer numbers. The _value space_ of `integer` is the infinite set `{...,-2,-1,0,1,2,...}`. The _base type_ of `integer` is `decimal`. # # @return [RDF::Vocabulary::Term] # attr_reader :integer # - # # language represents formal natural language identifiers, as defined by [BCP 47] (currently represented by [RFC 4646] and [RFC 4647]) or its successor(s). The ·value space· and ·lexical space· of language are the set of all strings that conform to the pattern [a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})* + # # `language` represents formal natural language identifiers, as defined by [BCP 47] (currently represented by [RFC 4646] and [RFC 4647]) or its successor(s). The _value space_ and _lexical space_ of `language` are the set of all strings that conform to the pattern `[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*`. # # @return [RDF::Vocabulary::Term] # attr_reader :language # - # # long is ·derived· from integer by setting the value of ·maxInclusive· to be 9223372036854775807 and ·minInclusive· to be -9223372036854775808. The ·base type· of long is integer. + # # `long` is _derived_ from `integer` by setting the value of `maxInclusive` to be `9223372036854775807` and `minInclusive` to be `-9223372036854775808`. The _base type_ of `long` is `integer`. # # @return [RDF::Vocabulary::Term] # attr_reader :long # - # # negativeInteger is ·derived· from nonPositiveInteger by setting the value of ·maxInclusive· to be -1. This results in the standard mathematical concept of the negative integers. The ·value space· of negativeInteger is the infinite set {...,-2,-1}. The ·base type· of negativeInteger is nonPositiveInteger. + # # `negativeInteger` is _derived_ from `nonPositiveInteger` by setting the value of `maxInclusive` to be `-1`. This results in the standard mathematical concept of the negative integers. The _value space_ of `negativeInteger` is the infinite set `{...,-2,-1}`. The _base type_ of `negativeInteger` is `nonPositiveInteger`. # # @return [RDF::Vocabulary::Term] # attr_reader :negativeInteger # - # # nonNegativeInteger is ·derived· from integer by setting the value of ·minInclusive· to be 0. This results in the standard mathematical concept of the non-negative integers. The ·value space· of nonNegativeInteger is the infinite set {0,1,2,...}. The ·base type· of nonNegativeInteger is integer. + # # `nonNegativeInteger` is _derived_ from `integer` by setting the value of `minInclusive` to be `0`. This results in the standard mathematical concept of the non-negative integers. The _value space_ of `nonNegativeInteger` is the infinite set `{0,1,2,...}`. The _base type_ of `nonNegativeInteger` is `integer`. # # @return [RDF::Vocabulary::Term] # attr_reader :nonNegativeInteger # - # # nonPositiveInteger is ·derived· from integer by setting the value of ·maxInclusive· to be 0. This results in the standard mathematical concept of the non-positive integers. The ·value space· of nonPositiveInteger is the infinite set {...,-2,-1,0}. The ·base type· of nonPositiveInteger is integer. + # # `nonPositiveInteger` is _derived_ from `integer` by setting the value of `maxInclusive` to be `0`. This results in the standard mathematical concept of the non-positive integers. The _value space_ of `nonPositiveInteger` is the infinite set `{...,-2,-1,0}`. The _base type_ of `nonPositiveInteger` is `integer`. # # @return [RDF::Vocabulary::Term] # attr_reader :nonPositiveInteger # - # # normalizedString represents white space normalized strings. The ·value space· of normalizedString is the set of strings that do not contain the carriage return (#xD), line feed (#xA) nor tab (#x9) characters. The ·lexical space· of normalizedString is the set of strings that do not contain the carriage return (#xD), line feed (#xA) nor tab (#x9) characters. The ·base type· of normalizedString is string. + # # `normalizedString` represents white space normalized strings. The _value space_ of `normalizedString` is the set of strings that do not contain the carriage return (`#xD`), line feed (`#xA`) nor tab (`#x9`) characters. The _lexical space_ of `normalizedString` is the set of strings that do not contain the carriage return (`#xD`), line feed (`#xA`) nor tab (`#x9`) characters. The _base type_ of `normalizedString` is `string`. # # @return [RDF::Vocabulary::Term] # attr_reader :normalizedString # - # # positiveInteger is ·derived· from nonNegativeInteger by setting the value of ·minInclusive· to be 1. This results in the standard mathematical concept of the positive integer numbers. The ·value space· of positiveInteger is the infinite set {1,2,...}. The ·base type· of positiveInteger is nonNegativeInteger. + # # `positiveInteger` is _derived_ from `nonNegativeInteger` by setting the value of `minInclusive` to be `1`. This results in the standard mathematical concept of the positive integer numbers. The _value space_ of `positiveInteger` is the infinite set `{1,2,...}`. The _base type_ of `positiveInteger` is `nonNegativeInteger`. # # @return [RDF::Vocabulary::Term] # attr_reader :positiveInteger # - # # short is ·derived· from int by setting the value of ·maxInclusive· to be 32767 and ·minInclusive· to be -32768. The ·base type· of short is int. + # # `short` is _derived_ from `int` by setting the value of `maxInclusive` to be `32767` and `minInclusive` to be `-32768`. The _base type_ of `short` is `int`. # # @return [RDF::Vocabulary::Term] # attr_reader :short # - # # The string datatype represents character strings in XML. + # # The `string` datatype represents character strings in XML. # # @return [RDF::Vocabulary::Term] # attr_reader :string # - # # time represents instants of time that recur at the same point in each calendar day, or that occur in some arbitrary calendar day. + # # `time` represents instants of time that recur at the same point in each calendar day, or that occur in some arbitrary calendar day. # # @return [RDF::Vocabulary::Term] # attr_reader :time # - # # token represents tokenized strings. The ·value space· of token is the set of strings that do not contain the carriage return (#xD), line feed (#xA) nor tab (#x9) characters, that have no leading or trailing spaces (#x20) and that have no internal sequences of two or more spaces. The ·lexical space· of token is the set of strings that do not contain the carriage return (#xD), line feed (#xA) nor tab (#x9) characters, that have no leading or trailing spaces (#x20) and that have no internal sequences of two or more spaces. The ·base type· of token is normalizedString. + # # `token` represents tokenized strings. The _value space_ of `token` is the set of strings that do not contain the carriage return (`#xD`), line feed (`#xA`) nor tab (`#x9`) characters, that have no leading or trailing spaces (`#x20`) and that have no internal sequences of two or more spaces. The _lexical space_ of `token` is the set of strings that do not contain the carriage return (`#xD`), line feed (`#xA`) nor tab (`#x9`) characters, that have no leading or trailing spaces (`#x20`) and that have no internal sequences of two or more spaces. The _base type_ of `token` is `normalizedString`. # # @return [RDF::Vocabulary::Term] # attr_reader :token # - # # nsignedByte is ·derived· from unsignedShort by setting the value of ·maxInclusive· to be 255. The ·base type· of unsignedByte is unsignedShort. + # # `unsignedByte` is _derived_ from `unsignedShort` by setting the value of `maxInclusive` to be `255`. The _base type_ of `unsignedByte` is `unsignedShort`. # # @return [RDF::Vocabulary::Term] # attr_reader :unsignedByte # - # # unsignedInt is ·derived· from unsignedLong by setting the value of ·maxInclusive· to be 4294967295. The ·base type· of unsignedInt is unsignedLong. + # # `unsignedInt` is _derived_ from `unsignedLong` by setting the value of `maxInclusive` to be `4294967295`. The _base type_ of `unsignedInt` is `unsignedLong`. # # @return [RDF::Vocabulary::Term] # attr_reader :unsignedInt # - # # unsignedLong is ·derived· from nonNegativeInteger by setting the value of ·maxInclusive· to be 18446744073709551615. The ·base type· of unsignedLong is nonNegativeInteger. + # # `unsignedLong` is _derived_ from `nonNegativeInteger` by setting the value of `maxInclusive` to be `18446744073709551615`. The _base type_ of `unsignedLong` is `nonNegativeInteger`. # # @return [RDF::Vocabulary::Term] # attr_reader :unsignedLong # - # # unsignedShort is ·derived· from unsignedInt by setting the value of ·maxInclusive· to be 65535. The ·base type· of unsignedShort is unsignedInt. + # # `unsignedShort` is _derived_ from `unsignedInt` by setting the value of `maxInclusive` to be `65535`. The _base type_ of `unsignedShort` is `unsignedInt`. # # @return [RDF::Vocabulary::Term] # attr_reader :unsignedShort # - # # yearMonthDuration is a datatype ·derived· from 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. + # # `yearMonthDuration` is a datatype _derived_ from `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. # # @return [RDF::Vocabulary::Term] # attr_reader :yearMonthDuration # @@ -212,67 +212,67 @@ module RDF # Datatype definitions term :ENTITIES, - comment: "\n ENTITIES represents the ENTITIES attribute type from [XML]. The ·value\n space· of ENTITIES is the set of finite, non-zero-length sequences of\n ·ENTITY· values that have been declared as unparsed entities in a document\n type definition. The ·lexical space· of ENTITIES is the set of\n space-separated lists of tokens, of which each token is in the ·lexical\n space· of ENTITY. The ·item type· of ENTITIES is ENTITY. ENTITIES is\n derived from ·anySimpleType· in two steps: an anonymous list type is\n defined, whose ·item type· is ENTITY; this is the ·base type· of ENTITIES,\n which restricts its value space to lists with at least one item.\n ", + comment: "\n `ENTITIES` represents the `ENTITIES` attribute type from [XML]. The _value\n space_ of `ENTITIES` is the set of finite, non-zero-length sequences of\n `ENTITY` values that have been declared as unparsed entities in a document\n type definition. The _lexical space_ of `ENTITIES` is the set of\n space-separated lists of tokens, of which each token is in the _lexical\n space_ of `ENTITY`. The _item type_ of `ENTITIES` is `ENTITY`. `ENTITIES` is\n derived from `anySimpleType` in two steps: an anonymous list type is\n defined, whose _item type_ is `ENTITY`; this is the _base type_ of `ENTITIES`,\n which restricts its value space to lists with at least one item.\n ", label: "ENTITIES", subClassOf: "http://www.w3.org/2001/XMLSchema#anySimpleType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :ENTITY, - comment: "\n ENTITY represents the ENTITY attribute type from [XML]. The ·value space·\n of ENTITY is the set of all strings that ·match· the NCName production in\n [Namespaces in XML] and have been declared as an unparsed entity in a\n document type definition. The ·lexical space· of ENTITY is the set of all\n strings that ·match· the NCName production in [Namespaces in XML]. The\n ·base type· of ENTITY is NCName.\n ", + comment: "\n `ENTITY` represents the `ENTITY` attribute type from [XML]. The _value space_\n of `ENTITY` is the set of all strings that match the `NCName` production in\n [Namespaces in XML] and have been declared as an unparsed entity in a\n document type definition. The _lexical space_ of ENTITY is the set of all\n strings that match the NCName production in [Namespaces in XML]. The\n _base type_ of ENTITY is NCName.\n ", label: "ENTITY", subClassOf: "http://www.w3.org/2001/XMLSchema#NCName", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :ID, - comment: "\n ID represents the ID attribute type from [XML]. The ·value space· of ID is\n the set of all strings that ·match· the NCName production in [Namespaces\n in XML]. The ·lexical space· of ID is the set of all strings that ·match·\n the NCName production in [Namespaces in XML]. The ·base type· of ID is\n NCName.\n ", + comment: "\n `ID` represents the `ID` attribute type from [XML]. The _value space_ of `ID` is\n the set of all strings that match the `NCName` production in [Namespaces\n in XML]. The _lexical space_ of `ID` is the set of all strings that match\n the `NCName` production in [Namespaces in XML]. The _base type_ of `ID` is\n `NCName`.\n ", label: "ID", subClassOf: "http://www.w3.org/2001/XMLSchema#NCName", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :IDREF, - comment: "\n IDREF represents the IDREF attribute type from [XML]. The ·value space· of\n IDREF is the set of all strings that ·match· the NCName production in\n [Namespaces in XML]. The ·lexical space· of IDREF is the set of strings\n that ·match· the NCName production in [Namespaces in XML]. The ·base type·\n of IDREF is NCName.\n ", + comment: "\n `IDREF` represents the `IDREF` attribute type from [XML]. The _value space_ of\n `IDREF` is the set of all strings that match the `NCName` production in\n [Namespaces in XML]. The _lexical space_ of `IDREF` is the set of strings\n that match the `NCName` production in [Namespaces in XML]. The _base type_\n of `IDREF` is `NCName`.\n ", label: "IDREF", subClassOf: "http://www.w3.org/2001/XMLSchema#NCName", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :IDREFS, - comment: "\n IDREFS represents the IDREFS attribute type from [XML]. The ·value space·\n of IDREFS is the set of finite, non-zero-length sequences of IDREFs. The\n ·lexical space· of IDREFS is the set of space-separated lists of tokens, of\n which each token is in the ·lexical space· of IDREF. The ·item type· of\n IDREFS is IDREF. IDREFS is derived from ·anySimpleType· in two steps: an\n anonymous list type is defined, whose ·item type· is IDREF; this is the\n ·base type· of IDREFS, which restricts its value space to lists with at\n least one item.\n ", + comment: "\n `IDREFS` represents the `IDREFS` attribute type from [XML]. The _value space_\n of `IDREFS` is the set of finite, non-zero-length sequences of `IDREF`s. The\n _lexical space_ of `IDREFS` is the set of space-separated lists of tokens, of\n which each token is in the _lexical space_ of `IDREF`. The _item type_ of\n `IDREFS` is `IDREF`. `IDREFS` is derived from `anySimpleType` in two steps: an\n anonymous list type is defined, whose _item type_ is `IDREF`; this is the\n _base type_ of `IDREFS`, which restricts its value space to lists with at\n least one item.\n ", label: "IDREFS", subClassOf: "http://www.w3.org/2001/XMLSchema#anySimpleType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :NCName, - comment: "\n NCName represents XML \"non-colonized\" Names. The ·value space· of NCName\n is the set of all strings which ·match· the NCName production of\n [Namespaces in XML]. The ·lexical space· of NCName is the set of all\n strings which ·match· the NCName production of [Namespaces in XML]. The\n ·base type· of NCName is Name.\n ", + comment: "\n `NCName` represents XML \"non-colonized\" Names. The _value space_ of `NCName`\n is the set of all strings which match the `NCName` production of\n [Namespaces in XML]. The _lexical space_ of `NCName` is the set of all\n strings which match the `NCName` production of [Namespaces in XML]. The\n _base type_ of `NCName` is `Name`.\n ", label: "NCName", subClassOf: "http://www.w3.org/2001/XMLSchema#Name", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :NMTOKEN, - comment: "\n NMTOKEN represents the NMTOKEN attribute type from [XML]. The ·value\n space· of NMTOKEN is the set of tokens that ·match· the Nmtoken production\n in [XML]. The ·lexical space· of NMTOKEN is the set of strings that\n ·match· the Nmtoken production in [XML]. The ·base type· of NMTOKEN is\n token.\n ", + comment: "\n `NMTOKEN` represents the `NMTOKEN` attribute type from [XML]. The _value\n space_ of `NMTOKEN` is the set of tokens that match the `Nmtoken` production\n in [XML]. The _lexical space_ of `NMTOKEN` is the set of strings that\n match the Nmtoken production in [XML]. The _base type_ of `NMTOKEN` is\n `token`.\n ", label: "NMTOKEN", subClassOf: "http://www.w3.org/2001/XMLSchema#token", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :NMTOKENS, - comment: "\n NMTOKENS represents the NMTOKENS attribute type from [XML]. The ·value\n space· of NMTOKENS is the set of finite, non-zero-length sequences of\n ·NMTOKEN·s. The ·lexical space· of NMTOKENS is the set of space-separated\n lists of tokens, of which each token is in the ·lexical space· of NMTOKEN.\n The ·item type· of NMTOKENS is NMTOKEN. NMTOKENS is derived from\n ·anySimpleType· in two steps: an anonymous list type is defined, whose\n ·item type· is NMTOKEN; this is the ·base type· of NMTOKENS, which\n restricts its value space to lists with at least one item.\n ", + comment: "\n `NMTOKENS` represents the `NMTOKENS` attribute type from [XML]. The _value\n space_ of `NMTOKENS` is the set of finite, non-zero-length sequences of\n `NMTOKEN`s. The _lexical space_ of `NMTOKENS` is the set of space-separated\n lists of tokens, of which each token is in the _lexical space_ of `NMTOKEN`.\n The _item type_ of `NMTOKENS` is `NMTOKEN`. `NMTOKENS` is derived from\n `anySimpleType` in two steps: an anonymous list type is defined, whose\n _item type_ is `NMTOKEN`; this is the _base type_ of `NMTOKENS`, which\n restricts its value space to lists with at least one item.\n ", label: "NMTOKENS", subClassOf: "http://www.w3.org/2001/XMLSchema#anySimpleType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :NOTATION, - comment: "\n NOTATION represents the NOTATION attribute type from [XML]. The ·value\n space· of NOTATION is the set of QNames of notations declared in the\n current schema. The ·lexical space· of NOTATION is the set of all names of\n notations declared in the current schema (in the form of QNames).\n ", + comment: "\n `NOTATION` represents the `NOTATION` attribute type from [XML]. The _value\n space_ of `NOTATION` is the set of `QNames` of notations declared in the\n current schema. The _lexical space_ of `NOTATION` is the set of all names of\n notations declared in the current schema (in the form of `QNames`).\n ", label: "NOTATION", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :Name, - comment: "\n Name represents XML Names. The ·value space· of Name is the set of all\n strings which ·match· the Name production of [XML]. The ·lexical space· of\n Name is the set of all strings which ·match· the Name production of [XML].\n The ·base type· of Name is token.\n ", + comment: "\n `Name` represents XML Names. The _value space_ of `Name` is the set of all\n strings which match the `Name` production of [XML]. The _lexical space_ of\n `Name` is the set of all strings which match the `Name` production of [XML].\n The _base type_ of `Name` is `token`.\n ", label: "Name", subClassOf: "http://www.w3.org/2001/XMLSchema#token", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :QName, - comment: "\n QName represents XML qualified names. The ·value space· of QName is the set\n of tuples {namespace name, local part}, where namespace name is an anyURI\n and local part is an NCName. The ·lexical space· of QName is the set of\n strings that ·match· the QName production of [Namespaces in XML].\n ", + comment: "\n `QName` represents XML qualified names. The _value space_ of `QName` is the set\n of tuples `{namespace name, local part}`, where namespace name is an `anyURI`\n and local part is an `NCName`. The _lexical space_ of `QName` is the set of\n strings that match the `QName` production of [Namespaces in XML].\n ", label: "QName", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :anyAtomicType, - comment: "\n anyAtomicType is a special ·restriction· of anySimpleType. The ·value· and\n ·lexical spaces· of anyAtomicType are the unions of the ·value· and\n ·lexical spaces· of all the ·primitive· datatypes, and anyAtomicType is\n their ·base type·.\n ", + comment: "\n `anyAtomicType` is a special _restriction_ of `anySimpleType`. The _value_ and\n _lexical spaces_ of `anyAtomicType` are the unions of the _value_ and\n _lexical spaces_ of all the _primitive_ datatypes, and `anyAtomicType` is\n their _base type_.\n ", label: "anySimpleType", subClassOf: "http://www.w3.org/2001/XMLSchema#anyType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :anySimpleType, - comment: "\n The definition of anySimpleType is a special ·restriction· of anyType. The\n ·lexical space· of anySimpleType is the set of all sequences of Unicode\n characters, and its ·value space· includes all ·atomic values· and all\n finite-length lists of zero or more ·atomic values·.\n ", + comment: "\n The definition of `anySimpleType` is a special _restriction_ of `anyType`. The\n _lexical space_ of a`nySimpleType` is the set of all sequences of Unicode\n characters, and its _value space_ includes all _atomic values_ and all\n finite-length lists of zero or more _atomic values_.\n ", label: "anySimpleType", subClassOf: "http://www.w3.org/2001/XMLSchema#anyType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" @@ -281,182 +281,182 @@ module RDF label: "anyType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :anyURI, - comment: "\n anyURI represents an Internationalized Resource Identifier Reference\n (IRI). An anyURI value can be absolute or relative, and may have an\n optional fragment identifier (i.e., it may be an IRI Reference). This\n type should be used when the value fulfills the role of an IRI, as\n defined in [RFC 3987] or its successor(s) in the IETF Standards Track.\n ", + comment: "\n `anyURI` represents an Internationalized Resource Identifier Reference\n (IRI). An `anyURI` value can be absolute or relative, and may have an\n optional fragment identifier (i.e., it may be an IRI Reference). This\n type should be used when the value fulfills the role of an IRI, as\n defined in [RFC 3987] or its successor(s) in the IETF Standards Track.\n ", label: "anyURI", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :base64Binary, - comment: "\n base64Binary represents arbitrary Base64-encoded binary data. For\n base64Binary data the entire binary stream is encoded using the Base64\n Encoding defined in [RFC 3548], which is derived from the encoding\n described in [RFC 2045].\n ", + comment: "\n `base64Binary` represents arbitrary Base64-encoded binary data. For\n `base64Binary` data the entire binary stream is encoded using the `Base64`\n Encoding defined in [RFC 3548], which is derived from the encoding\n described in [RFC 2045].\n ", label: "base64Binary", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :boolean, - comment: "\n boolean represents the values of two-valued logic.\n ", + comment: "\n `boolean` represents the values of two-valued logic.\n ", label: "boolean", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :byte, - comment: "\n byte is ·derived· from short by setting the value of ·maxInclusive· to be\n 127 and ·minInclusive· to be -128. The ·base type· of byte is short.\n ", + comment: "\n `byte` is _derived_ from `short` by setting the value of `maxInclusive` to be\n `127` and `minInclusive` to be `-128`. The _base type_ of `byte` is `short`.\n ", label: "byte", subClassOf: "http://www.w3.org/2001/XMLSchema#short", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :date, - comment: "\n date represents top-open intervals of exactly one day in length on the\n timelines of dateTime, beginning on the beginning moment of each day, up to\n but not including the beginning moment of the next day). For non-timezoned\n values, the top-open intervals disjointly cover the non-timezoned timeline,\n one per day. For timezoned values, the intervals begin at every minute and\n therefore overlap.\n ", + comment: "\n `date` represents top-open intervals of exactly one day in length on the\n timelines of `dateTime`, beginning on the beginning moment of each day, up to\n but not including the beginning moment of the next day). For non-timezoned\n values, the top-open intervals disjointly cover the non-timezoned timeline,\n one per day. For timezoned values, the intervals begin at every minute and\n therefore overlap.\n ", label: "date", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :dateTime, - comment: "\n dateTime represents instants of time, optionally marked with a particular\n time zone offset. Values representing the same instant but having different\n time zone offsets are equal but not identical.\n ", + comment: "\n `dateTime` represents instants of time, optionally marked with a particular\n time zone offset. Values representing the same instant but having different\n time zone offsets are equal but not identical.\n ", label: "dateTime", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :dateTimeStamp, - comment: "\n The dateTimeStamp datatype is ·derived· from dateTime by giving the value\n required to its explicitTimezone facet. The result is that all values of\n dateTimeStamp are required to have explicit time zone offsets and the\n datatype is totally ordered.\n ", + comment: "\n The `dateTimeStamp` datatype is _derived_ from `dateTime` by giving the value\n required to its `explicitTimezone` facet. The result is that all values of\n `dateTimeStamp` are required to have explicit time zone offsets and the\n datatype is totally ordered.\n ", label: "dateTimeStamp", subClassOf: "http://www.w3.org/2001/XMLSchema#dateTime", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :dayTimeDuration, - comment: "\n dayTimeDuration is a datatype ·derived· from duration by restricting its\n ·lexical representations· to instances of dayTimeDurationLexicalRep. The\n ·value space· of dayTimeDuration is therefore that of duration restricted\n to those whose ·months· property is 0. This results in a duration datatype\n which is totally ordered.\n ", + comment: "\n `dayTimeDuration` is a datatype _derived_ from `duration` by restricting its\n _lexical representations_ to instances of `dayTimeDurationLexicalRep`. The\n _value space_ of `dayTimeDuration` is therefore that of `duration` restricted\n to those whose `months` property is `0`. This results in a `duration` datatype\n which is totally ordered.\n ", label: "dayTimeDuration", subClassOf: "http://www.w3.org/2001/XMLSchema#duration", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :decimal, - comment: "\n decimal represents a subset of the real numbers, which can be represented\n by decimal numerals. The ·value space· of decimal is the set of numbers\n that can be obtained by dividing an integer by a non-negative power of ten,\n i.e., expressible as i / 10n where i and n are integers and n ≥ 0.\n Precision is not reflected in this value space; the number 2.0 is not\n distinct from the number 2.00. The order relation on decimal is the order\n relation on real numbers, restricted to this subset.\n ", + comment: "\n `decimal` represents a subset of the real numbers, which can be represented\n by decimal numerals. The _value space_ of decimal is the set of numbers\n that can be obtained by dividing an integer by a non-negative power of ten,\n i.e., expressible as `i / 10n` where `i` and `n` are integers and `n ≥ 0`.\n Precision is not reflected in this value space; the number `2.0` is not\n distinct from the number `2.00`. The order relation on `decimal` is the order\n relation on real numbers, restricted to this subset.\n ", label: "decimal", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :double, - comment: "\n The double datatype is patterned after the IEEE double-precision 64-bit\n floating point datatype [IEEE 754-2008]. Each floating point datatype has a\n value space that is a subset of the rational numbers. Floating point\n numbers are often used to approximate arbitrary real numbers.\n ", + comment: "\n The `double` datatype is patterned after the IEEE double-precision 64-bit\n floating point datatype [IEEE 754-2008]. Each floating point datatype has a\n value space that is a subset of the rational numbers. Floating point\n numbers are often used to approximate arbitrary real numbers.\n ", label: "double", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :duration, - comment: "\n duration is a datatype that represents durations of time. The concept of\n duration being captured is drawn from those of [ISO 8601], specifically\n durations without fixed endpoints. For example, \"15 days\" (whose most\n common lexical representation in duration is \"'P15D'\") is a duration value;\n \"15 days beginning 12 July 1995\" and \"15 days ending 12 July 1995\" are not\n duration values. duration can provide addition and subtraction operations\n between duration values and between duration/dateTime value pairs, and can\n be the result of subtracting dateTime values. However, only addition to\n dateTime is required for XML Schema processing and is defined in the\n function ·dateTimePlusDuration·.\n ", + comment: "\n `duration` is a datatype that represents durations of time. The concept of\n duration being captured is drawn from those of [ISO 8601], specifically\n durations without fixed endpoints. For example, \"15 days\" (whose most\n common lexical representation in duration is `\"'P15D'\"`) is a duration value;\n \"15 days beginning 12 July 1995\" and \"15 days ending 12 July 1995\" are not\n duration values. duration can provide addition and subtraction operations\n between duration values and between duration/dateTime value pairs, and can\n be the result of subtracting dateTime values. However, only addition to\n `dateTime` is required for XML Schema processing and is defined in the\n function `dateTimePlusDuration`.\n ", label: "duration", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :float, - comment: "\n The float datatype is patterned after the IEEE single-precision 32-bit\n floating point datatype [IEEE 754-2008]. Its value space is a subset of the\n rational numbers. Floating point numbers are often used to approximate\n arbitrary real numbers.\n ", + comment: "\n The `float` datatype is patterned after the IEEE single-precision 32-bit\n floating point datatype [IEEE 754-2008]. Its value space is a subset of the\n rational numbers. Floating point numbers are often used to approximate\n arbitrary real numbers.\n ", label: "float", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :gDay, - comment: "\n gDay represents whole days within an arbitrary month—days that recur at the\n same point in each (Gregorian) month. This datatype is used to represent a\n specific day of the month. To indicate, for example, that an employee gets\n a paycheck on the 15th of each month. (Obviously, days beyond 28 cannot\n occur in all months; they are nonetheless permitted, up to 31.)\n ", + comment: "\n `gDay` represents whole days within an arbitrary month—days that recur at the\n same point in each (Gregorian) month. This datatype is used to represent a\n specific day of the month. To indicate, for example, that an employee gets\n a paycheck on the 15th of each month. (Obviously, days beyond 28 cannot\n occur in all months; they are nonetheless permitted, up to 31.)\n ", label: "gDay", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :gMonth, - comment: "\n gMonth represents whole (Gregorian) months within an arbitrary year—months\n that recur at the same point in each year. It might be used, for example,\n to say what month annual Thanksgiving celebrations fall in different\n countries (--11 in the United States, --10 in Canada, and possibly other\n months in other countries).\n ", + comment: "\n `gMonth` represents whole (Gregorian) months within an arbitrary year—months\n that recur at the same point in each year. It might be used, for example,\n to say what month annual Thanksgiving celebrations fall in different\n countries (`--11` in the United States, `--10` in Canada, and possibly other\n months in other countries).\n ", label: "gMonth", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :gMonthDay, - comment: "\n gMonthDay represents whole calendar days that recur at the same point in\n each calendar year, or that occur in some arbitrary calendar year.\n (Obviously, days beyond 28 cannot occur in all Februaries; 29 is\n nonetheless permitted.)\n ", + comment: "\n `gMonthDay` represents whole calendar days that recur at the same point in\n each calendar year, or that occur in some arbitrary calendar year.\n (Obviously, days beyond 28 cannot occur in all Februaries; 29 is\n nonetheless permitted.)\n ", label: "gMonthDay", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :gYear, - comment: "\n gYear represents Gregorian calendar years.\n ", + comment: "\n `gYear` represents Gregorian calendar years.\n ", label: "gYear", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :gYearMonth, - comment: "\n gYearMonth represents specific whole Gregorian months in specific Gregorian years.\n ", + comment: "\n `gYearMonth` represents specific whole Gregorian months in specific Gregorian years.\n ", label: "gYearMonth", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :hexBinary, - comment: "\n hexBinary represents arbitrary hex-encoded binary data. \n ", + comment: "\n hexBinary` represents arbitrary hex-encoded binary data. \n ", label: "hexBinary", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :int, - comment: "\n int is ·derived· from long by setting the value of ·maxInclusive· to be\n 2147483647 and ·minInclusive· to be -2147483648. The ·base type· of int\n is long.\n ", + comment: "\n `int` is _derived_ from `long` by setting the value of `maxInclusive` to be\n `2147483647` and `minInclusive` to be `-2147483648`. The _base type_ of `int`\n is `long`.\n ", label: "int", subClassOf: "http://www.w3.org/2001/XMLSchema#long", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :integer, - comment: "\n integer is ·derived· from decimal by fixing the value of ·fractionDigits·\n to be 0 and disallowing the trailing decimal point. This results in the\n standard mathematical concept of the integer numbers. The ·value space· of\n integer is the infinite set {...,-2,-1,0,1,2,...}. The ·base type· of\n integer is decimal.\n ", + comment: "\n `integer` is _derived_ from `decimal` by fixing the value of `fractionDigits`\n to be `0` and disallowing the trailing decimal point. This results in the\n standard mathematical concept of the integer numbers. The _value space_ of\n `integer` is the infinite set `{...,-2,-1,0,1,2,...}`. The _base type_ of\n `integer` is `decimal`.\n ", label: "integer", subClassOf: "http://www.w3.org/2001/XMLSchema#decimal", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :language, - comment: "\n language represents formal natural language identifiers, as defined by [BCP\n 47] (currently represented by [RFC 4646] and [RFC 4647]) or its\n successor(s). The ·value space· and ·lexical space· of language are the set\n of all strings that conform to the pattern [a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*\n ", + comment: "\n `language` represents formal natural language identifiers, as defined by [BCP\n 47] (currently represented by [RFC 4646] and [RFC 4647]) or its\n successor(s). The _value space_ and _lexical space_ of `language` are the set\n of all strings that conform to the pattern `[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*`.\n ", label: "language", subClassOf: "http://www.w3.org/2001/XMLSchema#token", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :long, - comment: "\n long is ·derived· from integer by setting the value of ·maxInclusive· to\n be 9223372036854775807 and ·minInclusive· to be -9223372036854775808. The\n ·base type· of long is integer.\n ", + comment: "\n `long` is _derived_ from `integer` by setting the value of `maxInclusive` to\n be `9223372036854775807` and `minInclusive` to be `-9223372036854775808`. The\n _base type_ of `long` is `integer`.\n ", label: "long", subClassOf: "http://www.w3.org/2001/XMLSchema#integer", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :negativeInteger, - comment: "\n negativeInteger is ·derived· from nonPositiveInteger by setting the value\n of ·maxInclusive· to be -1. This results in the standard mathematical\n concept of the negative integers. The ·value space· of negativeInteger is\n the infinite set {...,-2,-1}. The ·base type· of negativeInteger is\n nonPositiveInteger.\n ", + comment: "\n `negativeInteger` is _derived_ from `nonPositiveInteger` by setting the value\n of `maxInclusive` to be `-1`. This results in the standard mathematical\n concept of the negative integers. The _value space_ of `negativeInteger` is\n the infinite set `{...,-2,-1}`. The _base type_ of `negativeInteger` is\n `nonPositiveInteger`.\n ", label: "negativeInteger", subClassOf: "http://www.w3.org/2001/XMLSchema#nonPositiveInteger", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :nonNegativeInteger, - comment: "\n nonNegativeInteger is ·derived· from integer by setting the value of\n ·minInclusive· to be 0. This results in the standard mathematical concept\n of the non-negative integers. The ·value space· of nonNegativeInteger is\n the infinite set {0,1,2,...}. The ·base type· of nonNegativeInteger is\n integer.\n ", + comment: "\n `nonNegativeInteger` is _derived_ from `integer` by setting the value of\n `minInclusive` to be `0`. This results in the standard mathematical concept\n of the non-negative integers. The _value space_ of `nonNegativeInteger` is\n the infinite set `{0,1,2,...}`. The _base type_ of `nonNegativeInteger` is\n `integer`.\n ", label: "nonNegativeInteger", subClassOf: "http://www.w3.org/2001/XMLSchema#integer", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :nonPositiveInteger, - comment: "\n nonPositiveInteger is ·derived· from integer by setting the value of\n ·maxInclusive· to be 0. This results in the standard mathematical concept\n of the non-positive integers. The ·value space· of nonPositiveInteger is\n the infinite set {...,-2,-1,0}. The ·base type· of nonPositiveInteger is\n integer.\n ", + comment: "\n `nonPositiveInteger` is _derived_ from `integer` by setting the value of\n `maxInclusive` to be `0`. This results in the standard mathematical concept\n of the non-positive integers. The _value space_ of `nonPositiveInteger` is\n the infinite set `{...,-2,-1,0}`. The _base type_ of `nonPositiveInteger` is\n `integer`.\n ", label: "nonPositiveInteger", subClassOf: "http://www.w3.org/2001/XMLSchema#integer", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :normalizedString, - comment: "\n normalizedString represents white space normalized strings. The ·value\n space· of normalizedString is the set of strings that do not contain the\n carriage return (#xD), line feed (#xA) nor tab (#x9) characters. The\n ·lexical space· of normalizedString is the set of strings that do not\n contain the carriage return (#xD), line feed (#xA) nor tab (#x9)\n characters. The ·base type· of normalizedString is string.\n ", + comment: "\n `normalizedString` represents white space normalized strings. The _value\n space_ of `normalizedString` is the set of strings that do not contain the\n carriage return (`#xD`), line feed (`#xA`) nor tab (`#x9`) characters. The\n _lexical space_ of `normalizedString` is the set of strings that do not\n contain the carriage return (`#xD`), line feed (`#xA`) nor tab (`#x9`)\n characters. The _base type_ of `normalizedString` is `string`.\n ", label: "normalizedString", subClassOf: "http://www.w3.org/2001/XMLSchema#string", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :positiveInteger, - comment: "\n positiveInteger is ·derived· from nonNegativeInteger by setting the value\n of ·minInclusive· to be 1. This results in the standard mathematical\n concept of the positive integer numbers. The ·value space· of\n positiveInteger is the infinite set {1,2,...}. The ·base type· of\n positiveInteger is nonNegativeInteger.\n ", + comment: "\n `positiveInteger` is _derived_ from `nonNegativeInteger` by setting the value\n of `minInclusive` to be `1`. This results in the standard mathematical\n concept of the positive integer numbers. The _value space_ of\n `positiveInteger` is the infinite set `{1,2,...}`. The _base type_ of\n `positiveInteger` is `nonNegativeInteger`.\n ", label: "positiveInteger", subClassOf: "http://www.w3.org/2001/XMLSchema#nonNegativeInteger", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :short, - comment: "\n short is ·derived· from int by setting the value of ·maxInclusive· to be\n 32767 and ·minInclusive· to be -32768. The ·base type· of short is int.\n ", + comment: "\n `short` is _derived_ from `int` by setting the value of `maxInclusive` to be\n `32767` and `minInclusive` to be `-32768`. The _base type_ of `short` is `int`.\n ", label: "short", subClassOf: "http://www.w3.org/2001/XMLSchema#int", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :string, - comment: "\n The string datatype represents character strings in XML.\n ", + comment: "\n The `string` datatype represents character strings in XML.\n ", label: "string", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :time, - comment: "\n time represents instants of time that recur at the same point in each\n calendar day, or that occur in some arbitrary calendar day.\n ", + comment: "\n `time` represents instants of time that recur at the same point in each\n calendar day, or that occur in some arbitrary calendar day.\n ", label: "time", subClassOf: "http://www.w3.org/2001/XMLSchema#anyAtomicType", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :token, - comment: "\n token represents tokenized strings. The ·value space· of token is the set\n of strings that do not contain the carriage return (#xD), line feed (#xA)\n nor tab (#x9) characters, that have no leading or trailing spaces (#x20)\n and that have no internal sequences of two or more spaces. The ·lexical\n space· of token is the set of strings that do not contain the carriage\n return (#xD), line feed (#xA) nor tab (#x9) characters, that have no\n leading or trailing spaces (#x20) and that have no internal sequences of\n two or more spaces. The ·base type· of token is normalizedString.\n ", + comment: "\n `token` represents tokenized strings. The _value space_ of `token` is the set\n of strings that do not contain the carriage return (`#xD`), line feed (`#xA`)\n nor tab (`#x9`) characters, that have no leading or trailing spaces (`#x20`)\n and that have no internal sequences of two or more spaces. The _lexical\n space_ of `token` is the set of strings that do not contain the carriage\n return (`#xD`), line feed (`#xA`) nor tab (`#x9`) characters, that have no\n leading or trailing spaces (`#x20`) and that have no internal sequences of\n two or more spaces. The _base type_ of `token` is `normalizedString`.\n ", label: "token", subClassOf: "http://www.w3.org/2001/XMLSchema#normalizedString", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :unsignedByte, - comment: "\n nsignedByte is ·derived· from unsignedShort by setting the value of\n ·maxInclusive· to be 255. The ·base type· of unsignedByte is\n unsignedShort.\n ", + comment: "\n `unsignedByte` is _derived_ from `unsignedShort` by setting the value of\n `maxInclusive` to be `255`. The _base type_ of `unsignedByte` is\n `unsignedShort`.\n ", label: "unsignedByte", subClassOf: "http://www.w3.org/2001/XMLSchema#unsignedShort", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :unsignedInt, - comment: "\n unsignedInt is ·derived· from unsignedLong by setting the value of\n ·maxInclusive· to be 4294967295. The ·base type· of unsignedInt is\n unsignedLong.\n ", + comment: "\n `unsignedInt` is _derived_ from `unsignedLong` by setting the value of\n `maxInclusive` to be `4294967295`. The _base type_ of `unsignedInt` is\n `unsignedLong`.\n ", label: "unsignedInt", subClassOf: "http://www.w3.org/2001/XMLSchema#unsignedLong", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :unsignedLong, - comment: "\n unsignedLong is ·derived· from nonNegativeInteger by setting the value of\n ·maxInclusive· to be 18446744073709551615. The ·base type· of unsignedLong\n is nonNegativeInteger.\n ", + comment: "\n `unsignedLong` is _derived_ from `nonNegativeInteger` by setting the value of\n `maxInclusive` to be `18446744073709551615`. The _base type_ of `unsignedLong`\n is `nonNegativeInteger`.\n ", label: "unsignedLong", subClassOf: "http://www.w3.org/2001/XMLSchema#nonNegativeInteger", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :unsignedShort, - comment: "\n unsignedShort is ·derived· from unsignedInt by setting the value of\n ·maxInclusive· to be 65535. The ·base type· of unsignedShort is\n unsignedInt.\n ", + comment: "\n `unsignedShort` is _derived_ from `unsignedInt` by setting the value of\n `maxInclusive` to be `65535`. The _base type_ of `unsignedShort` is\n `unsignedInt`.\n ", label: "unsignedShort", subClassOf: "http://www.w3.org/2001/XMLSchema#unsignedInt", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" term :yearMonthDuration, - comment: "\n yearMonthDuration is a datatype ·derived· from duration by restricting its\n ·lexical representations· to instances of yearMonthDurationLexicalRep. The\n ·value space· of yearMonthDuration is therefore that of duration\n restricted to those whose ·seconds· property is 0. This results in a\n duration datatype which is totally ordered.\n ", + comment: "\n `yearMonthDuration` is a datatype _derived_ from `duration` by restricting its\n _lexical representations_ to instances of `yearMonthDurationLexicalRep`. The\n _value space_ of `yearMonthDuration` is therefore that of `duration`\n restricted to those whose `seconds` property is `0`. This results in a\n `duration` datatype which is totally ordered.\n ", label: "yearMonthDuration", subClassOf: "http://www.w3.org/2001/XMLSchema#duration", type: "http://www.w3.org/2000/01/rdf-schema#Datatype" From e8703135f6cb77688d354a30f883132941dcfd36 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Sun, 20 Feb 2022 14:57:04 -0800 Subject: [PATCH 2/8] Updates to Date literal: * Object base is now `::DateTime` instead of `::Date` to record and manipulate timezone. * Better conformance to XSD and XPath specs. * Adds `#adjust_to_timezone` (and `#adjust_to_timezone!`) based on XPath function. Takes either a `[+1]HH:MM` or an xsd:dayTimeDuration restricted to hours and minutes. * Adds `<=>` comparison operator. * Adds `#year`, `#month`, and `#day` accessors. --- lib/rdf/model/literal.rb | 2 +- lib/rdf/model/literal/date.rb | 205 ++++++++++++++++++++--- spec/model_literal_spec.rb | 301 ++++++++++++++++++++++++++++------ 3 files changed, 427 insertions(+), 81 deletions(-) diff --git a/lib/rdf/model/literal.rb b/lib/rdf/model/literal.rb index e8ebd5e7..6c6a08ae 100644 --- a/lib/rdf/model/literal.rb +++ b/lib/rdf/model/literal.rb @@ -295,7 +295,7 @@ def ==(other) when self.simple? && other.simple? self.value_hash == other.value_hash && self.value == other.value when other.comperable_datatype?(self) || self.comperable_datatype?(other) - # Comoparing plain with undefined datatypes does not generate an error, but returns false + # Comparing plain with undefined datatypes does not generate an error, but returns false # From data-r2/expr-equal/eq-2-2. false else diff --git a/lib/rdf/model/literal/date.rb b/lib/rdf/model/literal/date.rb index 4507eb1f..a7cf24e5 100644 --- a/lib/rdf/model/literal/date.rb +++ b/lib/rdf/model/literal/date.rb @@ -7,19 +7,44 @@ module RDF; class Literal class Date < Literal DATATYPE = RDF::URI("http://www.w3.org/2001/XMLSchema#date") GRAMMAR = %r(\A(-?\d{4}-\d{2}-\d{2})((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z).freeze + + # Matches either -10:00 or -P1H0M forms + ZONE_GRAMMAR = %r(\A + (?:(?[+-])(?
\d{2}):(?:(?\d{2}))?) + |(?:(?-)?PT(?
\d{1,2})H(?:(?\d{1,2})M)?) + \z)x.freeze FORMAT = '%Y-%m-%d'.freeze ## - # @param [String, Date, #to_date] value + # Internally, a `Date` is represented using a native `::DateTime` object at noon. If initialized from a `::Date`, there is no timezone component, 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. + # + # @note If initialized using the `#to_datetime` method, time component is unchanged. Otherewise, it is set to 00:00 (midnight). + # + # @param [String, Date, #to_datetime] value # @param (see Literal#initialize) def initialize(value, datatype: nil, lexical: nil, **options) @datatype = RDF::URI(datatype || self.class.const_get(:DATATYPE)) @string = lexical || (value if value.is_a?(String)) @object = case - when value.is_a?(::Date) then value - when value.respond_to?(:to_date) then value.to_date - else ::Date.parse(value.to_s) - end rescue ::Date.new + when value.class == ::Date + @zone = nil + # Use noon as midpoint of the interval + ::DateTime.parse(value.strftime('%FT00:00:00')) + when value.respond_to?(:to_datetime) + dt = value.to_datetime + @zone = dt.zone + dt + else + md = value.to_s.match(GRAMMAR) + _, dt, tz = Array(md) + if tz + @zone = tz == 'Z' ? '+00:00' : tz + else + @zone = nil # No timezone + end + # Use noon as midpoint of the interval + ::DateTime.parse("#{dt}T00:00:00#{@zone}") + end rescue ::DateTime.new end ## @@ -30,7 +55,11 @@ def initialize(value, datatype: nil, lexical: nil, **options) # @return [RDF::Literal] `self` # @see http://www.w3.org/TR/xmlschema11-2/#date def canonicalize! - @string = @object.strftime(FORMAT) + self.tz.to_s if self.valid? + if self.valid? && @zone && @zone != '+00:00' + adjust_to_timezone! + else + @string = nil + end self end @@ -46,25 +75,12 @@ def valid? super && object && value !~ %r(\A0000) end - ## - # Does the literal representation include a timezone? Note that this is only possible if initialized using a string, or `:lexical` option. - # - # @return [Boolean] - # @since 1.1.6 - def timezone? - md = self.to_s.match(GRAMMAR) - md && !!md[2] - end - alias_method :tz?, :timezone? - alias_method :has_tz?, :timezone? - alias_method :has_timezone?, :timezone? - ## # Returns the value as a string. # # @return [String] def to_s - @string || @object.strftime(FORMAT) + @string || (@object.strftime(FORMAT) + self.tz) end ## @@ -75,32 +91,131 @@ def to_s def humanize(lang = :en) d = object.strftime("%A, %d %B %Y") if timezone? - d += if self.tz == 'Z' + d += if @zone == '+00:00' " UTC" else - " #{self.tz}" + " #{@zone}" end end d end + ## + # Does the literal representation include a timezone? Note that this is only possible if initialized using a string, or `:lexical` option. + # + # @return [Boolean] + # @since 1.1.6 + def timezone? + !@zone.nil? + end + alias_method :tz?, :timezone? + alias_method :has_tz?, :timezone? + alias_method :has_timezone?, :timezone? + + ## + # Adjust the timezone. + # + # From [fn:adjust-date-to-timezone](https://www.w3.org/TR/xpath-functions/#func-adjust-date-to-timezone) + # + # @overload adjust_to_timezone! + # Adjusts the timezone to UTC. + # + # @return [Date] `self` + # @raise [RangeError] if `zone < -14*60` or `zone > 14*60` + # @overload adjust_to_timezone!(zone) + # If `zone` is nil, then the timzeone component is removed. + # + # Otherwise, the timezone is set based on the difference between the current timezone offset (if any) and `zone`. + # + # @param [String] zone (nil) In the form of {ZONE_FORMAT} + # @return [Date] `self` + # @raise [RangeError] if `zone < -14*60` or `zone > 14*60` + # @see https://www.w3.org/TR/xpath-functions/#func-adjust-date-to-timezone + def adjust_to_timezone!(*args) + zone = args.first + md = zone.match(ZONE_GRAMMAR) if zone + raise ArgumentError, + "expected #{zone.inspect} to be a xsd:dayTimeDuration or +/-HH:MM" if + zone && !md + if args.empty? + @object = ::DateTime.parse(@object.strftime('%F')) + @zone = '+00:00' + elsif zone.nil? + # Remove timezone component + @object = ::DateTime.parse(@object.strftime('%F')) + @zone = nil + else + # Adjust to + si, hr, mi = md[:si], md[:hr], md[:mi] + si ||= '+' + offset = hr.to_i * 60 + mi.to_i + raise ArgumentError, + "Zone adjustment of #{zone} out of range" if + md.nil? || offset > 14*60 + + new_zone = "%s%.2d:%.2d" % [si, hr.to_i, mi.to_i] + dt = @zone.nil? ? @object : @object.new_offset(new_zone) + @object = ::DateTime.parse(dt.strftime("%FT00:00:00#{new_zone}")) + @zone = new_zone + end + @string = nil + self + end + + ## + # Functional version of `#adjust_to_timezone!`. + # + # @overload adjust_to_timezone + # @param (see #adjust_to_timezone!) + # @return [Date] + # @raise (see #adjust_to_timezone!) + # @overload adjust_to_timezone(zone) (see #adjust_to_timezone!) + # @return [Date] + # @raise (see #adjust_to_timezone!) + def adjust_to_timezone(*args) + self.dup.adjust_to_timezone!(*args) + end + ## # Returns the timezone part of arg as a simple literal. Returns the empty string if there is no timezone. # # @return [RDF::Literal] # @since 1.1.6 def tz - md = self.to_s.match(GRAMMAR) - zone = md[2].to_s - zone = "Z" if zone == "+00:00" - RDF::Literal(zone) + RDF::Literal(@zone == "+00:00" ? 'Z' : @zone) end + ## + # Returns the timezone part of arg as an xsd:dayTimeDuration, or `nil` + # if lexical form of literal does not include a timezone. + # + # From [fn:timezone-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-timezone-from-dateTime). + # + # @return [RDF::Literal] + # @see https://www.w3.org/TR/xpath-functions/#func-timezone-from-dateTime + def timezone + if @zone + md = @zone.match(ZONE_GRAMMAR) + si, hr, mi = md[:si], md[:hr].to_i, md[:mi].to_i + si = nil unless si == "-" + res = "#{si}PT#{hr}H#{"#{mi}M" if mi > 0}" + RDF::Literal(res, datatype: RDF::URI("http://www.w3.org/2001/XMLSchema#dayTimeDuration")) + end + end + + ## + # Updates the date to a new timezone, or no timezone. ## # Equal compares as Date objects + # + # From the XQuery function [op:date-equal](https://www.w3.org/TR/xpath-functions/#func-date-equal). + # + # @param [Date, Literal] other + # @return [Boolean] + # @see https://www.w3.org/TR/xpath-functions/#func-date-equal def ==(other) # If lexically invalid, use regular literal testing - return super unless self.valid? + return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?) case other when Literal::Date @@ -112,5 +227,41 @@ def ==(other) super end end + + ## + # Compares `self` to `other` for sorting purposes (with type check). + # + # @param [Object] other + # @return [Integer] `-1`, `0`, or `1` + def <=>(other) + # If lexically invalid, use regular literal testing + return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?) + return super unless other.is_a?(Date) + @object <=> other.object + end + + # Years + # + # From the XQuery function [fn:year-from-date](https://www.w3.org/TR/xpath-functions/#func-year-from-date). + # + # @return [Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-year-from-date + def year; Integer.new(object.year); end + + # Months + # + # From the XQuery function [fn:month-from-date](https://www.w3.org/TR/xpath-functions/#func-month-from-date). + # + # @return [Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-month-from-date + def month; Integer.new(object.month); end + + # Days + # + # From the XQuery function [fn:day-from-date](https://www.w3.org/TR/xpath-functions/#func-day-from-date). + # + # @return [Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-day-from-date + def day; Integer.new(object.day); end end # Date end; end # RDF::Literal diff --git a/spec/model_literal_spec.rb b/spec/model_literal_spec.rb index 2bca7ad5..51f4fac5 100644 --- a/spec/model_literal_spec.rb +++ b/spec/model_literal_spec.rb @@ -285,7 +285,7 @@ def self.literals(*selector) literal(:false) => false, literal(:long) => 9223372036854775807, literal(:double) => 3.1415, - literal(:date) => ::Date.new(2010), + literal(:date) => ::DateTime.new(2010), literal(:datetime) => ::DateTime.new(2011), # This is problematic when date changes between local testing location and UTC #literal(:time) => ::DateTime.parse('01:02:03Z') @@ -431,11 +431,11 @@ def self.literals(*selector) false => ["false", "false"] }.each do |obj, (str, canon)| it "to_str #{obj} to #{str.inspect}" do - expect(RDF::Literal::Boolean.new(obj).to_s).to eql str + expect(described_class.new(obj).to_s).to eql str end it "canonicalizes #{obj} to #{canon.inspect}" do - expect(RDF::Literal::Boolean.new(obj, canonicalize: true).to_s).to eql canon + expect(described_class.new(obj, canonicalize: true).to_s).to eql canon end end end @@ -462,11 +462,11 @@ def self.literals(*selector) 0 => ["0", "0"] }.each do |obj, (str, canon)| it "to_str #{obj} to #{str.inspect}" do - expect(RDF::Literal::Integer.new(obj).to_s).to eql str + expect(described_class.new(obj).to_s).to eql str end it "canonicalizes #{obj} to #{canon.inspect}" do - expect(RDF::Literal::Integer.new(obj, canonicalize: true).to_s).to eql canon + expect(described_class.new(obj, canonicalize: true).to_s).to eql canon end end end @@ -560,11 +560,11 @@ def self.literals(*selector) 1.1 => ["1.1", "1.1"], }.each do |obj, (str, canon)| it "to_str #{obj} to #{str.inspect}" do - expect(RDF::Literal::Decimal.new(obj).to_s).to eql str + expect(described_class.new(obj).to_s).to eql str end it "canonicalizes #{obj} to #{canon.inspect}" do - expect(RDF::Literal::Decimal.new(obj, canonicalize: true).to_s).to eql canon + expect(described_class.new(obj, canonicalize: true).to_s).to eql canon end end end @@ -644,17 +644,17 @@ def self.literals(*selector) 123.456e4 => ["1234560.0", "1.23456E6"] }.each do |obj, (str, canon)| it "to_str #{obj} to #{str.inspect}" do - expect(RDF::Literal::Double.new(obj).to_s).to eql str + expect(described_class.new(obj).to_s).to eql str end it "canonicalizes #{obj} to #{canon.inspect}" do - expect(RDF::Literal::Double.new(obj, canonicalize: true).to_s).to eql canon + expect(described_class.new(obj, canonicalize: true).to_s).to eql canon end end end - let(:nan) {RDF::Literal::Double.new("NaN")} - let(:inf) {RDF::Literal::Double.new("INF")} + let(:nan) {described_class.new("NaN")} + let(:inf) {described_class.new("INF")} it "recognizes INF" do expect(inf).to be_infinite @@ -674,10 +674,10 @@ def self.literals(*selector) expect {nan.canonicalize}.not_to raise_error end - [-1, 0, 1].map {|n| RDF::Literal::Double.new(n)}.each do |n| + [-1, 0, 1].map {|n| described_class.new(n)}.each do |n| { - :"+" => [RDF::Literal::Double.new("INF"), RDF::Literal::Double.new("INF"), RDF::Literal::Double.new("-INF"), RDF::Literal::Double.new("-INF")], - :"-" => [RDF::Literal::Double.new("INF"), RDF::Literal::Double.new("-INF"), RDF::Literal::Double.new("-INF"), RDF::Literal::Double.new("INF")], + :"+" => [described_class.new("INF"), described_class.new("INF"), described_class.new("-INF"), described_class.new("-INF")], + :"-" => [described_class.new("INF"), described_class.new("-INF"), described_class.new("-INF"), described_class.new("INF")], }.each do |op, (lp, rp, lm, rm)| it "returns #{lp} for INF #{op} #{n}" do expect(inf.send(op, n)).to eq lp @@ -704,23 +704,23 @@ def self.literals(*selector) # Multiplication { - -1 => RDF::Literal::Double.new("-INF"), + -1 => described_class.new("-INF"), 0 => :nan, - 1 => RDF::Literal::Double.new("INF"), + 1 => described_class.new("INF"), }.each do |n, p| it "returns #{p} for #{n} * INF" do if p == :nan - expect(RDF::Literal::Double.new(n) * inf).to be_nan + expect(described_class.new(n) * inf).to be_nan else - expect(RDF::Literal::Double.new(n) * inf).to eq p + expect(described_class.new(n) * inf).to eq p end end it "returns #{p} for INF * #{n}" do if p == :nan - expect(inf * RDF::Literal::Double.new(n)).to be_nan + expect(inf * described_class.new(n)).to be_nan else - expect(inf * RDF::Literal::Double.new(n)).to eq p + expect(inf * described_class.new(n)).to eq p end end end @@ -736,7 +736,7 @@ def self.literals(*selector) "0 > -inf" => [:>, "0", "-INF", true], }.each do |n, (op, l, r, result)| it "returns #{result} for #{l} #{op} #{r}" do - expect(RDF::Literal::Double.new(l).send(op, RDF::Literal::Double.new(r))).to eql result + expect(described_class.new(l).send(op, described_class.new(r))).to eql result end end @@ -754,17 +754,17 @@ def self.literals(*selector) describe "#**" do { - "INF^0": [RDF::Literal::Double.new('INF'), 0, 1.0e0], - "NaN^0": [RDF::Literal::Double.new('NaN'), 0, 1.0e0], + "INF^0": [described_class.new('INF'), 0, 1.0e0], + "NaN^0": [described_class.new('NaN'), 0, 1.0e0], "0e0^3": [0e0, 3, 0.0e0], "0e0^4": [0e0, 4, 0.0e0], "-0e0^3": [-0e0, 3, -0.0e0], - "0e0^-3": [0e0, -3, RDF::Literal::Double.new('INF')], - "0e0^-4": [0e0, -4, RDF::Literal::Double.new('INF')], - "-0e0^-3": [-0e0, -3, RDF::Literal::Double.new('-INF')], - "-0e0^-3.0e0": [-0e0, -3.0e0, RDF::Literal::Double.new('-INF')], - "0e0^-3.1e0": [0e0, -3.1e0, RDF::Literal::Double.new('INF')], - "-0e0^-3.1e0": [-0e0, -3.1e0, RDF::Literal::Double.new('INF')], + "0e0^-3": [0e0, -3, described_class.new('INF')], + "0e0^-4": [0e0, -4, described_class.new('INF')], + "-0e0^-3": [-0e0, -3, described_class.new('-INF')], + "-0e0^-3.0e0": [-0e0, -3.0e0, described_class.new('-INF')], + "0e0^-3.1e0": [0e0, -3.1e0, described_class.new('INF')], + "-0e0^-3.1e0": [-0e0, -3.1e0, described_class.new('INF')], }.each do |name, (n, e, result)| it name do expect(RDF::Literal(n) ** RDF::Literal(e)).to eq RDF::Literal(result) @@ -839,11 +839,11 @@ def self.literals(*selector) DateTime.parse("-2010-01-01T00:00:00Z") => ["-2010-01-01T00:00:00Z","-2010-01-01T00:00:00Z"], }.each do |obj, (str, canon)| it "to_str #{obj} to #{str.inspect}" do - expect(RDF::Literal::DateTime.new(obj).to_s).to eql str + expect(described_class.new(obj).to_s).to eql str end it "canonicalizes #{obj} to #{canon.inspect}" do - expect(RDF::Literal::DateTime.new(obj, canonicalize: true).to_s).to eql canon + expect(described_class.new(obj, canonicalize: true).to_s).to eql canon end end end @@ -856,7 +856,7 @@ def self.literals(*selector) "2011-02-01T01:02:03" => "", }.each do |l, r| it "#{l} => #{r}" do - expect(RDF::Literal::DateTime.new(l).tz).to eq RDF::Literal(r) + expect(described_class.new(l).tz).to eq RDF::Literal(r) end end end @@ -869,7 +869,71 @@ def self.literals(*selector) "2011-02-01T01:02:03" => nil, }.each do |l, r| it "#{l} => #{r.inspect}" do - expect(RDF::Literal::DateTime.new(l).timezone).to eq r + expect(described_class.new(l).timezone).to eq r + end + end + end + + describe "#==" do + { + ["2002-04-02T12:00:00-01:00", "2002-04-02T17:00:00+04:00"] => true, + #["2002-04-02T12:00:00", "2002-04-02T23:00:00+06:00"] => true, + ["2002-04-02T12:00:00", "2002-04-02T17:00:00"] => false, + ["2002-04-02T12:00:00", "2002-04-02T12:00:00"] => true, + ["2002-04-02T23:00:00-04:00", "2002-04-03T02:00:00-01:00"] => true, + ["1999-12-31T24:00:00", "2000-01-01T00:00:00"] => true, + ["2005-04-04T24:00:00", "2005-04-04T00:00:00"] => false, + }.each do |(a, b), res| + if res + it "#{a} == #{b}" do + expect(described_class.new(a)).to eq described_class.new(b) + end + else + it "#{a} != #{b}" do + expect(described_class.new(a)).not_to eq described_class.new(b) + end + end + end + end + + describe "#<" do + { + ["2010-06-21T11:28:01Z", "2010-06-21T11:28:01Z"] => false, + ["2010-06-21T11:28:01Z", "2010-06-21T11:28:02Z"] => true, + ["2010-06-21T11:28:01Z", "2010-06-21T11:28:00Z"] => false, + ["2010-06-21T02:28:00Z", "2010-06-21T11:28:00-08:00"] => true, + }.each do |(a, b), res| + if res + it "#{a} < #{b}" do + expect(described_class.new(a)).to be < described_class.new(b) + expect(described_class.new(a)).not_to be >= described_class.new(b) + end + else + it "#{a} !< #{b}" do + expect(described_class.new(a)).not_to be < described_class.new(b) + expect(described_class.new(a)).to be >= described_class.new(b) + end + end + end + end + + describe "#>" do + { + ["2010-06-21T11:28:01Z", "2010-06-21T11:28:01Z"] => false, + ["2010-06-21T11:28:01Z", "2010-06-21T11:28:02Z"] => false, + ["2010-06-21T11:28:01Z", "2010-06-21T11:28:00Z"] => true, + ["2010-06-21T02:28:00Z", "2010-06-21T11:28:00-08:00"] => false, + }.each do |(a, b), res| + if res + it "#{a} > #{b}" do + expect(described_class.new(a)).to be > described_class.new(b) + expect(described_class.new(a)).not_to be <= described_class.new(b) + end + else + it "#{a} !> #{b}" do + expect(described_class.new(a)).not_to be > described_class.new(b) + expect(described_class.new(a)).to be <= described_class.new(b) + end end end end @@ -878,16 +942,16 @@ def self.literals(*selector) describe RDF::Literal::Date do it_behaves_like 'RDF::Literal with datatype and grammar', "2010-01-01T00:00:00Z", RDF::XSD.date - it_behaves_like 'RDF::Literal equality', "2010-01-01T00:00:00Z", DateTime.parse("2010-01-01T00:00:00Z") - it_behaves_like 'RDF::Literal lexical values', "2010-01-01T00:00:00Z" + it_behaves_like 'RDF::Literal equality', "2010-01-01Z", DateTime.parse("2010-01-01T00:00:00+00:00") + it_behaves_like 'RDF::Literal lexical values', "2010-01-01Z" it_behaves_like 'RDF::Literal canonicalization', RDF::XSD.date, [ ["2010-01-01Z", "2010-01-01Z", "Friday, 01 January 2010 UTC"], ["2010-01-01", "2010-01-01", "Friday, 01 January 2010"], ["2010-01-01+00:00","2010-01-01Z", "Friday, 01 January 2010 UTC"], - ["2010-01-01+01:00","2010-01-01+01:00", "Friday, 01 January 2010 +01:00"], - ["2009-12-31-01:00","2009-12-31-01:00", "Thursday, 31 December 2009 -01:00"], + ["2010-01-01+01:00","2010-01-01Z", "Friday, 01 January 2010 +01:00"], + ["2009-12-31-01:00","2009-12-31Z", "Thursday, 31 December 2009 -01:00"], ["-2010-01-01Z", "-2010-01-01Z", "Friday, 01 January -2010 UTC"], - ["2014-09-01-08:00","2014-09-01-08:00", "Monday, 01 September 2014 -08:00"], + ["2014-09-01-08:00","2014-09-01Z", "Monday, 01 September 2014 -08:00"], ] it_behaves_like 'RDF::Literal validation', RDF::XSD.date, %w( @@ -911,15 +975,16 @@ def self.literals(*selector) context "object values" do { - Date.parse("2010-02-01") => ["2010-02-01", "2010-02-01"], - Date.parse("-2010-01-01") => ["-2010-01-01","-2010-01-01"], + ::Date.parse("2010-02-01") => ["2010-02-01", "2010-02-01"], + ::Date.parse("-2010-01-01") => ["-2010-01-01","-2010-01-01"], + ::DateTime.parse("2014-09-01T00:00:00-08:00") => ["2014-09-01-08:00", "2014-09-01Z"], }.each do |obj, (str, canon)| it "to_str #{obj} to #{str.inspect}" do - expect(RDF::Literal::Date.new(obj).to_s).to eql str + expect(described_class.new(obj).to_s).to eql str end it "canonicalizes #{obj} to #{canon.inspect}" do - expect(RDF::Literal::Date.new(obj, canonicalize: true).to_s).to eql canon + expect(described_class.new(obj, canonicalize: true).to_s).to eql canon end end end @@ -932,7 +997,137 @@ def self.literals(*selector) "2011-02-01" => "", }.each do |l, r| it "#{l} => #{r}" do - expect(RDF::Literal::Date.new(l).tz).to eq RDF::Literal(r) + expect(described_class.new(l).tz).to eq RDF::Literal(r) + end + end + end + + describe "#timezone" do + { + "2010-06-21Z" => RDF::Literal("PT0H", datatype: RDF::XSD.dayTimeDuration), + "2010-12-21-08:00" => RDF::Literal("-PT8H", datatype: RDF::XSD.dayTimeDuration), + "2010-12-21+08:00" => RDF::Literal("PT8H", datatype: RDF::XSD.dayTimeDuration), + "2008-06-20Z" => RDF::Literal("PT0H", datatype: RDF::XSD.dayTimeDuration), + "2011-02-01" => nil, + }.each do |l, r| + it "#{l} => #{r.inspect}" do + expect(described_class.new(l).timezone).to eq r + end + end + end + + describe "#adjust_to_timezone" do + { + # Spec examples + ["2002-03-07"] => "2002-03-07Z", + ["2002-03-07-07:00"] => "2002-03-07Z", + ["2002-03-07", "-PT10H"] => "2002-03-07-10:00", + ["2002-03-07-07:00", "-PT10H"] => "2002-03-06-10:00", + ["2002-03-07", nil] => "2002-03-07", + ["2002-03-07-07:00", nil] => "2002-03-07", + }.each do |args, r| + if r == ArgumentError + it "#{args.inspect} raises ArgumentError" do + source = described_class.new(args.shift) + expect {source.adjust_to_timezone(*args)}.to raise_error(ArgumentError) + end + else + it "#{args.inspect} => #{r.inspect}" do + source = described_class.new(args.shift) + result = described_class.new(r) + expect(source.adjust_to_timezone(*args)).to eq result + end + end + end + + { + # Test Suite https://github.com/w3c/qt3tests/blob/master/fn/adjust-date-to-timezone.xml + "fn-adjust-date-to-timezone1args-1": ["1970-01-01Z", "-PT10H", "1969-12-31-10:00"], + "fn-adjust-date-to-timezone1args-2": ["1983-11-17Z", "-PT10H", "1983-11-16-10:00"], + "fn-adjust-date-to-timezone1args-3": ["2030-12-31Z", "-PT10H", "2030-12-30-10:00"], + "fn-adjust-date-to-timezone-1": ["2002-03-07-05:00", "-PT5H0M", "2002-03-07-05:00"], + "fn-adjust-date-to-timezone-2": ["2002-03-07-07:00", "-PT5H0M", "2002-03-07-05:00"], + "fn-adjust-date-to-timezone-3": ["2002-03-07", "-PT10H", "2002-03-07-10:00"], + "fn-adjust-date-to-timezone-4": ["2002-03-07-07:00", "-PT10H", "2002-03-06-10:00"], + "fn-adjust-date-to-timezone-5": ["2002-03-07", nil, "2002-03-07"], + "fn-adjust-date-to-timezone-6": ["2002-03-07-07:00", nil, "2002-03-07"], + "K-AdjDateToTimezoneFunc-6": ["2001-02-03", "PT14H1M", ArgumentError], + "K-AdjDateToTimezoneFunc-7": ["2001-02-03", "-PT14H1M", ArgumentError], + "K-AdjDateToTimezoneFunc-8": ["2001-02-03", "PT14H0M0.001S", ArgumentError], + }.each do |title, (*args, r)| + it title do + source = described_class.new(args.shift) + if r == ArgumentError + expect {source.adjust_to_timezone(*args)}.to raise_error(ArgumentError) + else + result = described_class.new(r) + expect(source.adjust_to_timezone(*args)).to eq result + end + end + end + end + + describe "#==" do + { + ["2004-12-25Z", "2004-12-25+07:00"] => false, + ["2004-12-25-12:00", "2004-12-26+12:00"] => true, + ["2004-12-25Z", RDF::Literal::DateTime.new("2004-12-25Z")] => false, + ["2004-12-25Z", RDF::Literal::Time.new("00:00:00")] => false, + }.each do |(a, b), res| + if res + it "#{a} == #{b}" do + res = b.is_a?(String) ? described_class.new(b) : b + expect(described_class.new(a)).to eq res + end + else + it "#{a} != #{b}" do + res = b.is_a?(String) ? described_class.new(b) : b + expect(described_class.new(a)).not_to eq res + end + end + end + end + + describe "#<" do + { + ["2010-06-21Z", "2010-06-20Z"] => false, + ["2010-06-21Z", "2010-06-21Z"] => false, + ["2010-06-21Z", "2010-06-22Z"] => true, + ["2010-06-21Z", "2010-06-21-08:00"] => true, + ["2010-06-21Z", "2010-06-21+08:00"] => false, + }.each do |(a, b), res| + if res + it "#{a} < #{b}" do + expect(described_class.new(a)).to be < described_class.new(b) + expect(described_class.new(a)).not_to be >= described_class.new(b) + end + else + it "#{a} !< #{b}" do + expect(described_class.new(a)).not_to be < described_class.new(b) + expect(described_class.new(a)).to be >= described_class.new(b) + end + end + end + end + + describe "#>" do + { + ["2010-06-21Z", "2010-06-20Z"] => true, + ["2010-06-21Z", "2010-06-21Z"] => false, + ["2010-06-21Z", "2010-06-22Z"] => false, + ["2010-06-21Z", "2010-06-21-08:00"] => false, + ["2010-06-21Z", "2010-06-21+08:00"] => true, + }.each do |(a, b), res| + if res + it "#{a} > #{b}" do + expect(described_class.new(a)).to be > described_class.new(b) + expect(described_class.new(a)).not_to be <= described_class.new(b) + end + else + it "#{a} !> #{b}" do + expect(described_class.new(a)).not_to be > described_class.new(b) + expect(described_class.new(a)).to be <= described_class.new(b) + end end end end @@ -982,11 +1177,11 @@ def self.literals(*selector) DateTime.parse("07:00:00-01:00") => ["07:00:00-01:00", "08:00:00Z"], }.each do |obj, (str, canon)| it "to_str #{obj} to #{str.inspect}" do - expect(RDF::Literal::Time.new(obj).to_s).to eql str + expect(described_class.new(obj).to_s).to eql str end it "canonicalizes #{obj} to #{canon.inspect}" do - expect(RDF::Literal::Time.new(obj, canonicalize: true).to_s).to eql canon + expect(described_class.new(obj, canonicalize: true).to_s).to eql canon end end end @@ -995,8 +1190,8 @@ def self.literals(*selector) it "parses as string if #to_datetime raises an error" do expect(subject).to receive(:to_datetime).at_least(:once).and_raise(StandardError) - expect {RDF::Literal::Time.new(subject)}.not_to raise_error - expect(RDF::Literal::Time.new(subject).object).to eq ::DateTime.parse(subject.to_s) + expect {described_class.new(subject)}.not_to raise_error + expect(described_class.new(subject).object).to eq ::DateTime.parse(subject.to_s) end describe "#tz" do @@ -1007,7 +1202,7 @@ def self.literals(*selector) "01:02:03" => "", }.each do |l, r| it "#{l} => #{r}" do - expect(RDF::Literal::Time.new(l).tz).to eq RDF::Literal(r) + expect(described_class.new(l).tz).to eq RDF::Literal(r) end end end @@ -1034,7 +1229,7 @@ def self.literals(*selector) end it "Numeric does not implement #abs" do - expect {RDF::Literal::Numeric.new(-1).abs}.to raise_error(NotImplementedError) + expect {described_class.new(-1).abs}.to raise_error(NotImplementedError) end end @@ -1064,7 +1259,7 @@ def self.literals(*selector) end it "Numeric does not implement #round" do - expect {RDF::Literal::Numeric.new(-1).round}.to raise_error(NotImplementedError) + expect {described_class.new(-1).round}.to raise_error(NotImplementedError) end end @@ -1090,7 +1285,7 @@ def self.literals(*selector) end it "Numeric returns self" do - expect(RDF::Literal::Numeric.new(-1).ceil).to eql RDF::Literal::Numeric.new(-1) + expect(described_class.new(-1).ceil).to eql described_class.new(-1) end end @@ -1116,7 +1311,7 @@ def self.literals(*selector) end it "Numeric returns self" do - expect(RDF::Literal::Numeric.new(-1).floor).to eql RDF::Literal::Numeric.new(-1) + expect(described_class.new(-1).floor).to eql described_class.new(-1) end end @@ -1144,7 +1339,7 @@ def self.literals(*selector) end it "returns self for unary +" do - expect(+RDF::Literal::Numeric.new(1)).to eql RDF::Literal::Numeric.new(1) + expect(+described_class.new(1)).to eql described_class.new(1) end end From 7acc71dcae0849d59b50298de032e888539bb079 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Sun, 20 Feb 2022 16:26:07 -0800 Subject: [PATCH 3/8] Updates to DateTime literal: * Better conformance to XSD and XPath specs. * Adds `#adjust_to_timezone` (and `#adjust_to_timezone!`) based on XPath function. Takes either a `[+1]HH:MM` or an xsd:dayTimeDuration restricted to hours and minutes. * Adds `<=>` comparison operator. * Adds `#year`, `#month`, `#day`, `#hours`, `#minutes`, and `#seconds` accessors. --- lib/rdf/model/literal/date.rb | 30 ++--- lib/rdf/model/literal/datetime.rb | 217 ++++++++++++++++++++++++------ spec/model_literal_spec.rb | 61 ++++++++- 3 files changed, 248 insertions(+), 60 deletions(-) diff --git a/lib/rdf/model/literal/date.rb b/lib/rdf/model/literal/date.rb index a7cf24e5..73c91c04 100644 --- a/lib/rdf/model/literal/date.rb +++ b/lib/rdf/model/literal/date.rb @@ -7,16 +7,10 @@ module RDF; class Literal class Date < Literal DATATYPE = RDF::URI("http://www.w3.org/2001/XMLSchema#date") GRAMMAR = %r(\A(-?\d{4}-\d{2}-\d{2})((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z).freeze - - # Matches either -10:00 or -P1H0M forms - ZONE_GRAMMAR = %r(\A - (?:(?[+-])(?
\d{2}):(?:(?\d{2}))?) - |(?:(?-)?PT(?
\d{1,2})H(?:(?\d{1,2})M)?) - \z)x.freeze FORMAT = '%Y-%m-%d'.freeze ## - # Internally, a `Date` is represented using a native `::DateTime` object at noon. If initialized from a `::Date`, there is no timezone component, 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. + # Internally, a `Date` is represented using a native `::DateTime` object at midnight. If initialized from a `::Date`, there is no timezone component, 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. # # @note If initialized using the `#to_datetime` method, time component is unchanged. Otherewise, it is set to 00:00 (midnight). # @@ -28,7 +22,7 @@ def initialize(value, datatype: nil, lexical: nil, **options) @object = case when value.class == ::Date @zone = nil - # Use noon as midpoint of the interval + # Use midnight as midpoint of the interval ::DateTime.parse(value.strftime('%FT00:00:00')) when value.respond_to?(:to_datetime) dt = value.to_datetime @@ -42,7 +36,7 @@ def initialize(value, datatype: nil, lexical: nil, **options) else @zone = nil # No timezone end - # Use noon as midpoint of the interval + # Use midnight as midpoint of the interval ::DateTime.parse("#{dt}T00:00:00#{@zone}") end rescue ::DateTime.new end @@ -132,20 +126,16 @@ def timezone? # @raise [RangeError] if `zone < -14*60` or `zone > 14*60` # @see https://www.w3.org/TR/xpath-functions/#func-adjust-date-to-timezone def adjust_to_timezone!(*args) - zone = args.first - md = zone.match(ZONE_GRAMMAR) if zone - raise ArgumentError, - "expected #{zone.inspect} to be a xsd:dayTimeDuration or +/-HH:MM" if - zone && !md - if args.empty? - @object = ::DateTime.parse(@object.strftime('%F')) - @zone = '+00:00' - elsif zone.nil? + zone = args.empty? ? '+00:00' : args.first + if zone.nil? # Remove timezone component @object = ::DateTime.parse(@object.strftime('%F')) @zone = nil else - # Adjust to + md = zone.match(Literal::DateTime::ZONE_GRAMMAR) if zone + raise ArgumentError, + "expected #{zone.inspect} to be a xsd:dayTimeDuration or +/-HH:MM" unless md + # Adjust to zone si, hr, mi = md[:si], md[:hr], md[:mi] si ||= '+' offset = hr.to_i * 60 + mi.to_i @@ -195,7 +185,7 @@ def tz # @see https://www.w3.org/TR/xpath-functions/#func-timezone-from-dateTime def timezone if @zone - md = @zone.match(ZONE_GRAMMAR) + md = @zone.match(Literal::DateTime::ZONE_GRAMMAR) si, hr, mi = md[:si], md[:hr].to_i, md[:mi].to_i si = nil unless si == "-" res = "#{si}PT#{hr}H#{"#{mi}M" if mi > 0}" diff --git a/lib/rdf/model/literal/datetime.rb b/lib/rdf/model/literal/datetime.rb index 956030b7..931abbc3 100644 --- a/lib/rdf/model/literal/datetime.rb +++ b/lib/rdf/model/literal/datetime.rb @@ -2,23 +2,43 @@ module RDF; class Literal ## # A date/time literal. # - # @see http://www.w3.org/TR/xmlschema11-2/#dateTime#boolean + # @see http://www.w3.org/TR/xmlschema11-2/#dateTime # @since 0.2.1 class DateTime < Literal DATATYPE = RDF::URI("http://www.w3.org/2001/XMLSchema#dateTime") GRAMMAR = %r(\A(-?(?:\d{4}|[1-9]\d{4,})-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?)((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z).freeze - FORMAT = '%Y-%m-%dT%H:%M:%S.%L%:z'.freeze + FORMAT = '%Y-%m-%dT%H:%M:%S.%L'.freeze + + # Matches either -10:00 or -P1H0M forms + ZONE_GRAMMAR = %r(\A + (?:(?[+-])(?
\d{2}):(?:(?\d{2}))?) + |(?:(?-)?PT(?
\d{1,2})H(?:(?\d{1,2})M)?) + \z)x.freeze ## + # Internally, a `DateTime` is represented using a native `::DateTime`. If initialized from a `::Date`, there is no timezone component, 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. + # # @param [DateTime] value # @option options [String] :lexical (nil) def initialize(value, datatype: nil, lexical: nil, **options) @datatype = RDF::URI(datatype || self.class.const_get(:DATATYPE)) @string = lexical || (value if value.is_a?(String)) @object = case - when value.is_a?(::DateTime) then value - when value.respond_to?(:to_datetime) then value.to_datetime - else ::DateTime.parse(value.to_s) + when value.is_a?(::DateTime) + @zone = value.zone + value + when value.respond_to?(:to_datetime) + @zone = value.to_datetime.zone + value.to_datetime + else + md = value.to_s.match(GRAMMAR) + _, dt, tz = Array(md) + if tz + @zone = tz == 'Z' ? '+00:00' : tz + else + @zone = nil # No timezone + end + ::DateTime.parse(value.to_s) end rescue ::DateTime.new end @@ -29,12 +49,10 @@ def initialize(value, datatype: nil, lexical: nil, **options) # @return [RDF::Literal] `self` # @see http://www.w3.org/TR/xmlschema11-2/#dateTime def canonicalize! - if self.valid? - @string = if timezone? - @object.new_offset.new_offset.strftime(FORMAT[0..-4] + 'Z').sub('.000', '') - else - @object.strftime(FORMAT[0..-4]).sub('.000', '') - end + if self.valid? && @zone && @zone != '+00:00' + adjust_to_timezone! + else + @string = nil end self end @@ -43,18 +61,32 @@ def canonicalize! # Returns the timezone part of arg as a simple literal. Returns the empty string if there is no timezone. # # @return [RDF::Literal] - # @see http://www.w3.org/TR/sparql11-query/#func-tz def tz - zone = timezone? ? object.zone : "" - zone = "Z" if zone == "+00:00" - RDF::Literal(zone) + RDF::Literal(@zone == "+00:00" ? 'Z' : @zone) end + ## + # Does the literal representation include a timezone? Note that this is only possible if initialized using a string, or `:lexical` option. + # + # @return [Boolean] + # @since 1.1.6 + def timezone? + # Can only know there's a timezone from the string represntation + md = to_s.match(GRAMMAR) + md && !!md[2] + end + alias_method :tz?, :timezone? + alias_method :has_tz?, :timezone? + alias_method :has_timezone?, :timezone? + ## # Returns the timezone part of arg as an xsd:dayTimeDuration, or `nil` # if lexical form of literal does not include a timezone. # + # From [fn:timezone-from-date](https://www.w3.org/TR/xpath-functions/#func-timezone-from-date). + # # @return [RDF::Literal] + # @see https://www.w3.org/TR/xpath-functions/#func-timezone-from-date def timezone if tz == 'Z' RDF::Literal("PT0S", datatype: RDF::URI("http://www.w3.org/2001/XMLSchema#dayTimeDuration")) @@ -86,25 +118,12 @@ def valid? # @return [Boolean] # @since 1.1.6 def milliseconds? - self.format("%L").to_i > 0 + object.strftime("%L").to_i > 0 end alias_method :has_milliseconds?, :milliseconds? alias_method :has_ms?, :milliseconds? alias_method :ms?, :milliseconds? - ## - # Does the literal representation include a timezone? Note that this is only possible if initialized using a string, or `:lexical` option. - # - # @return [Boolean] - # @since 1.1.6 - def timezone? - md = self.to_s.match(GRAMMAR) - md && !!md[2] - end - alias_method :tz?, :timezone? - alias_method :has_tz?, :timezone? - alias_method :has_timezone?, :timezone? - ## # Returns the `timezone` of the literal. If the ## @@ -112,7 +131,7 @@ def timezone? # # @return [String] def to_s - @string || @object.strftime(FORMAT).sub("+00:00", 'Z').sub('.000', '') + @string || (@object.strftime(FORMAT).sub('.000', '') + self.tz) end ## @@ -123,25 +142,87 @@ def to_s def humanize(lang = :en) d = object.strftime("%r on %A, %d %B %Y") if timezone? - zone = if self.tz == 'Z' - "UTC" - else - self.tz - end - d.sub!(" on ", " #{zone} on ") + z = @zone == '+00:00' ? "UTC" : @zone + d.sub!(" on ", " #{z} on ") end d end + ## + # Adjust the timezone. + # + # From [fn:adjust-dateTime-to-timezone](https://www.w3.org/TR/xpath-functions/#func-adjust-dateTime-to-timezone) + # + # @overload adjust_to_timezone! + # Adjusts the timezone to UTC. + # + # @return [DateTime] `self` + # @raise [RangeError] if `zone < -14*60` or `zone > 14*60` + # @overload adjust_to_timezone!(zone) + # If `zone` is nil, then the timzeone component is removed. + # + # Otherwise, the timezone is set based on the difference between the current timezone offset (if any) and `zone`. + # + # @param [String] zone (nil) In the form of {ZONE_FORMAT} + # @return [DateTime] `self` + # @raise [RangeError] if `zone < -14*60` or `zone > 14*60` + # @see https://www.w3.org/TR/xpath-functions/#func-adjust-dateTime-to-timezone + def adjust_to_timezone!(*args) + zone = args.empty? ? '+00:00' : args.first + if zone.nil? + # Remove timezone component + @object = ::DateTime.parse(@object.strftime(FORMAT)) + @zone = nil + else + md = zone.match(Literal::DateTime::ZONE_GRAMMAR) if zone + raise ArgumentError, + "expected #{zone.inspect} to be a xsd:dayTimeDuration or +/-HH:MM" unless md + + # Adjust to zone + si, hr, mi = md[:si], md[:hr], md[:mi] + si ||= '+' + offset = hr.to_i * 60 + mi.to_i + raise ArgumentError, + "Zone adjustment of #{zone} out of range" if + md.nil? || offset > 14*60 + + new_zone = "%s%.2d:%.2d" % [si, hr.to_i, mi.to_i] + dt = @zone.nil? ? @object : @object.new_offset(new_zone) + @object = ::DateTime.parse(dt.strftime(FORMAT + new_zone)) + @zone = new_zone + end + @string = nil + self + end + + ## + # Functional version of `#adjust_to_timezone!`. + # + # @overload adjust_to_timezone + # @param (see #adjust_to_timezone!) + # @return [DateTime] + # @raise (see #adjust_to_timezone!) + # @overload adjust_to_timezone(zone) (see #adjust_to_timezone!) + # @return [DateTime] + # @raise (see #adjust_to_timezone!) + def adjust_to_timezone(*args) + self.dup.adjust_to_timezone!(*args) + end + ## # Equal compares as DateTime objects + # + # From the XQuery function [op:dateTime-equal](https://www.w3.org/TR/xpath-functions/#func-dateTime-equal). + # + # @param [Literal::Date, Literal] other + # @return [Boolean] + # @see https://www.w3.org/TR/xpath-functions/#func-dateTime-equal def ==(other) # If lexically invalid, use regular literal testing - return super unless self.valid? + return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?) case other when Literal::DateTime - return super unless other.valid? self.object == other.object when Literal::Time, Literal::Date false @@ -149,5 +230,65 @@ def ==(other) super end end + + ## + # Compares `self` to `other` for sorting purposes (with type check). + # + # @param [Object] other + # @return [Integer] `-1`, `0`, or `1` + def <=>(other) + # If lexically invalid, use regular literal testing + return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?) + return super unless other.is_a?(DateTime) + @object <=> other.object + end + + # Years + # + # From the XQuery function [fn:year-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-year-from-dateTime). + # + # @return [Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-year-from-dateTime + def year; Integer.new(object.year); end + + # Months + # + # From the XQuery function [fn:month-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-month-from-dateTime). + # + # @return [Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-month-from-dateTime + def month; Integer.new(object.month); end + + # Days + # + # From the XQuery function [fn:day-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-day-from-dateTime). + # + # @return [Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-day-from-dateTime + def day; Integer.new(object.day); end + + # Hours + # + # From the XQuery function [fn:hours-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-hours-from-dateTime). + # + # @return [Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-hours-from-dateTime + def hours; Integer.new(object.hour); end + + # Minutes + # + # From the XQuery function [fn:minutes-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-minutes-from-dateTime). + # + # @return [Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-minutes-from-dateTime + def minutes; Integer.new(object.min); end + + # Seconds + # + # From the XQuery function [fn:seconds-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-seconds-from-dateTime). + # + # @return [Decimal] + # @see https://www.w3.org/TR/xpath-functions/#func-seconds-from-dateTime + def seconds; Decimal.new(object.strftime("%S.%L")); end end # DateTime end; end # RDF::Literal diff --git a/spec/model_literal_spec.rb b/spec/model_literal_spec.rb index 51f4fac5..045bcd83 100644 --- a/spec/model_literal_spec.rb +++ b/spec/model_literal_spec.rb @@ -865,6 +865,7 @@ def self.literals(*selector) { "2010-06-21T11:28:01Z" => RDF::Literal("PT0S", datatype: RDF::XSD.dayTimeDuration), "2010-12-21T15:38:02-08:00" => RDF::Literal("-PT8H", datatype: RDF::XSD.dayTimeDuration), + "2010-12-21T15:38:02+08:00" => RDF::Literal("PT8H", datatype: RDF::XSD.dayTimeDuration), "2008-06-20T23:59:00Z" => RDF::Literal("PT0S", datatype: RDF::XSD.dayTimeDuration), "2011-02-01T01:02:03" => nil, }.each do |l, r| @@ -874,10 +875,66 @@ def self.literals(*selector) end end + describe "#adjust_to_timezone" do + { + # Spec examples + ["2002-03-07T10:00:00"] => "2002-03-07T10:00:00Z", + ["2002-03-07T10:00:00-07:00"] => "2002-03-07T17:00:00Z", + ["2002-03-07T10:00:00", "-PT10H"] => "2002-03-07T10:00:00-10:00", + ["2002-03-07T10:00:00-07:00", "-PT10H"] => "2002-03-07T07:00:00-10:00", + ["2002-03-07T10:00:00-07:00", "PT10H"] => "2002-03-08T03:00:00+10:00", + ["2002-03-07T00:00:00+01:00", "-PT8H"] => "2002-03-06T15:00:00-08:00", + ["2002-03-07T10:00:00", nil] => "2002-03-07T10:00:00", + ["2002-03-07T10:00:00-07:00", nil] => "2002-03-07T10:00:00", + }.each do |args, r| + if r == ArgumentError + it "#{args.inspect} raises ArgumentError" do + source = described_class.new(args.shift) + expect {source.adjust_to_timezone(*args)}.to raise_error(ArgumentError) + end + else + it "#{args.inspect} => #{r.inspect}" do + source = described_class.new(args.shift) + result = described_class.new(r) + expect(source.adjust_to_timezone(*args)).to eq result + end + end + end + + { + # Test Suite https://github.com/w3c/qt3tests/blob/master/fn/adjust-date-to-timezone.xml + "fn-adjust-dateTime-to-timezone1args-1": ["1970-01-01T00:00:00Z", "-PT10H", "1969-12-31T14:00:00-10:00"], + "fn-adjust-dateTime-to-timezone1args-2": ["1996-04-07T01:40:52Z", "-PT10H", "1996-04-06T15:40:52-10:00"], + "fn-adjust-dateTime-to-timezone1args-3": ["2030-12-31T23:59:59Z", "-PT10H", "2030-12-31T13:59:59-10:00"], + "fn-adjust-dateTime-to-timezone-1": ["2002-03-07T10:00:00-05:00", "-PT5H0M", "2002-03-07T10:00:00-05:00"], + "fn-adjust-dateTime-to-timezone-2": ["2002-03-07T10:00:00-07:00", "-PT5H0M", "2002-03-07T12:00:00-05:00"], + "fn-adjust-dateTime-to-timezone-3": ["2002-03-07T10:00:00", "-PT10H", "2002-03-07T10:00:00-10:00"], + "fn-adjust-dateTime-to-timezone-4": ["2002-03-07T10:00:00-07:00", "-PT10H", "2002-03-07T07:00:00-10:00"], + "fn-adjust-dateTime-to-timezone-5": ["2002-03-07T10:00:00-07:00", "PT10H", "2002-03-08T03:00:00+10:00"], + "fn-adjust-dateTime-to-timezone-6": ["2002-03-07T00:00:00+01:00", "-PT8H", "2002-03-06T15:00:00-08:00"], + "fn-adjust-dateTime-to-timezone-7": ["2002-03-07T10:00:00", "2002-03-07T10:00:00"], + "fn-adjust-dateTime-to-timezone-8": ["2002-03-07T10:00:00-07:00", nil, "2002-03-07T10:00:00"], + "fn-adjust-dateTime-to-timezone-11": ["2002-03-07T10:00:00-04:00", nil, "2002-03-07T10:00:00"], + "K-AdjDateTimeToTimezoneFunc-7": ["2001-02-03T08:02:00", "PT14H1M", ArgumentError], + "K-AdjDateTimeToTimezoneFunc-7": ["2001-02-03T08:02:00", "-PT14H1M", ArgumentError], + "K-AdjDateTimeToTimezoneFunc-8": ["2001-02-03T08:02:00", "PT14H0M0.001S", ArgumentError], + }.each do |title, (*args, r)| + it title do + source = described_class.new(args.shift) + if r == ArgumentError + expect {source.adjust_to_timezone(*args)}.to raise_error(ArgumentError) + else + result = described_class.new(r) + expect(source.adjust_to_timezone(*args)).to eq result + end + end + end + end + describe "#==" do { ["2002-04-02T12:00:00-01:00", "2002-04-02T17:00:00+04:00"] => true, - #["2002-04-02T12:00:00", "2002-04-02T23:00:00+06:00"] => true, + ["2002-04-02T12:00:00", "2002-04-02T23:00:00+06:00"] => false, ["2002-04-02T12:00:00", "2002-04-02T17:00:00"] => false, ["2002-04-02T12:00:00", "2002-04-02T12:00:00"] => true, ["2002-04-02T23:00:00-04:00", "2002-04-03T02:00:00-01:00"] => true, @@ -948,7 +1005,7 @@ def self.literals(*selector) ["2010-01-01Z", "2010-01-01Z", "Friday, 01 January 2010 UTC"], ["2010-01-01", "2010-01-01", "Friday, 01 January 2010"], ["2010-01-01+00:00","2010-01-01Z", "Friday, 01 January 2010 UTC"], - ["2010-01-01+01:00","2010-01-01Z", "Friday, 01 January 2010 +01:00"], + ["2010-01-01+01:00","2009-12-31Z", "Friday, 01 January 2010 +01:00"], ["2009-12-31-01:00","2009-12-31Z", "Thursday, 31 December 2009 -01:00"], ["-2010-01-01Z", "-2010-01-01Z", "Friday, 01 January -2010 UTC"], ["2014-09-01-08:00","2014-09-01Z", "Monday, 01 September 2014 -08:00"], From cd1da2f7d867b081b0ec837c411420e4676a903f Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Mon, 21 Feb 2022 13:40:14 -0800 Subject: [PATCH 4/8] Refectore bulk of Date, and DateTime into new Temporal class, and use to re-implement Time as well. --- lib/rdf/model/literal.rb | 1 + lib/rdf/model/literal/date.rb | 198 +----------------- lib/rdf/model/literal/datetime.rb | 245 +---------------------- lib/rdf/model/literal/decimal.rb | 12 ++ lib/rdf/model/literal/double.rb | 12 ++ lib/rdf/model/literal/integer.rb | 6 + lib/rdf/model/literal/numeric.rb | 29 ++- lib/rdf/model/literal/temporal.rb | 243 ++++++++++++++++++++++ lib/rdf/model/literal/time.rb | 124 +++--------- spec/model_literal_spec.rb | 322 +++++++++++++++++++++--------- 10 files changed, 552 insertions(+), 640 deletions(-) create mode 100644 lib/rdf/model/literal/temporal.rb diff --git a/lib/rdf/model/literal.rb b/lib/rdf/model/literal.rb index 6c6a08ae..9760afd6 100644 --- a/lib/rdf/model/literal.rb +++ b/lib/rdf/model/literal.rb @@ -77,6 +77,7 @@ def self.inherited(child) require 'rdf/model/literal/decimal' require 'rdf/model/literal/integer' require 'rdf/model/literal/double' + require 'rdf/model/literal/temporal' require 'rdf/model/literal/date' require 'rdf/model/literal/datetime' require 'rdf/model/literal/time' diff --git a/lib/rdf/model/literal/date.rb b/lib/rdf/model/literal/date.rb index 73c91c04..242cde3d 100644 --- a/lib/rdf/model/literal/date.rb +++ b/lib/rdf/model/literal/date.rb @@ -4,7 +4,7 @@ module RDF; class Literal # # @see http://www.w3.org/TR/xmlschema11-2/#date # @since 0.2.1 - class Date < Literal + class Date < Temporal DATATYPE = RDF::URI("http://www.w3.org/2001/XMLSchema#date") GRAMMAR = %r(\A(-?\d{4}-\d{2}-\d{2})((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z).freeze FORMAT = '%Y-%m-%d'.freeze @@ -41,42 +41,6 @@ def initialize(value, datatype: nil, lexical: nil, **options) end rescue ::DateTime.new end - ## - # Converts this literal into its canonical lexical representation. - # - # 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. - # - # @return [RDF::Literal] `self` - # @see http://www.w3.org/TR/xmlschema11-2/#date - def canonicalize! - if self.valid? && @zone && @zone != '+00:00' - adjust_to_timezone! - else - @string = nil - end - self - end - - ## - # Returns `true` if the value adheres to the defined grammar of the - # datatype. - # - # Special case for date and dateTime, for which '0000' is not a valid year - # - # @return [Boolean] - # @since 0.2.1 - def valid? - super && object && value !~ %r(\A0000) - end - - ## - # Returns the value as a string. - # - # @return [String] - def to_s - @string || (@object.strftime(FORMAT) + self.tz) - end - ## # Returns a human-readable value for the literal # @@ -93,165 +57,5 @@ def humanize(lang = :en) end d end - - ## - # Does the literal representation include a timezone? Note that this is only possible if initialized using a string, or `:lexical` option. - # - # @return [Boolean] - # @since 1.1.6 - def timezone? - !@zone.nil? - end - alias_method :tz?, :timezone? - alias_method :has_tz?, :timezone? - alias_method :has_timezone?, :timezone? - - ## - # Adjust the timezone. - # - # From [fn:adjust-date-to-timezone](https://www.w3.org/TR/xpath-functions/#func-adjust-date-to-timezone) - # - # @overload adjust_to_timezone! - # Adjusts the timezone to UTC. - # - # @return [Date] `self` - # @raise [RangeError] if `zone < -14*60` or `zone > 14*60` - # @overload adjust_to_timezone!(zone) - # If `zone` is nil, then the timzeone component is removed. - # - # Otherwise, the timezone is set based on the difference between the current timezone offset (if any) and `zone`. - # - # @param [String] zone (nil) In the form of {ZONE_FORMAT} - # @return [Date] `self` - # @raise [RangeError] if `zone < -14*60` or `zone > 14*60` - # @see https://www.w3.org/TR/xpath-functions/#func-adjust-date-to-timezone - def adjust_to_timezone!(*args) - zone = args.empty? ? '+00:00' : args.first - if zone.nil? - # Remove timezone component - @object = ::DateTime.parse(@object.strftime('%F')) - @zone = nil - else - md = zone.match(Literal::DateTime::ZONE_GRAMMAR) if zone - raise ArgumentError, - "expected #{zone.inspect} to be a xsd:dayTimeDuration or +/-HH:MM" unless md - # Adjust to zone - si, hr, mi = md[:si], md[:hr], md[:mi] - si ||= '+' - offset = hr.to_i * 60 + mi.to_i - raise ArgumentError, - "Zone adjustment of #{zone} out of range" if - md.nil? || offset > 14*60 - - new_zone = "%s%.2d:%.2d" % [si, hr.to_i, mi.to_i] - dt = @zone.nil? ? @object : @object.new_offset(new_zone) - @object = ::DateTime.parse(dt.strftime("%FT00:00:00#{new_zone}")) - @zone = new_zone - end - @string = nil - self - end - - ## - # Functional version of `#adjust_to_timezone!`. - # - # @overload adjust_to_timezone - # @param (see #adjust_to_timezone!) - # @return [Date] - # @raise (see #adjust_to_timezone!) - # @overload adjust_to_timezone(zone) (see #adjust_to_timezone!) - # @return [Date] - # @raise (see #adjust_to_timezone!) - def adjust_to_timezone(*args) - self.dup.adjust_to_timezone!(*args) - end - - ## - # Returns the timezone part of arg as a simple literal. Returns the empty string if there is no timezone. - # - # @return [RDF::Literal] - # @since 1.1.6 - def tz - RDF::Literal(@zone == "+00:00" ? 'Z' : @zone) - end - - ## - # Returns the timezone part of arg as an xsd:dayTimeDuration, or `nil` - # if lexical form of literal does not include a timezone. - # - # From [fn:timezone-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-timezone-from-dateTime). - # - # @return [RDF::Literal] - # @see https://www.w3.org/TR/xpath-functions/#func-timezone-from-dateTime - def timezone - if @zone - md = @zone.match(Literal::DateTime::ZONE_GRAMMAR) - si, hr, mi = md[:si], md[:hr].to_i, md[:mi].to_i - si = nil unless si == "-" - res = "#{si}PT#{hr}H#{"#{mi}M" if mi > 0}" - RDF::Literal(res, datatype: RDF::URI("http://www.w3.org/2001/XMLSchema#dayTimeDuration")) - end - end - - ## - # Updates the date to a new timezone, or no timezone. - ## - # Equal compares as Date objects - # - # From the XQuery function [op:date-equal](https://www.w3.org/TR/xpath-functions/#func-date-equal). - # - # @param [Date, Literal] other - # @return [Boolean] - # @see https://www.w3.org/TR/xpath-functions/#func-date-equal - def ==(other) - # If lexically invalid, use regular literal testing - return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?) - - case other - when Literal::Date - return super unless other.valid? - self.object == other.object - when Literal::Time, Literal::DateTime - false - else - super - end - end - - ## - # Compares `self` to `other` for sorting purposes (with type check). - # - # @param [Object] other - # @return [Integer] `-1`, `0`, or `1` - def <=>(other) - # If lexically invalid, use regular literal testing - return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?) - return super unless other.is_a?(Date) - @object <=> other.object - end - - # Years - # - # From the XQuery function [fn:year-from-date](https://www.w3.org/TR/xpath-functions/#func-year-from-date). - # - # @return [Integer] - # @see https://www.w3.org/TR/xpath-functions/#func-year-from-date - def year; Integer.new(object.year); end - - # Months - # - # From the XQuery function [fn:month-from-date](https://www.w3.org/TR/xpath-functions/#func-month-from-date). - # - # @return [Integer] - # @see https://www.w3.org/TR/xpath-functions/#func-month-from-date - def month; Integer.new(object.month); end - - # Days - # - # From the XQuery function [fn:day-from-date](https://www.w3.org/TR/xpath-functions/#func-day-from-date). - # - # @return [Integer] - # @see https://www.w3.org/TR/xpath-functions/#func-day-from-date - def day; Integer.new(object.day); end end # Date end; end # RDF::Literal diff --git a/lib/rdf/model/literal/datetime.rb b/lib/rdf/model/literal/datetime.rb index 931abbc3..db86f882 100644 --- a/lib/rdf/model/literal/datetime.rb +++ b/lib/rdf/model/literal/datetime.rb @@ -4,17 +4,11 @@ module RDF; class Literal # # @see http://www.w3.org/TR/xmlschema11-2/#dateTime # @since 0.2.1 - class DateTime < Literal + class DateTime < Temporal DATATYPE = RDF::URI("http://www.w3.org/2001/XMLSchema#dateTime") GRAMMAR = %r(\A(-?(?:\d{4}|[1-9]\d{4,})-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?)((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z).freeze FORMAT = '%Y-%m-%dT%H:%M:%S.%L'.freeze - # Matches either -10:00 or -P1H0M forms - ZONE_GRAMMAR = %r(\A - (?:(?[+-])(?
\d{2}):(?:(?\d{2}))?) - |(?:(?-)?PT(?
\d{1,2})H(?:(?\d{1,2})M)?) - \z)x.freeze - ## # Internally, a `DateTime` is represented using a native `::DateTime`. If initialized from a `::Date`, there is no timezone component, 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. # @@ -32,7 +26,7 @@ def initialize(value, datatype: nil, lexical: nil, **options) value.to_datetime else md = value.to_s.match(GRAMMAR) - _, dt, tz = Array(md) + _, _, tz = Array(md) if tz @zone = tz == 'Z' ? '+00:00' : tz else @@ -42,98 +36,6 @@ def initialize(value, datatype: nil, lexical: nil, **options) end rescue ::DateTime.new end - ## - # Converts this literal into its canonical lexical representation. - # with date and time normalized to UTC. - # - # @return [RDF::Literal] `self` - # @see http://www.w3.org/TR/xmlschema11-2/#dateTime - def canonicalize! - if self.valid? && @zone && @zone != '+00:00' - adjust_to_timezone! - else - @string = nil - end - self - end - - ## - # Returns the timezone part of arg as a simple literal. Returns the empty string if there is no timezone. - # - # @return [RDF::Literal] - def tz - RDF::Literal(@zone == "+00:00" ? 'Z' : @zone) - end - - ## - # Does the literal representation include a timezone? Note that this is only possible if initialized using a string, or `:lexical` option. - # - # @return [Boolean] - # @since 1.1.6 - def timezone? - # Can only know there's a timezone from the string represntation - md = to_s.match(GRAMMAR) - md && !!md[2] - end - alias_method :tz?, :timezone? - alias_method :has_tz?, :timezone? - alias_method :has_timezone?, :timezone? - - ## - # Returns the timezone part of arg as an xsd:dayTimeDuration, or `nil` - # if lexical form of literal does not include a timezone. - # - # From [fn:timezone-from-date](https://www.w3.org/TR/xpath-functions/#func-timezone-from-date). - # - # @return [RDF::Literal] - # @see https://www.w3.org/TR/xpath-functions/#func-timezone-from-date - def timezone - if tz == 'Z' - RDF::Literal("PT0S", datatype: RDF::URI("http://www.w3.org/2001/XMLSchema#dayTimeDuration")) - elsif md = tz.to_s.match(/^([+-])?(\d+):(\d+)?$/) - plus_minus, hour, min = md[1,3] - plus_minus = nil unless plus_minus == "-" - hour = hour.to_i - min = min.to_i - res = "#{plus_minus}PT#{hour}H#{"#{min}M" if min > 0}" - RDF::Literal(res, datatype: RDF::URI("http://www.w3.org/2001/XMLSchema#dayTimeDuration")) - end - end - - ## - # Returns `true` if the value adheres to the defined grammar of the - # datatype. - # - # Special case for date and dateTime, for which '0000' is not a valid year - # - # @return [Boolean] - # @since 0.2.1 - def valid? - super && object && value !~ %r(\A0000) - end - - ## - # Does the literal representation include millisectonds? - # - # @return [Boolean] - # @since 1.1.6 - def milliseconds? - object.strftime("%L").to_i > 0 - end - alias_method :has_milliseconds?, :milliseconds? - alias_method :has_ms?, :milliseconds? - alias_method :ms?, :milliseconds? - - ## - # Returns the `timezone` of the literal. If the - ## - # Returns the value as a string. - # - # @return [String] - def to_s - @string || (@object.strftime(FORMAT).sub('.000', '') + self.tz) - end - ## # Returns a human-readable value for the literal # @@ -147,148 +49,5 @@ def humanize(lang = :en) end d end - - ## - # Adjust the timezone. - # - # From [fn:adjust-dateTime-to-timezone](https://www.w3.org/TR/xpath-functions/#func-adjust-dateTime-to-timezone) - # - # @overload adjust_to_timezone! - # Adjusts the timezone to UTC. - # - # @return [DateTime] `self` - # @raise [RangeError] if `zone < -14*60` or `zone > 14*60` - # @overload adjust_to_timezone!(zone) - # If `zone` is nil, then the timzeone component is removed. - # - # Otherwise, the timezone is set based on the difference between the current timezone offset (if any) and `zone`. - # - # @param [String] zone (nil) In the form of {ZONE_FORMAT} - # @return [DateTime] `self` - # @raise [RangeError] if `zone < -14*60` or `zone > 14*60` - # @see https://www.w3.org/TR/xpath-functions/#func-adjust-dateTime-to-timezone - def adjust_to_timezone!(*args) - zone = args.empty? ? '+00:00' : args.first - if zone.nil? - # Remove timezone component - @object = ::DateTime.parse(@object.strftime(FORMAT)) - @zone = nil - else - md = zone.match(Literal::DateTime::ZONE_GRAMMAR) if zone - raise ArgumentError, - "expected #{zone.inspect} to be a xsd:dayTimeDuration or +/-HH:MM" unless md - - # Adjust to zone - si, hr, mi = md[:si], md[:hr], md[:mi] - si ||= '+' - offset = hr.to_i * 60 + mi.to_i - raise ArgumentError, - "Zone adjustment of #{zone} out of range" if - md.nil? || offset > 14*60 - - new_zone = "%s%.2d:%.2d" % [si, hr.to_i, mi.to_i] - dt = @zone.nil? ? @object : @object.new_offset(new_zone) - @object = ::DateTime.parse(dt.strftime(FORMAT + new_zone)) - @zone = new_zone - end - @string = nil - self - end - - ## - # Functional version of `#adjust_to_timezone!`. - # - # @overload adjust_to_timezone - # @param (see #adjust_to_timezone!) - # @return [DateTime] - # @raise (see #adjust_to_timezone!) - # @overload adjust_to_timezone(zone) (see #adjust_to_timezone!) - # @return [DateTime] - # @raise (see #adjust_to_timezone!) - def adjust_to_timezone(*args) - self.dup.adjust_to_timezone!(*args) - end - - ## - # Equal compares as DateTime objects - # - # From the XQuery function [op:dateTime-equal](https://www.w3.org/TR/xpath-functions/#func-dateTime-equal). - # - # @param [Literal::Date, Literal] other - # @return [Boolean] - # @see https://www.w3.org/TR/xpath-functions/#func-dateTime-equal - def ==(other) - # If lexically invalid, use regular literal testing - return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?) - - case other - when Literal::DateTime - self.object == other.object - when Literal::Time, Literal::Date - false - else - super - end - end - - ## - # Compares `self` to `other` for sorting purposes (with type check). - # - # @param [Object] other - # @return [Integer] `-1`, `0`, or `1` - def <=>(other) - # If lexically invalid, use regular literal testing - return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?) - return super unless other.is_a?(DateTime) - @object <=> other.object - end - - # Years - # - # From the XQuery function [fn:year-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-year-from-dateTime). - # - # @return [Integer] - # @see https://www.w3.org/TR/xpath-functions/#func-year-from-dateTime - def year; Integer.new(object.year); end - - # Months - # - # From the XQuery function [fn:month-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-month-from-dateTime). - # - # @return [Integer] - # @see https://www.w3.org/TR/xpath-functions/#func-month-from-dateTime - def month; Integer.new(object.month); end - - # Days - # - # From the XQuery function [fn:day-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-day-from-dateTime). - # - # @return [Integer] - # @see https://www.w3.org/TR/xpath-functions/#func-day-from-dateTime - def day; Integer.new(object.day); end - - # Hours - # - # From the XQuery function [fn:hours-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-hours-from-dateTime). - # - # @return [Integer] - # @see https://www.w3.org/TR/xpath-functions/#func-hours-from-dateTime - def hours; Integer.new(object.hour); end - - # Minutes - # - # From the XQuery function [fn:minutes-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-minutes-from-dateTime). - # - # @return [Integer] - # @see https://www.w3.org/TR/xpath-functions/#func-minutes-from-dateTime - def minutes; Integer.new(object.min); end - - # Seconds - # - # From the XQuery function [fn:seconds-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-seconds-from-dateTime). - # - # @return [Decimal] - # @see https://www.w3.org/TR/xpath-functions/#func-seconds-from-dateTime - def seconds; Decimal.new(object.strftime("%S.%L")); end end # DateTime end; end # RDF::Literal diff --git a/lib/rdf/model/literal/decimal.rb b/lib/rdf/model/literal/decimal.rb index 6b008fab..a32ebcd8 100644 --- a/lib/rdf/model/literal/decimal.rb +++ b/lib/rdf/model/literal/decimal.rb @@ -54,7 +54,10 @@ def canonicalize! ## # Returns the absolute value of `self`. # + # From the XQuery function [fn:abs](https://www.w3.org/TR/xpath-functions/#func-abs). + # # @return [RDF::Literal] + # @see https://www.w3.org/TR/xpath-functions/#func-abs # @since 0.2.3 def abs (d = to_d) && d > 0 ? self : RDF::Literal(d.abs) @@ -63,7 +66,10 @@ def abs ## # Returns the number with no fractional part that is closest to the argument. If there are two such numbers, then the one that is closest to positive infinity is returned. An error is raised if arg is not a numeric value. # + # From the XQuery function [fn:round](https://www.w3.org/TR/xpath-functions/#func-round). + # # @return [RDF::Literal::Decimal] + # @see https://www.w3.org/TR/xpath-functions/#func-round def round rounded = to_d.round(half: (to_d < 0 ? :down : :up)) if rounded == -0.0 @@ -77,10 +83,13 @@ def round ## # Returns the smallest integer greater than or equal to `self`. # + # From the XQuery function [fn:ceil](https://www.w3.org/TR/xpath-functions/#func-ceil). + # # @example # RDF::Literal(1).ceil #=> RDF::Literal(1) # # @return [RDF::Literal::Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-ceil def ceil RDF::Literal::Integer.new(to_d.ceil) end @@ -88,10 +97,13 @@ def ceil ## # Returns the largest integer less than or equal to `self`. # + # From the XQuery function [fn:floor](https://www.w3.org/TR/xpath-functions/#func-floor). + # # @example # RDF::Literal(1).floor #=> RDF::Literal(1) # # @return [RDF::Literal::Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-floor def floor RDF::Literal::Integer.new(to_d.floor) end diff --git a/lib/rdf/model/literal/double.rb b/lib/rdf/model/literal/double.rb index ff4d719a..376f1ec3 100644 --- a/lib/rdf/model/literal/double.rb +++ b/lib/rdf/model/literal/double.rb @@ -145,6 +145,8 @@ def infinite? ## # Returns the smallest integer greater than or equal to `self`. # + # From the XQuery function [fn:ceil](https://www.w3.org/TR/xpath-functions/#func-ceil). + # # @example # RDF::Literal(1.2).ceil #=> RDF::Literal(2) # RDF::Literal(-1.2).ceil #=> RDF::Literal(-1) @@ -152,6 +154,7 @@ def infinite? # RDF::Literal(-2.0).ceil #=> RDF::Literal(-2) # # @return [RDF::Literal::Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-ceil # @since 0.2.3 def ceil RDF::Literal::Integer.new(to_f.ceil) @@ -160,6 +163,8 @@ def ceil ## # Returns the largest integer less than or equal to `self`. # + # From the XQuery function [fn:floor](https://www.w3.org/TR/xpath-functions/#func-floor). + # # @example # RDF::Literal(1.2).floor #=> RDF::Literal(1) # RDF::Literal(-1.2).floor #=> RDF::Literal(-2) @@ -167,6 +172,7 @@ def ceil # RDF::Literal(-2.0).floor #=> RDF::Literal(-2) # # @return [RDF::Literal::Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-floor # @since 0.2.3 def floor RDF::Literal::Integer.new(to_f.floor) @@ -175,7 +181,10 @@ def floor ## # Returns the absolute value of `self`. # + # From the XQuery function [fn:abs](https://www.w3.org/TR/xpath-functions/#func-abs). + # # @return [RDF::Literal] + # @see https://www.w3.org/TR/xpath-functions/#func-abs # @since 0.2.3 def abs (f = to_f) && f > 0 ? self : self.class.new(f.abs) @@ -184,7 +193,10 @@ def abs ## # Returns the number with no fractional part that is closest to the argument. If there are two such numbers, then the one that is closest to positive infinity is returned. An error is raised if arg is not a numeric value. # + # From the XQuery function [fn:round](https://www.w3.org/TR/xpath-functions/#func-round). + # # @return [RDF::Literal::Double] + # @see https://www.w3.org/TR/xpath-functions/#func-round def round self.class.new(to_d.round(half: (to_d < 0 ? :down : :up))) end diff --git a/lib/rdf/model/literal/integer.rb b/lib/rdf/model/literal/integer.rb index 638085d8..052976d5 100644 --- a/lib/rdf/model/literal/integer.rb +++ b/lib/rdf/model/literal/integer.rb @@ -78,7 +78,10 @@ def odd? ## # Returns the absolute value of `self`. # + # From the XQuery function [fn:abs](https://www.w3.org/TR/xpath-functions/#func-abs). + # # @return [RDF::Literal] + # @see https://www.w3.org/TR/xpath-functions/#func-abs # @since 0.2.3 def abs (n = to_i) && n > 0 ? self : self.class.new(n.abs) @@ -87,7 +90,10 @@ def abs ## # Returns `self`. # + # From the XQuery function [fn:round](https://www.w3.org/TR/xpath-functions/#func-round). + # # @return [RDF::Literal] + # @see https://www.w3.org/TR/xpath-functions/#func-round def round self end diff --git a/lib/rdf/model/literal/numeric.rb b/lib/rdf/model/literal/numeric.rb index e10934ba..b237aa1b 100644 --- a/lib/rdf/model/literal/numeric.rb +++ b/lib/rdf/model/literal/numeric.rb @@ -67,10 +67,9 @@ def -@ ## # Returns the sum of `self` plus `other`. # - # For xs:float or xs:double values, if one of the operands is a zero or a finite number - # and the other is INF or -INF, INF or -INF is returned. If both operands are INF, INF is returned. - # If both operands are -INF, -INF is returned. If one of the operands is INF - # and the other is -INF, NaN is returned. + # From the XQuery function [op:numeric-add](https://www.w3.org/TR/xpath-functions/#func-numeric-add). + # + # @note For `xs:float` or `xs:double` values, if one of the operands is a zero or a finite number and the other is `INF` or `-INF`, `INF` or `-INF` is returned. If both operands are `INF`, `INF` is returned. If both operands are `-INF`, `-INF` is returned. If one of the operands is `INF` and the other is `-INF`, `NaN` is returned. # @param [Literal::Numeric, #to_i, #to_f, #to_d] other # @return [RDF::Literal::Numeric] # @since 0.2.3 @@ -90,6 +89,8 @@ def +(other) ## # Returns the difference of `self` minus `other`. # + # From the XQuery function [op:numeric-subtract](https://www.w3.org/TR/xpath-functions/#func-numeric-subtract). + # # @param [Literal::Numeric, #to_i, #to_f, #to_d] other # @return [RDF::Literal::Numeric] # @since 0.2.3 @@ -109,6 +110,8 @@ def -(other) ## # Returns the product of `self` times `other`. # + # From the XQuery function [op:numeric-multiply](https://www.w3.org/TR/xpath-functions/#func-numeric-multiply). + # # @param [Literal::Numeric, #to_i, #to_f, #to_d] other # @return [RDF::Literal::Numeric] # @since 0.2.3 @@ -130,6 +133,8 @@ def *(other) # # Promotes values, as necessary, with the result type depending on the input values. # + # From the XQuery function [math:pow](https://www.w3.org/TR/xpath-functions/#func-numeric-pow). + # # @param [Literal::Numeric, #to_i, #to_f, #to_d] other # @return [RDF::Literal::Numeric] # @since 0.2.3 @@ -143,6 +148,8 @@ def **(other) ## # Exponent − Performs remainder of `self` divided by `other`. # + # From the XQuery function [math:mod](https://www.w3.org/TR/xpath-functions/#func-numeric-mod). + # # @param [Literal::Numeric, #to_i, #to_f, #to_d] other # @return [RDF::Literal] # @since 0.2.3 @@ -165,6 +172,8 @@ def %(other) # As a special case, if the types of both $arg1 and $arg2 are xsd:integer, # then the return type is xsd:decimal. # + # From the XQuery function [op:numeric-divide](https://www.w3.org/TR/xpath-functions/#func-numeric-divide). + # # @param [Literal::Numeric, #to_i, #to_f, #to_d] other # @return [RDF::Literal::Numeric] # @raise [ZeroDivisionError] if divided by zero @@ -183,8 +192,11 @@ def /(other) ## # Returns the absolute value of `self`. # + # From the XQuery function [fn:abs](https://www.w3.org/TR/xpath-functions/#func-abs). + # # @return [RDF::Literal] # @raise [NotImplementedError] unless implemented in subclass + # @see https://www.w3.org/TR/xpath-functions/#func-abs def abs raise NotImplementedError end @@ -192,8 +204,11 @@ def abs ## # Returns the number with no fractional part that is closest to the argument. If there are two such numbers, then the one that is closest to positive infinity is returned. An error is raised if arg is not a numeric value. # + # From the XQuery function [fn:round](https://www.w3.org/TR/xpath-functions/#func-round). + # # @return [RDF::Literal] # @raise [NotImplementedError] unless implemented in subclass + # @see https://www.w3.org/TR/xpath-functions/#func-round def round raise NotImplementedError end @@ -201,10 +216,13 @@ def round ## # Returns the smallest integer greater than or equal to `self`. # + # From the XQuery function [fn:ceil](https://www.w3.org/TR/xpath-functions/#func-ceil). + # # @example # RDF::Literal(1).ceil #=> RDF::Literal(1) # # @return [RDF::Literal] + # @see https://www.w3.org/TR/xpath-functions/#func-ceil def ceil self end @@ -212,10 +230,13 @@ def ceil ## # Returns the largest integer less than or equal to `self`. # + # From the XQuery function [fn:floor](https://www.w3.org/TR/xpath-functions/#func-floor). + # # @example # RDF::Literal(1).floor #=> RDF::Literal(1) # # @return [RDF::Literal] + # @see https://www.w3.org/TR/xpath-functions/#func-floor def floor self end diff --git a/lib/rdf/model/literal/temporal.rb b/lib/rdf/model/literal/temporal.rb new file mode 100644 index 00000000..89d83fe8 --- /dev/null +++ b/lib/rdf/model/literal/temporal.rb @@ -0,0 +1,243 @@ +module RDF; class Literal + ## + # Shared methods and class ancestry for date, time, and dateTime literal classes. + # + # @since 3.1 + class Temporal < Literal + # Matches either -10:00 or -P1H0M forms + ZONE_GRAMMAR = %r(\A + (?:(?[+-])(?
\d{2}):(?:(?\d{2}))?) + |(?:(?-)?PT(?
\d{1,2})H(?:(?\d{1,2})M)?) + \z)x.freeze + + ## + # Compares this literal to `other` for sorting purposes. + # + # @param [Object] other + # @return [Integer] `-1`, `0`, or `1` + def <=>(other) + # If lexically invalid, use regular literal testing + return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?) + return super unless other.is_a?(self.class) + @object <=> other.object + end + + ## + # Returns `true` if this literal is equal to `other`. + # + # @param [Object] other + # @return [Boolean] `true` or `false` + # @since 0.3.0 + def ==(other) + # If lexically invalid, use regular literal testing + return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?) + + case other + when self.class + self.object == other.object + when Literal::Temporal + false + else + super + end + end + + ## + # Converts this literal into its canonical lexical representation. + # with date and time normalized to UTC. + # + # @return [RDF::Literal] `self` + # @see http://www.w3.org/TR/xmlschema11-2/#dateTime + def canonicalize! + if self.valid? && @zone && @zone != '+00:00' + adjust_to_timezone! + else + @string = nil + end + self + end + + ## + # Returns the timezone part of arg as a simple literal. Returns the empty string if there is no timezone. + # + # @return [RDF::Literal] + def tz + RDF::Literal(@zone == "+00:00" ? 'Z' : @zone) + end + + ## + # Does the literal representation include a timezone? Note that this is only possible if initialized using a string, or `:lexical` option. + # + # @return [Boolean] + # @since 1.1.6 + def timezone? + # Can only know there's a timezone from the string represntation + md = to_s.match(self.class.const_get(:GRAMMAR)) + md && !!md[2] + end + alias_method :tz?, :timezone? + alias_method :has_tz?, :timezone? + alias_method :has_timezone?, :timezone? + + ## + # Returns the timezone part of arg as an xsd:dayTimeDuration, or `nil` + # if lexical form of literal does not include a timezone. + # + # From [fn:timezone-from-date](https://www.w3.org/TR/xpath-functions/#func-timezone-from-date). + # + # @return [RDF::Literal] + # @see https://www.w3.org/TR/xpath-functions/#func-timezone-from-date + def timezone + if @zone + md = @zone.match(ZONE_GRAMMAR) + si, hr, mi = md[:si], md[:hr].to_i, md[:mi].to_i + si = nil unless si == "-" + res = "#{si}PT#{hr}H#{"#{mi}M" if mi > 0}" + RDF::Literal(res, datatype: RDF::URI("http://www.w3.org/2001/XMLSchema#dayTimeDuration")) + end + end + + ## + # Returns `true` if the value adheres to the defined grammar of the + # datatype. + # + # Special case for date and dateTime, for which '0000' is not a valid year + # + # @return [Boolean] + # @since 0.2.1 + def valid? + super && object && value !~ %r(\A0000) + end + + ## + # Does the literal representation include millisectonds? + # + # @return [Boolean] + # @since 1.1.6 + def milliseconds? + object.strftime("%L").to_i > 0 + end + alias_method :has_milliseconds?, :milliseconds? + alias_method :has_ms?, :milliseconds? + alias_method :ms?, :milliseconds? + + ## + # Returns the `timezone` of the literal. If the + ## + # Returns the value as a string. + # + # @return [String] + def to_s + @string || (@object.strftime(self.class.const_get(:FORMAT)).sub('.000', '') + self.tz) + end + + ## + # Adjust the timezone. + # + # From [fn:adjust-dateTime-to-timezone](https://www.w3.org/TR/xpath-functions/#func-adjust-dateTime-to-timezone) + # + # @overload adjust_to_timezone! + # Adjusts the timezone to UTC. + # + # @return [Temporal] `self` + # @raise [RangeError] if `zone < -14*60` or `zone > 14*60` + # @overload adjust_to_timezone!(zone) + # If `zone` is nil, then the timzeone component is removed. + # + # Otherwise, the timezone is set based on the difference between the current timezone offset (if any) and `zone`. + # + # @param [String] zone (nil) In the form of {ZONE_FORMAT} + # @return [Temporal] `self` + # @raise [RangeError] if `zone < -14*60` or `zone > 14*60` + # @see https://www.w3.org/TR/xpath-functions/#func-adjust-dateTime-to-timezone + def adjust_to_timezone!(*args) + zone = args.empty? ? '+00:00' : args.first + if zone.nil? + # Remove timezone component + @object = self.class.new(@object.strftime(self.class.const_get(:FORMAT))).object + @zone = nil + else + md = zone.match(ZONE_GRAMMAR) + raise ArgumentError, + "expected #{zone.inspect} to be a xsd:dayTimeDuration or +/-HH:MM" unless md + + # Adjust to zone + si, hr, mi = md[:si], md[:hr], md[:mi] + si ||= '+' + offset = hr.to_i * 60 + mi.to_i + raise ArgumentError, + "Zone adjustment of #{zone} out of range" if + md.nil? || offset > 14*60 + + new_zone = "%s%.2d:%.2d" % [si, hr.to_i, mi.to_i] + dt = @zone.nil? ? @object : @object.new_offset(new_zone) + @object = self.class.new(dt.strftime(self.class.const_get(:FORMAT) + new_zone)).object + @zone = new_zone + end + @string = nil + self + end + + ## + # Functional version of `#adjust_to_timezone!`. + # + # @overload adjust_to_timezone + # @param (see #adjust_to_timezone!) + # @return [DateTime] + # @raise (see #adjust_to_timezone!) + # @overload adjust_to_timezone(zone) (see #adjust_to_timezone!) + # @return [DateTime] + # @raise (see #adjust_to_timezone!) + def adjust_to_timezone(*args) + self.dup.adjust_to_timezone!(*args) + end + + # Years + # + # From the XQuery function [fn:year-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-year-from-dateTime). + # + # @return [Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-year-from-dateTime + def year; Integer.new(object.year); end + + # Months + # + # From the XQuery function [fn:month-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-month-from-dateTime). + # + # @return [Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-month-from-dateTime + def month; Integer.new(object.month); end + + # Days + # + # From the XQuery function [fn:day-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-day-from-dateTime). + # + # @return [Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-day-from-dateTime + def day; Integer.new(object.day); end + + # Hours + # + # From the XQuery function [fn:hours-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-hours-from-dateTime). + # + # @return [Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-hours-from-dateTime + def hours; Integer.new(object.hour); end + + # Minutes + # + # From the XQuery function [fn:minutes-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-minutes-from-dateTime). + # + # @return [Integer] + # @see https://www.w3.org/TR/xpath-functions/#func-minutes-from-dateTime + def minutes; Integer.new(object.min); end + + # Seconds + # + # From the XQuery function [fn:seconds-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-seconds-from-dateTime). + # + # @return [Decimal] + # @see https://www.w3.org/TR/xpath-functions/#func-seconds-from-dateTime + def seconds; Decimal.new(object.strftime("%S.%L")); end + end # Temporal +end; end # RDF::Literal diff --git a/lib/rdf/model/literal/time.rb b/lib/rdf/model/literal/time.rb index e00c7112..ea7bbc83 100644 --- a/lib/rdf/model/literal/time.rb +++ b/lib/rdf/model/literal/time.rb @@ -9,91 +9,41 @@ module RDF; class Literal # # @see http://www.w3.org/TR/xmlschema11-2/#time # @since 0.2.1 - class Time < Literal + class Time < Temporal DATATYPE = RDF::URI("http://www.w3.org/2001/XMLSchema#time") GRAMMAR = %r(\A(\d{2}:\d{2}:\d{2}(?:\.\d+)?)((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z).freeze - FORMAT = '%H:%M:%S.%L%:z'.freeze + FORMAT = '%H:%M:%S.%L'.freeze ## + # 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. + # # @param [String, DateTime, #to_datetime] value # @param (see Literal#initialize) def initialize(value, datatype: nil, lexical: nil, **options) @datatype = RDF::URI(datatype || self.class.const_get(:DATATYPE)) @string = lexical || (value if value.is_a?(String)) @object = case - when value.is_a?(::DateTime) then value - when value.respond_to?(:to_datetime) then value.to_datetime rescue ::DateTime.parse(value.to_s) - else ::DateTime.parse(value.to_s) - end rescue ::DateTime.new - end - - ## - # Converts this literal into its canonical lexical representation. - # - # §3.2.8.2 Canonical representation - # - # The canonical representation for time is defined by prohibiting - # certain options from the Lexical representation (§3.2.8.1). - # Specifically, either the time zone must be omitted or, if present, the - # time zone must be Coordinated Universal Time (UTC) indicated by a "Z". - # Additionally, the canonical representation for midnight is 00:00:00. - # - # @return [RDF::Literal] `self` - # @see http://www.w3.org/TR/xmlschema11-2/#time - def canonicalize! - if self.valid? - @string = if timezone? - @object.new_offset.new_offset.strftime(FORMAT[0..-4] + 'Z').sub('.000', '') + when value.respond_to?(:to_datetime) + dt = value.to_datetime + @zone = dt.zone + # Normalize to 1972-12-31 dateTime base + hms = dt.strftime(FORMAT) + ::DateTime.parse("1972-12-31T#{hms}#{@zone}") else - @object.strftime(FORMAT[0..-4]).sub('.000', '') - end - end - self - end - - ## - # Returns the timezone part of arg as a simple literal. Returns the empty string if there is no timezone. - # - # @return [RDF::Literal] - # @see http://www.w3.org/TR/sparql11-query/#func-tz - def tz - zone = timezone? ? object.zone : "" - zone = "Z" if zone == "+00:00" - RDF::Literal(zone) - end - - ## - # Returns `true` if the value adheres to the defined grammar of the - # datatype. - # - # Special case for date and dateTime, for which '0000' is not a valid year - # - # @return [Boolean] - # @since 0.2.1 - def valid? - super && !object.nil? - end - - ## - # Does the literal representation include a timezone? Note that this is only possible if initialized using a string, or `:lexical` option. - # - # @return [Boolean] - # @since 1.1.6 - def timezone? - md = self.to_s.match(GRAMMAR) - md && !!md[2] - end - alias_method :tz?, :timezone? - alias_method :has_tz?, :timezone? - alias_method :has_timezone?, :timezone? - - ## - # Returns the value as a string. - # Does not normalize timezone - # - # @return [String] - def to_s - @string || @object.strftime(FORMAT).sub("+00:00", 'Z').sub('.000', '') + md = value.to_s.match(GRAMMAR) + _, tm, tz = Array(md) + if tz + @zone = tz == 'Z' ? '+00:00' : tz + else + @zone = nil # No timezone + end + # Normalize 24:00:00 to 00:00:00 + hr, mi, se = tm.split(':') + hr = "%.2i" % (hr.to_i % 24) if hr.to_i > 23 + value = "#{hr}:#{mi}:#{se}" + # Normalize to 1972-12-31 dateTime base + ::DateTime.parse("1972-12-31T#{hr}:#{mi}:#{se}#{@zone}") + end rescue ::DateTime.new end ## @@ -104,32 +54,10 @@ def to_s def humanize(lang = :en) t = object.strftime("%r") if timezone? - t += if self.tz == 'Z' - " UTC" - else - " #{self.tz}" - end + z = @zone == '+00:00' ? "UTC" : @zone + t += " #{z}" end t end - - ## - # Equal compares as Time objects - def ==(other) - # If lexically invalid, use regular literal testing - return super unless self.valid? - - case other - when Literal::Time - return super unless other.valid? - # Compare as strings, as time includes a date portion, and adjusting for UTC - # can create a mismatch in the date portion. - self.object.new_offset.strftime('%H%M%S.%L') == other.object.new_offset.strftime('%H%M%S.%L') - when Literal::DateTime, Literal::Date - false - else - super - end - end end # Time end; end # RDF::Literal diff --git a/spec/model_literal_spec.rb b/spec/model_literal_spec.rb index 045bcd83..cbbd8233 100644 --- a/spec/model_literal_spec.rb +++ b/spec/model_literal_spec.rb @@ -473,21 +473,21 @@ def self.literals(*selector) describe "#**", skip: (RUBY_ENGINE == "jruby") do { - "2^3": [2, 3, 8], - "-2^3": [-2, 3, -8], - "2^-3": [2, -3, 0.125e0], - "-2^-3": [-2, -3, -0.125e0], - "2^0": [2, 0, 1], - "0^0": [0, 0, 1], - "0^4": [0, 4, 0], - "0^-4": [0, -4, RDF::Literal::Double.new('INF')], - "16^0.5e0": [16, 0.5e0, 4.0e0], - "16^0.25e0": [16, 0.25e0, 2.0e0], - "-1^INF": [-1, RDF::Literal::Double.new('INF'), 1.0e0], - "-1^-INF": [-1, RDF::Literal::Double.new('-INF'), 1.0e0], - "1^INF": [1, RDF::Literal::Double.new('INF'), 1.0e0], - "1^-INF": [1, RDF::Literal::Double.new('-INF'), 1.0e0], - "1^-NaN": [1, RDF::Literal::Double.new('NaN'), 1.0e0], + "2^3": [2, 3, 8], + "-2^3": [-2, 3, -8], + "2^-3": [2, -3, 0.125e0], + "-2^-3": [-2, -3, -0.125e0], + "2^0": [2, 0, 1], + "0^0": [0, 0, 1], + "0^4": [0, 4, 0], + "0^-4": [0, -4, RDF::Literal::Double.new('INF')], + "16^0.5e0": [16, 0.5e0, 4.0e0], + "16^0.25e0": [16, 0.25e0, 2.0e0], + "-1^INF": [-1, RDF::Literal::Double.new('INF'), 1.0e0], + "-1^-INF": [-1, RDF::Literal::Double.new('-INF'), 1.0e0], + "1^INF": [1, RDF::Literal::Double.new('INF'), 1.0e0], + "1^-INF": [1, RDF::Literal::Double.new('-INF'), 1.0e0], + "1^-NaN": [1, RDF::Literal::Double.new('NaN'), 1.0e0], }.each do |name, (n, e, result)| it name do expect(RDF::Literal(n) ** RDF::Literal(e)).to eq RDF::Literal(result) @@ -754,17 +754,17 @@ def self.literals(*selector) describe "#**" do { - "INF^0": [described_class.new('INF'), 0, 1.0e0], - "NaN^0": [described_class.new('NaN'), 0, 1.0e0], - "0e0^3": [0e0, 3, 0.0e0], - "0e0^4": [0e0, 4, 0.0e0], - "-0e0^3": [-0e0, 3, -0.0e0], - "0e0^-3": [0e0, -3, described_class.new('INF')], - "0e0^-4": [0e0, -4, described_class.new('INF')], - "-0e0^-3": [-0e0, -3, described_class.new('-INF')], - "-0e0^-3.0e0": [-0e0, -3.0e0, described_class.new('-INF')], - "0e0^-3.1e0": [0e0, -3.1e0, described_class.new('INF')], - "-0e0^-3.1e0": [-0e0, -3.1e0, described_class.new('INF')], + "INF^0": [described_class.new('INF'), 0, 1.0e0], + "NaN^0": [described_class.new('NaN'), 0, 1.0e0], + "0e0^3": [0e0, 3, 0.0e0], + "0e0^4": [0e0, 4, 0.0e0], + "-0e0^3": [-0e0, 3, -0.0e0], + "0e0^-3": [0e0, -3, described_class.new('INF')], + "0e0^-4": [0e0, -4, described_class.new('INF')], + "-0e0^-3": [-0e0, -3, described_class.new('-INF')], + "-0e0^-3.0e0": [-0e0, -3.0e0, described_class.new('-INF')], + "0e0^-3.1e0": [0e0, -3.1e0, described_class.new('INF')], + "-0e0^-3.1e0": [-0e0, -3.1e0, described_class.new('INF')], }.each do |name, (n, e, result)| it name do expect(RDF::Literal(n) ** RDF::Literal(e)).to eq RDF::Literal(result) @@ -832,11 +832,11 @@ def self.literals(*selector) context "object values" do { - DateTime.parse("2010-01-01T00:00:00Z") => ["2010-01-01T00:00:00Z", "2010-01-01T00:00:00Z"], - DateTime.parse("2010-02-01T00:00:00") => ["2010-02-01T00:00:00Z", "2010-02-01T00:00:00Z"], - DateTime.parse("2010-03-01T04:00:00+01:00") => ["2010-03-01T04:00:00+01:00", "2010-03-01T03:00:00Z"], - DateTime.parse("2009-12-31T04:00:00-01:00") => ["2009-12-31T04:00:00-01:00", "2009-12-31T05:00:00Z"], - DateTime.parse("-2010-01-01T00:00:00Z") => ["-2010-01-01T00:00:00Z","-2010-01-01T00:00:00Z"], + DateTime.parse("2010-01-01T00:00:00Z") => ["2010-01-01T00:00:00Z", "2010-01-01T00:00:00Z"], + DateTime.parse("2010-02-01T00:00:00") => ["2010-02-01T00:00:00Z", "2010-02-01T00:00:00Z"], + DateTime.parse("2010-03-01T04:00:00+01:00") => ["2010-03-01T04:00:00+01:00", "2010-03-01T03:00:00Z"], + DateTime.parse("2009-12-31T04:00:00-01:00") => ["2009-12-31T04:00:00-01:00", "2009-12-31T05:00:00Z"], + DateTime.parse("-2010-01-01T00:00:00Z") => ["-2010-01-01T00:00:00Z", "-2010-01-01T00:00:00Z"], }.each do |obj, (str, canon)| it "to_str #{obj} to #{str.inspect}" do expect(described_class.new(obj).to_s).to eql str @@ -863,10 +863,10 @@ def self.literals(*selector) describe "#timezone" do { - "2010-06-21T11:28:01Z" => RDF::Literal("PT0S", datatype: RDF::XSD.dayTimeDuration), + "2010-06-21T11:28:01Z" => RDF::Literal("PT0H", datatype: RDF::XSD.dayTimeDuration), "2010-12-21T15:38:02-08:00" => RDF::Literal("-PT8H", datatype: RDF::XSD.dayTimeDuration), "2010-12-21T15:38:02+08:00" => RDF::Literal("PT8H", datatype: RDF::XSD.dayTimeDuration), - "2008-06-20T23:59:00Z" => RDF::Literal("PT0S", datatype: RDF::XSD.dayTimeDuration), + "2008-06-20T23:59:00Z" => RDF::Literal("PT0H", datatype: RDF::XSD.dayTimeDuration), "2011-02-01T01:02:03" => nil, }.each do |l, r| it "#{l} => #{r.inspect}" do @@ -878,14 +878,14 @@ def self.literals(*selector) describe "#adjust_to_timezone" do { # Spec examples - ["2002-03-07T10:00:00"] => "2002-03-07T10:00:00Z", - ["2002-03-07T10:00:00-07:00"] => "2002-03-07T17:00:00Z", - ["2002-03-07T10:00:00", "-PT10H"] => "2002-03-07T10:00:00-10:00", - ["2002-03-07T10:00:00-07:00", "-PT10H"] => "2002-03-07T07:00:00-10:00", - ["2002-03-07T10:00:00-07:00", "PT10H"] => "2002-03-08T03:00:00+10:00", - ["2002-03-07T00:00:00+01:00", "-PT8H"] => "2002-03-06T15:00:00-08:00", - ["2002-03-07T10:00:00", nil] => "2002-03-07T10:00:00", - ["2002-03-07T10:00:00-07:00", nil] => "2002-03-07T10:00:00", + ["2002-03-07T10:00:00"] => "2002-03-07T10:00:00Z", + ["2002-03-07T10:00:00-07:00"] => "2002-03-07T17:00:00Z", + ["2002-03-07T10:00:00", "-PT10H"] => "2002-03-07T10:00:00-10:00", + ["2002-03-07T10:00:00-07:00", "-PT10H"] => "2002-03-07T07:00:00-10:00", + ["2002-03-07T10:00:00-07:00", "PT10H"] => "2002-03-08T03:00:00+10:00", + ["2002-03-07T00:00:00+01:00", "-PT8H"] => "2002-03-06T15:00:00-08:00", + ["2002-03-07T10:00:00", nil] => "2002-03-07T10:00:00", + ["2002-03-07T10:00:00-07:00", nil] => "2002-03-07T10:00:00", }.each do |args, r| if r == ArgumentError it "#{args.inspect} raises ArgumentError" do @@ -902,22 +902,22 @@ def self.literals(*selector) end { - # Test Suite https://github.com/w3c/qt3tests/blob/master/fn/adjust-date-to-timezone.xml - "fn-adjust-dateTime-to-timezone1args-1": ["1970-01-01T00:00:00Z", "-PT10H", "1969-12-31T14:00:00-10:00"], - "fn-adjust-dateTime-to-timezone1args-2": ["1996-04-07T01:40:52Z", "-PT10H", "1996-04-06T15:40:52-10:00"], - "fn-adjust-dateTime-to-timezone1args-3": ["2030-12-31T23:59:59Z", "-PT10H", "2030-12-31T13:59:59-10:00"], - "fn-adjust-dateTime-to-timezone-1": ["2002-03-07T10:00:00-05:00", "-PT5H0M", "2002-03-07T10:00:00-05:00"], - "fn-adjust-dateTime-to-timezone-2": ["2002-03-07T10:00:00-07:00", "-PT5H0M", "2002-03-07T12:00:00-05:00"], - "fn-adjust-dateTime-to-timezone-3": ["2002-03-07T10:00:00", "-PT10H", "2002-03-07T10:00:00-10:00"], - "fn-adjust-dateTime-to-timezone-4": ["2002-03-07T10:00:00-07:00", "-PT10H", "2002-03-07T07:00:00-10:00"], - "fn-adjust-dateTime-to-timezone-5": ["2002-03-07T10:00:00-07:00", "PT10H", "2002-03-08T03:00:00+10:00"], - "fn-adjust-dateTime-to-timezone-6": ["2002-03-07T00:00:00+01:00", "-PT8H", "2002-03-06T15:00:00-08:00"], - "fn-adjust-dateTime-to-timezone-7": ["2002-03-07T10:00:00", "2002-03-07T10:00:00"], - "fn-adjust-dateTime-to-timezone-8": ["2002-03-07T10:00:00-07:00", nil, "2002-03-07T10:00:00"], - "fn-adjust-dateTime-to-timezone-11": ["2002-03-07T10:00:00-04:00", nil, "2002-03-07T10:00:00"], - "K-AdjDateTimeToTimezoneFunc-7": ["2001-02-03T08:02:00", "PT14H1M", ArgumentError], - "K-AdjDateTimeToTimezoneFunc-7": ["2001-02-03T08:02:00", "-PT14H1M", ArgumentError], - "K-AdjDateTimeToTimezoneFunc-8": ["2001-02-03T08:02:00", "PT14H0M0.001S", ArgumentError], + # Test Suite https://github.com/w3c/qt3tests/blob/master/fn/adjust-dateTime-to-timezone.xml + "fn-adjust-dateTime-to-timezone1args-1": ["1970-01-01T00:00:00Z", "-PT10H", "1969-12-31T14:00:00-10:00"], + "fn-adjust-dateTime-to-timezone1args-2": ["1996-04-07T01:40:52Z", "-PT10H", "1996-04-06T15:40:52-10:00"], + "fn-adjust-dateTime-to-timezone1args-3": ["2030-12-31T23:59:59Z", "-PT10H", "2030-12-31T13:59:59-10:00"], + "fn-adjust-dateTime-to-timezone-1": ["2002-03-07T10:00:00-05:00", "-PT5H0M", "2002-03-07T10:00:00-05:00"], + "fn-adjust-dateTime-to-timezone-2": ["2002-03-07T10:00:00-07:00", "-PT5H0M", "2002-03-07T12:00:00-05:00"], + "fn-adjust-dateTime-to-timezone-3": ["2002-03-07T10:00:00", "-PT10H", "2002-03-07T10:00:00-10:00"], + "fn-adjust-dateTime-to-timezone-4": ["2002-03-07T10:00:00-07:00", "-PT10H", "2002-03-07T07:00:00-10:00"], + "fn-adjust-dateTime-to-timezone-5": ["2002-03-07T10:00:00-07:00", "PT10H", "2002-03-08T03:00:00+10:00"], + "fn-adjust-dateTime-to-timezone-6": ["2002-03-07T00:00:00+01:00", "-PT8H", "2002-03-06T15:00:00-08:00"], + "fn-adjust-dateTime-to-timezone-7": ["2002-03-07T10:00:00", "2002-03-07T10:00:00"], + "fn-adjust-dateTime-to-timezone-8": ["2002-03-07T10:00:00-07:00", nil, "2002-03-07T10:00:00"], + "fn-adjust-dateTime-to-timezone-11": ["2002-03-07T10:00:00-04:00", nil, "2002-03-07T10:00:00"], + "K-AdjDateTimeToTimezoneFunc-7": ["2001-02-03T08:02:00", "PT14H1M", ArgumentError], + "K-AdjDateTimeToTimezoneFunc-8": ["2001-02-03T08:02:00", "-PT14H1M", ArgumentError], + "K-AdjDateTimeToTimezoneFunc-9": ["2001-02-03T08:02:00", "PT14H0M0.001S", ArgumentError], }.each do |title, (*args, r)| it title do source = described_class.new(args.shift) @@ -934,12 +934,12 @@ def self.literals(*selector) describe "#==" do { ["2002-04-02T12:00:00-01:00", "2002-04-02T17:00:00+04:00"] => true, - ["2002-04-02T12:00:00", "2002-04-02T23:00:00+06:00"] => false, - ["2002-04-02T12:00:00", "2002-04-02T17:00:00"] => false, - ["2002-04-02T12:00:00", "2002-04-02T12:00:00"] => true, + ["2002-04-02T12:00:00", "2002-04-02T23:00:00+06:00"] => false, + ["2002-04-02T12:00:00", "2002-04-02T17:00:00"] => false, + ["2002-04-02T12:00:00", "2002-04-02T12:00:00"] => true, ["2002-04-02T23:00:00-04:00", "2002-04-03T02:00:00-01:00"] => true, - ["1999-12-31T24:00:00", "2000-01-01T00:00:00"] => true, - ["2005-04-04T24:00:00", "2005-04-04T00:00:00"] => false, + ["1999-12-31T24:00:00", "2000-01-01T00:00:00"] => true, + ["2005-04-04T24:00:00", "2005-04-04T00:00:00"] => false, }.each do |(a, b), res| if res it "#{a} == #{b}" do @@ -1032,8 +1032,8 @@ def self.literals(*selector) context "object values" do { - ::Date.parse("2010-02-01") => ["2010-02-01", "2010-02-01"], - ::Date.parse("-2010-01-01") => ["-2010-01-01","-2010-01-01"], + ::Date.parse("2010-02-01") => ["2010-02-01", "2010-02-01"], + ::Date.parse("-2010-01-01") => ["-2010-01-01","-2010-01-01"], ::DateTime.parse("2014-09-01T00:00:00-08:00") => ["2014-09-01-08:00", "2014-09-01Z"], }.each do |obj, (str, canon)| it "to_str #{obj} to #{str.inspect}" do @@ -1076,11 +1076,11 @@ def self.literals(*selector) describe "#adjust_to_timezone" do { # Spec examples - ["2002-03-07"] => "2002-03-07Z", - ["2002-03-07-07:00"] => "2002-03-07Z", - ["2002-03-07", "-PT10H"] => "2002-03-07-10:00", + ["2002-03-07"] => "2002-03-07Z", + ["2002-03-07-07:00"] => "2002-03-07Z", + ["2002-03-07", "-PT10H"] => "2002-03-07-10:00", ["2002-03-07-07:00", "-PT10H"] => "2002-03-06-10:00", - ["2002-03-07", nil] => "2002-03-07", + ["2002-03-07", nil] => "2002-03-07", ["2002-03-07-07:00", nil] => "2002-03-07", }.each do |args, r| if r == ArgumentError @@ -1102,15 +1102,15 @@ def self.literals(*selector) "fn-adjust-date-to-timezone1args-1": ["1970-01-01Z", "-PT10H", "1969-12-31-10:00"], "fn-adjust-date-to-timezone1args-2": ["1983-11-17Z", "-PT10H", "1983-11-16-10:00"], "fn-adjust-date-to-timezone1args-3": ["2030-12-31Z", "-PT10H", "2030-12-30-10:00"], - "fn-adjust-date-to-timezone-1": ["2002-03-07-05:00", "-PT5H0M", "2002-03-07-05:00"], - "fn-adjust-date-to-timezone-2": ["2002-03-07-07:00", "-PT5H0M", "2002-03-07-05:00"], - "fn-adjust-date-to-timezone-3": ["2002-03-07", "-PT10H", "2002-03-07-10:00"], - "fn-adjust-date-to-timezone-4": ["2002-03-07-07:00", "-PT10H", "2002-03-06-10:00"], - "fn-adjust-date-to-timezone-5": ["2002-03-07", nil, "2002-03-07"], - "fn-adjust-date-to-timezone-6": ["2002-03-07-07:00", nil, "2002-03-07"], - "K-AdjDateToTimezoneFunc-6": ["2001-02-03", "PT14H1M", ArgumentError], - "K-AdjDateToTimezoneFunc-7": ["2001-02-03", "-PT14H1M", ArgumentError], - "K-AdjDateToTimezoneFunc-8": ["2001-02-03", "PT14H0M0.001S", ArgumentError], + "fn-adjust-date-to-timezone-1": ["2002-03-07-05:00", "-PT5H0M", "2002-03-07-05:00"], + "fn-adjust-date-to-timezone-2": ["2002-03-07-07:00", "-PT5H0M", "2002-03-07-05:00"], + "fn-adjust-date-to-timezone-3": ["2002-03-07", "-PT10H", "2002-03-07-10:00"], + "fn-adjust-date-to-timezone-4": ["2002-03-07-07:00", "-PT10H", "2002-03-06-10:00"], + "fn-adjust-date-to-timezone-5": ["2002-03-07", nil, "2002-03-07"], + "fn-adjust-date-to-timezone-6": ["2002-03-07-07:00", nil, "2002-03-07"], + "K-AdjDateToTimezoneFunc-6": ["2001-02-03", "PT14H1M", ArgumentError], + "K-AdjDateToTimezoneFunc-7": ["2001-02-03", "-PT14H1M", ArgumentError], + "K-AdjDateToTimezoneFunc-8": ["2001-02-03", "PT14H0M0.001S", ArgumentError], }.each do |title, (*args, r)| it title do source = described_class.new(args.shift) @@ -1147,9 +1147,9 @@ def self.literals(*selector) describe "#<" do { - ["2010-06-21Z", "2010-06-20Z"] => false, - ["2010-06-21Z", "2010-06-21Z"] => false, - ["2010-06-21Z", "2010-06-22Z"] => true, + ["2010-06-21Z", "2010-06-20Z"] => false, + ["2010-06-21Z", "2010-06-21Z"] => false, + ["2010-06-21Z", "2010-06-22Z"] => true, ["2010-06-21Z", "2010-06-21-08:00"] => true, ["2010-06-21Z", "2010-06-21+08:00"] => false, }.each do |(a, b), res| @@ -1169,9 +1169,9 @@ def self.literals(*selector) describe "#>" do { - ["2010-06-21Z", "2010-06-20Z"] => true, - ["2010-06-21Z", "2010-06-21Z"] => false, - ["2010-06-21Z", "2010-06-22Z"] => false, + ["2010-06-21Z", "2010-06-20Z"] => true, + ["2010-06-21Z", "2010-06-21Z"] => false, + ["2010-06-21Z", "2010-06-22Z"] => false, ["2010-06-21Z", "2010-06-21-08:00"] => false, ["2010-06-21Z", "2010-06-21+08:00"] => true, }.each do |(a, b), res| @@ -1192,7 +1192,7 @@ def self.literals(*selector) describe RDF::Literal::Time do it_behaves_like 'RDF::Literal with datatype and grammar', "00:00:00Z", RDF::XSD.time - it_behaves_like 'RDF::Literal equality', "00:00:00Z", DateTime.parse("00:00:00Z") + it_behaves_like 'RDF::Literal equality', "00:00:00Z", DateTime.parse("1972-12-31T00:00:00Z") it_behaves_like 'RDF::Literal lexical values', "00:00:00Z" it_behaves_like 'RDF::Literal canonicalization', RDF::XSD.time, [ ["00:00:00Z", "00:00:00Z", "12:00:00 AM UTC"], @@ -1226,12 +1226,12 @@ def self.literals(*selector) context "object values" do { - DateTime.parse("00:00:00Z") => ["00:00:00Z", "00:00:00Z"], - DateTime.parse("01:00:00.0000Z") => ["01:00:00Z","01:00:00Z"], - DateTime.parse("02:00:00") => ["02:00:00Z", "02:00:00Z"], - DateTime.parse("03:00:00+00:00") => ["03:00:00Z", "03:00:00Z"], - DateTime.parse("05:00:00+01:00") => ["05:00:00+01:00", "04:00:00Z"], - DateTime.parse("07:00:00-01:00") => ["07:00:00-01:00", "08:00:00Z"], + DateTime.parse("00:00:00Z") => ["00:00:00Z", "00:00:00Z"], + DateTime.parse("01:00:00.0000Z") => ["01:00:00Z", "01:00:00Z"], + DateTime.parse("02:00:00") => ["02:00:00Z", "02:00:00Z"], + DateTime.parse("03:00:00+00:00") => ["03:00:00Z", "03:00:00Z"], + DateTime.parse("05:00:00+01:00") => ["05:00:00+01:00", "04:00:00Z"], + DateTime.parse("07:00:00-01:00") => ["07:00:00-01:00", "08:00:00Z"], }.each do |obj, (str, canon)| it "to_str #{obj} to #{str.inspect}" do expect(described_class.new(obj).to_s).to eql str @@ -1243,14 +1243,6 @@ def self.literals(*selector) end end - subject {double("time", to_s: "05:50:00")} - - it "parses as string if #to_datetime raises an error" do - expect(subject).to receive(:to_datetime).at_least(:once).and_raise(StandardError) - expect {described_class.new(subject)}.not_to raise_error - expect(described_class.new(subject).object).to eq ::DateTime.parse(subject.to_s) - end - describe "#tz" do { "11:28:01Z" => "Z", @@ -1263,6 +1255,140 @@ def self.literals(*selector) end end end + + describe "#timezone" do + { + "11:28:01Z" => RDF::Literal("PT0H", datatype: RDF::XSD.dayTimeDuration), + "15:38:02-08:00" => RDF::Literal("-PT8H", datatype: RDF::XSD.dayTimeDuration), + "23:59:00Z" => RDF::Literal("PT0H", datatype: RDF::XSD.dayTimeDuration), + "01:02:03" => nil, + }.each do |l, r| + it "#{l} => #{r.inspect}" do + expect(described_class.new(l).timezone).to eq r + end + end + end + + describe "#adjust_to_timezone" do + { + # Spec examples + ["01:02:03"] => "01:02:03Z", + ["01:02:03-07:00"] => "08:02:03Z", + ["01:02:03", "-PT10H"] => "01:02:03-10:00", + ["01:02:03-07:00", "-PT10H"] => "22:02:03-10:00", + ["01:02:03", nil] => "01:02:03", + ["01:02:03-07:00", nil] => "01:02:03", + }.each do |args, r| + if r == ArgumentError + it "#{args.inspect} raises ArgumentError" do + source = described_class.new(args.shift) + expect {source.adjust_to_timezone(*args)}.to raise_error(ArgumentError) + end + else + it "#{args.inspect} => #{r.inspect}" do + source = described_class.new(args.shift) + result = described_class.new(r) + expect(source.adjust_to_timezone(*args)).to eq result + end + end + end + + { + # Test Suite https://github.com/w3c/qt3tests/blob/master/fn/adjust-time-to-timezone.xml + "fn-adjust-time-to-timezone1args-1": ["00:00:00Z", "-PT10H", "14:00:00-10:00"], + "fn-adjust-time-to-timezone1args-2": ["08:03:35Z", "-PT10H", "22:03:35-10:00"], + "fn-adjust-time-to-timezone1args-3": ["23:59:59Z", "-PT10H", "13:59:59-10:00"], + "fn-adjust-time-to-timezone-1": ["10:00:00-05:00", "-PT5H0M", "10:00:00-05:00"], + "fn-adjust-time-to-timezone-2": ["10:00:00-07:00", "-PT5H0M", "12:00:00-05:00"], + "fn-adjust-time-to-timezone-3": ["10:00:00", "-PT10H", "10:00:00-10:00"], + "fn-adjust-time-to-timezone-4": ["10:00:00-07:00", "-PT10H", "07:00:00-10:00"], + "fn-adjust-time-to-timezone-5": ["10:00:00-05:00", nil, "10:00:00"], + "fn-adjust-time-to-timezone-6": ["10:00:00-07:00", nil, "10:00:00"], + "fn-adjust-time-to-timezone-7": ["10:00:00-07:00", "PT10H", "03:00:00+10:00"], + "K-AdjTimeToTimezoneFunc-6": ["08:02:00", "PT14H1M", ArgumentError], + "K-AdjTimeToTimezoneFunc-7": ["08:02:00", "-PT14H1M", ArgumentError], + "K-AdjTimeToTimezoneFunc-8": ["08:02:00", "PT14H0M0.001S", ArgumentError], + }.each do |title, (*args, r)| + it title do + source = described_class.new(args.shift) + if r == ArgumentError + expect {source.adjust_to_timezone(*args)}.to raise_error(ArgumentError) + else + result = described_class.new(r) + expect(source.adjust_to_timezone(*args)).to eq result + end + end + end + end + + describe "#==" do + { + ["01:02:03Z", "01:02:03+07:00"] => false, + ["01:02:03-12:00", "01:02:03-12:00"] => true, + ["01:02:03Z", RDF::Literal::DateTime.new("2004-12-26T01:02:03Z")] => false, + ["01:02:03Z", RDF::Literal::Date.new("2004-12-26")] => false, + ["08:00:00+09:00", "17:00:00-06:00"] => false, + ["21:30:00+10:30", "06:00:00-05:00"] => true, + ["24:00:00+01:00", "00:00:00+01:00"] => true, + }.each do |(a, b), res| + if res + it "#{a} == #{b}" do + res = b.is_a?(String) ? described_class.new(b) : b + expect(described_class.new(a)).to eq res + end + else + it "#{a} != #{b}" do + res = b.is_a?(String) ? described_class.new(b) : b + expect(described_class.new(a)).not_to eq res + end + end + end + end + + describe "#<" do + { + ["11:28:01Z", "11:28:01Z"] => false, + ["11:28:01Z", "11:28:02Z"] => true, + ["11:28:01Z", "11:28:00Z"] => false, + ["02:28:00Z", "11:28:00-08:00"] => true, + ["12:00:00-05:00", "23:00:00+06:00"] => false, + ["11:00:00-05:00", "17:00:00Z"] => true, + ["23:59:59-05:00", "24:00:00-05:00"] => false, + }.each do |(a, b), res| + if res + it "#{a} < #{b}" do + expect(described_class.new(a)).to be < described_class.new(b) + expect(described_class.new(a)).not_to be >= described_class.new(b) + end + else + it "#{a} !< #{b}" do + expect(described_class.new(a)).not_to be < described_class.new(b) + expect(described_class.new(a)).to be >= described_class.new(b) + end + end + end + end + + describe "#>" do + { + ["11:28:01Z", "11:28:01Z"] => false, + ["11:28:01Z", "11:28:02Z"] => false, + ["11:28:01Z", "11:28:00Z"] => true, + ["08:00:00+09:00", "17:00:00-06:00"] => false, + }.each do |(a, b), res| + if res + it "#{a} > #{b}" do + expect(described_class.new(a)).to be > described_class.new(b) + expect(described_class.new(a)).not_to be <= described_class.new(b) + end + else + it "#{a} !> #{b}" do + expect(described_class.new(a)).not_to be > described_class.new(b) + expect(described_class.new(a)).to be <= described_class.new(b) + end + end + end + end end describe RDF::Literal::Numeric do From c9a7677d9229edc7784fc6656905f6528a9cb720 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Tue, 22 Feb 2022 12:38:12 -0800 Subject: [PATCH 5/8] Add and subtract temporals with each other and durations, per XPath/XQuery functions spec. --- lib/rdf/model/literal/temporal.rb | 69 +++++++++- spec/model_literal_spec.rb | 216 +++++++++++++++++++++++++++++- 2 files changed, 283 insertions(+), 2 deletions(-) diff --git a/lib/rdf/model/literal/temporal.rb b/lib/rdf/model/literal/temporal.rb index 89d83fe8..dbca6661 100644 --- a/lib/rdf/model/literal/temporal.rb +++ b/lib/rdf/model/literal/temporal.rb @@ -146,7 +146,7 @@ def to_s # # Otherwise, the timezone is set based on the difference between the current timezone offset (if any) and `zone`. # - # @param [String] zone (nil) In the form of {ZONE_FORMAT} + # @param [String] zone (nil) In the form of {ZONE_GRAMMAR}. # @return [Temporal] `self` # @raise [RangeError] if `zone < -14*60` or `zone > 14*60` # @see https://www.w3.org/TR/xpath-functions/#func-adjust-dateTime-to-timezone @@ -192,6 +192,73 @@ def adjust_to_timezone(*args) self.dup.adjust_to_timezone!(*args) end + ## + # Add a Duration to a Temporal. + # + # For YearMonthDuration, turns duration into months and adds to internal DateTime object. + # + # For DayTimeDuration, turns duration into rational days, and adds to internal DateTime object. + # + # @note This depends on the parameter responding to `#to_i` or `#to_r`, which for Duration types, is implemented in the rdf-xsd gem. + # + # @param [YearMonthDuration, DayTimeDuration] other + # @return [Temporal] + # @see https://www.w3.org/TR/xpath-functions/#func-add-yearMonthDuration-to-dateTime + # @see https://www.w3.org/TR/xpath-functions/#func-add-dayTimeDuration-to-dateTime + def +(other) + new_dt = case other + when YearMonthDuration + @object >> other.to_i + when DayTimeDuration + @object + other.to_r + else + return super + end + + dt = new_dt.strftime(self.class.const_get(:FORMAT)) + tz + self.class.new(dt) + rescue NoMethodError => e + raise "Consider including the rdf-xsd class for method implementaions: #{e.message}" + end + + ## + # Subtract times or durations from a temporal. + # + # @overload +(other) + # For YearMonthDuration, turns duration into months and subtracts from internal DateTime object resulting in a new {Temporal} object. + # + # For DayTimeDuration, turns duration into rational days, and subtracts from internal DateTime object resulting in a new {Temporal} object. + # + # For Temporal, subtracts the two moments resulting in a `xsd:dayTimeDuration`. + # + # @param [YearMonthDuration, DayTimeDurationm, Temporal] other + # @return [Temporal, DayTimeDuration] + # @note This depends on the parameter responding to `#to_i` or `#to_r`, which for Duration types, is implemented in the rdf-xsd gem. + # @see https://www.w3.org/TR/xpath-functions/#func-subtract-yearMonthDuration-from-dateTime + # @see https://www.w3.org/TR/xpath-functions/#func-subtract-dayTimeDuration-from-dateTime + # @see https://www.w3.org/TR/xpath-functions/#func-subtract-dateTimes + def -(other) + new_dt = case other + when YearMonthDuration + @object << other.to_i + when DayTimeDuration + @object - other.to_r + when Temporal + @object - other.object + else + return super + end + + if new_dt.is_a?(Rational) + RDF::Literal(new_dt, datatype: RDF::XSD.dayTimeDuration) + else + dt = new_dt.strftime(self.class.const_get(:FORMAT)) + tz + self.class.new(dt) + end + rescue NoMethodError => e + raise "Consider including the rdf-xsd class for method implementaions: #{e.message}" + end + # Years # # From the XQuery function [fn:year-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-year-from-dateTime). diff --git a/spec/model_literal_spec.rb b/spec/model_literal_spec.rb index cbbd8233..626ecc1b 100644 --- a/spec/model_literal_spec.rb +++ b/spec/model_literal_spec.rb @@ -994,8 +994,88 @@ def self.literals(*selector) end end end - end + describe "#+" do + context "xsd:dayTimeDuration" do + { + ["2000-10-30T11:12:00", "P3DT1H15M"] => "2000-11-02T12:27:00", + ["2000-10-30T11:12:00Z", "P3DT1H15M"] => "2000-11-02T12:27:00Z", + ["2000-10-30T11:12:00-08:00", "P3DT1H15M"] => "2000-11-02T12:27:00-08:00", + ["2000-10-30T11:12:00", "-P3D"] => "2000-10-27T11:12:00", + }.each do |(t, d), res| + it "#{t} + #{d} == #{res}" do + t1 = described_class.new(t) + dur = RDF::Literal(d, datatype: RDF::XSD.dayTimeDuration) + expect(t1 + dur).to eq described_class.new(res) + end + end + end + + context "xsd:yearMonthDuration" do + { + ["2000-10-30T11:12:00", "P1Y2M"] => "2001-12-30T11:12:00", + ["2000-10-30T11:12:00Z", "P1Y2M"] => "2001-12-30T11:12:00Z", + ["2000-10-30T11:12:00-08:00", "P1Y2M"] => "2001-12-30T11:12:00-08:00", + ["2000-10-30T11:12:00", "-P1Y2M"] => "1999-08-30T11:12:00", + }.each do |(t, d), res| + it "#{t} + #{d} == #{res}" do + t1 = described_class.new(t) + dur = RDF::Literal(d, datatype: RDF::XSD.yearMonthDuration) + expect(t1 + dur).to eq described_class.new(res) + end + end + end + end + + describe "#-" do + context "xsd:dayTimeDuration" do + { + ["2000-10-30T11:12:00", "P3DT1H15M"] => "2000-10-27T09:57:00", + ["2000-10-30T11:12:00Z", "P3DT1H15M"] => "2000-10-27T09:57:00Z", + ["2000-10-30T11:12:00-08:00", "P3DT1H15M"] => "2000-10-27T09:57:00-08:00", + ["2000-10-30T11:12:00", "-P3D"] => "2000-11-02T11:12:00", + }.each do |(t, d), res| + it "#{t} - #{d} == #{res}" do + t1 = described_class.new(t) + dur = RDF::Literal(d, datatype: RDF::XSD.dayTimeDuration) + expect(t1 - dur).to eq described_class.new(res) + end + end + end + + context "xsd:yearMonthDuration" do + { + ["2000-10-30T11:12:00", "P1Y2M"] => "1999-08-30T11:12:00", + ["2000-10-30T11:12:00Z", "P1Y2M"] => "1999-08-30T11:12:00Z", + ["2000-10-30T11:12:00-08:00", "P1Y2M"] => "1999-08-30T11:12:00-08:00", + ["2000-10-30T11:12:00", "-P1Y2M"] => "2001-12-30T11:12:00", + }.each do |(t, d), res| + it "#{t} - #{d} == #{res}" do + t1 = described_class.new(t) + dur = RDF::Literal(d, datatype: RDF::XSD.yearMonthDuration) + expect(t1 - dur).to eq described_class.new(res) + end + end + end + + context "xsd:dateTime" do + { + ["2000-10-30T11:12:00", "2000-08-30T11:12:00"] => "P61D", + ["2000-10-30T11:12:00Z", "2000-08-30T11:12:00Z"] => "P61D", + ["2000-10-30T11:12:00-08:00", "2000-08-30T11:12:00-08:00"] => "P61D", + ["2000-10-30T11:12:00", "2000-12-30T11:12:00"] => "-P61D", + ["2000-10-30T06:12:00-05:00", "1999-11-28T09:00:00Z"] => "P337DT2H12M", + }.each do |(t1, t2), res| + it "#{t1} - #{t2} == #{res}" do + t1 = described_class.new(t1) + t2 = described_class.new(t2) + res = RDF::Literal(res, datatype: RDF::XSD.dayTimeDuration) + expect(t1 - t2).to eq res + end + end + end + end + end describe RDF::Literal::Date do it_behaves_like 'RDF::Literal with datatype and grammar', "2010-01-01T00:00:00Z", RDF::XSD.date @@ -1188,6 +1268,87 @@ def self.literals(*selector) end end end + + describe "#+" do + context "xsd:dayTimeDuration" do + { + ["2000-10-30", "P3DT1H15M"] => "2000-11-02", + ["2000-10-30Z", "P3DT1H15M"] => "2000-11-02Z", + ["2000-10-30-08:00", "P3DT1H15M"] => "2000-11-02-08:00", + ["2000-10-30", "-P3D"] => "2000-10-27", + ["2004-10-30Z", "P2DT2H30M0S"] => "2004-11-01Z", + }.each do |(t, d), res| + it "#{t} + #{d} == #{res}" do + t1 = described_class.new(t) + dur = RDF::Literal(d, datatype: RDF::XSD.dayTimeDuration) + expect(t1 + dur).to eq described_class.new(res) + end + end + end + + context "xsd:yearMonthDuration" do + { + ["2000-10-30", "P1Y2M"] => "2001-12-30", + ["2000-10-30Z", "P1Y2M"] => "2001-12-30Z", + ["2000-10-30-08:00", "P1Y2M"] => "2001-12-30-08:00", + ["2000-10-30", "-P1Y2M"] => "1999-08-30", + }.each do |(t, d), res| + it "#{t} + #{d} == #{res}" do + t1 = described_class.new(t) + dur = RDF::Literal(d, datatype: RDF::XSD.yearMonthDuration) + expect(t1 + dur).to eq described_class.new(res) + end + end + end + + describe "#-" do + context "xsd:dayTimeDuration" do + { + ["2000-10-30", "P3DT1H15M"] => "2000-10-26", + ["2000-10-30Z", "P3DT1H15M"] => "2000-10-26Z", + ["2000-10-30-08:00", "P3DT1H15M"] => "2000-10-26-08:00", + }.each do |(t, d), res| + it "#{t} - #{d} == #{res}" do + t1 = described_class.new(t) + dur = RDF::Literal(d, datatype: RDF::XSD.dayTimeDuration) + expect(t1 - dur).to eq described_class.new(res) + end + end + end + + context "xsd:yearMonthDuration" do + { + ["2000-10-30", "P1Y2M"] => "1999-08-30", + ["2000-02-29Z", "P1Y"] => "1999-02-28Z", + ["2000-10-31-05:00", "P1Y1M"] => "1999-09-30-05:00", + ["2000-10-30", "-P1Y2M"] => "2001-12-30", + }.each do |(t, d), res| + it "#{t} - #{d} == #{res}" do + t1 = described_class.new(t) + dur = RDF::Literal(d, datatype: RDF::XSD.yearMonthDuration) + expect(t1 - dur).to eq described_class.new(res) + end + end + end + + context "xsd:date" do + { + ["2000-10-30", "2000-08-30"] => "P61D", + ["2000-10-30Z", "2000-08-30Z"] => "P61D", + ["2000-10-30-08:00", "2000-08-30-08:00"] => "P61D", + ["2000-10-30", "2000-12-30"] => "-P61D", + ["2000-10-30-05:00", "1999-11-28Z"] => "P337DT5H", + }.each do |(t1, t2), res| + it "#{t1} - #{t2} == #{res}" do + t1 = described_class.new(t1) + t2 = described_class.new(t2) + res = RDF::Literal(res, datatype: RDF::XSD.dayTimeDuration) + expect(t1 - t2).to eq res + end + end + end + end + end end describe RDF::Literal::Time do @@ -1389,6 +1550,59 @@ def self.literals(*selector) end end end + + describe "#+" do + context "xsd:dayTimeDuration" do + { + ["11:12:00", "P3DT1H15M"] => "12:27:00", + ["11:12:00Z", "P3DT1H15M"] => "12:27:00Z", + ["11:12:00-08:00", "P3DT1H15M"] => "12:27:00-08:00", + ["11:12:00", "-P3D"] => "11:12:00", + }.each do |(t, d), res| + it "#{t} + #{d} == #{res}" do + t1 = described_class.new(t) + dur = RDF::Literal(d, datatype: RDF::XSD.dayTimeDuration) + expect(t1 + dur).to eq described_class.new(res) + end + end + end + end + + describe "#-" do + context "xsd:dayTimeDuration" do + { + ["11:12:00", "P3DT1H15M"] => "09:57:00", + ["11:12:00Z", "P3DT1H15M"] => "09:57:00Z", + ["11:12:00-08:00", "P3DT1H15M"] => "09:57:00-08:00", + ["11:12:00", "-PT3H"] => "14:12:00", + ["08:20:00-05:00", "P23DT10H10M"] => "22:10:00-05:00", + }.each do |(t, d), res| + it "#{t} - #{d} == #{res}" do + t1 = described_class.new(t) + dur = RDF::Literal(d, datatype: RDF::XSD.dayTimeDuration) + expect(t1 - dur).to eq described_class.new(res) + end + end + end + + context "xsd:time" do + { + ["11:12:00", "09:57:00"] => "PT1H15M", + ["11:12:00Z", "04:00:00-05:00"] => "PT2H12M", + ["11:00:00-05:00", "21:30:00+05:30"] => "PT0S", + ["17:00:00-06:00", "08:00:00+09:00"] => "P1D", + ["24:00:00", "23:59:59"] => "-PT23H59M59S", + ["11:12:00", "14:12:00"] => "-PT3H", + }.each do |(t1, t2), res| + it "#{t1} - #{t2} == #{res}" do + t1 = described_class.new(t1) + t2 = described_class.new(t2) + res = RDF::Literal(res, datatype: RDF::XSD.dayTimeDuration) + expect(t1 - t2).to eq res + end + end + end + end end describe RDF::Literal::Numeric do From 168a359bd334ba6ce193782d4b724f71a27f95be Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Tue, 22 Feb 2022 15:27:53 -0800 Subject: [PATCH 6/8] Add XPath math functions and constants to Literal::Numeric. `PI`, `#exp`, `#exp10`, `#log`, `#log10`, `#sqrt`, `#sin`, `#cos`, `#tan`, `#asin`, `#acos`, `#atan`, `#atan2`. --- lib/rdf/model/literal/double.rb | 8 + lib/rdf/model/literal/numeric.rb | 129 ++++++++++++ spec/model_literal_spec.rb | 324 ++++++++++++++++++++++++++++++- 3 files changed, 453 insertions(+), 8 deletions(-) diff --git a/lib/rdf/model/literal/double.rb b/lib/rdf/model/literal/double.rb index 376f1ec3..175ab0c2 100644 --- a/lib/rdf/model/literal/double.rb +++ b/lib/rdf/model/literal/double.rb @@ -34,6 +34,14 @@ def initialize(value, datatype: nil, lexical: nil, **options) end end + # Approximation of the mathematical constant π + # + # From the XQuery function [math:pi](https://www.w3.org/TR/xpath-functions/#func-math-pi). + # + # @return [Double] + # @see https://www.w3.org/TR/xpath-functions/#func-math-pi + PI = Double.new(Math::PI) + ## # Converts this literal into its canonical lexical representation. # diff --git a/lib/rdf/model/literal/numeric.rb b/lib/rdf/model/literal/numeric.rb index b237aa1b..6ca02517 100644 --- a/lib/rdf/model/literal/numeric.rb +++ b/lib/rdf/model/literal/numeric.rb @@ -241,6 +241,135 @@ def floor self end + ## + # Returns the value of `e``x`. + # + # @return [Double] + # @see https://www.w3.org/TR/xpath-functions/#func-math-exp + def exp + Double.new(Math.exp(self.to_f)) + end + + ## + # Returns the value of `10``x`. + # + # @return [Double] + # @see https://www.w3.org/TR/xpath-functions/#func-math-exp10 + def exp10 + Double.new(10**self.to_f) + end + + ## + # Returns the natural logarithm of the argument. + # + # @return [Double] + # @see https://www.w3.org/TR/xpath-functions/#func-math-log + def log + Double.new(Math.log(self.to_f)) + rescue Math::DomainError + Double.new(::Float::NAN) + end + + ## + # Returns the base-ten logarithm of the argument. + # + # @return [Double] + # @see https://www.w3.org/TR/xpath-functions/#func-math-log10 + def log10 + Double.new(Math.log10(self.to_f)) + rescue Math::DomainError + Double.new(::Float::NAN) + end + + ## + # Returns the non-negative square root of the argument. + # + # @return [Double] + # @see https://www.w3.org/TR/xpath-functions/#func-math-sqrt + def sqrt + Double.new(Math.sqrt(self.to_f)) + rescue Math::DomainError + Double.new(::Float::NAN) + end + + ## + # Returns the sine of the argument. The argument is an angle in radians. + # + # @return [Double] + # @see https://www.w3.org/TR/xpath-functions/#func-math-sin + def sin + Double.new(Math.sin(self.to_f)) + rescue Math::DomainError + Double.new(::Float::NAN) + end + + ## + # Returns the cosine of the argument. The argument is an angle in radians. + # + # @return [Double] + # @see https://www.w3.org/TR/xpath-functions/#func-math-cos + def cos + Double.new(Math.cos(self.to_f)) + rescue Math::DomainError + Double.new(::Float::NAN) + end + + ## + # Returns the tangent of the argument. The argument is an angle in radians. + # + # @return [Double] + # @see https://www.w3.org/TR/xpath-functions/#func-math-tan + def tan + Double.new(Math.tan(self.to_f)) + rescue Math::DomainError + Double.new(::Float::NAN) + end + + ## + # Returns the arc sine of the argument. + # + # @return [Double] + # @see https://www.w3.org/TR/xpath-functions/#func-math-asin + def asin + Double.new(Math.asin(self.to_f)) + rescue Math::DomainError + Double.new(::Float::NAN) + end + + ## + # Returns the arc cosine of the argument. + # + # @return [Double] + # @see https://www.w3.org/TR/xpath-functions/#func-math-acos + def acos + Double.new(Math.acos(self.to_f)) + rescue Math::DomainError + Double.new(::Float::NAN) + end + + ## + # Returns the arc tangent of the argument. + # + # @return [Double] + # @see https://www.w3.org/TR/xpath-functions/#func-math-atan + def atan + Double.new(Math.atan(self.to_f)) + rescue Math::DomainError + Double.new(::Float::NAN) + end + + ## + # Returns the angle in radians subtended at the origin by the point on a plane with coordinates (x, y) and the positive x-axis. + # + # @param [#to_f] arg + # @return [Double] + # @see https://www.w3.org/TR/xpath-functions/#func-math-atan2 + def atan2(arg) + Double.new(Math.atan2(self.to_f, arg.to_f)) + rescue Math::DomainError + Double.new(::Float::NAN) + end + ## # Returns the value as an integer. # diff --git a/spec/model_literal_spec.rb b/spec/model_literal_spec.rb index 626ecc1b..2aa3ce01 100644 --- a/spec/model_literal_spec.rb +++ b/spec/model_literal_spec.rb @@ -702,6 +702,10 @@ def self.literals(*selector) end end + describe RDF::Literal::Double::PI do + specify {expect(RDF::Literal::Double::PI.to_f).to eq Math::PI} + end + # Multiplication { -1 => described_class.new("-INF"), @@ -754,23 +758,61 @@ def self.literals(*selector) describe "#**" do { - "INF^0": [described_class.new('INF'), 0, 1.0e0], - "NaN^0": [described_class.new('NaN'), 0, 1.0e0], - "0e0^3": [0e0, 3, 0.0e0], - "0e0^4": [0e0, 4, 0.0e0], - "-0e0^3": [-0e0, 3, -0.0e0], - "0e0^-3": [0e0, -3, described_class.new('INF')], - "0e0^-4": [0e0, -4, described_class.new('INF')], "-0e0^-3": [-0e0, -3, described_class.new('-INF')], "-0e0^-3.0e0": [-0e0, -3.0e0, described_class.new('-INF')], - "0e0^-3.1e0": [0e0, -3.1e0, described_class.new('INF')], "-0e0^-3.1e0": [-0e0, -3.1e0, described_class.new('INF')], + "-0e0^3": [-0e0, 3, -0.0e0], + "-0e0^3.1e0": [-0e0, 3.1e0, 0.0e0], + "-1^-INF": [-1, described_class.new("-INF"), 1.0e0], + "-1^INF": [-1, described_class.new("INF"), 1.0e0], + "-2.5e0^2.0e0": [-2.5e0, 2.0e0, 6.25e0], + "-2^3": [-2, 3, -8], + "0e0^-3": [0e0, -3, described_class.new('INF')], + "0e0^-3.1e0": [0e0, -3.1e0, described_class.new('INF')], + "0e0^-4": [0e0, -4, described_class.new('INF')], + "0e0^3": [0e0, 3, 0.0e0], + "0e0^3.1e0": [0e0, 3.1e0, 0.0e0], + "0e0^4": [0e0, 4, 0.0e0], + "0^0": [0, 0, 1], + "0^4": [0, 4, 0], + "16^0.25e0": [16, 0.25e0, 2.0e0], + "16^0.5e0": [16, 0.5e0, 4.0e0], + "1^-INF": [1, described_class.new('-INF'), 1.0e0], + "1^INF": [1, described_class.new('INF'), 1.0e0], + "1^NaN": [1, described_class.new('NaN'), 1.0e0], + "2^-3": [2, -3, 0.125e0], + "2^0": [2, 0, 1], + "2^3": [2, 3, 8], + "INF^0": [described_class.new('INF'), 0, 1.0e0], + "NaN^0": [described_class.new('NaN'), 0, 1.0e0], + "PI^0": [described_class.const_get('PI'), 0, 1.0e0], }.each do |name, (n, e, result)| it name do expect(RDF::Literal(n) ** RDF::Literal(e)).to eq RDF::Literal(result) expect((RDF::Literal(n) ** RDF::Literal(e)).datatype).to eq RDF::Literal(result).datatype end end + + context '#infinite?' do + { + "0e0^-3": [0e0, -3], + "0e0^-4": [0e0, -4], + "-0e0^-3": [-0e0, -3], + "0e0^-3.0e0": [0e0, -3.0e0], + "-0e0^-3.0e0": [-0e0, -3.0e0], + "0^-4": [0, -4], + }.each do |name, (n, e)| + specify(name) {expect((RDF::Literal(n) ** RDF::Literal(e)).infinite?).to be_truthy} + end + end + + context '#nan?' do + { + #"-2.5e0^2.00000001e0": [-2.5e0, 2.00000001e0] + }.each do |name, (n, e)| + specify(name) {expect((RDF::Literal(n) ** RDF::Literal(e)).nan?).to be_truthy} + end + end end describe "#%" do @@ -1811,6 +1853,272 @@ def self.literals(*selector) end end end + + describe "#exp" do + { + 0 => 1.0e0, + 1 => 2.7182818284590455e0, + 2 => 7.38905609893065e0, + -1 => 0.36787944117144233e0, + Math::PI => 23.140692632779267e0, + -Float::INFINITY => 0, + }.each do |a, res| + it "#{a} => #{res}" do + expect(described_class.new(a).exp).to be_within(0.000001).of(described_class.new(res)) + end + end + + context '#nan?' do + [Float::NAN].each do |v| + specify("#{v}") {expect(described_class.new(v).exp.nan?).to be_truthy} + end + end + + context '#infinite?' do + [Float::INFINITY].each do |v| + specify("#{v}") {expect(described_class.new(v).exp.infinite?).to be_truthy} + end + end + end + + describe "#exp10" do + { + 0 => 1.0e0, + 1 => 1.0e1, + 0.5 => 3.1622776601683795e0, + -1 => 1.0e-1, + -Float::INFINITY => 0, + }.each do |a, res| + it "#{a} => #{res}" do + expect(described_class.new(a).exp10).to be_within(0.000001).of(described_class.new(res)) + end + end + + context '#nan?' do + [Float::NAN].each do |v| + specify("#{v}") {expect(described_class.new(v).exp10.nan?).to be_truthy} + end + end + + context '#infinite?' do + [Float::INFINITY].each do |v| + specify("#{v}") {expect(described_class.new(v).exp10.infinite?).to be_truthy} + end + end + end + + describe "#log" do + { + Math.exp(1) => 1.0e0, + 1.0e-3 => -6.907755278982137e0, + 2 => 0.6931471805599453e0, + }.each do |a, res| + it "#{a} => #{res}" do + expect(described_class.new(a).log).to be_within(0.000001).of(described_class.new(res)) + end + end + + context '#nan?' do + [-1, Float::NAN, -Float::INFINITY].each do |v| + specify("#{v}") {expect(described_class.new(v).log.nan?).to be_truthy} + end + end + + context '#infinite?' do + [0, Float::INFINITY].each do |v| + specify("#{v}") {expect(described_class.new(v).log.infinite?).to be_truthy} + end + end + end + + describe "#log10" do + { + 1.0e3 => 3, + 1.0e-3 => -3, + 2 => 0.3010299956639812e0, + }.each do |a, res| + it "#{a} => #{res}" do + expect(described_class.new(a).log10).to be_within(0.000001).of(described_class.new(res)) + end + end + + context '#nan?' do + [-1, Float::NAN, -Float::INFINITY].each do |v| + specify("#{v}") {expect(described_class.new(v).log10.nan?).to be_truthy} + end + end + + context '#infinite?' do + [0, Float::INFINITY].each do |v| + specify("#{v}") {expect(described_class.new(v).log10.infinite?).to be_truthy} + end + end + end + + describe "#sqrt" do + { + 0.0e0 => 0.0e0, + -0.0e0 => -0.0e0, + 1.0e6 => 1.0e3, + 2.0e0 => 1.4142135623730951e0, + }.each do |n, result| + it "#{n}" do + expect(RDF::Literal(n).sqrt).to be_within(0.000001).of(RDF::Literal(result)) + end + end + + context '#infinite?' do + [Float::INFINITY].each do |n| + specify("#{n}") {expect((RDF::Literal(n).sqrt).infinite?).to be_truthy} + end + end + + context '#nan?' do + [-2.0e0, -Float::INFINITY].each do |n| + specify("#{n}") {expect((RDF::Literal(n).sqrt).nan?).to be_truthy} + end + end + end + + describe "#sin" do + { + 0 => 0.0e0, + Math::PI/2 => 1.0e0, + -Math::PI/2 => -1.0e0, + Math::PI => 0.0e0, + }.each do |n, result| + it "#{n}" do + expect(RDF::Literal(n).sin).to be_within(0.000001).of(RDF::Literal(result)) + end + end + + context '#nan?' do + [Float::NAN, Float::INFINITY, -Float::INFINITY].each do |n| + specify("#{n}") {expect((RDF::Literal(n).sin).nan?).to be_truthy} + end + end + end + + describe "#cos" do + { + 0 => 1.0e0, + -0.0e0 => 1.0e0, + Math::PI/2 => 0.0e0, + -Math::PI/2 => 0.0e0, + Math::PI => -1.0e0, + }.each do |n, result| + it "#{n}" do + expect(RDF::Literal(n).cos).to be_within(0.000001).of(RDF::Literal(result)) + end + end + + context '#nan?' do + [Float::NAN, Float::INFINITY, -Float::INFINITY].each do |n| + specify("#{n}") {expect((RDF::Literal(n).cos).nan?).to be_truthy} + end + end + end + + describe "#tan" do + { + 0 => 0.0e0, + -0.0e0 => -0.0e0, + Math::PI/4 => 1.0e0, + -Math::PI/4 => -1.0e0, + #Math::PI/2 => 0.0e0, + #-Math::PI/2 => -0.0e0, + Math::PI => 0.0e0, + -Math::PI => -0.0e0, + }.each do |n, result| + it "#{n}" do + expect(RDF::Literal(n).tan).to be_within(0.000001).of(RDF::Literal(result)) + end + end + + context '#nan?' do + [Float::NAN, Float::INFINITY, -Float::INFINITY].each do |n| + specify("#{n}") {expect((RDF::Literal(n).tan).nan?).to be_truthy} + end + end + end + + describe "#asin" do + { + 0 => 0.0e0, + -0.0e0 => -0.0e0, + 1.0e0 => 1.5707963267948966e0, + -1.0e0 => -1.5707963267948966e0, + }.each do |n, result| + it "#{n}" do + expect(RDF::Literal(n).asin).to be_within(0.000001).of(RDF::Literal(result)) + end + end + + context '#nan?' do + [2.0e0, Float::NAN, Float::INFINITY, -Float::INFINITY].each do |n| + specify("#{n}") {expect((RDF::Literal(n).asin).nan?).to be_truthy} + end + end + end + + describe "#acos" do + { + 0 => 1.5707963267948966e0, + -0.0e0 => 1.5707963267948966e0, + 1.0e0 => 0.0e0, + -1.0e0 => 3.141592653589793e0, + }.each do |n, result| + it "#{n}" do + expect(RDF::Literal(n).acos).to be_within(0.000001).of(RDF::Literal(result)) + end + end + + context '#nan?' do + [2.0e0, Float::NAN, Float::INFINITY, -Float::INFINITY].each do |n| + specify("#{n}") {expect((RDF::Literal(n).acos).nan?).to be_truthy} + end + end + end + + describe "#atan" do + { + 0 => 0.0e0, + -0.0e0 => -0.0e0, + 1.0e0 => 0.7853981633974483e0, + -1.0e0 => -0.7853981633974483e0, + Float::INFINITY => 1.5707963267948966e0, + -Float::INFINITY => -1.5707963267948966e0, + }.each do |n, result| + it "#{n}" do + expect(RDF::Literal(n).atan).to be_within(0.000001).of(RDF::Literal(result)) + end + end + + context '#nan?' do + [Float::NAN].each do |n| + specify("#{n}") {expect((RDF::Literal(n).atan).nan?).to be_truthy} + end + end + end + + describe "#atan2" do + { + "+0.0e0, 0.0e0": [+0.0e0, 0.0e0, 0.0e0], + "-0.0e0, 0.0e0": [-0.0e0, 0.0e0, -0.0e0], + "+0.0e0, -0.0e0": [+0.0e0, -0.0e0, 3.141592653589793e0], + "-0.0e0, -0.0e0": [-0.0e0, -0.0e0, -3.141592653589793e0], + "-1, 0.0e0": [-1, 0.0e0, -1.5707963267948966e0], + "+1, 0.0e0": [+1, 0.0e0, 1.5707963267948966e0], + "-0.0e0, -1": [-0.0e0, -1, -3.141592653589793e0], + "+0.0e0, -1": [+0.0e0, -1, 3.141592653589793e0], + "-0.0e0, +1": [-0.0e0, +1, 0.0e0], + "+0.0e0, +1": [+0.0e0, +1, 0.0e0], + }.each do |name, (a, b, result)| + it name do + expect(RDF::Literal(a).atan2 RDF::Literal(b)).to eq RDF::Literal(result) + end + end + end end describe RDF::Literal::Integer do From 5e701853f76dcdbab1d07adf81c286dcd3970b82 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Tue, 22 Feb 2022 15:31:38 -0800 Subject: [PATCH 7/8] Update development dependency on rdf-xsd to >= 3.2.1 --- rdf.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rdf.gemspec b/rdf.gemspec index f1f0e181..99318e1a 100755 --- a/rdf.gemspec +++ b/rdf.gemspec @@ -33,7 +33,7 @@ Gem::Specification.new do |gem| gem.add_development_dependency 'rdf-spec', '~> 3.2' gem.add_development_dependency 'rdf-turtle', '~> 3.2' gem.add_development_dependency 'rdf-vocab', '~> 3.2' - gem.add_development_dependency 'rdf-xsd', '~> 3.2' + gem.add_development_dependency 'rdf-xsd', '~> 3.2', '>= 3.2.1' gem.add_development_dependency 'rest-client', '~> 2.1' gem.add_development_dependency 'rspec', '~> 3.10' gem.add_development_dependency 'rspec-its', '~> 1.3' From 4b9f2861d250eee6ea248c2e7a69b7a6a83c350a Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Tue, 22 Feb 2022 17:30:58 -0800 Subject: [PATCH 8/8] Version 3.2.5. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 351227fc..5ae69bd5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.2.4 +3.2.5