pennmarc 1.3.2 → 1.3.4

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: b69f7173f51a48c0748bf1d537392c6bda0919312009c85bd70e603cf4cb0240
4
- data.tar.gz: fa0e2d2c724e26734890fcc1fe4e20899a6141d0e0f0cdebe9e242b03070be35
3
+ metadata.gz: 3409e098b2447b1f3eb3295e8df39d2b3e5133a9594f93f0b017132700b3fdd6
4
+ data.tar.gz: 02a38f6ffff4ce8032b4f60e9bcc2de3945c14b8d249bf83e2ffff26cb8c1a60
5
5
  SHA512:
6
- metadata.gz: 4ed0b2699d095d4f07483e38fd99d8bcc52d2fd69f8c6b94dfba410a8d6f42329dda379e7eb8809ec43687d8552cc38471f85859ff0d73c0888026845caed1e6
7
- data.tar.gz: 62d4f90ff259a2188fc0cc5eee803cd18e9f1a83d15874de77ef956e6dd836ae6a822a433770c0e56e2f583c15f696919be30f7298c080b4404d27e3f247d245
6
+ metadata.gz: 7e3c34f9063ca03595f9e45adf23c4f8c4f27a369b874eaf9944ce11b60f16cf8298bfb7a169094c5fe9b6b1fc726eb68272b996085c5092a65d03bce9bde893
7
+ data.tar.gz: c304b6f45e769ecc13cb0b17230448a87d1f52b5fe496587663ed88383cc4a7288a4422dbca685c6229fee69fae8d6964ee9d332bb95c6aa0dd5e04ced5909b7
@@ -7,12 +7,15 @@ module PennMARC
7
7
  AT_THE_LIBRARY = 'At the library'
8
8
  HANDLE_BASE_URL = 'hdl.library.upenn.edu'
9
9
  COLENDA_BASE_URL = 'colenda.library.upenn.edu'
10
+ REQUIRED_ONLINE_MARC_INDICATOR_COUNT = 2
10
11
 
11
12
  class << self
12
13
  # Based on enhanced metadata fields added by Alma publishing process or API, determine if the record has
13
14
  # electronic access or has physical holdings, and is therefore "Online" or "At the library". If a record is "At
14
15
  # the library", but has a link to a finding aid in the 856 field (matching certain criteria), also add 'Online' as
15
16
  # an access method.
17
+ # Because Alma E-Collections don't return electronic inventory, check some MARC control fields and other fields
18
+ # for indicators of an online resource, but only if no other Online indicators are present.
16
19
  # @param record [MARC::Record]
17
20
  # @return [Array]
18
21
  def facet(record)
@@ -24,7 +27,7 @@ module PennMARC
24
27
  return values if values.size == 2 # return early if all values are already present
25
28
 
26
29
  # only check if ONLINE isn't already there
27
- values << ONLINE if values.exclude?(ONLINE) && resource_link?(record)
30
+ values << ONLINE if values.exclude?(ONLINE) && marc_indicators?(record)
28
31
  values.uniq
29
32
  end
30
33
 
@@ -44,6 +47,24 @@ module PennMARC
44
47
  field.tag.in? [Enriched::Pub::PHYS_INVENTORY_TAG, Enriched::Api::PHYS_INVENTORY_TAG]
45
48
  end
46
49
 
50
+ # In order to determine if a record has Online access, we should also check some MARC fields. This is because the
51
+ # Alma inventory publishing process does not include tags for E-Collections associated with a record. Here we
52
+ # check for obvious indicators:
53
+ # - a "Resource Link" matching certain criteria
54
+ # - a field indicating that the record is part of our curated "Databases" collection
55
+ # If there's still no online access, check for at least two other positive indicators in other MARC control fields
56
+ # and other tags.
57
+ # @param record [MARC::Record]
58
+ # @return [Boolean]
59
+ def marc_indicators?(record)
60
+ return true if resource_link?(record) || electronic_database?(record)
61
+
62
+ [eresource_form?(record),
63
+ eresource_material_designation?(record),
64
+ online_computer_file_form?(record),
65
+ online_carrier_type?(record)].count(true) >= REQUIRED_ONLINE_MARC_INDICATOR_COUNT
66
+ end
67
+
47
68
  # Check if a record contains an 856 entry with a Penn Handle server link meeting these criteria:
48
69
  # 1. Indicator 1 is 4 (HTTP resource)
49
70
  # 2. Indicator 2 is NOT 2 (indicating the linkage is to a "related" thing)
@@ -58,6 +79,58 @@ module PennMARC
58
79
  record.fields('856').any? { |field| valid_resource_field?(field) }
59
80
  end
60
81
 
