cocina-models 0.110.0 → 0.110.1
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/Gemfile.lock +2 -2
- data/lib/cocina/models/mapping/from_marc/contributor.rb +0 -2
- data/lib/cocina/models/mapping/from_marc/description_builder.rb +1 -1
- data/lib/cocina/models/mapping/from_marc/event.rb +25 -8
- data/lib/cocina/models/mapping/from_marc/note.rb +5 -5
- data/lib/cocina/models/mapping/from_marc/related_resource.rb +169 -0
- data/lib/cocina/models/mapping/from_marc/util.rb +6 -2
- data/lib/cocina/models/version.rb +1 -1
- data/lib/cocina/models.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9ba030653ba2790a20c4d071881472d3889bb4739c3c4637bb68d11d4c320207
|
|
4
|
+
data.tar.gz: 1f5d68d708a345aaf833908dca817af1c5c8499723d7f5194e2b0097817cb3a5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 796ab6c265801899f9b31ff131313d413133fbaf2829e2899dd0535a616345af723201d76aca3cecd4e9efaab5c2afa3151a5281a32cfb3adb46ece694378a13
|
|
7
|
+
data.tar.gz: 6ef1fc9300e553734fe55bc59b2cee35d80020e80b6539990ceb81d9c6f809e48449995fe6d0173ac9cf1d2a46d1aa264bfd86afa0c587999b7ae927590e84f9
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
cocina-models (0.110.
|
|
4
|
+
cocina-models (0.110.1)
|
|
5
5
|
activesupport
|
|
6
6
|
deprecation
|
|
7
7
|
dry-struct (~> 1.0)
|
|
@@ -211,7 +211,7 @@ CHECKSUMS
|
|
|
211
211
|
attr_extras (7.1.0) sha256=d96fc9a9dd5d85ba2d37762440a816f840093959ae26bb90da994c2d9f1fc827
|
|
212
212
|
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
|
|
213
213
|
bigdecimal (4.0.1) sha256=8b07d3d065a9f921c80ceaea7c9d4ae596697295b584c296fe599dd0ad01c4a7
|
|
214
|
-
cocina-models (0.110.
|
|
214
|
+
cocina-models (0.110.1)
|
|
215
215
|
concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab
|
|
216
216
|
connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
|
|
217
217
|
date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
|
|
@@ -19,19 +19,15 @@ module Cocina
|
|
|
19
19
|
|
|
20
20
|
# @return [Array<Hash>] an array of event hashes
|
|
21
21
|
def build
|
|
22
|
-
linked_264_field = Util.linked_field(marc, marc['264']) if marc['264']
|
|
23
22
|
[
|
|
24
23
|
publication_from008,
|
|
25
24
|
publication(marc['260']),
|
|
26
25
|
manufacture(marc['260']),
|
|
27
|
-
|
|
28
26
|
production(marc['264']),
|
|
29
|
-
production(linked_264_field),
|
|
30
|
-
|
|
31
27
|
edition_statement(marc['250']),
|
|
32
28
|
frequency_statement(marc['310']),
|
|
33
29
|
mode_of_issuance(marc['334'])
|
|
34
|
-
].compact
|
|
30
|
+
].flatten.compact
|
|
35
31
|
end
|
|
36
32
|
|
|
37
33
|
MARC_264_INDICATOR2 = {
|
|
@@ -69,6 +65,13 @@ module Cocina
|
|
|
69
65
|
def production(field)
|
|
70
66
|
return unless field
|
|
71
67
|
|
|
68
|
+
fields = [build_production(field)]
|
|
69
|
+
alt_script_field = Util.linked_field(marc, field)
|
|
70
|
+
fields << build_production(alt_script_field) if alt_script_field
|
|
71
|
+
fields
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def build_production(field)
|
|
72
75
|
indicator = MARC_264_INDICATOR2.fetch(field.indicator2)
|
|
73
76
|
return copyright(field) if indicator[:type] == 'copyright notice'
|
|
74
77
|
|
|
@@ -95,6 +98,13 @@ module Cocina
|
|
|
95
98
|
def edition_statement(field)
|
|
96
99
|
return unless field
|
|
97
100
|
|
|
101
|
+
fields = [build_edition_statement(field)]
|
|
102
|
+
alt_script_field = Util.linked_field(marc, field)
|
|
103
|
+
fields << build_edition_statement(alt_script_field) if alt_script_field
|
|
104
|
+
fields
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def build_edition_statement(field)
|
|
98
108
|
statement = field.subfields.select { %w[a b].include? it.code }.map(&:value).join(' ')
|
|
99
109
|
{ type: 'publication', note: [{ value: statement, type: 'edition' }]}
|
|
100
110
|
end
|
|
@@ -116,13 +126,20 @@ module Cocina
|
|
|
116
126
|
def publication(field)
|
|
117
127
|
return unless field
|
|
118
128
|
|
|
119
|
-
|
|
129
|
+
fields = [build_publication(field)]
|
|
130
|
+
alt_script_field = Util.linked_field(marc, field)
|
|
131
|
+
fields << build_publication(alt_script_field) if alt_script_field
|
|
132
|
+
fields
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def build_publication(field)
|
|
136
|
+
publication_places = field.subfields.filter_map { Util.strip_punctuation(it.value) if it.code == 'a' }
|
|
120
137
|
publisher = field.subfields.find { it.code == 'b' }&.value
|
|
121
138
|
publication_date = field.subfields.find { it.code == 'c' }.value.delete_suffix('.')
|
|
122
139
|
|
|
123
140
|
{
|
|
124
141
|
type: 'publication',
|
|
125
|
-
place:
|
|
142
|
+
place: publication_places.map { { value: it } },
|
|
126
143
|
contributor: [{ name: [{ value: Util.strip_punctuation(publisher) }], role: [{ value: 'publisher' }] }],
|
|
127
144
|
date: [{ value: publication_date, type: 'publication' }]
|
|
128
145
|
}
|
|
@@ -133,9 +150,9 @@ module Cocina
|
|
|
133
150
|
|
|
134
151
|
manufacture_place = field.subfields.find { |subfield| subfield.code == 'e' }&.value
|
|
135
152
|
manufacturer = field.subfields.find { |subfield| subfield.code == 'f' }&.value
|
|
136
|
-
manufacture_date = field.subfields.find { |subfield| subfield.code == 'g' }&.value
|
|
137
153
|
return nil unless manufacture_place || manufacturer
|
|
138
154
|
|
|
155
|
+
manufacture_date = field.subfields.find { |subfield| subfield.code == 'g' }&.value
|
|
139
156
|
{
|
|
140
157
|
type: 'manufacture',
|
|
141
158
|
place: [{ value: Util.strip_punctuation(manufacture_place) }],
|
|
@@ -37,7 +37,7 @@ module Cocina
|
|
|
37
37
|
'530' => { codes: %w[a b c d u 3], type: 'additional physical form' },
|
|
38
38
|
'532' => %w[a 3],
|
|
39
39
|
'533' => { codes: %w[a b c d e f m n y 3], type: 'reproduction' },
|
|
40
|
-
'534' => %w[
|
|
40
|
+
'534' => %w[a b c e f k l m n o p t x z 3],
|
|
41
41
|
'535' => { codes: %w[3 a b c d g], type: 'original location' },
|
|
42
42
|
'536' => { codes: %w[a b c d e f g h], type: 'funding' },
|
|
43
43
|
'538' => { codes: ['a'], type: 'system details' },
|
|
@@ -50,18 +50,18 @@ module Cocina
|
|
|
50
50
|
'547' => ['a'],
|
|
51
51
|
'550' => ['a'],
|
|
52
52
|
'552' => %w[a b c d e f g h i j k l m n o p u z],
|
|
53
|
-
'555' => %w[
|
|
53
|
+
'555' => %w[a b c d u 3],
|
|
54
54
|
'556' => %w[a z],
|
|
55
55
|
'561' => { codes: %w[a u 3], type: 'ownership' },
|
|
56
|
-
'562' => { codes: %w[
|
|
56
|
+
'562' => { codes: %w[a b c d e 3], type: 'version identification' },
|
|
57
57
|
'563' => { codes: %w[a u 3], type: 'binding' },
|
|
58
58
|
'565' => %w[a b c d e 3],
|
|
59
59
|
'567' => %w[a b],
|
|
60
60
|
'580' => ['a'],
|
|
61
61
|
'581' => { codes: %w[a z 3], type: 'publications' },
|
|
62
|
-
'583' => { codes: %w[
|
|
62
|
+
'583' => { codes: %w[a b c d e f h i j k l n o u z 3], type: 'action' },
|
|
63
63
|
'584' => %w[3 a b 3],
|
|
64
|
-
'585' => { codes: %w[
|
|
64
|
+
'585' => { codes: %w[a 3], type: 'exhibitions' },
|
|
65
65
|
'586' => %w[a 3],
|
|
66
66
|
'588' => ['a'],
|
|
67
67
|
'590' => ['a'],
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cocina
|
|
4
|
+
module Models
|
|
5
|
+
module Mapping
|
|
6
|
+
module FromMarc
|
|
7
|
+
# Maps relatedResource information from MARC records to Cocina models.
|
|
8
|
+
class RelatedResource # rubocop:disable Metrics/ClassLength
|
|
9
|
+
# @see #initialize
|
|
10
|
+
# @see #build
|
|
11
|
+
def self.build(...)
|
|
12
|
+
new(...).build
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @param [MARC::Record] marc MARC record from FOLIO
|
|
16
|
+
def initialize(marc:)
|
|
17
|
+
@marc = marc
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @return [Array<Hash>] an array of relatedResource hashes
|
|
21
|
+
def build
|
|
22
|
+
[
|
|
23
|
+
in_series(marc['490']),
|
|
24
|
+
marc.fields.select { it.tag == '700' }.map { has_part(it) }.compact,
|
|
25
|
+
marc.fields.select { it.tag == '700' }.map { related_title(it) }.compact,
|
|
26
|
+
has_part_corporate(marc['710']),
|
|
27
|
+
related_to_meeting(marc['711'])
|
|
28
|
+
].flatten.compact_blank
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def in_series(field)
|
|
34
|
+
return unless field
|
|
35
|
+
|
|
36
|
+
{ type: 'in series', title: [field['3'], field['a'], field['v'], field['l'], field['x']].join(' ') }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def has_part(field) # rubocop:disable Naming/PredicatePrefix
|
|
40
|
+
return unless field && field.indicator2 == '2' && field['t']
|
|
41
|
+
|
|
42
|
+
contributor = if field.indicator1 == '3'
|
|
43
|
+
family_contributor(field)
|
|
44
|
+
else
|
|
45
|
+
person_contributor(field)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
body_has_part(field, contributor)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def has_part_corporate(field) # rubocop:disable Naming/PredicatePrefix
|
|
52
|
+
return unless field && field.indicator2 == '2' && field['t']
|
|
53
|
+
|
|
54
|
+
contributor = corporate_contributor(field)
|
|
55
|
+
body_has_part(field, contributor)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def body_has_part(field, contributor)
|
|
59
|
+
{
|
|
60
|
+
type: 'has part',
|
|
61
|
+
displayLabel: field['i'],
|
|
62
|
+
title: [
|
|
63
|
+
{
|
|
64
|
+
value: [field['t'], field['f'], field['g'], field['k'], field['l'], field['m'], field['n'], field['p'], field['o'], field['r'], field['s']].compact.join(' ')
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
contributor: [contributor]
|
|
68
|
+
}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def related_title(field)
|
|
72
|
+
return unless field && field.indicator2 != '2' && field['t']
|
|
73
|
+
|
|
74
|
+
linked = Util.linked_field(marc, field)
|
|
75
|
+
vals = [build_related_title(field)]
|
|
76
|
+
vals << build_related_title(linked) if linked
|
|
77
|
+
vals
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def build_related_title(field)
|
|
81
|
+
contributor = if field.indicator1 == '3'
|
|
82
|
+
family_contributor(field)
|
|
83
|
+
else
|
|
84
|
+
person_contributor(field)
|
|
85
|
+
end
|
|
86
|
+
body_related_to(field, contributor)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def related_to_meeting(field)
|
|
90
|
+
return unless field && field.indicator2 != '2' && field['t']
|
|
91
|
+
|
|
92
|
+
contributor = meeting_contributor(field)
|
|
93
|
+
body_related_to(field, contributor)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def body_related_to(field, contributor)
|
|
97
|
+
{
|
|
98
|
+
type: 'related to',
|
|
99
|
+
displayLabel: field['i'],
|
|
100
|
+
title: [
|
|
101
|
+
{
|
|
102
|
+
value: [field['t'], field['f'], field['g'], field['k'], field['l'], field['m'], field['n'], field['p'], field['o'], field['r'], field['s']].compact.join(' ')
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
contributor: [
|
|
106
|
+
contributor
|
|
107
|
+
]
|
|
108
|
+
}.compact
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def person_contributor(field)
|
|
112
|
+
name = field.subfields.filter_map { it.value if %w[a b c d j q].include?(it.code) }.join(' ').delete_suffix(',')
|
|
113
|
+
{
|
|
114
|
+
type: 'person',
|
|
115
|
+
|
|
116
|
+
name: [{ value: name }],
|
|
117
|
+
affiliation: [{ value: field['u'] }.compact].compact_blank,
|
|
118
|
+
role: [{ value: field['e']&.delete_suffix('.') }.compact].compact_blank,
|
|
119
|
+
identifier: [{ uri: field['1'] }.compact].compact_blank
|
|
120
|
+
}.compact_blank
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def family_contributor(field)
|
|
124
|
+
{
|
|
125
|
+
type: 'family',
|
|
126
|
+
name: [
|
|
127
|
+
{
|
|
128
|
+
value: [field['a'], field['b'], field['c'], field['d'], field['j'], field['q']].compact.join(' ').delete_suffix(',')
|
|
129
|
+
}
|
|
130
|
+
],
|
|
131
|
+
affiliation: [{ value: field['u'] }.compact].compact_blank,
|
|
132
|
+
role: [{ value: field['e']&.delete_suffix('.') }.compact].compact_blank,
|
|
133
|
+
identifier: [{ uri: field['1'] }.compact].compact_blank
|
|
134
|
+
}.compact_blank
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def corporate_contributor(field)
|
|
138
|
+
{
|
|
139
|
+
type: 'organization',
|
|
140
|
+
name: [
|
|
141
|
+
{
|
|
142
|
+
value: [field['a'], field['b'], field['c'], field['d']].compact.join(' ').delete_suffix(',')
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
role: [{ value: field['e']&.delete_suffix('.') }.compact].compact_blank,
|
|
146
|
+
identifier: [{ uri: field['1'] }.compact].compact_blank
|
|
147
|
+
}.compact_blank
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def meeting_contributor(field)
|
|
151
|
+
{
|
|
152
|
+
type: 'organization',
|
|
153
|
+
name: [
|
|
154
|
+
{
|
|
155
|
+
value: [field['a'], field['b'], field['c'], field['d'], field['e'], field['q']].compact.join(' ').delete_suffix(',')
|
|
156
|
+
}
|
|
157
|
+
],
|
|
158
|
+
affiliation: [{ value: field['u'] }.compact].compact_blank,
|
|
159
|
+
role: [{ value: field['j']&.delete_suffix('.') }.compact].compact_blank,
|
|
160
|
+
identifier: [{ uri: field['1'] }.compact].compact_blank
|
|
161
|
+
}.compact_blank
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
attr_reader :marc
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
@@ -13,12 +13,16 @@ module Cocina
|
|
|
13
13
|
value.gsub(regex, '')
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
# Parse a MARC 880$6
|
|
17
|
+
# See https://www.loc.gov/marc/bibliographic/ecbdcntf.html
|
|
16
18
|
def self.linked_field(marc, field)
|
|
17
19
|
pointer = field.subfields.find { |subfield| subfield.code == '6' }
|
|
18
20
|
return unless pointer
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
# Subfield $6 is formatted thusly:
|
|
23
|
+
# $6 [linking tag]-[occurrence number]/[script identification code]/[field orientation code]
|
|
24
|
+
linking_tag, occurrence_number = pointer.value.split(%r{-|/})
|
|
25
|
+
marc.fields(linking_tag)[occurrence_number.to_i - 1]
|
|
22
26
|
end
|
|
23
27
|
end
|
|
24
28
|
end
|
data/lib/cocina/models.rb
CHANGED
|
@@ -23,6 +23,7 @@ class CocinaModelsInflector < Zeitwerk::Inflector
|
|
|
23
23
|
'dro_structural' => 'DROStructural',
|
|
24
24
|
'dro_with_metadata' => 'DROWithMetadata',
|
|
25
25
|
'libraries_doi' => 'LibrariesDOI',
|
|
26
|
+
'marc_relators' => 'MARC_RELATORS',
|
|
26
27
|
'preregistered_repository_doi' => 'PreregisteredRepositoryDOI',
|
|
27
28
|
'repository_doi' => 'RepositoryDOI',
|
|
28
29
|
'request_dro' => 'RequestDRO',
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cocina-models
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.110.
|
|
4
|
+
version: 0.110.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Coyne
|
|
@@ -431,6 +431,7 @@ files:
|
|
|
431
431
|
- lib/cocina/models/mapping/from_marc/language.rb
|
|
432
432
|
- lib/cocina/models/mapping/from_marc/marc_relators.rb
|
|
433
433
|
- lib/cocina/models/mapping/from_marc/note.rb
|
|
434
|
+
- lib/cocina/models/mapping/from_marc/related_resource.rb
|
|
434
435
|
- lib/cocina/models/mapping/from_marc/title.rb
|
|
435
436
|
- lib/cocina/models/mapping/from_marc/util.rb
|
|
436
437
|
- lib/cocina/models/mapping/from_mods/access.rb
|