cocina-models 0.82.0 → 0.84.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +1 -1
- data/.gitignore +0 -2
- data/.rubocop.yml +26 -1
- data/Gemfile.lock +158 -0
- data/README.md +5 -14
- data/lib/cocina/models/doi_exceptions.rb +9 -0
- data/lib/cocina/models/{doi.rb → doi_pattern.rb} +1 -1
- data/lib/cocina/models/identification.rb +1 -2
- data/lib/cocina/models/mapping/from_mods/subject.rb +2 -1
- data/lib/cocina/models/mapping/to_mods/geographic.rb +3 -5
- data/lib/cocina/models/mapping/to_mods/subject.rb +12 -2
- data/lib/cocina/models/validators/date_time_validator.rb +12 -2
- data/lib/cocina/models/validators/validator.rb +2 -1
- data/lib/cocina/models/version.rb +1 -1
- data/lib/cocina/models.rb +8 -1
- data/openapi.yml +12 -2
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e1b47286ce6d52c99a76f6370a1f1a902d204759a7e0d11966b42d94d01ee19
|
4
|
+
data.tar.gz: e6f5f432fab07a70965b78b94f3f5a1ff6e103ce274011ee55b7a130ae7bc974
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0908f1699111ae772ebea61c0f5824c78cd694640aa3acaaded5311f2039a366469765206cf88f49410734054d660cbb6414afa0695c5a3b831b42be857e30ac'
|
7
|
+
data.tar.gz: 075d804c7525993965ffe30ae6d7e266c62d8a1b842cebc7096db3cd0c824af1b733180740faf3ba7db246cdd4c822ca9e67699cfa160810e62f12e0e919ea5d
|
data/.circleci/config.yml
CHANGED
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -184,7 +184,7 @@ Style/SoleNestedConditional: # (new in 0.89)
|
|
184
184
|
Style/StringConcatenation:
|
185
185
|
Enabled: true
|
186
186
|
|
187
|
-
Gemspec/
|
187
|
+
Gemspec/DeprecatedAttributeAssignment: # new in 1.10
|
188
188
|
Enabled: true
|
189
189
|
Gemspec/RequireMFA: # new in 1.23
|
190
190
|
Enabled: true
|
@@ -311,3 +311,28 @@ Style/RedundantInitialize: # new in 1.27
|
|
311
311
|
Enabled: true
|
312
312
|
RSpec/VerifiedDoubleReference: # new in 2.10.0
|
313
313
|
Enabled: true
|
314
|
+
|
315
|
+
Layout/LineContinuationLeadingSpace: # new in 1.31
|
316
|
+
Enabled: true
|
317
|
+
Layout/LineContinuationSpacing: # new in 1.31
|
318
|
+
Enabled: true
|
319
|
+
Lint/ConstantOverwrittenInRescue: # new in 1.31
|
320
|
+
Enabled: true
|
321
|
+
Lint/NonAtomicFileOperation: # new in 1.31
|
322
|
+
Enabled: true
|
323
|
+
Lint/RequireRangeParentheses: # new in 1.32
|
324
|
+
Enabled: true
|
325
|
+
Style/EmptyHeredoc: # new in 1.32
|
326
|
+
Enabled: true
|
327
|
+
Style/EnvHome: # new in 1.29
|
328
|
+
Enabled: true
|
329
|
+
Style/MagicCommentFormat: # new in 1.35
|
330
|
+
Enabled: true
|
331
|
+
Style/MapCompactWithConditionalBlock: # new in 1.30
|
332
|
+
Enabled: true
|
333
|
+
RSpec/ChangeByZero: # new in 2.11.0
|
334
|
+
Enabled: true
|
335
|
+
RSpec/Capybara/SpecificMatcher: # new in 2.12
|
336
|
+
Enabled: false
|
337
|
+
RSpec/Rails/HaveHttpStatus: # new in 2.12
|
338
|
+
Enabled: false
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
cocina-models (0.84.1)
|
5
|
+
activesupport
|
6
|
+
deprecation
|
7
|
+
dry-struct (~> 1.0)
|
8
|
+
dry-types (~> 1.1)
|
9
|
+
edtf
|
10
|
+
equivalent-xml
|
11
|
+
jsonpath
|
12
|
+
nokogiri
|
13
|
+
openapi3_parser
|
14
|
+
openapi_parser (>= 0.11.1, < 1.0)
|
15
|
+
rss
|
16
|
+
super_diff
|
17
|
+
thor
|
18
|
+
zeitwerk (~> 2.1)
|
19
|
+
|
20
|
+
GEM
|
21
|
+
remote: https://rubygems.org/
|
22
|
+
specs:
|
23
|
+
activesupport (7.0.3.1)
|
24
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
25
|
+
i18n (>= 1.6, < 2)
|
26
|
+
minitest (>= 5.1)
|
27
|
+
tzinfo (~> 2.0)
|
28
|
+
ast (2.4.2)
|
29
|
+
attr_extras (6.2.5)
|
30
|
+
byebug (11.1.3)
|
31
|
+
committee (4.4.0)
|
32
|
+
json_schema (~> 0.14, >= 0.14.3)
|
33
|
+
openapi_parser (>= 0.11.1, < 1.0)
|
34
|
+
rack (>= 1.5)
|
35
|
+
commonmarker (0.23.5)
|
36
|
+
concurrent-ruby (1.1.10)
|
37
|
+
deprecation (1.1.0)
|
38
|
+
activesupport
|
39
|
+
diff-lcs (1.5.0)
|
40
|
+
docile (1.4.0)
|
41
|
+
dry-container (0.10.1)
|
42
|
+
concurrent-ruby (~> 1.0)
|
43
|
+
dry-core (0.8.1)
|
44
|
+
concurrent-ruby (~> 1.0)
|
45
|
+
dry-inflector (0.3.0)
|
46
|
+
dry-logic (1.2.0)
|
47
|
+
concurrent-ruby (~> 1.0)
|
48
|
+
dry-core (~> 0.5, >= 0.5)
|
49
|
+
dry-struct (1.4.0)
|
50
|
+
dry-core (~> 0.5, >= 0.5)
|
51
|
+
dry-types (~> 1.5)
|
52
|
+
ice_nine (~> 0.11)
|
53
|
+
dry-types (1.5.1)
|
54
|
+
concurrent-ruby (~> 1.0)
|
55
|
+
dry-container (~> 0.3)
|
56
|
+
dry-core (~> 0.5, >= 0.5)
|
57
|
+
dry-inflector (~> 0.1, >= 0.1.2)
|
58
|
+
dry-logic (~> 1.0, >= 1.0.2)
|
59
|
+
edtf (3.1.0)
|
60
|
+
activesupport (>= 3.0, < 8.0)
|
61
|
+
equivalent-xml (0.6.0)
|
62
|
+
nokogiri (>= 1.4.3)
|
63
|
+
i18n (1.12.0)
|
64
|
+
concurrent-ruby (~> 1.0)
|
65
|
+
ice_nine (0.11.2)
|
66
|
+
json (2.6.2)
|
67
|
+
json_schema (0.21.0)
|
68
|
+
jsonpath (1.1.2)
|
69
|
+
multi_json
|
70
|
+
mini_portile2 (2.8.0)
|
71
|
+
minitest (5.16.3)
|
72
|
+
multi_json (1.15.0)
|
73
|
+
nokogiri (1.13.8)
|
74
|
+
mini_portile2 (~> 2.8.0)
|
75
|
+
racc (~> 1.4)
|
76
|
+
openapi3_parser (0.9.2)
|
77
|
+
commonmarker (~> 0.17)
|
78
|
+
openapi_parser (0.15.0)
|
79
|
+
optimist (3.0.1)
|
80
|
+
parallel (1.22.1)
|
81
|
+
parser (3.1.2.1)
|
82
|
+
ast (~> 2.4.1)
|
83
|
+
patience_diff (1.2.0)
|
84
|
+
optimist (~> 3.0)
|
85
|
+
racc (1.6.0)
|
86
|
+
rack (2.2.4)
|
87
|
+
rainbow (3.1.1)
|
88
|
+
rake (13.0.6)
|
89
|
+
regexp_parser (2.5.0)
|
90
|
+
rexml (3.2.5)
|
91
|
+
rspec (3.11.0)
|
92
|
+
rspec-core (~> 3.11.0)
|
93
|
+
rspec-expectations (~> 3.11.0)
|
94
|
+
rspec-mocks (~> 3.11.0)
|
95
|
+
rspec-core (3.11.0)
|
96
|
+
rspec-support (~> 3.11.0)
|
97
|
+
rspec-expectations (3.11.0)
|
98
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
99
|
+
rspec-support (~> 3.11.0)
|
100
|
+
rspec-mocks (3.11.1)
|
101
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
102
|
+
rspec-support (~> 3.11.0)
|
103
|
+
rspec-support (3.11.0)
|
104
|
+
rspec_junit_formatter (0.5.1)
|
105
|
+
rspec-core (>= 2, < 4, != 2.12.0)
|
106
|
+
rss (0.2.9)
|
107
|
+
rexml
|
108
|
+
rubocop (1.35.1)
|
109
|
+
json (~> 2.3)
|
110
|
+
parallel (~> 1.10)
|
111
|
+
parser (>= 3.1.2.1)
|
112
|
+
rainbow (>= 2.2.2, < 4.0)
|
113
|
+
regexp_parser (>= 1.8, < 3.0)
|
114
|
+
rexml (>= 3.2.5, < 4.0)
|
115
|
+
rubocop-ast (>= 1.20.1, < 2.0)
|
116
|
+
ruby-progressbar (~> 1.7)
|
117
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
118
|
+
rubocop-ast (1.21.0)
|
119
|
+
parser (>= 3.1.1.0)
|
120
|
+
rubocop-rake (0.6.0)
|
121
|
+
rubocop (~> 1.0)
|
122
|
+
rubocop-rspec (2.12.1)
|
123
|
+
rubocop (~> 1.31)
|
124
|
+
ruby-progressbar (1.11.0)
|
125
|
+
simplecov (0.21.2)
|
126
|
+
docile (~> 1.1)
|
127
|
+
simplecov-html (~> 0.11)
|
128
|
+
simplecov_json_formatter (~> 0.1)
|
129
|
+
simplecov-html (0.12.3)
|
130
|
+
simplecov_json_formatter (0.1.4)
|
131
|
+
super_diff (0.9.0)
|
132
|
+
attr_extras (>= 6.2.4)
|
133
|
+
diff-lcs
|
134
|
+
patience_diff
|
135
|
+
thor (1.2.1)
|
136
|
+
tzinfo (2.0.5)
|
137
|
+
concurrent-ruby (~> 1.0)
|
138
|
+
unicode-display_width (2.2.0)
|
139
|
+
zeitwerk (2.6.0)
|
140
|
+
|
141
|
+
PLATFORMS
|
142
|
+
ruby
|
143
|
+
|
144
|
+
DEPENDENCIES
|
145
|
+
bundler (~> 2.0)
|
146
|
+
byebug
|
147
|
+
cocina-models!
|
148
|
+
committee
|
149
|
+
rake (~> 13.0)
|
150
|
+
rspec (~> 3.0)
|
151
|
+
rspec_junit_formatter
|
152
|
+
rubocop (~> 1.24)
|
153
|
+
rubocop-rake
|
154
|
+
rubocop-rspec (~> 2.1)
|
155
|
+
simplecov
|
156
|
+
|
157
|
+
BUNDLED WITH
|
158
|
+
2.3.17
|
data/README.md
CHANGED
@@ -51,10 +51,10 @@ Beyond what is necessary to test the generator, the Cocina model classes are not
|
|
51
51
|
|
52
52
|
## Testing validation changes
|
53
53
|
|
54
|
-
If there is a possibility that a model or validation change will conflict with some existing objects then [validate-cocina](https://github.com/sul-dlss/dor-services-app/blob/main/bin/validate-cocina) should be used for testing. This must be run on sdr-
|
54
|
+
If there is a possibility that a model or validation change will conflict with some existing objects then [validate-cocina](https://github.com/sul-dlss/dor-services-app/blob/main/bin/validate-cocina) should be used for testing. This must be run on sdr-infra since it requires deploying a branch of cocina-models.
|
55
55
|
|
56
|
-
1. Create a cocina-models branch containing the proposed change and push to
|
57
|
-
2. On sdr-
|
56
|
+
1. Create a cocina-models branch containing the proposed change and push to GitHub.
|
57
|
+
2. On sdr-infra, check out `main`, update the `Gemfile` so that cocina-models references the branch, and `bundle install`.
|
58
58
|
3. Select the appropriate database.
|
59
59
|
For QA:
|
60
60
|
```
|
@@ -124,18 +124,9 @@ At the same, we have found it convenient to use these PRs to also bump the versi
|
|
124
124
|
|
125
125
|
### Step 4: Update other dependent applications
|
126
126
|
|
127
|
-
Once the above listed steps have been completed, all
|
127
|
+
Once the above listed steps have been completed, all applications that use cocina-models should be updated and released at the same time. "Cocina Level 2" describes this set of updates. The applications that use cocina-models are those in [this list](https://github.com/sul-dlss/access-update-scripts/blob/master/infrastructure/projects.yml) that are NOT marked with `cocina_level2: false`.
|
128
128
|
|
129
|
-
|
130
|
-
* [sul-dlss/common-accessioning](https://github.com/sul-dlss/common-accessioning/)
|
131
|
-
* [sul-dlss/dor_indexing_app](https://github.com/sul-dlss/dor_indexing_app/)
|
132
|
-
* [sul-dlss/google-books](https://github.com/sul-dlss/google-books/)
|
133
|
-
* [sul-dlss/happy-heron](https://github.com/sul-dlss/happy-heron/)
|
134
|
-
* [sul-dlss/hydra_etd](https://github.com/sul-dlss/hydra_etd/)
|
135
|
-
* [sul-dlss/infrastructure-integration-test](https://github.com/sul-dlss/infrastructure-integration-test/)
|
136
|
-
* [sul-dlss/pre-assembly](https://github.com/sul-dlss/pre-assembly/)
|
137
|
-
|
138
|
-
There are scripts to help with this:
|
129
|
+
There are scripts to help with updating other dependent applications:
|
139
130
|
|
140
131
|
#### Step 4A: Create the PRs
|
141
132
|
|
@@ -7,8 +7,7 @@ module Cocina
|
|
7
7
|
attribute? :barcode, Types::Nominal::Any
|
8
8
|
attribute :catalogLinks, Types::Strict::Array.of(CatalogLink).default([].freeze)
|
9
9
|
# Digital Object Identifier (https://www.doi.org)
|
10
|
-
|
11
|
-
attribute? :doi, Types::Strict::String
|
10
|
+
attribute? :doi, Types::Nominal::Any
|
12
11
|
# Unique identifier in some other system. This is because a large proportion of what is deposited in SDR, historically and currently, are representations of objects that are also represented in other systems. For example, digitized paper and A/V collections have physical manifestations, and those physical objects are managed in systems that have their own identifiers. Similarly, books have barcodes, archival materials have collection numbers and physical locations, etc. The sourceId allows determining if an item has been deposited before and where to look for the original item if you're looking at its SDR representation. The format is: "namespace:identifier"
|
13
12
|
|
14
13
|
# example: sul:PC0170_s3_Fiesta_Bowl_2012-01-02_210609_2026
|
@@ -339,7 +339,8 @@ module Cocina
|
|
339
339
|
end
|
340
340
|
notes = name_notes_for(full_name[:role], node)
|
341
341
|
name_attrs[:note] = notes unless notes.empty?
|
342
|
-
name_attrs
|
342
|
+
name_attrs[:identifier] = full_name[:identifier]
|
343
|
+
name_attrs.compact.merge(attrs)
|
343
344
|
end
|
344
345
|
|
345
346
|
def name_notes_for(roles, name_node)
|
@@ -70,12 +70,10 @@ module Cocina
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def extract_type(geo)
|
73
|
-
type = geo
|
74
|
-
form
|
73
|
+
type = geo.form.find do |form|
|
74
|
+
form.type.match?(TYPE_REGEX) || (form.type.match?(MEDIA_REGEX) && form.value == 'Image')
|
75
75
|
end
|
76
|
-
|
77
|
-
|
78
|
-
nil
|
76
|
+
type&.value
|
79
77
|
end
|
80
78
|
|
81
79
|
def about(druid)
|
@@ -230,8 +230,11 @@ module Cocina
|
|
230
230
|
# Write nodes within MODS subject
|
231
231
|
def write_topic(subject, subject_value, is_parallel: false, type: nil, subject_values_have_same_authority: true)
|
232
232
|
type ||= subject_value.type
|
233
|
-
topic_attributes = topic_attributes_for(subject,
|
234
|
-
|
233
|
+
topic_attributes = topic_attributes_for(subject,
|
234
|
+
subject_value,
|
235
|
+
type,
|
236
|
+
is_parallel: is_parallel,
|
237
|
+
subject_values_have_same_authority: subject_values_have_same_authority)
|
235
238
|
case type
|
236
239
|
when 'person'
|
237
240
|
xml.name topic_attributes.merge(type: 'personal') do
|
@@ -395,6 +398,7 @@ module Cocina
|
|
395
398
|
write_name_part(subject_value)
|
396
399
|
write_display_form(display_values)
|
397
400
|
write_roles(subject_value.note)
|
401
|
+
write_identifier(subject.identifier)
|
398
402
|
write_other_notes(subject.note, 'description')
|
399
403
|
write_other_notes(subject.note, 'affiliation')
|
400
404
|
end
|
@@ -427,6 +431,12 @@ module Cocina
|
|
427
431
|
end.each { |role| RoleWriter.write(xml: xml, role: role) }
|
428
432
|
end
|
429
433
|
|
434
|
+
def write_identifier(identifiers)
|
435
|
+
identifiers.each do |identifier|
|
436
|
+
xml.nameIdentifier identifier.value, type: identifier.source.code
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
430
440
|
def write_other_notes(notes, type)
|
431
441
|
Array(notes).filter { |note| note.type == type }.each { |note| xml.public_send(type, note.value) }
|
432
442
|
end
|
@@ -68,7 +68,15 @@ module Cocina
|
|
68
68
|
Date.edtf!(value)
|
69
69
|
true
|
70
70
|
rescue StandardError
|
71
|
-
|
71
|
+
# NOTE: the upstream EDTF implementation in the `edtf` gem does not
|
72
|
+
# allow a valid pattern that we use (possibly because only level
|
73
|
+
# 0 of the spec was implemented?):
|
74
|
+
#
|
75
|
+
# * Y-20555
|
76
|
+
#
|
77
|
+
# So we catch the false positives from the upstream gem and allow
|
78
|
+
# this pattern to validate
|
79
|
+
/\AY-?\d{5,}\Z/.match?(value)
|
72
80
|
end
|
73
81
|
|
74
82
|
def valid_iso8601?(value)
|
@@ -90,7 +98,9 @@ module Cocina
|
|
90
98
|
#
|
91
99
|
# So we catch the false positives from the upstream gem and allow
|
92
100
|
# these two patterns to validate
|
93
|
-
|
101
|
+
#
|
102
|
+
# Also have a temporary exemption for MM/DD/YY
|
103
|
+
%r{\A((\d{4}(-0[1-9]|-1[0-2])?)|(\d{2}/\d{2}/\d{2}))\Z}.match?(value)
|
94
104
|
end
|
95
105
|
|
96
106
|
def druid
|
data/lib/cocina/models.rb
CHANGED
@@ -40,7 +40,7 @@ loader = Zeitwerk::Loader.new
|
|
40
40
|
loader.inflector = CocinaModelsInflector.new
|
41
41
|
loader.push_dir(File.absolute_path("#{__FILE__}/../.."))
|
42
42
|
loader.ignore("#{__dir__}/rspec.rb")
|
43
|
-
loader.ignore("#{__dir__}/rspec
|
43
|
+
loader.ignore("#{__dir__}/rspec")
|
44
44
|
loader.setup
|
45
45
|
|
46
46
|
module Cocina
|
@@ -153,5 +153,12 @@ module Cocina
|
|
153
153
|
raise ValidationError, 'Type field not found'
|
154
154
|
end
|
155
155
|
private_class_method :type_for
|
156
|
+
|
157
|
+
def self.druid_regex
|
158
|
+
@druid_regex ||= begin
|
159
|
+
str = Openapi3Parser.load_file('openapi.yml').components.schemas['Druid'].pattern
|
160
|
+
Regexp.new(str)
|
161
|
+
end
|
162
|
+
end
|
156
163
|
end
|
157
164
|
end
|
data/openapi.yml
CHANGED
@@ -390,7 +390,7 @@ components:
|
|
390
390
|
- catalogRecordId
|
391
391
|
- refresh
|
392
392
|
CatkeyBarcode:
|
393
|
-
description: The barcode associated with a DRO object based on catkey, prefixed with
|
393
|
+
description: The barcode associated with a DRO object based on catkey, prefixed with a catkey followed by a hyphen
|
394
394
|
type: string
|
395
395
|
pattern: '^[0-9]+-[0-9]+$'
|
396
396
|
example: '6772719-1001'
|
@@ -896,8 +896,18 @@ components:
|
|
896
896
|
# description: An alphabet or other notation used to represent a
|
897
897
|
# language or other symbolic system of the descriptive element value.
|
898
898
|
DOI:
|
899
|
-
type: string
|
900
899
|
description: Digital Object Identifier (https://www.doi.org)
|
900
|
+
oneOf:
|
901
|
+
- $ref: '#/components/schemas/DoiPattern'
|
902
|
+
- $ref: '#/components/schemas/DoiExceptions'
|
903
|
+
DoiExceptions:
|
904
|
+
type: string
|
905
|
+
description: pre-existing Digital Object Identifiers (https://www.doi.org) not matching the pattern (case insensitive)
|
906
|
+
pattern: '^10\.(25740\/([vV][aA]90-[cC][tT]15|[sS][yY][xX][aA]-[mM]256|12[qQ][fF]-5243|65[jJ]8-6114)|25936\/629[tT]-[bB][xX]79)$'
|
907
|
+
example: '10.25740/12qF-5243'
|
908
|
+
DoiPattern:
|
909
|
+
type: string
|
910
|
+
description: Digital Object Identifier (https://www.doi.org) regex pattern
|
901
911
|
# The prod and test prefixes are permitted
|
902
912
|
pattern: '^10\.(25740|80343)\/[b-df-hjkmnp-tv-z]{2}[0-9]{3}[b-df-hjkmnp-tv-z]{2}[0-9]{4}$'
|
903
913
|
example: '10.25740/bc123df4567'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cocina-models
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.84.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Coyne
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -339,6 +339,7 @@ files:
|
|
339
339
|
- ".rubocop.yml"
|
340
340
|
- ".rubocop_todo.yml"
|
341
341
|
- Gemfile
|
342
|
+
- Gemfile.lock
|
342
343
|
- README.md
|
343
344
|
- Rakefile
|
344
345
|
- bin/console
|
@@ -397,7 +398,8 @@ files:
|
|
397
398
|
- lib/cocina/models/descriptive_structured_value.rb
|
398
399
|
- lib/cocina/models/descriptive_value.rb
|
399
400
|
- lib/cocina/models/descriptive_value_language.rb
|
400
|
-
- lib/cocina/models/
|
401
|
+
- lib/cocina/models/doi_exceptions.rb
|
402
|
+
- lib/cocina/models/doi_pattern.rb
|
401
403
|
- lib/cocina/models/dro.rb
|
402
404
|
- lib/cocina/models/dro_access.rb
|
403
405
|
- lib/cocina/models/dro_structural.rb
|