82
+ # Does the record have an 006 suggesting an electronic resource?
83
+ # Check position 6 "Form of item" for an `o` indicating "Online"
84
+ # @see https://www.loc.gov/marc/bibliographic/bd006.html
85
+ # @see https://www.loc.gov/marc/bibliographic/bd008c.html
86
+ # @param record [MARC::Record]
87
+ # @return [Boolean]
88
+ def eresource_form?(record)
89
+ return false unless field_defined?(record, '006')
90
+
91
+ record.fields('006').first.value[6] == 'o'
92
+ end
93
+
94
+ # Does the record have an 007 indicating an electronic resource?
95
+ # Check pos 0 for a `c` ("Electronic resource") and position 1 for an `r` ("Remote")
96
+ # @see https://www.loc.gov/marc/bibliographic/bd007c.html
97
+ # @param record [MARC::Record]
98
+ # @return [Boolean]
99
+ def eresource_material_designation?(record)
100
+ return false unless field_defined?(record, '007')
101
+
102
+ record.fields('007').first.value[0..1] == 'cr'
103
+ end
104
+
105
+ # Does the record have an 008 indicating an electronic resource?
106
+ # https://www.loc.gov/marc/bibliographic/bd008c.html
107
+ # @param record [MARC::Record]
108
+ # @return [Boolean]
109
+ def online_computer_file_form?(record)
110
+ return false unless field_defined?(record, '008')
111
+
112
+ record.fields('008').first.value[23] == 'o'
113
+ end
114
+
115
+ # Does the record have an 338 indicating an electronic resource?
116
+ # @see https://www.loc.gov/marc/bibliographic/bd338.html, https://www.loc.gov/standards/valuelist/rdacarrier.html
117
+ # @param record [MARC::Record]
118
+ # @return [Boolean]
119
+ def online_carrier_type?(record)
120
+ return false unless field_defined?(record, '338')
121
+
122
+ return false unless subfield_values_for(tag: '338', subfield: 'a', record: record).include?('online resource')
123
+
124
+ subfield_values_for(tag: '338', subfield: 'b', record: record).include?('cr')
125
+ end
126
+
127
+ # Databases are always electronic resources
128
+ # @param record [MARC::Record]
129
+ # @return [Boolean]
130
+ def electronic_database?(record)
131
+ Database.type_facet(record).any?
132
+ end
133
+
61
134
  # Check if a field contains valid resource
62
135
  # @param field [MARC::Field]
63
136
  # @return [Boolean]
@@ -90,9 +90,10 @@ module PennMARC
90
90
  # @return [Array<String>] array of author/creator values for display
91
91
  def extended_show(record, relator_map: Mappers.relator)
92
92
  fields = record.fields(%w[100 700])
