rdf-edtf 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile +3 -0
- data/README.md +45 -0
- data/UNLICENSE +24 -0
- data/lib/rdf.rb +0 -0
- data/lib/rdf/edtf.rb +21 -0
- data/lib/rdf/edtf/literal.rb +159 -0
- data/lib/rdf/edtf/version.rb +5 -0
- data/rdf-edtf.gemspec +29 -0
- data/spec/edtf_spec.rb +174 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/shared_examples/literal.rb +123 -0
- metadata +130 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ce99d4757012d81466654f14a746edf6b1af5094
|
4
|
+
data.tar.gz: 631e8d3b07ee24555c790af3106464e983a0c623
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d9d9a547ae659cf53239a790e7cf7dbfacc457aa56e16dc0ad4a7cbe8ed82e6ace879946696f18d05768d45a32a35701b99a0baea11dd62eb70d829920566caa
|
7
|
+
data.tar.gz: 39f5ddb16660031cc928335b48c35e8642aab8d785ed7d95cc6cf219eb3ecaf5cdbc28e91f4e7f4a0a9f6bd91b1cf53ce145faf7b2c4ed45c7511565d6fde8a9
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
v0.1.0
|
2
|
+
------
|
3
|
+
|
4
|
+
- Initial release
|
5
|
+
- Implements BNF grammar as a `Regexp` at `RDF::EDTF::Literal::GRAMMAR`
|
6
|
+
- Supports EDTF level 0-2, with minor caveats:
|
7
|
+
- Datetimes without a zone offset will be parsed and reserialized as UTC with
|
8
|
+
`+00:00`. See: https://github.com/inukshuk/edtf-ruby/issues/14
|
9
|
+
- Sets will be reserialized with spaces in their separators. See:
|
10
|
+
https://github.com/inukshuk/edtf-ruby/issues/15
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
RDF::EDTF
|
2
|
+
=========
|
3
|
+
|
4
|
+
This is an `RDF::Literal` implementation around
|
5
|
+
[Extended Date Time Format](http://www.loc.gov/standards/datetime/pre-submission.html).
|
6
|
+
|
7
|
+
The underlying EDTF parser and implementation is provided by
|
8
|
+
[`edtf-ruby`](https://github.com/inukshuk/edtf-ruby/). The parser supports all
|
9
|
+
EDTF features, with caveats noted below.
|
10
|
+
|
11
|
+
Usage
|
12
|
+
-----
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
require 'rdf/edtf'
|
16
|
+
|
17
|
+
RDF::EDTF::Literal.new('1076?')
|
18
|
+
# or
|
19
|
+
RDF::Literal('1076?', datatype: RDF::EDTF::Literal::DATATYPE)
|
20
|
+
```
|
21
|
+
|
22
|
+
Known Issues
|
23
|
+
------------
|
24
|
+
|
25
|
+
- Datetimes without a zone offset will be parsed and reserialized as UTC with
|
26
|
+
`+00:00`. See: https://github.com/inukshuk/edtf-ruby/issues/14
|
27
|
+
- Sets will be reserialized with spaces in their separators. See:
|
28
|
+
https://github.com/inukshuk/edtf-ruby/issues/15
|
29
|
+
|
30
|
+
Contribution Guidelines
|
31
|
+
-----------------------
|
32
|
+
|
33
|
+
Please observe the following guidelines:
|
34
|
+
|
35
|
+
- Write tests for your contributions.
|
36
|
+
- Document methods you add using YARD annotations.
|
37
|
+
- Follow the included style guidelines (i.e. run `rubocop` before committing).
|
38
|
+
- Use well formed commit messages.
|
39
|
+
|
40
|
+
Do note that in order for us to merge any non-trivial changes (as a rule of thumb, additions larger than about 15 lines of code), we need an explicit public domain dedication on record from you.
|
41
|
+
|
42
|
+
License
|
43
|
+
-------
|
44
|
+
|
45
|
+
This is free and unencumbered public domain software. For more information, see http://unlicense.org/ or the accompanying {file:UNLICENSE} file.
|
data/UNLICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
2
|
+
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
4
|
+
distribute this software, either in source code form or as a compiled
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
6
|
+
means.
|
7
|
+
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
9
|
+
of this software dedicate any and all copyright interest in the
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
11
|
+
of the public at large and to the detriment of our heirs and
|
12
|
+
successors. We intend this dedication to be an overt act of
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
14
|
+
software under copyright law.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
For more information, please refer to <http://unlicense.org/>
|
data/lib/rdf.rb
ADDED
File without changes
|
data/lib/rdf/edtf.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rdf'
|
2
|
+
|
3
|
+
module RDF
|
4
|
+
##
|
5
|
+
# A module implementing Extended Date Time Format (EDTF) handling for
|
6
|
+
# {RDF::Literal}.
|
7
|
+
#
|
8
|
+
# @example requiring RDF::EDTF
|
9
|
+
# require 'rdf/edtf'
|
10
|
+
#
|
11
|
+
# @example Initializing an EDTF literal with {RDF::Literal}
|
12
|
+
# RDF::Literal('107x', datatype: RDF::EDTF::Literal::DATATYPE)
|
13
|
+
#
|
14
|
+
# @see RDF::Literal
|
15
|
+
# @see http://www.loc.gov/standards/datetime/pre-submission.html the EDTF
|
16
|
+
# Specification
|
17
|
+
# @see http://id.loc.gov/datatypes/edtf.html
|
18
|
+
module EDTF
|
19
|
+
autoload :Literal, 'rdf/edtf/literal'
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'edtf'
|
2
|
+
|
3
|
+
module RDF::EDTF
|
4
|
+
##
|
5
|
+
# An EDTF Date literal
|
6
|
+
#
|
7
|
+
# @example Initializing an EDTF literal with {RDF::Literal}
|
8
|
+
# RDF::Literal('107x', datatype: RDF::EDTF::Literal::DATATYPE)
|
9
|
+
#
|
10
|
+
class Literal < RDF::Literal
|
11
|
+
DATATYPE = RDF::URI('http://id.loc.gov/datatypes/edtf/EDTF')
|
12
|
+
|
13
|
+
YEAR = %r(-*[0-9]{4}).freeze
|
14
|
+
ONETHRU12 = %r((01|02|03|04|05|06|07|08|09|10|11|12)).freeze
|
15
|
+
ONETHRU13 = Regexp.union(ONETHRU12, /13/).freeze
|
16
|
+
ONETHRU23 = Regexp.union(ONETHRU13, %r((14|15|16|17|18|19|20|21|22|23)))
|
17
|
+
.freeze
|
18
|
+
ZEROTHRU23 = Regexp.union(/00/, ONETHRU23).freeze
|
19
|
+
ONETHRU29 = Regexp.union(ONETHRU23, %r((24|25|26|27|28|29))).freeze
|
20
|
+
ONETHRU30 = Regexp.union(ONETHRU29, /30/).freeze
|
21
|
+
ONETHRU31 = Regexp.union(ONETHRU30, /31/).freeze
|
22
|
+
|
23
|
+
ONETHRU59 = Regexp.union(ONETHRU31,
|
24
|
+
%r((32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59)))
|
25
|
+
.freeze
|
26
|
+
ZEROTHRU59 = Regexp.union(/00/, ONETHRU59).freeze
|
27
|
+
|
28
|
+
POSITIVEDIGIT = %r((1|2|3|4|5|6|7|8|9)).freeze
|
29
|
+
DIGIT = Regexp.union(POSITIVEDIGIT, /0/).freeze
|
30
|
+
|
31
|
+
DAY = ONETHRU31
|
32
|
+
MONTH = ONETHRU12
|
33
|
+
MONTHDAY = %r(((01|03|05|07|08|10|12)-#{ONETHRU31})|((04|06|09|11)\-#{ONETHRU30})|(02\-#{ONETHRU29}))
|
34
|
+
.freeze
|
35
|
+
YEARMONTH = %r(#{YEAR}\-#{MONTH}).freeze
|
36
|
+
YEARMONTHDAY = %r(#{YEAR}\-#{MONTHDAY}).freeze
|
37
|
+
HOUR = ZEROTHRU23
|
38
|
+
MINUTE = ZEROTHRU59
|
39
|
+
SECOND = ZEROTHRU59
|
40
|
+
|
41
|
+
POSITIVEYEAR = %r((#{POSITIVEDIGIT}#{DIGIT}#{DIGIT}#{DIGIT})|(#{DIGIT}#{POSITIVEDIGIT}#{DIGIT}#{DIGIT})|(#{DIGIT}#{DIGIT}#{POSITIVEDIGIT}#{DIGIT})|(#{DIGIT}#{DIGIT}#{DIGIT}#{POSITIVEDIGIT})).freeze
|
42
|
+
NEGATIVEYEAR = %r(\-#{POSITIVEYEAR}).freeze
|
43
|
+
YYEAR = %r((#{POSITIVEYEAR}|#{NEGATIVEYEAR}|0000)).freeze
|
44
|
+
DATE = %r((#{YYEAR}|#{YEARMONTH}|#{YEARMONTHDAY})).freeze
|
45
|
+
|
46
|
+
BASETIME = %r((#{HOUR}\:#{MINUTE}\:#{SECOND}|(24\:00\:00))).freeze
|
47
|
+
# Zone offset is specified loosely, due to the issue documented here:
|
48
|
+
# https://github.com/inukshuk/edtf-ruby/issues/14
|
49
|
+
# The correct specification is:
|
50
|
+
# ZONEOFFSET = %r(Z|((\+|\-))(#{ONETHRU13}((\:#{MINUTE})|$)|14\:00|00\:#{ONETHRU59})).freeze
|
51
|
+
ZONEOFFSET = %r(Z|((\+|\-))(#{ONETHRU13}((\:#{MINUTE})|$)|14\:00|00\:#{MINUTE})).freeze
|
52
|
+
TIME = %r(#{BASETIME}(#{ZONEOFFSET}|$)).freeze
|
53
|
+
DATEANDTIME = %r(#{DATE}T#{TIME}).freeze
|
54
|
+
|
55
|
+
L0INTERVAL = %r(#{DATE}\/#{DATE}).freeze
|
56
|
+
|
57
|
+
LEVEL0EXPRESSION = Regexp.union(/^#{DATE}$/, /^#{DATEANDTIME}/, /^#{L0INTERVAL}$/).freeze
|
58
|
+
|
59
|
+
UASYMBOL = %r((\?|\~|\?\~)).freeze
|
60
|
+
SEASONNUMBER = %r((21|22|23|24)).freeze
|
61
|
+
SEASON = %r(#{YYEAR}\-#{SEASONNUMBER}).freeze
|
62
|
+
DATEORSEASON = %r((#{DATE}|#{SEASON})).freeze
|
63
|
+
|
64
|
+
UNCERTAINORAPPROXDATE = %r(#{DATE}#{UASYMBOL}).freeze
|
65
|
+
YEARWITHONEORTWOUNSPECIFEDDIGITS = %r(#{DIGIT}#{DIGIT}(#{DIGIT}|u)u).freeze
|
66
|
+
MONTHUNSPECIFIED = %r(#{YEAR}\-uu).freeze
|
67
|
+
DAYUNSPECIFIED = %r(#{YEARMONTH}\-uu).freeze
|
68
|
+
DAYANDMONTHUNSPECIFIED = %r(#{YEAR}\-uu\-uu).freeze
|
69
|
+
UNSPECIFIED = Regexp.union(YEARWITHONEORTWOUNSPECIFEDDIGITS,
|
70
|
+
MONTHUNSPECIFIED,
|
71
|
+
DAYUNSPECIFIED,
|
72
|
+
DAYANDMONTHUNSPECIFIED).freeze
|
73
|
+
|
74
|
+
L1START = %r((#{DATEORSEASON}(#{UASYMBOL})*)|unknown).freeze
|
75
|
+
L1END = %r((#{L1START}|open)).freeze
|
76
|
+
|
77
|
+
L1INTERVAL = %r(#{L1START}\/#{L1END}).freeze
|
78
|
+
|
79
|
+
LONGYEARSIMPLE = %r(y\-?#{POSITIVEDIGIT}#{DIGIT}#{DIGIT}#{DIGIT}#{DIGIT}+).freeze
|
80
|
+
|
81
|
+
LEVEL1EXPRESSION = %r(^(#{UNCERTAINORAPPROXDATE}|#{UNSPECIFIED}|#{L1INTERVAL}|#{LONGYEARSIMPLE}|#{SEASON})$).freeze
|
82
|
+
|
83
|
+
IUABASE = %r((#{YEAR}#{UASYMBOL}\-#{MONTH}(\-\(#{DAY}\)#{UASYMBOL})?|#{YEAR}#{UASYMBOL}\-#{MONTHDAY}#{UASYMBOL}?|#{YEAR}#{UASYMBOL}?\-\(#{MONTH}\)#{UASYMBOL}(\-\(#{DAY}\)#{UASYMBOL})?|#{YEAR}#{UASYMBOL}?\-\(#{MONTH}\)#{UASYMBOL}(\-#{DAY})?|#{YEARMONTH}#{UASYMBOL}\-\(#{DAY}\)#{UASYMBOL}|#{YEARMONTH}#{UASYMBOL}\-#{DAY}|#{YEARMONTH}\-\(#{DAY}\)#{UASYMBOL}|#{YEAR}\-\(#{MONTHDAY}\)#{UASYMBOL}|#{SEASON}#{UASYMBOL})).freeze
|
84
|
+
|
85
|
+
INTERNALUNCERTAINORAPPROXIMATE = %r(#{IUABASE}|\(#{IUABASE}\)#{UASYMBOL}).freeze
|
86
|
+
|
87
|
+
POSITIVEDIGITORU = %r(#{POSITIVEDIGIT}|u).freeze
|
88
|
+
DIGITORU = %r(#{POSITIVEDIGITORU}|0).freeze
|
89
|
+
ONETHRU3 = %r(1|2|3).freeze
|
90
|
+
|
91
|
+
YEARWITHU = %r(u#{DIGITORU}#{DIGITORU}#{DIGITORU}|#{DIGITORU}u#{DIGITORU}#{DIGITORU}|#{DIGITORU}#{DIGITORU}u#{DIGITORU}|#{DIGITORU}#{DIGITORU}#{DIGITORU}u)
|
92
|
+
DAYWITHU = %r(#{ONETHRU31}|u#{DIGITORU}|#{ONETHRU3}u)
|
93
|
+
MONTHWITHU = %r(#{ONETHRU12}|0u|1u|(u#{DIGITORU})).freeze
|
94
|
+
|
95
|
+
# these allow days out of range for the month given (e.g. 2013-02-31)
|
96
|
+
# is this a bug in the EDTF BNF?
|
97
|
+
YEARMONTHWITHU = %r((#{YEAR}|#{YEARWITHU})\-#{MONTHWITHU}|#{YEARWITHU}\-#{MONTH}).freeze
|
98
|
+
MONTHDAYWITHU = %r((#{MONTH}|#{MONTHWITHU})\-#{DAYWITHU}|#{MONTHWITHU}\-#{DAY}).freeze
|
99
|
+
YEARMONTHDAYWITHU = %r((#{YEARWITHU}|#{YEAR})\-#{MONTHDAYWITHU}|#{YEARWITHU}\-#{MONTHDAY}).freeze
|
100
|
+
|
101
|
+
INTERNALUNSPECIFIED = Regexp.union(YEARWITHU, YEARMONTHWITHU, YEARMONTHDAYWITHU).freeze
|
102
|
+
|
103
|
+
DATEWITHINTERNALUNCERTAINTY = Regexp.union(INTERNALUNCERTAINORAPPROXIMATE, INTERNALUNSPECIFIED).freeze
|
104
|
+
|
105
|
+
EARLIER = %r(\.\.#{DATE}).freeze
|
106
|
+
LATER = %r(#{DATE}\.\.).freeze
|
107
|
+
CONSECUTIVES = %r(#{YEARMONTHDAY}\.\.#{YEARMONTHDAY}|#{YEARMONTH}\.\.#{YEARMONTH}|#{YEAR}\.\.#{YEAR}).freeze
|
108
|
+
|
109
|
+
LISTELEMENT = %r(#{DATE}|#{DATEWITHINTERNALUNCERTAINTY}|#{UNCERTAINORAPPROXDATE}|#{UNSPECIFIED}|#{CONSECUTIVES}).freeze
|
110
|
+
# list contents are specified here to allow spaces:
|
111
|
+
# e.g. [1995, 1996, 1997]
|
112
|
+
# this is not allowed in the specification's grammar
|
113
|
+
# see: https://github.com/inukshuk/edtf-ruby/issues/15
|
114
|
+
LISTCONTENT = %r((#{EARLIER}(\,\s?#{LISTELEMENT})*|(#{EARLIER}\,\s?)?(#{LISTELEMENT}\,\s?)*#{LATER}|#{LISTELEMENT}(\,\s?#{LISTELEMENT})+|#{CONSECUTIVES})).freeze
|
115
|
+
|
116
|
+
CHOICELIST = %r(\[#{LISTCONTENT}\]).freeze
|
117
|
+
INCLUSIVELIST = %r(\{#{LISTCONTENT}\}).freeze
|
118
|
+
|
119
|
+
MASKEDPRECISION = %r(#{DIGIT}#{DIGIT}((#{DIGIT}x)|xx)).freeze
|
120
|
+
|
121
|
+
L2INTERVAL = %r((#{DATEORSEASON}\/#{DATEWITHINTERNALUNCERTAINTY})|(#{DATEWITHINTERNALUNCERTAINTY}\/#{DATEORSEASON})|(#{DATEWITHINTERNALUNCERTAINTY}\/#{DATEWITHINTERNALUNCERTAINTY})).freeze
|
122
|
+
|
123
|
+
POSITIVEINTEGER = %r(#{POSITIVEDIGIT}#{DIGIT}*).freeze
|
124
|
+
LONGYEARSCIENTIFIC = %r(y\-?#{POSITIVEINTEGER}e#{POSITIVEINTEGER}(p#{POSITIVEINTEGER})?).freeze
|
125
|
+
|
126
|
+
QUALIFYINGSTRING = %r(\S+).freeze
|
127
|
+
SEASONQUALIFIED = %r(#{SEASON}\^#{QUALIFYINGSTRING}).freeze
|
128
|
+
|
129
|
+
LEVEL2EXPRESSION = %r(^(#{INTERNALUNCERTAINORAPPROXIMATE}|#{INTERNALUNSPECIFIED}|#{CHOICELIST}|#{INCLUSIVELIST}|#{MASKEDPRECISION}|#{L2INTERVAL}|#{LONGYEARSCIENTIFIC}|#{SEASONQUALIFIED})$).freeze
|
130
|
+
|
131
|
+
##
|
132
|
+
# Grammar is articulated according to the BNF in the EDTF 1.0 pre-submission
|
133
|
+
# specification, except where noted above.
|
134
|
+
#
|
135
|
+
# @todo investigate the allowance for out-of-range days (e.g. 2013-02-31) in
|
136
|
+
# `INTERNALUNSPECIFIED`
|
137
|
+
# @todo follow up on zone offset `00:00`; disallow, if appropriate, once
|
138
|
+
# {https://github.com/inukshuk/edtf-ruby/issues/14} is closed
|
139
|
+
# @todo disallow spaces in LISTCONTENT when
|
140
|
+
# {https://github.com/inukshuk/edtf-ruby/issues/15} is closed
|
141
|
+
#
|
142
|
+
# @see http://www.loc.gov/standards/datetime/pre-submission.html#bnf
|
143
|
+
GRAMMAR = Regexp.union(LEVEL0EXPRESSION, LEVEL1EXPRESSION, LEVEL2EXPRESSION).freeze
|
144
|
+
|
145
|
+
##
|
146
|
+
# Initializes an RDF::Literal with EDTF datatype.
|
147
|
+
#
|
148
|
+
# Casts lexical values with the correct datatype to EDTF, if they are
|
149
|
+
# parsable. Otherwise retains their original value as an `#invalid?`
|
150
|
+
# literal.
|
151
|
+
#
|
152
|
+
# @see RDF::Literal
|
153
|
+
def initialize(value, options = {})
|
154
|
+
value = EDTF.parse(value) || value
|
155
|
+
@string = value.edtf if value.respond_to? :edtf
|
156
|
+
super
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
data/rdf-edtf.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'rdf/edtf/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "rdf-edtf"
|
7
|
+
s.version = RDF::EDTF::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['Tom Johnson']
|
10
|
+
s.homepage = 'https://github.com/dpla/rdf-edtf'
|
11
|
+
s.email = 'tom@dp.la'
|
12
|
+
s.summary = %q{An `RDF::Literal` implementation around Extended Date Time Format.}
|
13
|
+
s.description = %q{Supports serializing and parsing EDTF (all levels) as typed literals in RDF.}
|
14
|
+
s.license = 'UNLICENSE'
|
15
|
+
s.required_ruby_version = '>= 2.0.0'
|
16
|
+
|
17
|
+
s.add_dependency('rdf', '~> 1.1')
|
18
|
+
s.add_dependency('edtf', '~>2.1.0')
|
19
|
+
|
20
|
+
s.add_development_dependency('pry')
|
21
|
+
s.add_development_dependency('rspec')
|
22
|
+
s.add_development_dependency('rdf-spec')
|
23
|
+
|
24
|
+
s.files = `git ls-files`.split("\n")
|
25
|
+
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
26
|
+
|
27
|
+
s.extra_rdoc_files = ['UNLICENSE',
|
28
|
+
'README.md']
|
29
|
+
end
|
data/spec/edtf_spec.rb
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RDF::EDTF::Literal do
|
4
|
+
it_behaves_like 'RDF::Literal with datatype',
|
5
|
+
EDTF.parse!('1076'),
|
6
|
+
'http://id.loc.gov/datatypes/edtf/EDTF'
|
7
|
+
|
8
|
+
let(:date) { EDTF.parse('1076') }
|
9
|
+
subject { described_class.new(EDTF.parse!('1076')) }
|
10
|
+
|
11
|
+
describe '#initialize' do
|
12
|
+
context 'with string' do
|
13
|
+
let(:date) { '199u' }
|
14
|
+
|
15
|
+
it 'casts object value to EDTF' do
|
16
|
+
expect(described_class.new(date).object).to eq EDTF.parse(date)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'sets lexical value' do
|
20
|
+
expect(described_class.new(date).value).to eq date
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'as invalid edtf' do
|
24
|
+
let(:date) { 'not a valid edtf date' }
|
25
|
+
|
26
|
+
it 'retains original value as object' do
|
27
|
+
expect(described_class.new(date).object).to eq date
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'gives #to_s as lexical value' do
|
31
|
+
expect(described_class.new(date).value).to eq date.to_s
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'gives value if invalid edtf' do
|
37
|
+
date = '19!!'
|
38
|
+
expect(described_class.new(date).object).to eq date
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#<=>' do
|
43
|
+
it 'is less than succeding date' do
|
44
|
+
expect(subject).to be < described_class.new(date.succ)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'is greater than than previous date' do
|
48
|
+
expect(subject).to be > described_class.new(date.prev)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'is not equal to date of different precision' do
|
52
|
+
day_date = date.clone
|
53
|
+
day_date.precision = :day
|
54
|
+
expect(subject).not_to eq described_class.new(day_date)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'is not equal to date of different approximation' do
|
58
|
+
approx_date = date.clone
|
59
|
+
approx_date.approximate!
|
60
|
+
expect(subject).not_to eq described_class.new(approx_date)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#value' do
|
65
|
+
it 'gives an edtf string representation' do
|
66
|
+
expect(subject.value).to eq date.edtf
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe RDF::Literal do
|
72
|
+
include_examples 'RDF::Literal lookup',
|
73
|
+
{ RDF::EDTF::Literal::DATATYPE => RDF::EDTF::Literal }
|
74
|
+
|
75
|
+
include_examples 'RDF::Literal canonicalization',
|
76
|
+
RDF::EDTF::Literal::DATATYPE,
|
77
|
+
{}
|
78
|
+
|
79
|
+
include_examples 'RDF::Literal validation',
|
80
|
+
RDF::EDTF::Literal::DATATYPE,
|
81
|
+
# valid value examples taken from:
|
82
|
+
# http://www.loc.gov/standards/datetime/pre-submission.html
|
83
|
+
['2001-02-03',
|
84
|
+
'2008-12',
|
85
|
+
'2008',
|
86
|
+
'-2008',
|
87
|
+
'0000',
|
88
|
+
'2001-02-03T09:30:01',
|
89
|
+
'2004-01-01T10:10:10Z',
|
90
|
+
'2004-01-01T10:10:10+05:00',
|
91
|
+
'1964/2008',
|
92
|
+
'2004-06/2006-08',
|
93
|
+
'2004-02-01/2005-02-08',
|
94
|
+
'2004-02-01/2005-02',
|
95
|
+
'2004-02-01/2005',
|
96
|
+
'2005/2006-02',
|
97
|
+
'1984?',
|
98
|
+
'2004-06?',
|
99
|
+
'2004-06-11?',
|
100
|
+
'1984~',
|
101
|
+
'1984?~',
|
102
|
+
'199u',
|
103
|
+
'19uu',
|
104
|
+
'1999-uu',
|
105
|
+
'1999-01-uu',
|
106
|
+
'1999-uu-uu',
|
107
|
+
'2004-06-01/unknown',
|
108
|
+
'2004-01-01/open',
|
109
|
+
'1984~/2004-06',
|
110
|
+
'1984/2004-06~',
|
111
|
+
'1984?/2004?~',
|
112
|
+
'y170000002',
|
113
|
+
'y-170000002',
|
114
|
+
'2001-21',
|
115
|
+
'2001-22',
|
116
|
+
'2001-23',
|
117
|
+
'2001-24',
|
118
|
+
'2004?-06-11',
|
119
|
+
'2004-06~-11',
|
120
|
+
'2004-(06)?-11',
|
121
|
+
'2004-06-(11)~',
|
122
|
+
'2004-(06)?~',
|
123
|
+
'2004-(06-11)?',
|
124
|
+
'2004?-06-(11)~',
|
125
|
+
'(2004-(06)~)?',
|
126
|
+
'2004?-(06)?~',
|
127
|
+
# in addition to being unsupproed by EDTF.parse, these
|
128
|
+
# appear to be disallowed by EDTF's BNF:
|
129
|
+
# '(2004)?-06-04~', # unsupported; EDTF.parse returns nil
|
130
|
+
# '(2011)-06-04~', # unsupported; EDTF.parse returns nil,
|
131
|
+
'2011-(06-04)~',
|
132
|
+
'2011-23~',
|
133
|
+
'156u-12-25',
|
134
|
+
'15uu-12-25',
|
135
|
+
'15uu-12-uu',
|
136
|
+
'1560-uu-25',
|
137
|
+
'[1667,1668,1670..1672]',
|
138
|
+
'[..1760-12-03]',
|
139
|
+
'[1760-12..]',
|
140
|
+
'[1760-01,1760-02,1760-12..]',
|
141
|
+
'[1667,1760-12]',
|
142
|
+
'{1667,1668,1670..1672}',
|
143
|
+
'{1960,1961-12}',
|
144
|
+
'196x',
|
145
|
+
'19xx',
|
146
|
+
'2004-06-(01)~/2004-06-(20)~',
|
147
|
+
'2004-06-uu/2004-07-03',
|
148
|
+
'y17e7',
|
149
|
+
'y-17e7',
|
150
|
+
'y17101e4p3', # unsupported; EDTF.parse returns nil
|
151
|
+
'2001-21^southernHemisphere'],
|
152
|
+
['abc', '123', '1921-1', '100000', '1923-13', '192?',
|
153
|
+
'1924a', '1234-22abc', '1xxx']
|
154
|
+
|
155
|
+
describe 'initializing with datatype' do
|
156
|
+
subject { RDF::Literal(date, datatype: RDF::EDTF::Literal::DATATYPE) }
|
157
|
+
|
158
|
+
context 'with edtf value' do
|
159
|
+
let(:date) { EDTF.parse!('1076') }
|
160
|
+
|
161
|
+
it 'sets date to object' do
|
162
|
+
expect(subject.object).to eql date
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'with edtf value' do
|
167
|
+
let(:date) { '1076' }
|
168
|
+
|
169
|
+
it 'parses date to edtf' do
|
170
|
+
expect(subject.object).to eq EDTF.parse(date)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
Bundler.setup
|
3
|
+
|
4
|
+
require 'rdf/edtf'
|
5
|
+
|
6
|
+
# Load support files
|
7
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.color = true
|
11
|
+
config.tty = true
|
12
|
+
|
13
|
+
# Uncomment the following line to get errors and backtrace for deprecation warnings
|
14
|
+
# config.raise_errors_for_deprecations!
|
15
|
+
|
16
|
+
# Use the specified formatter
|
17
|
+
config.formatter = :progress
|
18
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
|
2
|
+
shared_examples 'RDF::Literal with datatype' do |value, datatype_uri|
|
3
|
+
subject { described_class.new(value) }
|
4
|
+
|
5
|
+
it 'has a DATATYPE' do
|
6
|
+
expect(described_class::DATATYPE).to be_a RDF::URI
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'has a GRAMMAR' do
|
10
|
+
expect(described_class::GRAMMAR).to respond_to :=~
|
11
|
+
end
|
12
|
+
|
13
|
+
it { is_expected.to be_literal }
|
14
|
+
it { is_expected.to be_typed }
|
15
|
+
it { is_expected.not_to be_plain }
|
16
|
+
it { is_expected.not_to be_anonymous }
|
17
|
+
|
18
|
+
it 'has correct datatype' do
|
19
|
+
expect(subject.datatype).to eq datatype_uri
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#==' do
|
23
|
+
it { is_expected.to eq subject }
|
24
|
+
it { expect(subject.object).to eq value }
|
25
|
+
it { is_expected.not_to eq described_class.new('OTHER') }
|
26
|
+
it { is_expected.not_to eq nil }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#humanize' do
|
30
|
+
it 'gives a string representation' do
|
31
|
+
expect(subject.humanize).to be_a String
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#to_s' do
|
36
|
+
it 'gives a string representation' do
|
37
|
+
expect(subject.to_s).to be_a String
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#object' do
|
42
|
+
it 'is the given value' do
|
43
|
+
expect(subject.humanize).to be_a String
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
shared_examples 'RDF::Literal lookup' do |uri_hash|
|
49
|
+
uri_hash.each do |uri, klass|
|
50
|
+
it "finds #{klass} for #{uri}" do
|
51
|
+
expect(RDF::Literal("0", :datatype => uri).class).to eq klass
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
shared_examples 'RDF::Literal canonicalization' do |datatype, pairs|
|
57
|
+
pairs.each do |value, str|
|
58
|
+
|
59
|
+
klass = RDF::Literal.datatyped_class(datatype.to_s)
|
60
|
+
|
61
|
+
it "does not normalize '#{value}' by default" do
|
62
|
+
expect(RDF::Literal.new(value,
|
63
|
+
datatype: datatype ,
|
64
|
+
canonicalize: false).to_s)
|
65
|
+
.to eq value
|
66
|
+
end
|
67
|
+
|
68
|
+
it "normalizes double '#{value}' to '#{str}'" do
|
69
|
+
expect(RDF::Literal.new(value,
|
70
|
+
datatype: datatype,
|
71
|
+
canonicalize: true).to_s)
|
72
|
+
.to eq str
|
73
|
+
end
|
74
|
+
|
75
|
+
it "humanizes double '#{value}' to '#{str}'" do
|
76
|
+
expect(RDF::Literal.new(value,
|
77
|
+
datatype: datatype,
|
78
|
+
canonicalize: false).humanize)
|
79
|
+
.to eq value
|
80
|
+
end
|
81
|
+
|
82
|
+
it "instantiates '#{value}' as #{klass}" do
|
83
|
+
expect(RDF::Literal.new(value,
|
84
|
+
datatype: datatype,
|
85
|
+
canonicalize: true))
|
86
|
+
.to be_a(klass)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "causes normalized '#{value}' to be == '#{str}'" do
|
90
|
+
expect(RDF::Literal.new(value,
|
91
|
+
datatype: datatype,
|
92
|
+
canonicalize: true))
|
93
|
+
.to eq RDF::Literal.new(str, datatype: datatype, canonicalize: false)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
shared_examples 'RDF::Literal validation' do |datatype,
|
99
|
+
valid_values,
|
100
|
+
invalid_values|
|
101
|
+
|
102
|
+
klass = RDF::Literal.datatyped_class(datatype.to_s)
|
103
|
+
|
104
|
+
valid_values.each do |value|
|
105
|
+
it "validates #{klass} '#{value}'" do
|
106
|
+
expect(RDF::Literal.new(value, datatype: datatype)).to be_valid
|
107
|
+
end
|
108
|
+
|
109
|
+
it "does not invalidate #{klass} '#{value}'" do
|
110
|
+
expect(RDF::Literal.new(value, datatype: datatype)).not_to be_invalid
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
invalid_values.each do |value|
|
115
|
+
it "invalidates #{klass} '#{value}'" do
|
116
|
+
expect(RDF::Literal.new(value, datatype: datatype)).to be_invalid
|
117
|
+
end
|
118
|
+
|
119
|
+
it "does not validate #{klass} '#{value}'" do
|
120
|
+
expect(RDF::Literal.new(value, datatype: datatype)).not_to be_valid
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rdf-edtf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tom Johnson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rdf
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: edtf
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.1.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.1.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rdf-spec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Supports serializing and parsing EDTF (all levels) as typed literals
|
84
|
+
in RDF.
|
85
|
+
email: tom@dp.la
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files:
|
89
|
+
- UNLICENSE
|
90
|
+
- README.md
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- CHANGELOG.md
|
94
|
+
- Gemfile
|
95
|
+
- README.md
|
96
|
+
- UNLICENSE
|
97
|
+
- lib/rdf.rb
|
98
|
+
- lib/rdf/edtf.rb
|
99
|
+
- lib/rdf/edtf/literal.rb
|
100
|
+
- lib/rdf/edtf/version.rb
|
101
|
+
- rdf-edtf.gemspec
|
102
|
+
- spec/edtf_spec.rb
|
103
|
+
- spec/spec_helper.rb
|
104
|
+
- spec/support/shared_examples/literal.rb
|
105
|
+
homepage: https://github.com/dpla/rdf-edtf
|
106
|
+
licenses:
|
107
|
+
- UNLICENSE
|
108
|
+
metadata: {}
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 2.0.0
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 2.2.1
|
126
|
+
signing_key:
|
127
|
+
specification_version: 4
|
128
|
+
summary: An `RDF::Literal` implementation around Extended Date Time Format.
|
129
|
+
test_files: []
|
130
|
+
has_rdoc:
|