pennmarc 1.0.18 → 1.0.20

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f6b5628a407dc533c2f41b5c93d4b47239a36cc106c873b5bc7768825959451
4
- data.tar.gz: 55db336dac7987be256abfec2830d72e9fc599346e49c2cc92c0cf61f7c810ff
3
+ metadata.gz: 5cec796509d9822289de751b33395fa6de1c1c23fdbdf78de54de11152674733
4
+ data.tar.gz: 9a2aa7d1ca7c7bd27627fac7f676492100eb36cb823469fd5b7e987244795cee
5
5
  SHA512:
6
- metadata.gz: 4e2c930016793ae39d206d55a574c3e26d329507f6be46cde19628bcf6f9cc55213fcc9e8c7866e3f031510261fbba1cd64e54fe429c1bb92f0cb9c9c03dc9f8
7
- data.tar.gz: 2162e68b8aa887239e36333a9c1650a3f989cc1906b0c4271e419c4ad21a20e8cf2a19455fa3e77b8dbbf9bf4cdf4b9fdf6f99b6cfb61d68050d7362ae8867e3
6
+ metadata.gz: 2076675bbbc9bc38f3c36ba0932211ee4726d618de8d3781cae5d314576162b13bd256918910e534b638cd601a5f0e2db0936c7e8fd7fb58f1788ef1f28552d2
7
+ data.tar.gz: d963b043b08eff3567d904b18d938cddd3edc7a8d5238c720203cce52657cc86f6f20445e3d1c0de7221c628822990c87ea4cb0a2191b33b49992f8d6fa87ac9
@@ -19,6 +19,8 @@ module PennMARC
19
19
  # subfields NOT to join when combining raw subfield values
20
20
  NAME_EXCLUDED_SUBFIELDS = %w[a 1 4 5 6 8 t].freeze
21
21
 
22
+ CONTRIBUTOR_TAGS = %w[700 710].freeze
23
+
22
24
  # Author/Creator search field. Includes all subfield values (even ǂ0 URIs) from
23
25
  # {https://www.oclc.org/bibformats/en/1xx/100.html 100 Main Entry--Personal Name} and
24
26
  # {https://www.oclc.org/bibformats/en/1xx/110.html 110 Main Entry--Corporate Name}. Maps any relator codes found
@@ -48,27 +50,29 @@ module PennMARC
48
50
  name_search_values record: record, tags: AUX_TAGS, relator_map: relator_map
49
51
  end
50
52
 
51
- # All author/creator values for display (like #show, but multivalued?) - no 880 linkage
52
- # @note ported from get_author_creator_values (indexed as author_creator_a) - shown on results page
53
+ # Retrieve creator values for display from fields {https://www.loc.gov/marc/bibliographic/bd100.html 100}
54
+ # and {https://www.loc.gov/marc/bibliographic/bd110.html 110} and their linked alternates. Appends any encoded
55
+ # relationships found in $4. If there are no valid encoded relationships, uses the value found in $e.
53
56
  # @param [MARC::Record] record
54
- # @param [Hash] relator_map
55
57
  # @return [Array<String>] array of author/creator values for display
56
- def values(record, relator_map: Mappers.relator)
57
- record.fields(TAGS).map do |field|
58
- name_from_main_entry(field, relator_map)
59
- end
58
+ def show(record, relator_map: Mappers.relator)
59
+ fields = record.fields(TAGS)
60
+ fields += record.fields('880').select { |field| subfield_value?(field, '6', /^(#{TAGS.join('|')})/) }
61
+ fields.filter_map { |field|
62
+ creator = join_subfields(field, &subfield_not_in?(%w[0 1 4 6 8 e w]))
63
+ append_relator(field: field, joined_subfields: creator, relator_term_sf: 'e', relator_map: relator_map)
64
+ }.uniq
60
65
  end
61
66
 
62
- # Author/Creator values for display
63
- # @todo ported from get_author_display - used on record show page. porting did not include 4, e or w values,
64
- # which were part of the link object as 'append' values in franklin
67
+ # All author/creator values for display (like #show, but multivalued?) - no 880 linkage
68
+ # Performs additional normalization of author names
69
+ # @note ported from get_author_creator_values (indexed as author_creator_a) - shown on results page
65
70
  # @param [MARC::Record] record
71
+ # @param [Hash] relator_map
66
72
  # @return [Array<String>] array of author/creator values for display
67
- def show(record)
68
- fields = record.fields(TAGS)
69
- fields += record.fields('880').select { |field| subfield_value_in?(field, '6', TAGS) }
70
- fields.filter_map { |field|
71
- join_subfields(field, &subfield_not_in?(%w[0 1 4 6 8 e w]))
73
+ def show_aux(record, relator_map: Mappers.relator)
74
+ record.fields(TAGS).map { |field|
75
+ name_from_main_entry(field, relator_map)
72
76
  }.uniq
73
77
  end
74
78
 
@@ -118,8 +122,8 @@ module PennMARC
118
122
  # @todo what is ǂi for?
119
123
  # @param [MARC::Record] record
120
124
  # @return [Array<String>] array of conference values
121
- def conference_detail_show(record)
122
- values = record.fields(%w[111 711]).filter_map do |field|
125
+ def conference_detail_show(record, relator_map: Mappers.relator)
126
+ conferences = record.fields(%w[111 711]).filter_map do |field|
123
127
  next unless field.indicator2.in? ['', ' ']
124
128
 
125
129
  conf = if subfield_undefined? field, 'i'
@@ -127,17 +131,21 @@ module PennMARC
127
131
  else
128
132
  ''
129
133
  end
130
- conf_extra = join_subfields field, &subfield_in?(%w[e j w])
131
- join_and_squish [conf, conf_extra].compact_blank
134
+ sub_unit = join_subfields(field, &subfield_in?(%w[e w]))
135
+ conf = [conf, sub_unit].compact_blank.join(' ')
136
+
137
+ append_relator(field: field, joined_subfields: conf, relator_term_sf: 'j', relator_map: relator_map)
132
138
  end
133
- conferences = values + record.fields('880').filter_map do |field|
134
- next unless subfield_value_in? field, '6', %w[111 711]
139
+ conferences += record.fields('880').filter_map do |field|
140
+ next unless subfield_value? field, '6', /^(111|711)/
135
141
 
136
142
  next if subfield_defined? field, 'i'
137
143
 
138
144
  conf = join_subfields(field, &subfield_not_in?(%w[0 4 5 6 8 e j w]))
139
- conf_extra = join_subfields(field, &subfield_in?(%w[4 e j w]))
140
- join_and_squish [conf, conf_extra]
145
+ sub_unit = join_subfields(field, &subfield_in?(%w[e w]))
146
+ conf = [conf, sub_unit].compact_blank.join(' ')
147
+
148
+ append_relator(field: field, joined_subfields: conf, relator_term_sf: 'j', relator_map: relator_map)
141
149
  end
142
150
  conferences.uniq
143
151
  end
@@ -153,39 +161,24 @@ module PennMARC
153
161
 
154
162
  # Retrieve contributor values for display from fields {https://www.oclc.org/bibformats/en/7xx/700.html 700}
155
163
  # and {https://www.oclc.org/bibformats/en/7xx/710.html 710} and their linked alternates. Joins subfields
156
- # 'a', 'b', 'c', 'd', 'j', and 'q'. Then appends resulting string with joined subfields 'e', 'u', '3', and '4'.
164
+ # 'a', 'b', 'c', 'd', 'j', and 'q', 'u', and '3'. Then appends resulting string with any encoded relationships
165
+ # found in $4. If there are no valid encoded relationships, uses the value found in $e.
157
166
  # @note legacy version returns array of hash objects including data for display link
167
+ # @todo is it okay to include 880 $4 here? Legacy includes $4 in main author display 880 but not here.
158
168
  # @param [MARC::Record] record
159
169
  # @ param [Hash] relator_map
160
170
  # @return [Array<String>]
161
171
  def contributor_show(record, relator_map: Mappers.relator)
162
172
  indicator_2_options = ['', ' ', '0']
163
- values = record.fields(%w[700 710]).filter_map do |field|
164
- next unless indicator_2_options.member?(field.indicator2)
173
+ fields = record.fields(CONTRIBUTOR_TAGS)
174
+ fields += record.fields('880').select { |f| subfield_value?(f, '6', /^(#{CONTRIBUTOR_TAGS.join('|')})/) }
175
+ fields.filter_map { |field|
176
+ next if indicator_2_options.exclude?(field.indicator2) && field.tag.in?(CONTRIBUTOR_TAGS)
165
177
  next if subfield_defined? field, 'i'
166
178
 
167
- contributor = join_subfields(field, &subfield_in?(%w[a b c d j q]))
168
- contributor_append_subfields = %w[e u 3 4]
169
- contributor_append = field.filter_map { |subfield|
170
- next unless contributor_append_subfields.member?(subfield.code)
171
-
172
- if subfield.code == '4'
173
- ", #{translate_relator(subfield.value, relator_map)}"
174
- else
175
- " #{subfield.value}"
176
- end
177
- }.join
178
- "#{contributor} #{contributor_append}".squish
179
- end
180
- contributors = values + record.fields('880').filter_map do |field|
181
- next unless subfield_value_in?(field, '6', %w[700 710])
182
- next if subfield_defined?(field, 'i')
183
-
184
- contributor = join_subfields(field, &subfield_in?(%w[a b c d j q]))
185
- contributor_append = join_subfields(field, &subfield_in?(%w[e u 3]))
186
- "#{contributor} #{contributor_append}".squish
187
- end
188
- contributors.uniq
179
+ contributor = join_subfields(field, &subfield_in?(%w[a b c d j q u 3]))
180
+ append_relator(field: field, joined_subfields: contributor, relator_term_sf: 'e', relator_map: relator_map)
181
+ }.uniq
189
182
  end
190
183
 
191
184
  private
@@ -204,7 +197,7 @@ module PennMARC
204
197
  end
205
198
 
206
199
  acc += record.fields(['880']).filter_map do |field|
207
- next unless field.any? { |sf| sf.code == '6' && sf.value.in?(tags) }
200
+ next unless subfield_value?(field, '6', /^(#{tags.join('|')})/)
208
201
 
209
202
  suba = field.find_all(&subfield_in?(%w[a])).filter_map { |sf|
210
203
  convert_name_order(sf.value)
@@ -242,19 +235,23 @@ module PennMARC
242
235
  # @param [Boolean] should_convert_name_order
243
236
  # @return [String] joined subfield values for value from field
244
237
  def name_from_main_entry(field, mapping, should_convert_name_order: false)
245
- s = field.filter_map { |sf|
238
+ relator_term_sf = relator_term_subfield(field)
239
+ name = field.filter_map { |sf|
246
240
  if sf.code == 'a'
247
241
  should_convert_name_order ? convert_name_order(sf.value) : sf.value
242
+ elsif sf.code == relator_term_sf
243
+ next
248
244
  elsif NAME_EXCLUDED_SUBFIELDS.exclude?(sf.code)
249
- " #{sf.value}"
250
- elsif sf.code == '4'
251
- relator = translate_relator(sf.value, mapping)
252
- next if relator.blank?
253
-
254
- ", #{relator}"
245
+ sf.value
255
246
  end
256
- }.join
257
- (s + (%w[. -].member?(s.last) ? '' : '.')).squish
247
+ }.join(' ')
248
+
249
+ name_and_relator = append_relator(field: field,
250
+ joined_subfields: name,
251
+ relator_term_sf: relator_term_sf,
252
+ relator_map: mapping)
253
+
254
+ name_and_relator + (%w[. -].member?(name_and_relator.last) ? '' : '.')
258
255
  end
259
256
 
260
257
  # Convert "Lastname, First" to "First Lastname"
@@ -44,7 +44,7 @@ module PennMARC
44
44
  other_edition_value(field, relator_map)
45
45
  end
46
46
  editions = values + record.fields('880').filter_map do |field|
47
- next unless field.indicator2.blank? && subfield_value_in?(field, '6', %w[775]) &&
47
+ next unless field.indicator2.blank? && subfield_value?(field, '6', /^775/) &&
48
48
  subfield_defined?(field, 'i')
49
49
 
50
50
  other_edition_value(field, relator_map)
@@ -26,6 +26,9 @@ module PennMARC
26
26
  VIDEO = 'Video'
27
27
  WEBSITE_DATABASE = 'Website/Database'
28
28
 
29
+ # Values encoded in MARC that we use to determine "Archive" format
30
+ ARCHIVE_LOCATIONS = %w[archarch musearch scfreed univarch archivcoll].freeze
31
+
29
32
  # Get any Format values from {https://www.oclc.org/bibformats/en/3xx/300.html 300},
30
33
  # 254, 255, 310, 342, 352, 362 or {https://www.oclc.org/bibformats/en/3xx/340.html 340} field. based on the source
31
34
  # field, different subfields are used.
@@ -40,7 +43,7 @@ module PennMARC
40
43
  results += record.fields('340').map { |f| join_subfields(f, &subfield_not_in?(%w[0 2 6 8])) }
41
44
  results += record.fields('880').map do |f|
42
45
  # skip any 880s associated with non format fields
43
- next unless subfield_value_in?(f, '6', %w[254 255 300 310 340 342 352 362])
46
+ next unless subfield_value?(f, '6', /^(254|255|300|310|340|342|352|362)/)
44
47
 
45
48
  subfield_to_ignore = if subfield_value?(f, 6, /^300/)
46
49
  %w[3 6 8]
@@ -74,7 +77,7 @@ module PennMARC
74
77
  # @param [Hash] location_map
75
78
  # @return [Array<String>] format values for faceting
76
79
 
77
- def facet(record, location_map: Mappers.location)
80
+ def facet(record)
78
81
  formats = []
79
82
  format_code = leader_format(record.leader)
80
83
  f007 = record.fields('007').map(&:value)
@@ -83,49 +86,29 @@ module PennMARC
83
86
  title_medium = subfield_values_for tag: '245', subfield: :h, record: record
84
87
  media_type = subfield_values_for tag: '337', subfield: :a, record: record
85
88
 
86
- # get all specific_location values from inventory info
87
- locations = Location.location record: record, location_map: location_map,
88
- display_value: :specific_location
89
-
90
- if include_manuscripts?(locations)
91
- formats << MANUSCRIPT
92
- elsif archives_but_not_cajs_or_nursing?(locations)
93
- formats << ARCHIVE
94
- elsif micro_or_microform?(call_nums(record), locations, media_type, title_medium)
95
- formats << MICROFORMAT
96
- else
97
- # any of these
98
- formats << THESIS_DISSERTATION if thesis_or_dissertation?(format_code, record)
99
- formats << CONFERENCE_EVENT if conference_event?(record)
100
- formats << NEWSPAPER if newspaper?(f008, format_code)
101
- formats << GOVDOC if government_document?(f008, record, format_code)
102
-
103
- # but only one of these
104
- formats << if website_database?(f006_forms, format_code)
105
- WEBSITE_DATABASE
106
- elsif book?(format_code, title_medium, record)
107
- BOOK
108
- elsif musical_score?(format_code)
109
- MUSICAL_SCORE
110
- elsif map_atlas?(format_code)
111
- MAP_ATLAS
112
- elsif graphical_media?(format_code)
113
- graphical_media_type(f007)
114
- elsif sound_recording?(format_code)
115
- SOUND_RECORDING
116
- elsif image?(format_code)
117
- IMAGE
118
- elsif datafile?(format_code)
119
- DATAFILE
120
- elsif journal_periodical?(format_code)
121
- JOURNAL_PERIODICAL
122
- elsif three_d_object?(format_code)
123
- THREE_D_OBJECT
124
- else
125
- OTHER
126
- end
127
- end
128
- formats.concat(curated_format(record)).uniq
89
+ # any of these
90
+ formats << MANUSCRIPT if include_manuscripts?(format_code)
91
+ formats << ARCHIVE if archive?(record)
92
+ formats << MICROFORMAT if micro_or_microform?(call_nums(record), f007, f008, media_type, title_medium)
93
+ formats << THESIS_DISSERTATION if thesis_or_dissertation?(format_code, record)
94
+ formats << CONFERENCE_EVENT if conference_event?(record)
95
+ formats << NEWSPAPER if newspaper?(f008, format_code)
96
+ formats << GOVDOC if government_document?(f008, record, format_code)
97
+ formats << WEBSITE_DATABASE if website_database?(f006_forms, format_code)
98
+ formats << BOOK if book?(format_code, media_type, record)
99
+ formats << MUSICAL_SCORE if musical_score?(format_code)
100
+ formats << MAP_ATLAS if map_atlas?(format_code)
101
+ formats << graphical_media_type(f007) if graphical_media?(format_code)
102
+ formats << SOUND_RECORDING if sound_recording?(format_code)
103
+ formats << IMAGE if image?(format_code)
104
+ formats << DATAFILE if datafile?(format_code)
105
+ formats << JOURNAL_PERIODICAL if journal_periodical?(format_code)
106
+ formats << THREE_D_OBJECT if three_d_object?(format_code)
107
+ formats.concat(curated_format(record))
108
+
109
+ formats << OTHER if formats.empty?
110
+
111
+ formats.uniq
129
112
  end
130
113
 
131
114
  # Show "Other Format" values from {https://www.oclc.org/bibformats/en/7xx/776.html 776} and any 880 linkage.
@@ -155,11 +138,11 @@ module PennMARC
155
138
  }.uniq
156
139
  end
157
140
 
158
- # Check if a set of locations has any locations that include the term 'manuscripts'
159
- # @param [Array<String>] locations
141
+ # Check if leader format code is either 't', 'f', or 'd'
142
+ # @param [String] format_code
160
143
  # @return [Boolean]
161
- def include_manuscripts?(locations)
162
- locations.any? { |loc| loc =~ /manuscripts/i }
144
+ def include_manuscripts?(format_code)
145
+ format_code.first.in? %w[t f d]
163
146
  end
164
147
 
165
148
  private
@@ -242,18 +225,18 @@ module PennMARC
242
225
  # @param [String] format_code
243
226
  # @return [Boolean]
244
227
  def musical_score?(format_code)
245
- format_code.in?(%w[ca cb cd cm cs dm])
228
+ format_code.in?(%w[ca cb cc cd cm cs dc dm])
246
229
  end
247
230
 
248
231
  # @param [String] format_code
249
- # @param [Array<String>] title_medium
232
+ # @param [Array<String>] media_type
250
233
  # @param [MARC::Record] record
251
234
  # @return [Boolean]
252
- def book?(format_code, title_medium, record)
235
+ def book?(format_code, media_type, record)
253
236
  title_forms = subfield_values_for tag: '245', subfield: :k, record: record
254
237
  format_code.in?(%w[aa ac am tm]) &&
255
238
  title_forms.none? { |v| v =~ /kit/i } &&
256
- title_medium.none? { |v| v =~ /micro/i }
239
+ media_type.none? { |val| val =~ /micro/i }
257
240
  end
258
241
 
259
242
  # @param [Array<String>] f006_forms
@@ -293,29 +276,38 @@ module PennMARC
293
276
  # @param [String] format_code
294
277
  # @return [Boolean]
295
278
  def thesis_or_dissertation?(format_code, record)
296
- record.fields('502').any? && format_code == 'tm'
279
+ record.fields('502').any? && format_code.in?(%w[am tm dm])
297
280
  end
298
281
 
282
+ # @param [Array<String>] call_nums
283
+ # @param [Array<String>] f007
284
+ # @param [String] f008
299
285
  # @param [Array<String>] title_medium
300
286
  # @param [Array<String>] media_type
301
- # @param [Array<String>] locations
302
- # @param [Array<String>] call_nums
303
287
  # @return [Boolean]
304
- def micro_or_microform?(call_nums, locations, media_type, title_medium)
305
- locations.any? { |loc| loc =~ /micro/i } ||
288
+ def micro_or_microform?(call_nums, f007, f008, media_type, title_medium)
289
+ [f008[23], f008[29]].any? { |v| v.in?(%w[a b c]) } ||
290
+ f007.any? { |v| v.start_with?('h') } ||
306
291
  title_medium.any? { |val| val =~ /micro/i } ||
307
292
  call_nums.any? { |val| val =~ /micro/i } ||
308
- media_type.any? { |val| val =~ /microform/i }
293
+ media_type.any? { |val| val =~ /micro/i }
309
294
  end
310
295
 
311
- # @todo "cajs" has no match in our location map, so it is not doing anything. Does this intend to catch cjsambx
312
- # "Library at the Katz Center - Archives"?
313
- # @param [Array<String>] locations
296
+ # Determine archive format by checking if {https://www.loc.gov/marc/bibliographic/hd852.html 852} and
297
+ # {PennMARC::Enriched} Publishing Tag 'ITM' have values that match any of the following archive locations:
298
+ # archarch, musearch, scfreed, univarch, archivcoll
299
+ # @param [MARC::Record] record
314
300
  # @return [Boolean]
315
- def archives_but_not_cajs_or_nursing?(locations)
316
- locations.any? { |loc| loc =~ /archives/i } &&
317
- locations.none? { |loc| loc =~ /cajs/i } &&
318
- locations.none? { |loc| loc =~ /nursing/i }
301
+ def archive?(record)
302
+ enriched_tag = Enriched::Pub::ITEM_TAG
303
+ enriched_sf = Enriched::Pub::ITEM_CURRENT_LOCATION
304
+
305
+ record.fields([enriched_tag, '852']).each do |field|
306
+ return true if field.tag == enriched_tag && subfield_value_in?(field, enriched_sf, ARCHIVE_LOCATIONS)
307
+
308
+ return true if field.tag == '852' && subfield_value_in?(field, 'c', ARCHIVE_LOCATIONS)
309
+ end
310
+ false
319
311
  end
320
312
 
321
313
  # Consider {https://www.loc.gov/marc/bibliographic/bd007g.html 007} to determine graphical media format
@@ -32,7 +32,7 @@ module PennMARC
32
32
  record.fields(%w[655 880]).filter_map { |field|
33
33
  next unless allowed_genre_field?(field)
34
34
 
35
- next if field.tag == '880' && subfield_values(field, '6').exclude?('655')
35
+ next if field.tag == '880' && no_subfield_value_matches?(field, '6', /^655/)
36
36
 
37
37
  subfields = %w[a b]
38
38
  sub_with_hyphens = field.find_all(&subfield_not_in?(%w[0 2 5 6 8 c e w])).map { |sf|
@@ -47,12 +47,10 @@ module PennMARC
47
47
  # @todo the Genre facet in Franklin is pretty ugly. It could be cleaned up by limiting the subfields included
48
48
  # here and cleaning up punctuation.
49
49
  # @param [MARC::Record] record
50
- # @param [Hash] location_map
51
50
  # @return [Array<String>]
52
- def facet(record, location_map: Mappers.location)
53
- locations = Location.location record: record, location_map: location_map,
54
- display_value: :specific_location
55
- manuscript = Format.include_manuscripts?(locations)
51
+ def facet(record)
52
+ format_code = record.leader[6] || ' '
53
+ manuscript = Format.include_manuscripts?(format_code)
56
54
  video = record.fields('007').any? { |field| field.value.starts_with? 'v' }
57
55
  return [] unless manuscript || video
58
56
 
@@ -112,7 +112,7 @@ module PennMARC
112
112
  # @return [Array<string>]
113
113
  def publisher_number_show(record)
114
114
  record.fields(%w[024 028 880]).filter_map { |field|
115
- next if field.tag == '880' && subfield_value_not_in?(field, '6', %w[024 028])
115
+ next if field.tag == '880' && no_subfield_value_matches?(field, '6', /^(024|028)/)
116
116
 
117
117
  # do not return doi values from 024 ǂ2
118
118
  if field.tag == '024' && subfield_value_in?(field, '2', %w[doi])
@@ -17,7 +17,7 @@ module PennMARC
17
17
  def notes_show(record)
18
18
  notes_fields = %w[500 502 504 515 518 525 533 540 550 580 586 588]
19
19
  record.fields(notes_fields + ['880']).filter_map { |field|
20
- next if field.tag == '880' && subfield_value_not_in?(field, '6', notes_fields)
20
+ next if field.tag == '880' && no_subfield_value_matches?(field, '6', /^(#{notes_fields.join('|')})/)
21
21
 
22
22
  join_subfields(field, &subfield_not_in?(%w[5 6 8]))
23
23
  }.uniq
@@ -39,7 +39,7 @@ module PennMARC
39
39
  additional_fields = %w[562 563 585 590]
40
40
 
41
41
  notes = local_notes + record.fields(additional_fields + ['880']).filter_map do |field|
42
- next if field.tag == '880' && subfield_value_not_in?(field, '6', additional_fields)
42
+ next if field.tag == '880' && no_subfield_value_matches?(field, '6', /^(#{additional_fields.join('|')})/)
43
43
 
44
44
  join_subfields(field, &subfield_not_in?(%w[5 6 8]))
45
45
  end
@@ -58,7 +58,7 @@ module PennMARC
58
58
 
59
59
  next unless field.indicator2.in?([' ', ''])
60
60
 
61
- next if field.tag == '880' && subfield_value_not_in?(field, '6', %w[561])
61
+ next if field.tag == '880' && no_subfield_value_matches?(field, '6', /^561/)
62
62
 
63
63
  next if subfield_value?(field, 'a', /^Athenaeum copy: /)
64
64
 
@@ -74,7 +74,7 @@ module PennMARC
74
74
  # @return [Array<String>]
75
75
  def contents_show(record)
76
76
  record.fields(%w[505 880]).filter_map { |field|
77
- next if field.tag == '880' && subfield_value_not_in?(field, '6', %w[505])
77
+ next if field.tag == '880' && no_subfield_value_matches?(field, '6', /^505/)
78
78
 
79
79
  join_subfields(field, &subfield_not_in?(%w[6 8])).split('--')
80
80
  }.flatten.uniq
@@ -144,22 +144,22 @@ module PennMARC
144
144
  # @return [Array<String>]
145
145
  def system_details_show(record)
146
146
  system_details_notes = record.fields(%w[538 880]).filter_map do |field|
147
- next if field.tag == '880' && subfield_value_not_in?(field, '6', ['538'])
147
+ next if field.tag == '880' && no_subfield_value_matches?(field, '6', /^538/)
148
148
 
149
149
  sub3_and_other_subs(field, &subfield_in?(%w[a i u]))
150
150
  end
151
151
  system_details_notes += record.fields(%w[344 880]).filter_map do |field|
152
- next if field.tag == '880' && subfield_value_not_in?(field, '6', ['344'])
152
+ next if field.tag == '880' && no_subfield_value_matches?(field, '6', /^344/)
153
153
 
154
154
  sub3_and_other_subs(field, &subfield_in?(%w[a b c d e f g h]))
155
155
  end
156
156
  system_details_notes += record.fields(%w[345 346 880]).filter_map do |field|
157
- next if field.tag == '880' && subfield_value_not_in?(field, '6', %w[345 346])
157
+ next if field.tag == '880' && no_subfield_value_matches?(field, '6', /^(345|346)/)
158
158
 
159
159
  sub3_and_other_subs(field, &subfield_in?(%w[a b]))
160
160
  end
161
161
  system_details_notes += record.fields(%w[347 880]).filter_map do |field|
162
- next if field.tag == '880' && subfield_value_not_in?(field, '6', ['347'])
162
+ next if field.tag == '880' && no_subfield_value_matches?(field, '6', /^347/)
163
163
 
164
164
  sub3_and_other_subs(field, &subfield_in?(%w[a b c d e f]))
165
165
  end
@@ -96,7 +96,7 @@ module PennMARC
96
96
  # @return [Array<String>]
97
97
  def place_of_publication_show(record)
98
98
  record.fields(%w[752 880]).filter_map { |field|
99
- next if field.tag == '880' && subfield_values(field, '6').exclude?('752')
99
+ next if field.tag == '880' && no_subfield_value_matches?(field, '6', /^752/)
100
100
 
101
101
  place = join_subfields(field, &subfield_not_in?(%w[6 8 e w]))
102
102
  place_extra = join_subfields(field, &subfield_in?(%w[e w]))
@@ -49,45 +49,46 @@ module PennMARC
49
49
  # @param [Hash] relator_map
50
50
  # @return [Array]
51
51
  def related_work_show(record, relator_map: Mappers.relator)
52
- values = record.fields(RELATED_WORK_FIELDS).filter_map do |field|
52
+ fields = record.fields(RELATED_WORK_FIELDS)
53
+ fields += record.fields('880').select { |f| subfield_value?(f, '6', /^(#{RELATED_WORK_FIELDS.join('|')})/) }
54
+ fields.filter_map { |field|
53
55
  next if field.indicator2.present?
54
56
 
55
57
  next unless subfield_defined?(field, 't')
56
58
 
57
- values_with_title_prefix(field, sf_exclude: %w[0 4 6 8 i], relator_map: relator_map)
58
- end
59
- relation_values = values + record.fields('880').filter_map do |field|
60
- next if field.indicator2.present?
59
+ relator_term_sf = relator_term_subfield(field)
61
60
 
62
- next unless subfield_value?(field, '6', /^(#{RELATED_WORK_FIELDS.join('|')})/)
63
-
64
- next unless subfield_defined?(field, 't')
61
+ sf_exclude = %w[0 4 6 8 i] << relator_term_sf
65
62
 
66
- values_with_title_prefix(field, sf_exclude: %w[0 4 6 8 i], relator_map: relator_map)
67
- end
68
- relation_values.uniq
63
+ values_with_title_prefix(field,
64
+ relator_term_sf: relator_term_sf,
65
+ relator_map: relator_map,
66
+ &subfield_not_in?(sf_exclude))
67
+ }.uniq
69
68
  end
70
69
 
71
70
  # Get "Contains" values from {CONTAINS_FIELDS} in the 7XX range. Must have indicator 2 value of 2 indicating an
72
71
  # "Analytical Entry" meaning that the record is contained by the matching field. Map relator codes in sf 4. Ignore
73
72
  # values in sf 0, 5, 6, and 8.
73
+ # @todo is it okay to include 880 $4 here? Legacy includes untranslated $4, why?
74
74
  # @param [MARC::Record] record
75
75
  # @param [Hash] relator_map
76
76
  # @return [Array<String>]
77
77
  def contains_show(record, relator_map: Mappers.relator)
78
- values = record.fields(CONTAINS_FIELDS).filter_map do |field|
78
+ fields = record.fields(CONTAINS_FIELDS)
79
+ fields += record.fields('880').select { |f| subfield_value?(f, '6', /^(#{CONTAINS_FIELDS.join('|')})/) }
80
+ fields.filter_map { |field|
79
81
  next unless field.indicator2 == '2'
80
82
 
81
- values_with_title_prefix(field, sf_exclude: %w[0 4 5 6 8 i], relator_map: relator_map)
82
- end
83
- contains_values = values + record.fields('880').filter_map do |field|
84
- next unless field.indicator2 == '2'
83
+ relator_term_sf = relator_term_subfield(field)
85
84
 
86
- next unless subfield_value?(field, '6', /^(#{CONTAINS_FIELDS.join('|')})/)
85
+ sf_exclude = %w[0 4 5 6 8 i] << relator_term_sf
87
86
 
88
- values_with_title_prefix(field, sf_include: %w[0 5 6 8 i])
89
- end
90
- contains_values.uniq
87
+ values_with_title_prefix(field,
88
+ relator_term_sf: relator_term_sf,
89
+ relator_map: relator_map,
90
+ &subfield_not_in?(sf_exclude))
91
+ }.uniq
91
92
  end
92
93
 
93
94
  # Get "Constituent Unit" values from {https://www.oclc.org/bibformats/en/7xx/774.html MARC 774}. Include
@@ -114,24 +115,21 @@ module PennMARC
114
115
 
115
116
  # Handle common behavior when a relator field references a title in subfield i
116
117
  # @param [MARC::DataField] field
117
- # @param [Array, nil] sf_include subfields to include, optional
118
- # @param [Array, nil] sf_exclude subfields to exclude, optional
118
+ # @param [String, nil] relator_term_sf subfield that holds relator term
119
119
  # @param [Hash, nil] relator_map map relator in sf4 using this map, optional
120
+ # @param [Proc] join_selector
120
121
  # @return [String] extracted and processed values from field
121
- def values_with_title_prefix(field, sf_include: nil, sf_exclude: nil, relator_map: nil)
122
- raise ArgumentError('Define only sf_include or sf_exclude.') if sf_include.present? && sf_exclude.present?
123
-
122
+ def values_with_title_prefix(field, relator_term_sf: nil, relator_map: nil, &join_selector)
124
123
  subi = remove_paren_value_from_subfield_i(field) || ''
125
- relator = translate_relator(subfield_values(field, '4').first, relator_map) if relator_map.present?
126
- contains = if sf_include.present?
127
- join_subfields(field, &subfield_not_in?(sf_include))
128
- elsif sf_exclude.present?
129
- join_subfields(field, &subfield_not_in?(sf_exclude))
130
- end
131
- [
132
- subi,
133
- [contains, relator].compact_blank.join(', ')
134
- ].compact_blank.join(': ')
124
+
125
+ title = join_subfields(field, &join_selector)
126
+
127
+ title_with_relator = append_relator(field: field,
128
+ joined_subfields: title,
129
+ relator_term_sf: relator_term_sf,
130
+ relator_map: relator_map)
131
+
132
+ [subi, title_with_relator].compact_blank.join(': ')
135
133
  end
136
134
  end
137
135
  end