neu-mods 0.4.0 → 0.5.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 +4 -4
- data/.version +1 -1
- data/README.md +5 -0
- data/lib/neu/mods/projection.rb +47 -11
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1469790b96ff15516d9766db6673159fb9ad14128e02c4399842580c198a1740
|
|
4
|
+
data.tar.gz: 97c442fbd0765c6de753bbb140da3fa2ac61fedcb63104d38801c569a876ddcd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5b2fdf0e42f5fd65fccbc732ddf4a15b3f311f4719a3a95a294517da643c8005dcbb3c25a7b3e2b1e7afcb67c1f29f9cecacf7ec157640ef3a2b2d56e13197ac
|
|
7
|
+
data.tar.gz: 4ffc16684b6176a667fcf62dadc6e20c5fed2733c1f6bdcd39df345fe6df77f5cd412f62fe879676f1075f7c690ca6cb368b6876bfca0e4a98477af8112731c2
|
data/.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.5.0
|
data/README.md
CHANGED
|
@@ -33,6 +33,11 @@ doc.title_parts # => { non_sort:, subtitle:, title:, part_name:, part_number:
|
|
|
33
33
|
doc.abstract # => normalized, paragraph-joined String
|
|
34
34
|
doc.topical_subjects # => ["Civil society", ...] (every <topic>, for the access copy)
|
|
35
35
|
doc.keywords # => [...] (only the editable attribute-free keyword subjects)
|
|
36
|
+
doc.date_created_with_precision
|
|
37
|
+
# => [DateTime, "year"|"month"|"day"] w3cdtf YYYY, YYYY-MM
|
|
38
|
+
# and YYYY-MM-DD all parse; the precision says which shape
|
|
39
|
+
# the record declared, so display cannot invent a month or
|
|
40
|
+
# a day the record never claimed
|
|
36
41
|
doc.to_h # => full projection, keyed to Atlas's Metadata::MODS attributes
|
|
37
42
|
|
|
38
43
|
# Pure title composition (no document needed) — for callers that already hold
|
data/lib/neu/mods/projection.rb
CHANGED
|
@@ -171,32 +171,48 @@ module NEU
|
|
|
171
171
|
node && clean(node.text)
|
|
172
172
|
end
|
|
173
173
|
|
|
174
|
-
#
|
|
175
|
-
#
|
|
176
|
-
|
|
174
|
+
# The three w3cdtf date shapes a dateCreated may stop at: year, year-month,
|
|
175
|
+
# or a full date. Matching the shape explicitly, rather than widening
|
|
176
|
+
# DateTime.parse, is what lets the declared precision fall out of the parse
|
|
177
|
+
# instead of being guessed after it.
|
|
178
|
+
W3CDTF_DATE = /\A(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?\z/
|
|
179
|
+
|
|
180
|
+
# Parsed dateCreated paired with the granularity the record declared, as
|
|
181
|
+
# [value, precision]. value is nil if no originInfo/dateCreated, or "" if
|
|
182
|
+
# present but unparseable (mirrors Atlas's safe_date_parse rescue).
|
|
183
|
+
# precision is "year", "month" or "day", and nil whenever value is not a
|
|
184
|
+
# DateTime.
|
|
185
|
+
#
|
|
186
|
+
# The precision has to be captured here, at the only point where the shape
|
|
187
|
+
# is still visible: a year-only date parses to January 1st, and no consumer
|
|
188
|
+
# downstream can tell that month and day from a record that claimed them.
|
|
189
|
+
# A preservation repository must not project a precision it was not given.
|
|
190
|
+
def date_created_with_precision
|
|
177
191
|
node = doc.at_xpath("/mods:mods/mods:originInfo/mods:dateCreated", NAMESPACE)
|
|
178
|
-
return nil unless node
|
|
192
|
+
return [nil, nil] unless node
|
|
179
193
|
|
|
180
194
|
str = NEU::MODS.canonical_ws(node.text)
|
|
181
|
-
return nil if str.empty?
|
|
195
|
+
return [nil, nil] if str.empty?
|
|
182
196
|
|
|
183
|
-
|
|
184
|
-
DateTime.parse(str)
|
|
185
|
-
rescue Date::Error
|
|
186
|
-
""
|
|
187
|
-
end
|
|
197
|
+
parse_w3cdtf(str)
|
|
188
198
|
end
|
|
189
199
|
|
|
200
|
+
def date_created = date_created_with_precision.first
|
|
201
|
+
def date_created_precision = date_created_with_precision.last
|
|
202
|
+
|
|
190
203
|
# --- Full projection -----------------------------------------------------
|
|
191
204
|
|
|
192
205
|
# The complete read projection, keyed to Atlas's Metadata::MODS attribute
|
|
193
206
|
# names -- a drop-in source for `convert_xml_to_json`.
|
|
194
207
|
def to_h
|
|
208
|
+
date, date_precision = date_created_with_precision
|
|
209
|
+
|
|
195
210
|
{
|
|
196
211
|
main_title: access_title_parts,
|
|
197
212
|
names: names,
|
|
198
213
|
languages: languages,
|
|
199
|
-
date_created:
|
|
214
|
+
date_created: date,
|
|
215
|
+
date_created_precision: date_precision,
|
|
200
216
|
resource_type: resource_type,
|
|
201
217
|
genres: genres,
|
|
202
218
|
format: format,
|
|
@@ -223,6 +239,26 @@ module NEU
|
|
|
223
239
|
|
|
224
240
|
# --- helpers -------------------------------------------------------------
|
|
225
241
|
|
|
242
|
+
# A shape-matched but impossible date (2026-13, 2026-02-30) reaches DateTime
|
|
243
|
+
# and raises; it falls to the "" sentinel like any other unparseable value.
|
|
244
|
+
# Anything outside the three shapes keeps the old permissive parse, so a
|
|
245
|
+
# timestamp still projects as a full date.
|
|
246
|
+
def parse_w3cdtf(str)
|
|
247
|
+
m = W3CDTF_DATE.match(str)
|
|
248
|
+
return [DateTime.parse(str), "day"] unless m
|
|
249
|
+
|
|
250
|
+
precision = if m[3]
|
|
251
|
+
"day"
|
|
252
|
+
elsif m[2]
|
|
253
|
+
"month"
|
|
254
|
+
else
|
|
255
|
+
"year"
|
|
256
|
+
end
|
|
257
|
+
[DateTime.new(m[1].to_i, (m[2] || 1).to_i, (m[3] || 1).to_i), precision]
|
|
258
|
+
rescue Date::Error
|
|
259
|
+
["", nil]
|
|
260
|
+
end
|
|
261
|
+
|
|
226
262
|
def text_at(xpath)
|
|
227
263
|
node = doc.at_xpath(xpath, NAMESPACE)
|
|
228
264
|
node ? NEU::MODS.canonical_ws(node.text) : ""
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: neu-mods
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Cliff
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-09-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: nokogiri
|