pennmarc 1.0.12 → 1.0.15.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +7 -12
- data/.rubocop_todo.yml +2 -2
- data/lib/pennmarc/enriched.rb +93 -0
- data/lib/pennmarc/helpers/access.rb +2 -2
- data/lib/pennmarc/helpers/citation.rb +4 -4
- data/lib/pennmarc/helpers/classification.rb +8 -8
- data/lib/pennmarc/helpers/creator.rb +70 -73
- data/lib/pennmarc/helpers/database.rb +6 -6
- data/lib/pennmarc/helpers/date.rb +3 -3
- data/lib/pennmarc/helpers/edition.rb +4 -2
- data/lib/pennmarc/helpers/format.rb +15 -14
- data/lib/pennmarc/helpers/helper.rb +1 -1
- data/lib/pennmarc/helpers/identifier.rb +16 -14
- data/lib/pennmarc/helpers/inventory.rb +92 -0
- data/lib/pennmarc/helpers/inventory_entry/base.rb +23 -0
- data/lib/pennmarc/helpers/inventory_entry/electronic.rb +20 -0
- data/lib/pennmarc/helpers/inventory_entry/physical.rb +38 -0
- data/lib/pennmarc/helpers/language.rb +3 -2
- data/lib/pennmarc/helpers/location.rb +19 -14
- data/lib/pennmarc/helpers/note.rb +10 -8
- data/lib/pennmarc/helpers/production.rb +9 -9
- data/lib/pennmarc/helpers/relation.rb +12 -9
- data/lib/pennmarc/helpers/series.rb +10 -8
- data/lib/pennmarc/helpers/subject.rb +12 -12
- data/lib/pennmarc/helpers/title.rb +20 -16
- data/lib/pennmarc/mappings/locations.yml +4 -0
- data/lib/pennmarc/util.rb +19 -4
- data/lib/pennmarc/version.rb +1 -1
- data/spec/lib/pennmarc/helpers/access_spec.rb +5 -5
- data/spec/lib/pennmarc/helpers/classification_spec.rb +6 -6
- data/spec/lib/pennmarc/helpers/creator_spec.rb +41 -7
- data/spec/lib/pennmarc/helpers/format_spec.rb +4 -4
- data/spec/lib/pennmarc/helpers/inventory_spec.rb +129 -0
- data/spec/lib/pennmarc/helpers/location_spec.rb +40 -9
- data/spec/lib/pennmarc/helpers/subject_spec.rb +37 -13
- metadata +10 -5
- data/lib/pennmarc/enriched_marc.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd846248b3c6fcde1cfd8a74312d84f46ce28f534effaff22ec112a5456afd2f
|
4
|
+
data.tar.gz: 7e5789d9ef2594767e438a5b1fd2978b1508afad975785059b3520d795fda15b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82a79402e68c4b48f3d38fa165042472aab3a8d811797145811af8a873d177ceb9020a2e71c9853f5c792a37d0533d7a87c7ec94506507c817e3dc09db345dcf
|
7
|
+
data.tar.gz: 87196088380e9b7f6750511434edcc49467ca9ee47e9577cb3f42ce75e595a2f7cb62605ede37d1a4b17b59876dec437a0beee131ee97eb19f1c411751c849cc
|
data/.gitlab-ci.yml
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
include:
|
2
|
+
- project: "devops/gitlab/ci-templates/general"
|
3
|
+
file:
|
4
|
+
- ".install_hashicorp_vault.yml"
|
5
|
+
- ".vault_jwt_auth.yml"
|
2
6
|
- project: "devops/gitlab/ci-templates/ruby"
|
3
7
|
ref: "sans-dind"
|
4
8
|
file:
|
@@ -37,19 +41,10 @@ gem_publication:
|
|
37
41
|
image: ruby:3.2.2
|
38
42
|
variables:
|
39
43
|
GEMSPEC_FILE: "${CI_PROJECT_NAME}.gemspec"
|
40
|
-
VAULT_VERSION: "1.
|
44
|
+
VAULT_VERSION: "1.15.5"
|
41
45
|
before_script:
|
42
|
-
-
|
43
|
-
|
44
|
-
wget \
|
45
|
-
unzip && \
|
46
|
-
wget https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_linux_amd64.zip -O /tmp/vault_${VAULT_VERSION}.zip && \
|
47
|
-
unzip /tmp/vault_${VAULT_VERSION}.zip -d /usr/bin && \
|
48
|
-
rm -fr /tmp/vault_${VAULT_VERSION}.zip && \
|
49
|
-
apt-get remove -y wget unzip && \
|
50
|
-
apt-get clean
|
51
|
-
- export VAULT_ADDR=${VAULT_URL}
|
52
|
-
- export VAULT_TOKEN="$(vault write -field=token auth/jwt/${CI_SERVER_HOST}/login role=${JWT_ROLE} jwt=${CI_JOB_JWT})"
|
46
|
+
- !reference [.install_hashicorp_vault, before_script]
|
47
|
+
- !reference [.vault_jwt_auth, before_script]
|
53
48
|
- export GEM_HOST_API_KEY="$(vault kv get -field=rubygems_api_key ${VAULT_KV_ENDPOINT}${ENVIRONMENT})"
|
54
49
|
- |
|
55
50
|
gem -v
|
data/.rubocop_todo.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 10000`
|
3
|
-
# on 2024-01-
|
3
|
+
# on 2024-01-17 17:00:02 UTC using RuboCop version 1.51.0.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
@@ -60,7 +60,7 @@ Metrics/CyclomaticComplexity:
|
|
60
60
|
- 'lib/pennmarc/helpers/title.rb'
|
61
61
|
- 'lib/pennmarc/util.rb'
|
62
62
|
|
63
|
-
# Offense count:
|
63
|
+
# Offense count: 26
|
64
64
|
# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
|
65
65
|
Metrics/MethodLength:
|
66
66
|
Exclude:
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Constants for Alma's MARC enrichment, performed and included in the MARCXML either by the Publishing process or by
|
4
|
+
# API service
|
5
|
+
module PennMARC
|
6
|
+
module Enriched
|
7
|
+
# Enriched MARC fields added by configurable setting in the Publishing profile that generates the MARCXML
|
8
|
+
# TODO: review if we can/should modify the subfields used in the pub profile to create parity with API subfields as
|
9
|
+
# that could simplify this mapping tremendously
|
10
|
+
module Pub
|
11
|
+
# Enrichment Tag Names
|
12
|
+
PHYS_INVENTORY_TAG = 'hld'
|
13
|
+
ELEC_INVENTORY_TAG = 'prt'
|
14
|
+
ITEM_TAG = 'itm'
|
15
|
+
|
16
|
+
# Subfields for HLD tags
|
17
|
+
# Follow MARC 852 spec: https://www.loc.gov/marc/holdings/hd852.html, but names are translated into Alma parlance
|
18
|
+
PHYS_LOCATION_NAME = 'b' # e.g., Libra
|
19
|
+
PHYS_LOCATION_CODE = 'c' # e.g., stor
|
20
|
+
HOLDING_CLASSIFICATION_PART = 'h' # "classification part" first part of call num e.g., KF6450
|
21
|
+
HOLDING_ITEM_PART = 'i' # "item part?" second part of call num e.g., .C59 1989
|
22
|
+
PHYS_PUBLIC_NOTE = 'z'
|
23
|
+
PHYS_INTERNAL_NOTE = 'x'
|
24
|
+
PHYS_HOLDING_ID = '8'
|
25
|
+
|
26
|
+
# Subfields for ITM tags
|
27
|
+
ITEM_CURRENT_LOCATION = 'g'
|
28
|
+
ITEM_CALL_NUMBER_TYPE = 'h'
|
29
|
+
ITEM_CALL_NUMBER = 'i'
|
30
|
+
ITEM_DATE_CREATED = 'q'
|
31
|
+
|
32
|
+
# Subfields for PRT tags
|
33
|
+
ELEC_PORTFOLIO_ID = 'a'
|
34
|
+
ELEC_SERVICE_URL = 'b'
|
35
|
+
ELEC_COLLECTION_NAME = 'c'
|
36
|
+
ELEC_INTERFACE_NAME = 'e'
|
37
|
+
ELEC_PUBLIC_NOTE = 'f'
|
38
|
+
ELEC_COVERAGE_STMT = 'g'
|
39
|
+
|
40
|
+
# other values that could be added if we configured the Alma pub profile (and values are set on the record)
|
41
|
+
# - Authentication note
|
42
|
+
# - "static URL"
|
43
|
+
# - Electronic material type
|
44
|
+
# - Collection ID
|
45
|
+
# - create/update/activation date
|
46
|
+
# - license code
|
47
|
+
# - portfolio coverage info
|
48
|
+
# - from year, until year (month, day volume issue)
|
49
|
+
# - portfolio embargo info
|
50
|
+
# - years/months embargo'd
|
51
|
+
|
52
|
+
# TODO: evaluate this in context of changed boundwiths processing
|
53
|
+
# Franklin legacy note:
|
54
|
+
# a subfield code NOT used by the MARC 21 spec for 852 holdings records.
|
55
|
+
# we add this subfield during preprocessing to store boundwith record IDs.
|
56
|
+
# BOUND_WITH_ID = 'y'
|
57
|
+
end
|
58
|
+
|
59
|
+
# MARC enrichment originating from Alma API
|
60
|
+
# @see https://developers.exlibrisgroup.com/alma/apis/docs/bibs/R0VUIC9hbG1hd3MvdjEvYmlicy97bW1zX2lkfQ==/ Alma docs
|
61
|
+
# We cannot modify these subfield settings
|
62
|
+
module Api
|
63
|
+
# Enrichment Tag Names
|
64
|
+
PHYS_INVENTORY_TAG = 'AVA'
|
65
|
+
ELEC_INVENTORY_TAG = 'AVE'
|
66
|
+
|
67
|
+
# Physical Holding (AVA) subfields
|
68
|
+
PHYS_CALL_NUMBER = 'd'
|
69
|
+
PHYS_CALL_NUMBER_TYPE = 'k'
|
70
|
+
PHYS_LIBRARY_CODE = 'b'
|
71
|
+
PHYS_LIBRARY_NAME = 'q'
|
72
|
+
PHYS_LOCATION_CODE = 'j'
|
73
|
+
PHYS_LOCATION_NAME = 'c'
|
74
|
+
PHYS_HOLDING_ID = '8'
|
75
|
+
PHYS_AVAILABILITY = 'e'
|
76
|
+
PHYS_TOTAL_ITEMS = 'f'
|
77
|
+
PHYS_UNAVAILABLE_ITEMS = 'g'
|
78
|
+
PHYS_SUMMARY_INFO = 'v'
|
79
|
+
PHYS_PRIORITY = 'p'
|
80
|
+
|
81
|
+
# Electronic Portfolio (AVE) subfields
|
82
|
+
ELEC_LIBRARY_CODE = 'l'
|
83
|
+
ELEC_COLLECTION_NAME = 'm'
|
84
|
+
ELEC_PUBLIC_NOTE = 'n'
|
85
|
+
ELEC_SERVICE_URL = 'u'
|
86
|
+
ELEC_COVERAGE_STMT = 's'
|
87
|
+
ELEC_INTERFACE_NAME = 't'
|
88
|
+
ELEC_PORTFOLIO_ID = '8'
|
89
|
+
ELEC_COLLECTION_ID = 'c'
|
90
|
+
ELEC_ACTIVATION_STATUS = 'e'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -33,14 +33,14 @@ module PennMARC
|
|
33
33
|
# @param [MARC::Field] field
|
34
34
|
# @return [Boolean]
|
35
35
|
def electronic_holding_tag?(field)
|
36
|
-
field.tag.in? [
|
36
|
+
field.tag.in? [Enriched::Pub::ELEC_INVENTORY_TAG, Enriched::Api::ELEC_INVENTORY_TAG]
|
37
37
|
end
|
38
38
|
|
39
39
|
# Does the record have added physical holding info?
|
40
40
|
# @param [MARC::Field] field
|
41
41
|
# @return [Boolean]
|
42
42
|
def physical_holding_tag?(field)
|
43
|
-
field.tag.in? [
|
43
|
+
field.tag.in? [Enriched::Pub::PHYS_INVENTORY_TAG, Enriched::Api::PHYS_INVENTORY_TAG]
|
44
44
|
end
|
45
45
|
|
46
46
|
# Check if a record contains an 856 entry for an online finding aid, meeting these criteria:
|
@@ -11,9 +11,9 @@ module PennMARC
|
|
11
11
|
# field 520 (Summary, Etc. Note).
|
12
12
|
# https://www.loc.gov/marc/bibliographic/bd510.html
|
13
13
|
# @param [MARC::Record] record
|
14
|
-
# @return [Array] array of citations and any linked alternates
|
14
|
+
# @return [Array<String>] array of citations and any linked alternates
|
15
15
|
def cited_in_show(record)
|
16
|
-
datafield_and_linked_alternate(record, '510')
|
16
|
+
datafield_and_linked_alternate(record, '510').uniq
|
17
17
|
end
|
18
18
|
|
19
19
|
# Field 524 is the Preferred Citation of Described Materials Note. It is the Format for the citation of the
|
@@ -22,9 +22,9 @@ module PennMARC
|
|
22
22
|
# introductory phrase that is generated as a display constant based on the first indicator value.
|
23
23
|
# https://www.loc.gov/marc/bibliographic/bd524.html
|
24
24
|
# @param [MARC::Record] record
|
25
|
-
# @return [Array] array of citation of described materials note and any linked alternates
|
25
|
+
# @return [Array<String>] array of citation of described materials note and any linked alternates
|
26
26
|
def cite_as_show(record)
|
27
|
-
datafield_and_linked_alternate(record, '524')
|
27
|
+
datafield_and_linked_alternate(record, '524').uniq
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -16,19 +16,19 @@ module PennMARC
|
|
16
16
|
}.freeze
|
17
17
|
|
18
18
|
# Enriched MARC tags that hold classification data
|
19
|
-
TAGS = [
|
19
|
+
TAGS = [Enriched::Pub::ITEM_TAG, Enriched::Api::PHYS_INVENTORY_TAG].freeze
|
20
20
|
|
21
21
|
class << self
|
22
22
|
# Parse classification values for faceting. We retrieve classification values from enriched MARC fields 'itm' or
|
23
23
|
# 'AVA' originating respectively from the Alma publishing process or from the Alma Api. We return the
|
24
24
|
# highest level LOC or Dewey classifications from each available call number, joining the class code with
|
25
|
-
# its title in a single string. See {PennMARC::
|
25
|
+
# its title in a single string. See {PennMARC::Enriched} and {PennMARC::Enriched::Api} for more
|
26
26
|
# information on the enriched MARC fields.
|
27
27
|
# @see https://developers.exlibrisgroup.com/alma/apis/docs/bibs/R0VUIC9hbG1hd3MvdjEvYmlicy97bW1zX2lkfQ==/ AVA docs
|
28
28
|
# @param [MARC::Record] record
|
29
29
|
# @return [Array<String>] array of classifications
|
30
30
|
def facet(record)
|
31
|
-
record.fields(TAGS).flat_map
|
31
|
+
record.fields(TAGS).flat_map { |field|
|
32
32
|
call_number_type = subfield_values(field, call_number_type_sf(field))&.first
|
33
33
|
call_numbers = subfield_values(field, call_number_sf(field))
|
34
34
|
|
@@ -39,7 +39,7 @@ module PennMARC
|
|
39
39
|
|
40
40
|
format_facet(class_code, call_number_type, title)
|
41
41
|
end
|
42
|
-
|
42
|
+
}.uniq
|
43
43
|
end
|
44
44
|
|
45
45
|
private
|
@@ -48,18 +48,18 @@ module PennMARC
|
|
48
48
|
# @param [MARC::DataField] field
|
49
49
|
# @return [String]
|
50
50
|
def call_number_sf(field)
|
51
|
-
return
|
51
|
+
return Enriched::Pub::ITEM_CALL_NUMBER if field.tag == Enriched::Pub::ITEM_TAG
|
52
52
|
|
53
|
-
|
53
|
+
Enriched::Api::PHYS_CALL_NUMBER
|
54
54
|
end
|
55
55
|
|
56
56
|
# Retrieve subfield code that stores call number type on enriched marc field
|
57
57
|
# @param [MARC::DataField] field
|
58
58
|
# @return [String]
|
59
59
|
def call_number_type_sf(field)
|
60
|
-
return
|
60
|
+
return Enriched::Pub::ITEM_CALL_NUMBER_TYPE if field.tag == Enriched::Pub::ITEM_TAG
|
61
61
|
|
62
|
-
|
62
|
+
Enriched::Api::PHYS_CALL_NUMBER_TYPE
|
63
63
|
end
|
64
64
|
|
65
65
|
# retrieve title of classification based on single char classification code and call number type
|
@@ -10,82 +10,43 @@ module PennMARC
|
|
10
10
|
class << self
|
11
11
|
# Main tags for Author/Creator information
|
12
12
|
TAGS = %w[100 110].freeze
|
13
|
+
|
13
14
|
# Aux tags for Author/Creator information, for use in search_aux method
|
14
15
|
AUX_TAGS = %w[100 110 111 400 410 411 700 710 711 800 810 811].freeze
|
15
16
|
|
17
|
+
CONFERENCE_SEARCH_TAGS = %w[111 711 811].freeze
|
18
|
+
|
19
|
+
# subfields NOT to join when combining raw subfield values
|
20
|
+
NAME_EXCLUDED_SUBFIELDS = %w[a 1 4 5 6 8 t].freeze
|
21
|
+
|
16
22
|
# Author/Creator search field. Includes all subfield values (even ǂ0 URIs) from
|
17
23
|
# {https://www.oclc.org/bibformats/en/1xx/100.html 100 Main Entry--Personal Name} and
|
18
24
|
# {https://www.oclc.org/bibformats/en/1xx/110.html 110 Main Entry--Corporate Name}. Maps any relator codes found
|
19
25
|
# in ǂ4. To better handle name searches, returns names as both "First Last" and "Last, First" if a comma is found
|
20
|
-
# in ǂa. Also indexes any linked values in the 880.
|
21
|
-
#
|
22
|
-
# @todo
|
23
|
-
# but this should be reexamined in the relevancy-tuning phase. URIs should def be removed. and shouldn't
|
24
|
-
# indicator1 tell us the order of the name?
|
26
|
+
# in ǂa. Also indexes any linked values in the 880.
|
27
|
+
# @todo are we including too many details here and gumming up our index? consider UIRs, relator labels, dates...
|
28
|
+
# @todo shouldn't indicator1 tell us the order of the name? do we not trust the indicator?
|
25
29
|
# @note ported from get_author_creator_1_search_values
|
26
30
|
# @param [MARC::Record] record
|
27
31
|
# @param [Hash] relator_map
|
28
32
|
# @return [Array<String>] array of author/creator values for indexing
|
29
33
|
def search(record, relator_map: Mappers.relator)
|
30
|
-
|
31
|
-
acc = record.fields(TAGS).map do |field|
|
32
|
-
pieces = field.filter_map do |sf|
|
33
|
-
if sf.code == 'a'
|
34
|
-
convert_name_order(sf.value)
|
35
|
-
elsif creator_subfields.exclude?(sf.code)
|
36
|
-
sf.value
|
37
|
-
elsif sf.code == '4'
|
38
|
-
relator = translate_relator(sf.value, relator_map)
|
39
|
-
next if relator.blank?
|
40
|
-
|
41
|
-
relator
|
42
|
-
end
|
43
|
-
end
|
44
|
-
value = join_and_squish(pieces)
|
45
|
-
if value.end_with?('.', '-')
|
46
|
-
value
|
47
|
-
else
|
48
|
-
"#{value}."
|
49
|
-
end
|
50
|
-
end
|
51
|
-
# a second iteration over the same fields produces name entries with the names not reordered
|
52
|
-
secondary_subfields = %w[4 6 8]
|
53
|
-
acc += record.fields(TAGS).map do |field|
|
54
|
-
pieces = field.filter_map do |sf|
|
55
|
-
if secondary_subfields.exclude?(sf.code)
|
56
|
-
sf.value
|
57
|
-
elsif sf.code == '4'
|
58
|
-
relator = translate_relator(sf.value, relator_map)
|
59
|
-
next if relator.blank?
|
60
|
-
|
61
|
-
relator
|
62
|
-
end
|
63
|
-
end
|
64
|
-
value = join_and_squish(pieces)
|
65
|
-
if value.end_with?('.', '-')
|
66
|
-
value
|
67
|
-
else
|
68
|
-
"#{value}."
|
69
|
-
end
|
70
|
-
end
|
71
|
-
acc += record.fields(%w[880]).filter_map do |field|
|
72
|
-
next unless field.any? { |sf| sf.code == '6' && sf.value.in?(%w[100 110]) }
|
73
|
-
|
74
|
-
suba = field.find_all(&subfield_in?(%w[a])).map { |sf|
|
75
|
-
convert_name_order(sf.value)
|
76
|
-
}.first
|
77
|
-
oth = join_and_squish(field.find_all(&subfield_not_in?(%w[6 8 a t])).map(&:value))
|
78
|
-
join_and_squish [suba, oth]
|
79
|
-
end
|
80
|
-
acc.uniq
|
34
|
+
name_search_values record: record, tags: TAGS, relator_map: relator_map
|
81
35
|
end
|
82
36
|
|
83
37
|
# Auxiliary Author/Creator search field
|
38
|
+
# This duplicates the values returned by the search method, but adds in additional MARC tags to include
|
39
|
+
# creator-adjacent entities. The added 4xx tags are mostly obsolete, but the 7xx tags are important. See:
|
40
|
+
# {https://www.loc.gov/marc/bibliographic/bd700.html MARC 700},
|
41
|
+
# {https://www.loc.gov/marc/bibliographic/bd710.html MARC 710},
|
42
|
+
# and {https://www.loc.gov/marc/bibliographic/bd711.html MARC 711}. The 800, 810 and 8111 tags are similar in
|
43
|
+
# theme to the 7xx fields but apply to serial records.
|
84
44
|
# @note ported from get_author_creator_2_search_values
|
85
|
-
# @todo port this later
|
86
45
|
# @param [MARC::Record] record
|
87
46
|
# @return [Array<String>] array of extended author/creator values for indexing
|
88
|
-
def search_aux(record)
|
47
|
+
def search_aux(record, relator_map: Mappers.relator)
|
48
|
+
name_search_values record: record, tags: AUX_TAGS, relator_map: relator_map
|
49
|
+
end
|
89
50
|
|
90
51
|
# All author/creator values for display (like #show, but multivalued?) - no 880 linkage
|
91
52
|
# @note ported from get_author_creator_values (indexed as author_creator_a) - shown on results page
|
@@ -106,9 +67,9 @@ module PennMARC
|
|
106
67
|
def show(record)
|
107
68
|
fields = record.fields(TAGS)
|
108
69
|
fields += record.fields('880').select { |field| subfield_value_in?(field, '6', TAGS) }
|
109
|
-
fields.filter_map
|
70
|
+
fields.filter_map { |field|
|
110
71
|
join_subfields(field, &subfield_not_in?(%w[0 1 4 6 8 e w]))
|
111
|
-
|
72
|
+
}.uniq
|
112
73
|
end
|
113
74
|
|
114
75
|
# Author/Creator sort. Does not map and include any relator codes.
|
@@ -134,11 +95,11 @@ module PennMARC
|
|
134
95
|
700 => 'abcdjq', 710 => 'abcdjq', 711 => 'abcen',
|
135
96
|
800 => 'abcdjq', 810 => 'abcdjq', 811 => 'abcen'
|
136
97
|
}
|
137
|
-
source_map.flat_map
|
98
|
+
source_map.flat_map { |field_num, subfields|
|
138
99
|
record.fields(field_num.to_s).map do |field|
|
139
100
|
trim_punctuation(join_subfields(field, &subfield_in?(subfields.chars)))
|
140
101
|
end
|
141
|
-
|
102
|
+
}.uniq
|
142
103
|
end
|
143
104
|
|
144
105
|
# Conference for display, intended for results display
|
@@ -147,9 +108,9 @@ module PennMARC
|
|
147
108
|
# @param [Hash] relator_map
|
148
109
|
# @return [Array<String>] array of conference values
|
149
110
|
def conference_show(record, relator_map: Mappers.relator)
|
150
|
-
record.fields('111').filter_map
|
111
|
+
record.fields('111').filter_map { |field|
|
151
112
|
name_from_main_entry field, relator_map
|
152
|
-
|
113
|
+
}.uniq
|
153
114
|
end
|
154
115
|
|
155
116
|
# Conference detailed display, intended for record show page.
|
@@ -169,7 +130,7 @@ module PennMARC
|
|
169
130
|
conf_extra = join_subfields field, &subfield_in?(%w[e j w])
|
170
131
|
join_and_squish [conf, conf_extra].compact_blank
|
171
132
|
end
|
172
|
-
values + record.fields('880').filter_map do |field|
|
133
|
+
conferences = values + record.fields('880').filter_map do |field|
|
173
134
|
next unless subfield_value_in? field, '6', %w[111 711]
|
174
135
|
|
175
136
|
next if subfield_defined? field, 'i'
|
@@ -178,11 +139,17 @@ module PennMARC
|
|
178
139
|
conf_extra = join_subfields(field, &subfield_in?(%w[4 e j w]))
|
179
140
|
join_and_squish [conf, conf_extra]
|
180
141
|
end
|
142
|
+
conferences.uniq
|
181
143
|
end
|
182
144
|
|
183
|
-
#
|
184
|
-
# @
|
185
|
-
|
145
|
+
# Conference name values for searching
|
146
|
+
# @param [MARC::Record] record
|
147
|
+
# @return [Array<String>]
|
148
|
+
def conference_search(record)
|
149
|
+
record.fields(CONFERENCE_SEARCH_TAGS).filter_map { |field|
|
150
|
+
join_subfields(field, &subfield_in?(%w[a c d e]))
|
151
|
+
}.uniq
|
152
|
+
end
|
186
153
|
|
187
154
|
# Retrieve contributor values for display from fields {https://www.oclc.org/bibformats/en/7xx/700.html 700}
|
188
155
|
# and {https://www.oclc.org/bibformats/en/7xx/710.html 710} and their linked alternates. Joins subfields
|
@@ -193,7 +160,7 @@ module PennMARC
|
|
193
160
|
# @return [Array<String>]
|
194
161
|
def contributor_show(record, relator_map: Mappers.relator)
|
195
162
|
indicator_2_options = ['', ' ', '0']
|
196
|
-
|
163
|
+
values = record.fields(%w[700 710]).filter_map do |field|
|
197
164
|
next unless indicator_2_options.member?(field.indicator2)
|
198
165
|
next if subfield_defined? field, 'i'
|
199
166
|
|
@@ -210,7 +177,7 @@ module PennMARC
|
|
210
177
|
}.join
|
211
178
|
"#{contributor} #{contributor_append}".squish
|
212
179
|
end
|
213
|
-
contributors + record.fields('880').filter_map do |field|
|
180
|
+
contributors = values + record.fields('880').filter_map do |field|
|
214
181
|
next unless subfield_value_in?(field, '6', %w[700 710])
|
215
182
|
next if subfield_defined?(field, 'i')
|
216
183
|
|
@@ -218,10 +185,37 @@ module PennMARC
|
|
218
185
|
contributor_append = join_subfields(field, &subfield_in?(%w[e u 3]))
|
219
186
|
"#{contributor} #{contributor_append}".squish
|
220
187
|
end
|
188
|
+
contributors.uniq
|
221
189
|
end
|
222
190
|
|
223
191
|
private
|
224
192
|
|
193
|
+
# @param [MARC::Record] record
|
194
|
+
# @param [Array] tags to consider
|
195
|
+
# @param [Hash] relator_map
|
196
|
+
# @return [Array<String>] name values from given tags
|
197
|
+
def name_search_values(record:, tags:, relator_map:)
|
198
|
+
acc = record.fields(tags).filter_map do |field|
|
199
|
+
name_from_main_entry field, relator_map, should_convert_name_order: false
|
200
|
+
end
|
201
|
+
|
202
|
+
acc += record.fields(tags).filter_map do |field|
|
203
|
+
name_from_main_entry field, relator_map, should_convert_name_order: true
|
204
|
+
end
|
205
|
+
|
206
|
+
acc += record.fields(['880']).filter_map do |field|
|
207
|
+
next unless field.any? { |sf| sf.code == '6' && sf.value.in?(tags) }
|
208
|
+
|
209
|
+
suba = field.find_all(&subfield_in?(%w[a])).filter_map { |sf|
|
210
|
+
convert_name_order(sf.value)
|
211
|
+
}.first
|
212
|
+
oth = join_and_squish(field.find_all(&subfield_not_in?(%w[6 8 a t])).map(&:value))
|
213
|
+
join_and_squish [suba, oth]
|
214
|
+
end
|
215
|
+
|
216
|
+
acc.uniq
|
217
|
+
end
|
218
|
+
|
225
219
|
# Trim punctuation method extracted from Traject macro, to ensure consistent output
|
226
220
|
# @todo move to Util?
|
227
221
|
# @param [String] string
|
@@ -244,11 +238,14 @@ module PennMARC
|
|
244
238
|
|
245
239
|
# Extract the information we care about from 1xx fields, map relator codes, and use appropriate punctuation
|
246
240
|
# @param [MARC::Field] field
|
241
|
+
# @param [Hash] mapping
|
242
|
+
# @param [Boolean] should_convert_name_order
|
247
243
|
# @return [String] joined subfield values for value from field
|
248
|
-
def name_from_main_entry(field, mapping)
|
249
|
-
name_subfields = %w[0 1 4 6 8]
|
244
|
+
def name_from_main_entry(field, mapping, should_convert_name_order: false)
|
250
245
|
s = field.filter_map { |sf|
|
251
|
-
if
|
246
|
+
if sf.code == 'a'
|
247
|
+
should_convert_name_order ? convert_name_order(sf.value) : sf.value
|
248
|
+
elsif NAME_EXCLUDED_SUBFIELDS.exclude?(sf.code)
|
252
249
|
" #{sf.value}"
|
253
250
|
elsif sf.code == '4'
|
254
251
|
relator = translate_relator(sf.value, mapping)
|
@@ -19,13 +19,13 @@ module PennMARC
|
|
19
19
|
# @param [Marc::Record]
|
20
20
|
# @return [Array<string>] Array of types
|
21
21
|
def type_facet(record)
|
22
|
-
record.fields('944').filter_map
|
22
|
+
record.fields('944').filter_map { |field|
|
23
23
|
# skip unless specified database format type present
|
24
24
|
next unless subfield_value?(field, 'a', /#{DATABASES_FACET_VALUE}/o)
|
25
25
|
|
26
26
|
type = field.find { |subfield| subfield.code == 'b' }
|
27
27
|
type&.value
|
28
|
-
|
28
|
+
}.uniq
|
29
29
|
end
|
30
30
|
|
31
31
|
# Retrieves database subject category/communities of interest (subfield 'a') from
|
@@ -37,13 +37,13 @@ module PennMARC
|
|
37
37
|
def category_facet(record)
|
38
38
|
return [] unless curated_db?(record)
|
39
39
|
|
40
|
-
record.fields('943').filter_map
|
40
|
+
record.fields('943').filter_map { |field|
|
41
41
|
# skip unless Community of Interest code is in subfield '2'
|
42
42
|
next unless subfield_value?(field, '2', /#{COI_CODE}/o)
|
43
43
|
|
44
44
|
category = field.find { |subfield| subfield.code == 'a' }
|
45
45
|
category&.value
|
46
|
-
|
46
|
+
}.uniq
|
47
47
|
end
|
48
48
|
|
49
49
|
# Concatenates database subject category with database sub subject category in the format "category--subcategory"
|
@@ -58,7 +58,7 @@ module PennMARC
|
|
58
58
|
def subcategory_facet(record)
|
59
59
|
return [] unless curated_db?(record)
|
60
60
|
|
61
|
-
record.fields('943').filter_map
|
61
|
+
record.fields('943').filter_map { |field|
|
62
62
|
# skip unless Community of Interest code is in subfield '2'
|
63
63
|
next unless subfield_value?(field, '2', /#{COI_CODE}/o)
|
64
64
|
|
@@ -73,7 +73,7 @@ module PennMARC
|
|
73
73
|
next if subcategory.blank?
|
74
74
|
|
75
75
|
"#{category.value}--#{subcategory.value}"
|
76
|
-
|
76
|
+
}.uniq
|
77
77
|
end
|
78
78
|
|
79
79
|
private
|
@@ -20,13 +20,13 @@ module PennMARC
|
|
20
20
|
end
|
21
21
|
|
22
22
|
# Retrieve date added (subfield 'q') from enriched marc 'itm' field.
|
23
|
-
# {PennMARC::
|
23
|
+
# {PennMARC::Enriched} maps enriched marc fields and subfields created during Alma publishing. The enriched
|
24
24
|
# metadata provided by the Alma API does not include the date created value, so we can't work with that here.
|
25
25
|
# @param [MARC::Record] record
|
26
26
|
# @return [DateTime, nil] The date added, or nil if date found in record is invalid
|
27
27
|
def added(record)
|
28
|
-
record.fields(
|
29
|
-
subfield_values(field,
|
28
|
+
record.fields(Enriched::Pub::ITEM_TAG).flat_map { |field|
|
29
|
+
subfield_values(field, Enriched::Pub::ITEM_DATE_CREATED).filter_map do |date_added|
|
30
30
|
# On 2022-05-02, this field value (as exported in enriched publishing
|
31
31
|
# job from Alma) began truncating time to day-level granularity. We have
|
32
32
|
# no guarantee that this won't switch back in the future, so for the
|
@@ -14,9 +14,10 @@ module PennMARC
|
|
14
14
|
# @param [MARC::Record] record
|
15
15
|
# @return [Array<String>] array of editions and their alternates
|
16
16
|
def show(record)
|
17
|
-
record.fields('250').map { |field|
|
17
|
+
editions = record.fields('250').map { |field|
|
18
18
|
join_subfields(field, &subfield_not_in?(%w[6 8]))
|
19
19
|
} + linked_alternate_not_6_or_8(record, '250')
|
20
|
+
editions.uniq
|
20
21
|
end
|
21
22
|
|
22
23
|
# Edition values for display in search results. Just grab the first 250 field.
|
@@ -42,12 +43,13 @@ module PennMARC
|
|
42
43
|
|
43
44
|
other_edition_value(field, relator_map)
|
44
45
|
end
|
45
|
-
values + record.fields('880').filter_map do |field|
|
46
|
+
editions = values + record.fields('880').filter_map do |field|
|
46
47
|
next unless field.indicator2.blank? && subfield_value_in?(field, '6', %w[775]) &&
|
47
48
|
subfield_defined?(field, 'i')
|
48
49
|
|
49
50
|
other_edition_value(field, relator_map)
|
50
51
|
end
|
52
|
+
editions.uniq
|
51
53
|
end
|
52
54
|
|
53
55
|
private
|
@@ -48,7 +48,7 @@ module PennMARC
|
|
48
48
|
end
|
49
49
|
join_subfields(f, &subfield_not_in?(subfield_to_ignore))
|
50
50
|
end
|
51
|
-
results.compact_blank
|
51
|
+
results.compact_blank.uniq
|
52
52
|
end
|
53
53
|
|
54
54
|
# Get Format values for faceting. Format values are determined using complex logic for each possible format value.
|
@@ -122,23 +122,24 @@ module PennMARC
|
|
122
122
|
OTHER
|
123
123
|
end
|
124
124
|
end
|
125
|
-
formats.concat(curated_format(record))
|
125
|
+
formats.concat(curated_format(record)).uniq
|
126
126
|
end
|
127
127
|
|
128
128
|
# Show "Other Format" values from {https://www.oclc.org/bibformats/en/7xx/776.html 776} and any 880 linkage.
|
129
129
|
# @todo is 774 an error in the linked field in legacy? i changed to 776 here
|
130
130
|
# @param [MARC::Record] record
|
131
|
-
# @return [Array] other format values for display
|
131
|
+
# @return [Array<String>] other format values for display
|
132
132
|
def other_show(record)
|
133
|
-
|
133
|
+
values = record.fields('776').filter_map do |field|
|
134
134
|
value = join_subfields(field, &subfield_in?(%w[i a s t o]))
|
135
135
|
next if value.blank?
|
136
136
|
|
137
137
|
value
|
138
138
|
end
|
139
|
-
other_formats + linked_alternate(record, '776') do |sf|
|
139
|
+
other_formats = values + linked_alternate(record, '776') do |sf|
|
140
140
|
sf.code.in? %w[i a s t o]
|
141
141
|
end
|
142
|
+
other_formats.uniq
|
142
143
|
end
|
143
144
|
|
144
145
|
# Retrieve cartographic reference data for map/atlas formats for display from
|
@@ -146,9 +147,9 @@ module PennMARC
|
|
146
147
|
# @param [MARC::Record] record
|
147
148
|
# @return [Array<String>]
|
148
149
|
def cartographic_show(record)
|
149
|
-
record.fields(%w[255 342]).map
|
150
|
+
record.fields(%w[255 342]).map { |field|
|
150
151
|
join_subfields(field, &subfield_not_in?(%w[6 8]))
|
151
|
-
|
152
|
+
}.uniq
|
152
153
|
end
|
153
154
|
|
154
155
|
# Check if a set of locations has any locations that include the term 'manuscripts'
|
@@ -165,14 +166,14 @@ module PennMARC
|
|
165
166
|
# @param [MARC::Record] record
|
166
167
|
# @return [Array]
|
167
168
|
def call_nums(record)
|
168
|
-
if field_defined?(record,
|
169
|
-
record.fields(
|
170
|
-
join_subfields(field, &subfield_in?([
|
171
|
-
|
169
|
+
if field_defined?(record, Enriched::Pub::PHYS_INVENTORY_TAG)
|
170
|
+
record.fields(Enriched::Pub::PHYS_INVENTORY_TAG).map do |field|
|
171
|
+
join_subfields(field, &subfield_in?([Enriched::Pub::HOLDING_CLASSIFICATION_PART,
|
172
|
+
Enriched::Pub::HOLDING_ITEM_PART]))
|
172
173
|
end
|
173
|
-
elsif field_defined?(record,
|
174
|
-
record.fields(
|
175
|
-
join_subfields(field, &subfield_in?([
|
174
|
+
elsif field_defined?(record, Enriched::Api::PHYS_INVENTORY_TAG)
|
175
|
+
record.fields(Enriched::Api::PHYS_INVENTORY_TAG).map do |field|
|
176
|
+
join_subfields(field, &subfield_in?([Enriched::Api::PHYS_CALL_NUMBER_TYPE]))
|
176
177
|
end
|
177
178
|
else
|
178
179
|
[]
|