93
+ fields += record.fields('880').select { |field| subfield_value?(field, '6', /^(#{TAGS.join('|')})/) }
93
94
  fields.filter_map { |field|
94
- # for 700 entries, only include ones with relator code ('4') = aut, or code 'e' = 'author'
95
- next if field.tag == '700' && !(field['4']&.downcase == 'aut' || field['e']&.downcase&.start_with?('author'))
95
+ # for 700 and 880 entries, only include ones with relator code ('4') = aut, or code 'e' = 'author'
96
+ next if field.tag.in?(%w[700 880]) && !describes_author?(field)
96
97
 
97
98
  parse_show_value(field, relator_map: relator_map)
98
99
  }.uniq
@@ -106,7 +107,7 @@ module PennMARC
106
107
  def extended_show_facet_map(record, relator_map: Mappers.relator)
107
108
  creators = record.fields(%w[100 700]).filter_map do |field|
108
109
  # for 700 entries, only include ones with relator code ('4') = aut, or code 'e' = 'author'
109
- next if field.tag == '700' && !(field['4']&.downcase == 'aut' || field['e']&.downcase&.start_with?('author'))
110
+ next if field.tag == '700' && !describes_author?(field)
110
111
 
111
112
  show = parse_show_value(field, relator_map: relator_map)
112
113
  facet = parse_facet_value(field, FACET_SOURCE_MAP[field.tag.to_i].chars)
@@ -313,6 +314,42 @@ module PennMARC
313
314
  }.uniq
314
315
  end
315
316
 
317
+ # Similar to contributor_show, excluding the authors included in extended_show
318
+ # @param record [MARC::Record]
319
+ # @param relator_map [Hash]
320
+ # @param name_only [Boolean]
321
+ # @param vernacular [Boolean]
322
+ # @return [Array<String>]
323
+ def contributor_noauthor_show(record, relator_map: Mappers.relator, name_only: false, vernacular: true)
324
+ contributor_fields = record.fields(CONTRIBUTOR_TAGS)
325
+
326
+ # Exclude the 700 authors and collect their linkages
327
+ excluded_linkages = []
328
+ filtered_fields = contributor_fields.reject do |f|
329
+ is_author = f.tag == '700' && (f['4']&.downcase == 'aut' || f['e']&.downcase&.start_with?('author'))
330
+ excluded_linkages << "700-#{f['6'].split('-').last}" if is_author && f['6']
331
+ is_author
332
+ end
333
+
334
+ # Add vernacular fields that are not excluded by checking the linkages
335
+ if vernacular
336
+ vernacular_fields = record.fields('880').select do |f|
337
+ CONTRIBUTOR_TAGS.any? { |tag| f['6']&.start_with?(tag) } && !excluded_linkages.include?(f['6'])
338
+ end
339
+ filtered_fields.concat(vernacular_fields)
340
+ end
341
+
342
+ sf = name_only ? %w[a] : CONTRIBUTOR_DISPLAY_SUBFIELDS
343
+
344
+ filtered_fields.filter_map { |field|
345
+ next if ['', ' ', '0'].exclude?(field.indicator2) && field.tag.in?(CONTRIBUTOR_TAGS)
346
+ next if subfield_defined? field, 'i'
347
+
348
+ contributor = join_subfields(field, &subfield_in?(sf))
349
+ append_relator(field: field, joined_subfields: contributor, relator_term_sf: 'e', relator_map: relator_map)
350
+ }.uniq
351
+ end
352
+
316
353
  private
317
354
 
318
355
  # @param record [MARC::Record]
@@ -429,6 +466,13 @@ module PennMARC
429
466
 
430
467
  append_relator(field: field, joined_subfields: conf, relator_term_sf: 'j', relator_map: relator_map)
431
468
  end
469
+
470
+ # Does the given field describe an author record, as indicated by the relator fields of sf 4 or sf e ?
471
+ # @param [MARC::Field] field
472
+ # @return [Boolean]
473
+ def describes_author?(field)
474
+ field['4']&.downcase == 'aut' || field['e']&.downcase&.start_with?('author')
475
+ end
432
476
  end
433
477
  end
434
478
  end
@@ -66,10 +66,6 @@ carpco:
66
66
  library: Special Collections
67
67
  display: Carpenters' Company of the City and County of Philadelphia
68
68
  aeon: true
69
- catoffice:
70
- specific_location: Athenaeum of Philadelphia - Cataloging Office
71
- library: Athenaeum of Philadelphia
72
- display: Athenaeum of Philadelphia - Cataloging Office
73
69
  circcoll:
74
70
  specific_location: Athenaeum of Philadelphia - Circulating Collection
75
71
  library: Athenaeum of Philadelphia
@@ -83,10 +79,6 @@ cidirbusrm:
83
79
  library: Athenaeum of Philadelphia
84
80
  display: Athenaeum of Philadelphia - City Directories Busch Room
85
81
  aeon: true
86
- collcare:
87
- specific_location: Athenaeum of Philadelphia - Collections Care Manager
88
- library: Athenaeum of Philadelphia
89
- display: Athenaeum of Philadelphia - Collections Care Manager
90
82
  fic:
91
83
  specific_location: Athenaeum of Philadelphia - Fiction
92
84
  library: Athenaeum of Philadelphia
@@ -101,6 +93,10 @@ litaward:
101
93
  library: Athenaeum of Philadelphia
102
94
  display: Athenaeum of Philadelphia - Literary Award
103
95
  aeon: true
96
+ lounge:
97
+ specific_location: Athenaeum of Philadelphia - Member Lounge
98
+ library: Athenaeum of Philadelphia
99
+ display: Athenaeum of Philadelphia - Member Lounge
104
100
  microfilm:
105
101
  specific_location: Athenaeum of Philadelphia - Microfilm
106
102
  library: Athenaeum of Philadelphia
@@ -124,11 +120,6 @@ rarecoll:
124
120
  library: Athenaeum of Philadelphia
125
121
  display: Athenaeum of Philadelphia - Rare Books Collection
126
122
  aeon: true
127
- reevecoll:
128
- specific_location: Athenaeum of Philadelphia - Reeve Collection
129
- library: Athenaeum of Philadelphia
130
- display: Athenaeum of Philadelphia - Reeve Collection
131
- aeon: true
132
123
  ref:
133
124
  specific_location: Athenaeum of Philadelphia - Reference
134
125
  library: Athenaeum of Philadelphia
@@ -289,13 +280,6 @@ cjsarcths:
289
280
  - Library at the Katz Center for Advanced Judaic Studies
290
281
  display: Library at the Katz Center - Archives Thesis
291
282
  aeon: true
292
- cjsartif:
293
- specific_location: Library at the Katz Center - Reading Room
294
- library:
295
- - Special Collections
296
- - Library at the Katz Center for Advanced Judaic Studies
297
- display: Library at the Katz Center - Artifacts
298
- aeon: true
299
283
  cjsbox1:
300
284
  specific_location: Library at the Katz Center - Stacks
301
285
  library: Library at the Katz Center for Advanced Judaic Studies
@@ -308,22 +292,10 @@ cjsbox3:
308
292
  specific_location: Library at the Katz Center - Stacks
309
293
  library: Library at the Katz Center for Advanced Judaic Studies
310
294
  display: Library at the Katz Center - Stacks Box 3
311
- cjsbox4:
312
- specific_location: Library at the Katz Center - Stacks
313
- library: Library at the Katz Center for Advanced Judaic Studies
314
- display: Library at the Katz Center - Stacks Box 4
315
295
  cjscdrom:
316
296
  specific_location: Library at the Katz Center - Reading Room
317
297
  library: Library at the Katz Center for Advanced Judaic Studies
318
298
  display: Library at the Katz Center - CD-ROM
319
- cjscirc:
320
- specific_location: Library at the Katz Center - Reading Room
321
- library: Library at the Katz Center for Advanced Judaic Studies
322
- display: Library at the Katz Center - Circulation
323
- cjscomp:
324
- specific_location: Library at the Katz Center - Reading Room
325
- library: Library at the Katz Center for Advanced Judaic Studies
326
- display: Library at the Katz Center - Computer Room
327
299
  cjsdir:
328
300
  specific_location: Library at the Katz Center - Stacks
329
301
  library: Library at the Katz Center for Advanced Judaic Studies
@@ -434,10 +406,6 @@ cjspergal:
434
406
  specific_location: Library at the Katz Center - Reading Room
435
407
  library: Library at the Katz Center for Advanced Judaic Studies
436
408
  display: Library at the Katz Center - Periodicals Gallery
437
- cjsperover:
438
- specific_location: Library at the Katz Center - Stacks
439
- library: Library at the Katz Center for Advanced Judaic Studies
440
- display: Library at the Katz Center - Periodicals Oversize
441
409
  cjsrar:
442
410
  specific_location: Library at the Katz Center - Rare Book Room
443
411
  library:
@@ -527,12 +495,6 @@ cjsreffol+:
527
495
  specific_location: Library at the Katz Center - Reading Room
528
496
  library: Library at the Katz Center for Advanced Judaic Studies
529
497
  display: Library at the Katz Center - Reference Oversize
530
- cjsres:
531
- specific_location: Library at the Katz Center - Reading Room
532
- library:
533
- - Library at the Katz Center for Advanced Judaic Studies
534
- - Reserve
535
- display: Library at the Katz Center - Reserves
536
498
  cjsspec:
537
499
  specific_location: Library at the Katz Center - Stacks
538
500
  library:
@@ -838,12 +800,7 @@ mideast:
838
800
  specific_location: Van Pelt - Stapleton Seminar Room
839
801
  library: Van Pelt-Dietrich Library Center
840
802
  display: Van Pelt - Stapleton Seminar Room (523)
841
- mideastres:
842
- specific_location: Van Pelt - Middle East Seminar Reserve
843
- library:
844
- - Van Pelt-Dietrich Library Center
845
- - Reserve
846
- display: Van Pelt - Middle East Seminar Reserve
803
+
847
804
  mscirc:
848
805
  specific_location: Penn Museum Library - Circulation
849
806
  library: Penn Museum Library
@@ -970,12 +927,11 @@ newbofc:
970
927
  - 'Veterinary: du Pont Library (New Bolton)'
971
928
  display: 'Veterinary: du Pont Library (New Bolton) - Office'
972
929
  newbrare:
973
- specific_location: Kislak Center for Special Collections - Fairman Rogers Collection
930
+ specific_location: LIBRA - Fairman Rogers Collection
974
931
  library:
975
932
  - Special Collections
976
- - Kislak Center for Special Collections
977
- - Van Pelt-Dietrich Library Center
978
- display: Kislak Center for Special Collections - Fairman Rogers Coll.
933
+ - LIBRA
934
+ display: LIBRA - Fairman Rogers Collection
979
935
  aeon: true
980
936
  newbrefe:
981
937
  specific_location: 'Veterinary: du Pont Library (New Bolton) - Reference'
@@ -1070,12 +1026,6 @@ sasiarefe:
1070
1026
  specific_location: Van Pelt - Govindaraju/Chandrasekhara South Asia Studies Seminar Room
1071
1027
  library: Van Pelt-Dietrich Library Center
1072
1028
  display: Van Pelt - Govindaraju/Chandrasekhara South Asia Studies Seminar Room (551)
1073
- sasiarese:
1074
- specific_location: Van Pelt - South Asian Reserve
1075
- library:
1076
- - Van Pelt-Dietrich Library Center
1077
- - Reserve
1078
- display: Van Pelt - South Asia Reserve (551)
1079
1029
  scg123:
1080
1030
  specific_location: Kislak Center for Special Collections - Rare Book Collection
1081
1031
  library:
@@ -1085,20 +1035,18 @@ scg123:
1085
1035
  display: Kislak Center for Special Collections - Rare Book Collection 123
1086
1036
  aeon: true
1087
1037
  sc1100c:
1088
- specific_location: Kislak Center for Special Collections - 1100C Collection
1038
+ specific_location: LIBRA - 1100C Collection
1089
1039
  library:
1090
1040
  - Special Collections
1091
- - Kislak Center for Special Collections
1092
- - Van Pelt-Dietrich Library Center
1093
- display: Kislak Center for Special Collections - 1100C Collection
1041
+ - LIBRA
1042
+ display: LIBRA - 1100C Collection
1094
1043
  aeon: true
1095
1044
  scadams:
1096
- specific_location: Kislak Center for Special Collections - Adams Collection
1045
+ specific_location: LIBRA - Adams Collection
1097
1046
  library:
1098
1047
  - Special Collections
1099
- - Kislak Center for Special Collections
1100
- - Van Pelt-Dietrich Library Center
1101
- display: Kislak Center for Special Collections - Adams Collection
1048
+ - LIBRA
1049
+ display: LIBRA - Adams Collection
1102
1050
  aeon: true
1103
1051
  scartbk:
1104
1052
  specific_location: Kislak Center for Special Collections - Artists' Books
@@ -1117,12 +1065,11 @@ scbanks:
1117
1065
  display: Kislak Center for Special Collections - Joanna Banks Collection
1118
1066
  aeon: true
1119
1067
  scblank:
1120
- specific_location: Kislak Center for Special Collections - Blank Collection
1068
+ specific_location: LIBRA - Blank Collection
1121
1069
  library:
1122
1070
  - Special Collections
1123
- - Kislak Center for Special Collections
1124
- - Van Pelt-Dietrich Library Center
1125
- display: Kislak Center for Special Collections - Blank Collection
1071
+ - LIBRA
1072
+ display: LIBRA - Blank Collection
1126
1073
  aeon: true
1127
1074
  scbyron:
1128
1075
  specific_location: Kislak Center for Special Collections - Byron Collection
@@ -1205,12 +1152,11 @@ scelz:
1205
1152
  display: Kislak Center for Special Collections - Elzevier Collection
1206
1153
  aeon: true
1207
1154
  scfast:
1208
- specific_location: Kislak Center for Special Collections - Fast Collection
1155
+ specific_location: LIBRA - Fast Collection
1209
1156
  library:
1210
1157
  - Special Collections
1211
- - Kislak Center for Special Collections
1212
- - Van Pelt-Dietrich Library Center
1213
- display: Kislak Center for Special Collections - Fast Collection
1158
+ - LIBRA
1159
+ display: LIBRA - Fast Collection
1214
1160
  aeon: true
1215
1161
  scforr:
1216
1162
  specific_location: Kislak Center for Special Collections - Forrest Collection
@@ -1253,20 +1199,18 @@ scfurnlib:
1253
1199
  display: Kislak Center for Special Collections - Furness Shakespeare Library (Van
1254
1200
  Pelt 628)
1255
1201
  scfurnst:
1256
- specific_location: Kislak Center for Special Collections - Furness Collection
1202
+ specific_location: LIBRA - Furness Collection
1257
1203
  library:
1258
1204
  - Special Collections
1259
- - Kislak Center for Special Collections
1260
- - Van Pelt-Dietrich Library Center
1261
- display: Kislak Center for Special Collections - Furness Storage
1205
+ - LIBRA
1206
+ display: LIBRA - Furness Storage
1262
1207
  aeon: true
1263
1208
  scgull:
1264
- specific_location: Kislak Center for Special Collections - Gulliver's Travels Collection
1209
+ specific_location: LIBRA - Gulliver's Travels Collection
1265
1210
  library:
1266
1211
  - Special Collections
1267
- - Kislak Center for Special Collections
1268
- - Van Pelt-Dietrich Library Center
1269
- display: Kislak Center for Special Collections - Gulliver's Travels Collection
1212
+ - LIBRA
1213
+ display: LIBRA - Gulliver's Travels Collection
1270
1214
  aeon: true
1271
1215
  scinc:
1272
1216
  specific_location: Kislak Center for Special Collections - Incunables
@@ -1309,12 +1253,11 @@ scmss:
1309
1253
  display: Kislak Center for Special Collections - Manuscripts
1310
1254
  aeon: true
1311
1255
  scmst:
1312
- specific_location: Kislak Center for Special Collections - Manuscripts Storage
1256
+ specific_location: LIBRA - Manuscripts Storage
1313
1257
  library:
1314
1258
  - Special Collections
1315
- - Kislak Center for Special Collections
1316
- - Van Pelt-Dietrich Library Center
1317
- display: Kislak Center for Special Collections - Manuscripts Storage
1259
+ - LIBRA
1260
+ display: LIBRA - Manuscripts Storage
1318
1261
  aeon: true
1319
1262
  scmsw:
1320
1263
  specific_location: Kislak Center for Special Collections - Web
@@ -1367,12 +1310,11 @@ screfe:
1367
1310
  display: Kislak Center for Special Collections - Reference Collection
1368
1311
  aeon: true
1369
1312
  screfestor:
1370
- specific_location: Kislak Center for Special Collections - Reference Storage
1313
+ specific_location: LIBRA - Reference Storage
1371
1314
  library:
1372
1315
  - Special Collections
1373
- - Kislak Center for Special Collections
1374
- - Van Pelt-Dietrich Library Center
1375
- display: Kislak Center for Special Collections Reference Storage
1316
+ - LIBRA
1317
+ display: LIBRA - Reference Storage
1376
1318
  aeon: true
1377
1319
  scschimmel:
1378
1320
  specific_location: Kislak Center for Special Collections - Schimmel Collection
@@ -1399,12 +1341,11 @@ scsmith:
1399
1341
  display: Kislak Center for Special Collections - E.F. Smith Collection
1400
1342
  aeon: true
1401
1343
  scsmithst:
1402
- specific_location: Kislak Center for Special Collections - E.F. Smith Collection
1344
+ specific_location: LIBRA - E.F. Smith Collection
1403
1345
  library:
1404
1346
  - Special Collections
1405
- - Kislak Center for Special Collections
1406
- - Van Pelt-Dietrich Library Center
1407
- display: Kislak Center for Special Collections - E.F. Smith Collection Storage
1347
+ - LIBRA
1348
+ display: LIBRA - E.F. Smith Collection Storage
1408
1349
  aeon: true
1409
1350
  scsterne:
1410
1351
  specific_location: Kislak Center for Special Collections - Day Sterne Collection
@@ -1415,12 +1356,11 @@ scsterne:
1415
1356
  display: Kislak Center for Special Collections - Day Sterne Collection
1416
1357
  aeon: true
1417
1358
  scstor:
1418
- specific_location: Kislak Center for Special Collections - Rare Book Collection
1359
+ specific_location: LIBRA - Rare Book Collection
1419
1360
  library:
1420
1361
  - Special Collections
1421
- - Kislak Center for Special Collections
1422
- - Van Pelt-Dietrich Library Center
1423
- display: Kislak Center for Special Collections - Rare Book Collection Storage
1362
+ - LIBRA
1363
+ display: LIBRA - Rare Book Collection Storage
1424
1364
  aeon: true
1425
1365
  scstorvil:
1426
1366
  specific_location: LIBRA Vilain-Wieck Collection
@@ -1486,10 +1426,6 @@ stor:
1486
1426
  specific_location: LIBRA
1487
1427
  library: LIBRA
1488
1428
  display: LIBRA
1489
- storcirc:
1490
- specific_location: LIBRA - Circulation
1491
- library: LIBRA
1492
- display: LIBRA - Circulation
1493
1429
  storcrstxt:
1494
1430
  specific_location: GIC Collection at Penn Libraries
1495
1431
  library:
@@ -1533,13 +1469,6 @@ scrunning:
1533
1469
  - LIBRA
1534
1470
  display: LIBRA Running Press Collection
1535
1471
  aeon: true
1536
- storvilain:
1537
- specific_location: LIBRA Vilain-Wieck Collection
1538
- library:
1539
- - Special Collections
1540
- - LIBRA
1541
- display: LIBRA Vilain-Wieck Collection
1542
- aeon: true
1543
1472
  univarch:
1544
1473
  specific_location: University Archives
1545
1474
  library: University Archives
@@ -1649,7 +1578,14 @@ veteresov:
1649
1578
  - 'Veterinary: Atwood Library (Campus)'
1650
1579
  - Reserve
1651
1580
  display: 'Veterinary: Atwood Library (Campus) - Reserve Oversize'
1652
- vpexhibit:
1581
+ vetewellrm:
1582
+ specific_location: 'Veterinary: Atwood Library (Campus)- Wellness Room'
1583
+ library:
1584
+ - Health Sciences Libraries
1585
+ - Veterinary
1586
+ - 'Veterinary: Atwood Library (Campus)'
1587
+ display: 'Veterinary: Atwood Library (Campus)- Wellness Room'
1588
+ vpexhibits:
1653
1589
  specific location: Van Pelt - Exhibits and Events
1654
1590
  library: Van Pelt-Dietrich Library Center
1655
1591
  display: Van Pelt - Exhibits and Events -- First Floor, Circulation Desk
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PennMARC
4
- VERSION = '1.3.2'
4
+ VERSION = '1.3.4'
5
5
  end
@@ -105,5 +105,64 @@ describe 'PennMARC::Access' do
105
105
  end
106
106
  end
107
107
  end
108
+
109
+ context 'with an electronic record but no electronic inventory provided' do
110
+ let(:record) { marc_record fields: fields }
111
+
112
+ context 'with physical inventory' do
113
+ let(:fields) do
114
+ [marc_field(tag: PennMARC::Enriched::Pub::PHYS_INVENTORY_TAG),
115
+ marc_field(tag: '944', subfields: { a: 'Database & Article Index',
116
+ b: 'Dictionaries and Thesauri (language based)' })]
117
+ end
118
+
119
+ it 'adds in additional Online access value' do
120
+ expect(helper.facet(record)).to contain_exactly PennMARC::Access::AT_THE_LIBRARY, PennMARC::Access::ONLINE
121
+ end
122
+ end
123
+
124
+ context 'with a 944 indicating an online database' do
125
+ let(:fields) do
126
+ [marc_field(tag: '944', subfields: { a: 'Database & Article Index',
127
+ b: 'Dictionaries and Thesauri (language based)' })]
128
+ end
129
+
130
+ it 'returns expected Online access value' do
131
+ expect(helper.facet(record)).to contain_exactly(PennMARC::Access::ONLINE)
132
+ end
133
+ end
134
+
135
+ context 'with a single MARC indicator check suggesting an online database' do
136
+ let(:fields) do
137
+ [marc_control_field(tag: '006', value: ' o ')]
138
+ end
139
+
140
+ it 'does not return Online access value' do
141
+ expect(helper.facet(record)).not_to include PennMARC::Access::ONLINE
142
+ end
143
+ end
144
+
145
+ context 'with two MARC indicators suggesting an online database' do
146
+ let(:fields) do
147
+ [marc_control_field(tag: '006', value: ' o '),
148
+ marc_control_field(tag: '007', value: 'cr')]
149
+ end
150
+
151
+ it 'returns expected Online access value' do
152
+ expect(helper.facet(record)).to contain_exactly(PennMARC::Access::ONLINE)
153
+ end
154
+ end
155
+
156
+ context 'with other two MARC indicators suggesting an online database' do
157
+ let(:fields) do
158
+ [marc_control_field(tag: '008', value: '970325c19959999nyuwr d o 0 2eng '),
159
+ marc_field(tag: '338', subfields: { a: 'online resource', b: 'cr' })]
160
+ end
161
+
162
+ it 'returns expected Online access value' do
163
+ expect(helper.facet(record)).to contain_exactly(PennMARC::Access::ONLINE)
164
+ end
165
+ end
166
+ end
108
167
  end
109
168
  end
@@ -100,12 +100,12 @@ describe 'PennMARC::Creator' do
100
100
  let(:fields) do
101
101
  [marc_field(tag: '100', subfields: { a: 'Surname, Name', '0': 'http://cool.uri/12345', d: '1900-2000',
102
102
  e: 'author.', '4': 'http://cool.uri/vocabulary/relators/aut' }),
103
- marc_field(tag: '880', subfields: { a: 'Surname, Alternative', '6': '100' })]
103
+ marc_field(tag: '880', subfields: { a: 'Surname, Alternative', e: 'author', '6': '100' })]
104
104
  end
105
105
 
106
- it 'returns single author values with no URIs anywhere (the same as show)' do
106
+ it 'returns single author values and linked alternate with no URIs anywhere (the same as show)' do
107
107
  values = helper.extended_show(record)
108
- expect(values).to contain_exactly 'Surname, Name 1900-2000, author.'
108
+ expect(values).to contain_exactly 'Surname, Name 1900-2000, author.', 'Surname, Alternative, author.'
109
109
  expect(values.join.downcase).not_to include 'http'
110
110
  end
111
111
  end
@@ -478,7 +478,7 @@ describe 'PennMARC::Creator' do
478
478
  describe '.contributor_show' do
479
479
  let(:record) { marc_record fields: fields }
480
480
 
481
- context 'when idicator2 is "1"' do
481
+ context 'when indicator2 is "1"' do
482
482
  let(:fields) do
483
483
  [marc_field(tag: '700', subfields: { a: 'Ignore' }, indicator2: '1')]
484
484
  end
@@ -554,4 +554,184 @@ describe 'PennMARC::Creator' do
554
554
  end
555
555
  end
556
556
  end
557
+
558
+ describe '.contributor_noauthor_show' do
559
+ let(:record) { marc_record fields: fields }
560
+
561
+ context 'when indicator2 is "1"' do
562
+ let(:fields) do
563
+ [marc_field(tag: '700', subfields: { a: 'Ignore' }, indicator2: '1')]
564
+ end
565
+
566
+ it 'ignores the field' do
567
+ values = helper.contributor_noauthor_show(record, relator_map: mapping)
568
+ expect(values).to be_empty
569
+ end
570
+ end
571
+
572
+ context 'with subfield "i"' do
573
+ let(:fields) do
574
+ [
575
+ marc_field(tag: '700', subfields: { i: 'Ignore', e: 'author' }),
576
+ marc_field(tag: '880', subfields: { i: 'Ignore', '6': '700' })
577
+ ]
578
+ end
579
+
580
+ it 'ignores the field' do
581
+ values = helper.contributor_noauthor_show(record, relator_map: mapping)
582
+ expect(values).to be_empty
583
+ end
584
+ end
585
+
586
+ context 'with a single contributor and linked alternate' do
587
+ let(:fields) do
588
+ [
589
+ marc_field(tag: '700', subfields: { a: 'Name', b: 'I', c: 'laureate', d: '1968', e: 'author',
590
+ j: 'pseud', q: 'Fuller Name', u: 'affiliation', '3': 'materials',
591
+ '4': 'aut' }),
592
+ marc_field(tag: '880', subfields: { '6': '700', a: 'Alt Name', b: 'Alt num', c: 'Alt title',
593
+ d: 'Alt date', e: 'Alt relator', j: 'Alt qualifier',
594
+ q: 'Alt Fuller Name', u: 'Alt affiliation', '3': 'Alt material' })
595
+ ]
596
+ end
597
+
598
+ it 'returns the non-author contributor only' do
599
+ values = helper.contributor_noauthor_show(record, relator_map: mapping)
600
+ expect(values).to contain_exactly(
601
+ 'Alt Name Alt num Alt title Alt date Alt qualifier Alt Fuller Name Alt affiliation Alt material, Alt relator.'
602
+ )
603
+ end
604
+
605
+ it 'returns the non-author contributor name only when called with name_only as true' do
606
+ values = helper.contributor_noauthor_show(record, relator_map: mapping, name_only: true)
607
+ expect(values).to contain_exactly 'Alt Name, Alt relator.'
608
+ end
609
+
610
+ it 'returns empty when called with vernacular as false' do
611
+ values = helper.contributor_noauthor_show(record, relator_map: mapping, vernacular: false)
612
+ expect(values).to be_empty
613
+ end
614
+ end
615
+
616
+ context 'with four contributors two of which are authors' do
617
+ let(:fields) do
618
+ [
619
+ marc_field(tag: '700', subfields: { a: '01 (Ignore)', b: 'I', c: 'laureate',
620
+ j: 'pseud', q: 'Fuller Name', u: 'affiliation', '3': 'materials',
621
+ '4': 'aut', '6': '880-01' }),
622
+ marc_field(tag: '700', subfields: { a: '02 (Ignore)', d: '1968', e: 'author',
623
+ j: 'pseud', q: 'Fuller Name', u: 'affiliation', '3': 'materials',
624
+ '6': '880-02' }),
625
+ marc_field(tag: '700', subfields: { a: '03 (Show)', b: 'J', c: 'laureate',
626
+ j: 'pseud', q: 'Fuller Name', u: 'affiliation', '3': 'materials',
627
+ '4': 'edt', '6': '880-03' }),
628
+ marc_field(tag: '700', subfields: { a: '04 (Show)', d: '1968', e: 'editor',
629
+ j: 'pseud', q: 'Fuller Name', u: 'affiliation', '3': 'materials',
630
+ '6': '880-04' })
631
+ ]
632
+ end
633
+
634
+ it 'returns two non-author contributors' do
635
+ values = helper.contributor_noauthor_show(record, relator_map: mapping)
636
+ expect(values).to contain_exactly(
637
+ '03 (Show) J laureate pseud Fuller Name affiliation materials',
638
+ '04 (Show) 1968 pseud Fuller Name affiliation materials, editor.'
639
+ )
640
+ end
641
+
642
+ it 'returns contributor name only when called with name_only as true' do
643
+ values = helper.contributor_noauthor_show(record, relator_map: mapping, name_only: true)
644
+ expect(values).to contain_exactly('03 (Show)', '04 (Show), editor.')
645
+ end
646
+
647
+ it 'returns contributor values without alternatives when called with vernacular as false' do
648
+ values = helper.contributor_noauthor_show(record, relator_map: mapping, vernacular: false)
649
+ expect(values).to contain_exactly(
650
+ '03 (Show) J laureate pseud Fuller Name affiliation materials',
651
+ '04 (Show) 1968 pseud Fuller Name affiliation materials, editor.'
652
+ )
653
+ end
654
+ end
655
+
656
+ context 'with four contributors having respective alternatives, two of the contributors are authors' do
657
+ let(:fields) do
658
+ [
659
+ marc_field(tag: '700', subfields: { a: '01 (Ignore)', b: 'I', c: 'laureate',
660
+ j: 'pseud', q: 'Fuller Name', u: 'affiliation', '3': 'materials',
661
+ '4': 'aut', '6': '880-01' }),
662
+ marc_field(tag: '700', subfields: { a: '02 (Ignore)', d: '1968', e: 'author',
663
+ j: 'pseud', q: 'Fuller Name', u: 'affiliation', '3': 'materials',
664
+ '6': '880-02' }),
665
+ marc_field(tag: '700', subfields: { a: '03 (Show)', b: 'J', c: 'laureate',
666
+ j: 'pseud', q: 'Fuller Name', u: 'affiliation', '3': 'materials',
667
+ '4': 'edt', '6': '880-03' }),
668
+ marc_field(tag: '700', subfields: { a: '04 (Show)', d: '1968', e: 'editor',
669
+ j: 'pseud', q: 'Fuller Name', u: 'affiliation', '3': 'materials',
670
+ '6': '880-04' }),
671
+ marc_field(tag: '880', subfields: { a: 'Alt Name 01 (Ignore)', '6': '700-01', b: 'Alt num 01',
672
+ c: 'Alt title 01', d: 'Alt date 01', e: 'Alt relator 01',
673
+ j: 'Alt qualifier 01', q: 'Alt Fuller Name 01', u: 'Alt affiliation 01',
674
+ '3': 'Alt material 01' }),
675
+ marc_field(tag: '880', subfields: { a: 'Alt Name 02 (Ignore)', '6': '700-02', b: 'Alt num 02',
676
+ c: 'Alt title 02', d: 'Alt date 02', e: 'Alt relator 02',
677
+ j: 'Alt qualifier 02', q: 'Alt Fuller Name 02', u: 'Alt affiliation 02',
678
+ '3': 'Alt material 02' }),
679
+ marc_field(tag: '880', subfields: { a: 'Alt Name 03 (Show)', '6': '700-03', b: 'Alt num 03',
680
+ c: 'Alt title 03', d: 'Alt date 03', e: 'Alt relator 03',
681
+ j: 'Alt qualifier 03', q: 'Alt Fuller Name 03', u: 'Alt affiliation 03',
682
+ '3': 'Alt material 03' }),
683
+ marc_field(tag: '880', subfields: { a: 'Alt Name 04 (Show)', '6': '700-04', b: 'Alt num 04',
684
+ c: 'Alt title 04', d: 'Alt date 04', e: 'Alt relator 04',
685
+ j: 'Alt qualifier 04', q: 'Alt Fuller Name 04', u: 'Alt affiliation 04',
686
+ '3': 'Alt material 04' })
687
+ ]
688
+ end
689
+
690
+ it 'returns two non-author contributors with their alternatives' do
691
+ values = helper.contributor_noauthor_show(record, relator_map: mapping)
692
+ expect(values).to contain_exactly(
693
+ '03 (Show) J laureate pseud Fuller Name affiliation materials',
694
+ '04 (Show) 1968 pseud Fuller Name affiliation materials, editor.',
695
+ 'Alt Name 03 (Show) Alt num 03 Alt title 03 Alt date 03 Alt qualifier 03 Alt Fuller Name 03 '\
696
+ 'Alt affiliation 03 Alt material 03, Alt relator 03.',
697
+ 'Alt Name 04 (Show) Alt num 04 Alt title 04 Alt date 04 Alt qualifier 04 Alt Fuller Name 04 '\
698
+ 'Alt affiliation 04 Alt material 04, Alt relator 04.'
699
+ )
700
+ end
701
+
702
+ it 'returns two non-author contributors name and alternative names only when called with name_only as true' do
703
+ values = helper.contributor_noauthor_show(record, relator_map: mapping, name_only: true)
704
+ expect(values).to contain_exactly('03 (Show)', 'Alt Name 03 (Show), Alt relator 03.',
705
+ '04 (Show), editor.', 'Alt Name 04 (Show), Alt relator 04.')
706
+ end
707
+
708
+ it 'returns two non-author contributors without alternatives when called with vernacular as false' do
709
+ values = helper.contributor_noauthor_show(record, relator_map: mapping, vernacular: false)
710
+ expect(values).to contain_exactly(
711
+ '03 (Show) J laureate pseud Fuller Name affiliation materials',
712
+ '04 (Show) 1968 pseud Fuller Name affiliation materials, editor.'
713
+ )
714
+ end
715
+ end
716
+
717
+ context 'with a corporate contributor and linked alternate' do
718
+ let(:fields) do
719
+ [
720
+ marc_field(tag: '710', subfields: { a: 'Corporation', b: 'A division', c: 'Office', d: '1968', e: 'author',
721
+ u: 'affiliation', '3': 'materials', '4': 'aut' }),
722
+ marc_field(tag: '880', subfields: { '6': '710', a: 'Alt Corp Name', b: 'Alt unit', c: 'Alt location',
723
+ d: 'Alt date', e: ['Alt relator', 'another'], u: 'Alt Affiliation',
724
+ '3': 'Alt materials' })
725
+ ]
726
+ end
727
+
728
+ it 'returns expected contributor values' do
729
+ values = helper.contributor_noauthor_show(record)
730
+ expect(values).to contain_exactly(
731
+ 'Corporation A division Office 1968 affiliation materials, Author.',
732
+ 'Alt Corp Name Alt unit Alt location Alt date Alt Affiliation Alt materials, Alt relator, another.'
733
+ )
734
+ end
735
+ end
736
+ end
557
737
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pennmarc
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 1.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Kanning
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2025-08-22 00:00:00.000000000 Z
15
+ date: 2025-10-02 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: activesupport