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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a36a4c39bf28e6e40d3adccaccf0c89cd14b24c3807c8bde9ac6ee58fcb1b42e
4
- data.tar.gz: 4898c15f9fbe3c6b1b3d3fb33edbe93b4fea5d2c1ca96edd25b91b9166967b29
3
+ metadata.gz: 9cf74f9126fce8106b3bfd5964c11731c460546a4f457da9ba7f35f895243c7a
4
+ data.tar.gz: 58467364ec8a96eac4f6d335dce400c0086833830f5704e263bae7365741d473
5
5
  SHA512:
6
- metadata.gz: 790a2ec388b08ace732d85d27b6544343f658b037791bff63d69527c3baa036073785ff52d4a67a5d483b7bda6da075068f3589db612130df9c15d76b29b7946
7
- data.tar.gz: 9b73c7b24751999006863cb8c181f715ff7ff844b83db3d74b5f94a2297860b2a18b4fc31f41fb2ff5af8654d6e7ef1c6701299142b1b232f8d96b55dcd8f2c4
6
+ metadata.gz: e2106344f663362d1609f5e40daf001c43f976abbbe7ae8a43c52295b2a2e280952c7d6d01b6f6b4cbdf124a07c26372bdfc17f9a903cce666edc39ba3b3db35
7
+ data.tar.gz: 5675d10901a099d8869baed51c4bdb82608305053d0e830130c28577644daddf73a650410cb20425e4e27ff4dfc60188f0e2cb0b77954c49bd3f00980ee56cf1
data/.rubocop.yml CHANGED
@@ -116,6 +116,9 @@ Naming/PredicateName:
116
116
 
117
117
  # ----- RSpec ------
118
118
 
119
+ RSpec/NestedGroups:
120
+ Max: 5
121
+
119
122
  RSpec/BeEq: # new in 2.9.0
120
123
  Enabled: true
121
124
 
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-06-20 05:46:00 UTC using RuboCop version 1.52.1.
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: 87
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: 239
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.91.4)
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.4)
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.1)
100
+ racc (1.7.3)
100
101
  rack (3.0.8)
101
102
  rainbow (3.1.1)
102
- rake (13.0.6)
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.1)
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.29.0)
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.24.1)
143
- rubocop (~> 1.33)
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.2.2)
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)
@@ -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
@@ -363,6 +363,8 @@ _Path: identifier.type_
363
363
  * document number
364
364
  * DOI
365
365
  * druid
366
+ * FOLIO
367
+ * FOLIO HRID for the source record of the metadata.
366
368
  * GTIN-14 ID
367
369
  * Handle
368
370
  * inventory number
@@ -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, Types::Strict::String
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 })
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocina
4
+ module Models
5
+ FileUse = Types::String
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocina
4
+ module Models
5
+ LanguageTag = Types::String
6
+ end
7
+ end
@@ -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
- attribute? :use, Types::Strict::String
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
- @error_paths = []
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
- return if error_paths.empty?
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, :error_paths
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
- validate_values(hash, path)
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 validate_values(hash, path)
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
- error_paths << path_to_s(path)
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
@@ -15,7 +15,8 @@ module Cocina
15
15
  # See also spec/cocina/models/validatable_spec.rb:59
16
16
  # DescriptionTypesValidator,
17
17
  DescriptionValuesValidator,
18
- DateTimeValidator
18
+ DateTimeValidator,
19
+ LanguageTagValidator
19
20
  ].freeze
20
21
 
21
22
  def self.validate(clazz, attributes)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Cocina
4
4
  module Models
5
- VERSION = '0.91.4'
5
+ VERSION = '0.93.0'
6
6
  end
7
7
  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
- description: Use for the File.
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
- type: string
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.91.4
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-10-18 00:00:00.000000000 Z
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.3.7
565
+ rubygems_version: 3.4.19
549
566
  signing_key:
550
567
  specification_version: 4
551
568
  summary: Data models for the SDR