cocina-models 0.91.4 → 0.93.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/.rubocop_todo.yml +3 -10
- data/Gemfile.lock +10 -10
- data/cocina-models.gemspec +1 -0
- data/docs/description_types.md +2 -0
- data/lib/cocina/models/file.rb +3 -1
- data/lib/cocina/models/file_use.rb +7 -0
- data/lib/cocina/models/language_tag.rb +7 -0
- data/lib/cocina/models/request_file.rb +4 -1
- data/lib/cocina/models/validators/dark_validator.rb +1 -6
- data/lib/cocina/models/validators/description_values_validator.rb +15 -8
- data/lib/cocina/models/validators/language_tag_validator.rb +74 -0
- data/lib/cocina/models/validators/validator.rb +2 -1
- data/lib/cocina/models/version.rb +1 -1
- data/openapi.yml +14 -3
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9cf74f9126fce8106b3bfd5964c11731c460546a4f457da9ba7f35f895243c7a
|
4
|
+
data.tar.gz: 58467364ec8a96eac4f6d335dce400c0086833830f5704e263bae7365741d473
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2106344f663362d1609f5e40daf001c43f976abbbe7ae8a43c52295b2a2e280952c7d6d01b6f6b4cbdf124a07c26372bdfc17f9a903cce666edc39ba3b3db35
|
7
|
+
data.tar.gz: 5675d10901a099d8869baed51c4bdb82608305053d0e830130c28577644daddf73a650410cb20425e4e27ff4dfc60188f0e2cb0b77954c49bd3f00980ee56cf1
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config --auto-gen-only-exclude`
|
3
|
-
# on 2023-
|
3
|
+
# on 2023-11-01 19:51:40 UTC using RuboCop version 1.57.2.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
@@ -57,18 +57,11 @@ Metrics/ParameterLists:
|
|
57
57
|
RSpec/DescribeClass:
|
58
58
|
Enabled: false
|
59
59
|
|
60
|
-
# Offense count:
|
60
|
+
# Offense count: 224
|
61
61
|
# Configuration parameters: CountAsOne.
|
62
62
|
RSpec/ExampleLength:
|
63
63
|
Max: 103
|
64
64
|
|
65
|
-
# Offense count: 10
|
66
|
-
# Configuration parameters: Max, AllowedGroups.
|
67
|
-
RSpec/NestedGroups:
|
68
|
-
Exclude:
|
69
|
-
- 'spec/cocina/models/mapping/normalizers/mods/origin_info_normalizer_spec.rb'
|
70
|
-
- 'spec/cocina/models/validators/date_time_validator_spec.rb'
|
71
|
-
|
72
65
|
# Offense count: 19
|
73
66
|
RSpec/PendingWithoutReason:
|
74
67
|
Exclude:
|
@@ -99,7 +92,7 @@ Style/MultilineBlockChain:
|
|
99
92
|
- 'lib/cocina/models/mapping/to_mods/form.rb'
|
100
93
|
- 'lib/cocina/models/mapping/to_mods/subject.rb'
|
101
94
|
|
102
|
-
# Offense count:
|
95
|
+
# Offense count: 249
|
103
96
|
# This cop supports safe autocorrection (--autocorrect).
|
104
97
|
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
|
105
98
|
# URISchemes: http, https
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cocina-models (0.
|
4
|
+
cocina-models (0.93.0)
|
5
5
|
activesupport
|
6
6
|
deprecation
|
7
7
|
dry-struct (~> 1.0)
|
8
8
|
dry-types (~> 1.1)
|
9
9
|
edtf
|
10
10
|
equivalent-xml
|
11
|
+
i18n
|
11
12
|
jsonpath
|
12
13
|
nokogiri
|
13
14
|
openapi3_parser
|
@@ -79,7 +80,7 @@ GEM
|
|
79
80
|
jsonpath (1.1.5)
|
80
81
|
multi_json
|
81
82
|
language_server-protocol (3.17.0.3)
|
82
|
-
mini_portile2 (2.8.
|
83
|
+
mini_portile2 (2.8.5)
|
83
84
|
minitest (5.20.0)
|
84
85
|
multi_json (1.15.0)
|
85
86
|
mutex_m (0.1.2)
|
@@ -96,10 +97,10 @@ GEM
|
|
96
97
|
racc
|
97
98
|
patience_diff (1.2.0)
|
98
99
|
optimist (~> 3.0)
|
99
|
-
racc (1.7.
|
100
|
+
racc (1.7.3)
|
100
101
|
rack (3.0.8)
|
101
102
|
rainbow (3.1.1)
|
102
|
-
rake (13.0
|
103
|
+
rake (13.1.0)
|
103
104
|
regexp_parser (2.8.2)
|
104
105
|
rexml (3.2.6)
|
105
106
|
rspec (3.12.0)
|
@@ -119,8 +120,7 @@ GEM
|
|
119
120
|
rspec-core (>= 2, < 4, != 2.12.0)
|
120
121
|
rss (0.3.0)
|
121
122
|
rexml
|
122
|
-
rubocop (1.57.
|
123
|
-
base64 (~> 0.1.1)
|
123
|
+
rubocop (1.57.2)
|
124
124
|
json (~> 2.3)
|
125
125
|
language_server-protocol (>= 3.17.0)
|
126
126
|
parallel (~> 1.10)
|
@@ -131,7 +131,7 @@ GEM
|
|
131
131
|
rubocop-ast (>= 1.28.1, < 2.0)
|
132
132
|
ruby-progressbar (~> 1.7)
|
133
133
|
unicode-display_width (>= 2.4.0, < 3.0)
|
134
|
-
rubocop-ast (1.
|
134
|
+
rubocop-ast (1.30.0)
|
135
135
|
parser (>= 3.2.1.0)
|
136
136
|
rubocop-capybara (2.19.0)
|
137
137
|
rubocop (~> 1.41)
|
@@ -139,8 +139,8 @@ GEM
|
|
139
139
|
rubocop (~> 1.33)
|
140
140
|
rubocop-rake (0.6.0)
|
141
141
|
rubocop (~> 1.0)
|
142
|
-
rubocop-rspec (2.
|
143
|
-
rubocop (~> 1.
|
142
|
+
rubocop-rspec (2.25.0)
|
143
|
+
rubocop (~> 1.40)
|
144
144
|
rubocop-capybara (~> 2.17)
|
145
145
|
rubocop-factory_bot (~> 2.22)
|
146
146
|
ruby-progressbar (1.13.0)
|
@@ -155,7 +155,7 @@ GEM
|
|
155
155
|
attr_extras (>= 6.2.4)
|
156
156
|
diff-lcs
|
157
157
|
patience_diff
|
158
|
-
thor (1.
|
158
|
+
thor (1.3.0)
|
159
159
|
tzinfo (2.0.6)
|
160
160
|
concurrent-ruby (~> 1.0)
|
161
161
|
unicode-display_width (2.5.0)
|
data/cocina-models.gemspec
CHANGED
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_dependency 'dry-types', '~> 1.1'
|
31
31
|
spec.add_dependency 'edtf' # used for date/time validation
|
32
32
|
spec.add_dependency 'equivalent-xml' # for diffing MODS
|
33
|
+
spec.add_dependency 'i18n' # for validating BCP 47 language tags, according to RFC 4646
|
33
34
|
spec.add_dependency 'jsonpath' # used for date/time validation
|
34
35
|
spec.add_dependency 'nokogiri'
|
35
36
|
spec.add_dependency 'openapi3_parser' # Parsing openapi doc
|
data/docs/description_types.md
CHANGED
data/lib/cocina/models/file.rb
CHANGED
@@ -22,8 +22,10 @@ module Cocina
|
|
22
22
|
attribute :version, Types::Strict::Integer
|
23
23
|
# MIME Type of the File.
|
24
24
|
attribute? :hasMimeType, Types::Strict::String
|
25
|
+
# BCP 47 language tag: https://www.rfc-editor.org/rfc/rfc4646.txt -- other applications (like media players) expect language codes of this format, see e.g. https://videojs.com/guides/text-tracks/#srclang
|
26
|
+
attribute? :languageTag, LanguageTag.optional
|
25
27
|
# Use for the File.
|
26
|
-
attribute? :use,
|
28
|
+
attribute? :use, FileUse.optional
|
27
29
|
attribute :hasMessageDigests, Types::Strict::Array.of(MessageDigest).default([].freeze)
|
28
30
|
attribute(:access, FileAccess.default { FileAccess.new })
|
29
31
|
attribute(:administrative, FileAdministrative.default { FileAdministrative.new })
|
@@ -13,8 +13,11 @@ module Cocina
|
|
13
13
|
attribute? :size, Types::Strict::Integer
|
14
14
|
attribute :version, Types::Strict::Integer
|
15
15
|
attribute? :hasMimeType, Types::Strict::String
|
16
|
+
# BCP 47 language tag: https://www.rfc-editor.org/rfc/rfc4646.txt -- other applications (like media players) expect language codes of this format, see e.g. https://videojs.com/guides/text-tracks/#srclang
|
17
|
+
attribute? :languageTag, LanguageTag.optional
|
16
18
|
attribute? :externalIdentifier, Types::Strict::String
|
17
|
-
|
19
|
+
# Use for the File.
|
20
|
+
attribute? :use, FileUse.optional
|
18
21
|
attribute :hasMessageDigests, Types::Strict::Array.of(MessageDigest).default([].freeze)
|
19
22
|
attribute(:access, FileAccess.default { FileAccess.new })
|
20
23
|
attribute(:administrative, FileAdministrative.default { FileAdministrative.new })
|
@@ -39,12 +39,7 @@ module Cocina
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def invalid_files
|
42
|
-
@invalid_files ||=
|
43
|
-
[].tap do |invalid_files|
|
44
|
-
files.each do |file|
|
45
|
-
invalid_files << file if invalid?(file)
|
46
|
-
end
|
47
|
-
end
|
42
|
+
@invalid_files ||= files.select { |file| invalid?(file) }
|
48
43
|
end
|
49
44
|
|
50
45
|
def invalid_filenames
|
@@ -12,7 +12,8 @@ module Cocina
|
|
12
12
|
def initialize(clazz, attributes)
|
13
13
|
@clazz = clazz
|
14
14
|
@attributes = attributes
|
15
|
-
@
|
15
|
+
@error_paths_multiple = []
|
16
|
+
@error_paths_blank = []
|
16
17
|
end
|
17
18
|
|
18
19
|
def validate
|
@@ -20,21 +21,21 @@ module Cocina
|
|
20
21
|
|
21
22
|
validate_obj(attributes, [])
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
raise ValidationError, "Multiple value, groupedValue, structuredValue, and parallelValue in description: #{error_paths.join(', ')}"
|
24
|
+
raise ValidationError, "Multiple value, groupedValue, structuredValue, and parallelValue in description: #{error_paths_multiple.join(', ')}" unless error_paths_multiple.empty?
|
25
|
+
raise ValidationError, "Blank value in description: #{error_paths_blank.join(', ')}" unless error_paths_blank.empty?
|
26
26
|
end
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
-
attr_reader :clazz, :attributes, :
|
30
|
+
attr_reader :clazz, :attributes, :error_paths_blank, :error_paths_multiple
|
31
31
|
|
32
32
|
def meets_preconditions?
|
33
33
|
[Cocina::Models::Description, Cocina::Models::RequestDescription].include?(clazz)
|
34
34
|
end
|
35
35
|
|
36
36
|
def validate_hash(hash, path)
|
37
|
-
|
37
|
+
validate_values_for_blanks(hash, path)
|
38
|
+
validate_values_for_multiples(hash, path)
|
38
39
|
hash.each do |key, obj|
|
39
40
|
validate_obj(obj, path + [key])
|
40
41
|
end
|
@@ -51,10 +52,16 @@ module Cocina
|
|
51
52
|
validate_array(obj, path) if obj.is_a?(Array)
|
52
53
|
end
|
53
54
|
|
54
|
-
def
|
55
|
+
def validate_values_for_blanks(hash, path)
|
56
|
+
return unless hash[:value] && hash[:value].is_a?(String) && /\A\s+\z/.match?(hash[:value]) # rubocop:disable Style/SafeNavigation
|
57
|
+
|
58
|
+
error_paths_blank << path_to_s(path)
|
59
|
+
end
|
60
|
+
|
61
|
+
def validate_values_for_multiples(hash, path)
|
55
62
|
return unless hash.count { |key, value| %i[value groupedValue structuredValue parallelValue].include?(key) && value.present? } > 1
|
56
63
|
|
57
|
-
|
64
|
+
error_paths_multiple << path_to_s(path)
|
58
65
|
end
|
59
66
|
|
60
67
|
def path_to_s(path)
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cocina
|
4
|
+
module Models
|
5
|
+
module Validators
|
6
|
+
# Validates that a languageTag is valid according to RFC 4646, if one is present
|
7
|
+
class LanguageTagValidator
|
8
|
+
def self.validate(clazz, attributes)
|
9
|
+
new(clazz, attributes).validate
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(clazz, attributes)
|
13
|
+
@clazz = clazz
|
14
|
+
@attributes = attributes
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate
|
18
|
+
return unless meets_preconditions?
|
19
|
+
|
20
|
+
return if invalid_files.empty?
|
21
|
+
|
22
|
+
raise ValidationError, 'Some files have invalid language tags according to RFC 4646: ' \
|
23
|
+
"#{invalid_filenames_with_language_tags.join(', ')}"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :clazz, :attributes
|
29
|
+
|
30
|
+
def meets_preconditions?
|
31
|
+
dro?
|
32
|
+
end
|
33
|
+
|
34
|
+
def dro?
|
35
|
+
(clazz::TYPES & DRO::TYPES).any?
|
36
|
+
rescue NameError
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
40
|
+
def valid_language_tag?(file)
|
41
|
+
# I18n::Locale::Tag::Rfc4646.tag will return an instance of I18n::Locale::Tag::Rfc4646 (with fields like language, script,
|
42
|
+
# region) for strings that can be parsed according to RFC 4646, and nil for strings that do not conform to the spec.
|
43
|
+
I18n::Locale::Tag::Rfc4646.tag(file[:languageTag]).present?
|
44
|
+
end
|
45
|
+
|
46
|
+
def invalid_files
|
47
|
+
@invalid_files ||= language_tag_files.reject { |file| valid_language_tag?(file) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def invalid_filenames_with_language_tags
|
51
|
+
invalid_files.map { |invalid_file| "#{invalid_file[:filename] || invalid_file[:label]} (#{invalid_file[:languageTag]})" }
|
52
|
+
end
|
53
|
+
|
54
|
+
def language_tag_files
|
55
|
+
files.select { |file| file[:languageTag].present? }
|
56
|
+
end
|
57
|
+
|
58
|
+
def files
|
59
|
+
[].tap do |files|
|
60
|
+
next if attributes.dig(:structural, :contains).nil?
|
61
|
+
|
62
|
+
attributes[:structural][:contains].each do |fileset|
|
63
|
+
next if fileset.dig(:structural, :contains).nil?
|
64
|
+
|
65
|
+
fileset[:structural][:contains].each do |file|
|
66
|
+
files << file
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/openapi.yml
CHANGED
@@ -1044,9 +1044,10 @@ components:
|
|
1044
1044
|
hasMimeType:
|
1045
1045
|
description: MIME Type of the File.
|
1046
1046
|
type: string
|
1047
|
+
languageTag:
|
1048
|
+
$ref: '#/components/schemas/LanguageTag'
|
1047
1049
|
use:
|
1048
|
-
|
1049
|
-
type: string
|
1050
|
+
$ref: '#/components/schemas/FileUse'
|
1050
1051
|
hasMessageDigests:
|
1051
1052
|
type: array
|
1052
1053
|
items:
|
@@ -1141,6 +1142,10 @@ components:
|
|
1141
1142
|
type: array
|
1142
1143
|
items:
|
1143
1144
|
$ref: '#/components/schemas/File'
|
1145
|
+
FileUse:
|
1146
|
+
description: Use for the File.
|
1147
|
+
type: string
|
1148
|
+
nullable: true
|
1144
1149
|
FolioCatalogLink:
|
1145
1150
|
description: A linkage between an object and a Folio catalog record
|
1146
1151
|
type: object
|
@@ -1269,6 +1274,10 @@ components:
|
|
1269
1274
|
valueLanguage:
|
1270
1275
|
# description: present for mapping to additional schemas in the future and for consistency but not otherwise used
|
1271
1276
|
$ref: "#/components/schemas/DescriptiveValueLanguage"
|
1277
|
+
LanguageTag:
|
1278
|
+
description: "BCP 47 language tag: https://www.rfc-editor.org/rfc/rfc4646.txt -- other applications (like media players) expect language codes of this format, see e.g. https://videojs.com/guides/text-tracks/#srclang"
|
1279
|
+
type: string
|
1280
|
+
nullable: true
|
1272
1281
|
License:
|
1273
1282
|
description: The license governing reuse of the DRO. Should be an IRI for known licenses (i.e. CC, RightsStatement.org URI, etc.).
|
1274
1283
|
type: string
|
@@ -1775,10 +1784,12 @@ components:
|
|
1775
1784
|
type: integer
|
1776
1785
|
hasMimeType:
|
1777
1786
|
type: string
|
1787
|
+
languageTag:
|
1788
|
+
$ref: '#/components/schemas/LanguageTag'
|
1778
1789
|
externalIdentifier:
|
1779
1790
|
type: string
|
1780
1791
|
use:
|
1781
|
-
|
1792
|
+
$ref: '#/components/schemas/FileUse'
|
1782
1793
|
hasMessageDigests:
|
1783
1794
|
type: array
|
1784
1795
|
items:
|
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.93.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Coyne
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: i18n
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: jsonpath
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -415,11 +429,13 @@ files:
|
|
415
429
|
- lib/cocina/models/file_set.rb
|
416
430
|
- lib/cocina/models/file_set_structural.rb
|
417
431
|
- lib/cocina/models/file_set_type.rb
|
432
|
+
- lib/cocina/models/file_use.rb
|
418
433
|
- lib/cocina/models/folio_catalog_link.rb
|
419
434
|
- lib/cocina/models/geographic.rb
|
420
435
|
- lib/cocina/models/identification.rb
|
421
436
|
- lib/cocina/models/lane_medical_barcode.rb
|
422
437
|
- lib/cocina/models/language.rb
|
438
|
+
- lib/cocina/models/language_tag.rb
|
423
439
|
- lib/cocina/models/license.rb
|
424
440
|
- lib/cocina/models/location_based_access.rb
|
425
441
|
- lib/cocina/models/location_based_download_access.rb
|
@@ -516,6 +532,7 @@ files:
|
|
516
532
|
- lib/cocina/models/validators/date_time_validator.rb
|
517
533
|
- lib/cocina/models/validators/description_types_validator.rb
|
518
534
|
- lib/cocina/models/validators/description_values_validator.rb
|
535
|
+
- lib/cocina/models/validators/language_tag_validator.rb
|
519
536
|
- lib/cocina/models/validators/open_api_validator.rb
|
520
537
|
- lib/cocina/models/validators/purl_validator.rb
|
521
538
|
- lib/cocina/models/validators/validator.rb
|
@@ -545,7 +562,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
545
562
|
- !ruby/object:Gem::Version
|
546
563
|
version: '0'
|
547
564
|
requirements: []
|
548
|
-
rubygems_version: 3.
|
565
|
+
rubygems_version: 3.4.19
|
549
566
|
signing_key:
|
550
567
|
specification_version: 4
|
551
568
|
summary: Data models for the SDR
|