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.
@@ -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
@@ -0,0 +1,3 @@
1
+ #*#
2
+ *~
3
+ Gemfile.lock
@@ -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
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -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.
@@ -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/>
File without changes
@@ -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
@@ -0,0 +1,5 @@
1
+ module RDF
2
+ module EDTF
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -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
@@ -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
@@ -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: