pennmarc 1.0.18 → 1.0.20

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: 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