pennmarc 1.0.24 → 1.0.26
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/.rubocop_todo.yml +8 -9
- data/lib/pennmarc/enriched.rb +1 -0
- data/lib/pennmarc/helpers/access.rb +8 -6
- data/lib/pennmarc/helpers/creator.rb +139 -65
- data/lib/pennmarc/helpers/edition.rb +5 -3
- data/lib/pennmarc/helpers/identifier.rb +12 -0
- data/lib/pennmarc/helpers/note.rb +24 -19
- data/lib/pennmarc/helpers/production.rb +113 -20
- data/lib/pennmarc/helpers/subject.rb +10 -4
- data/lib/pennmarc/helpers/title.rb +39 -26
- data/lib/pennmarc/test/marc_helpers.rb +83 -0
- data/lib/pennmarc/util.rb +98 -69
- data/lib/pennmarc/version.rb +1 -1
- data/lib/pennmarc.rb +7 -0
- data/spec/lib/pennmarc/helpers/access_spec.rb +11 -2
- data/spec/lib/pennmarc/helpers/citation_spec.rb +0 -2
- data/spec/lib/pennmarc/helpers/classification_spec.rb +0 -2
- data/spec/lib/pennmarc/helpers/creator_spec.rb +103 -2
- data/spec/lib/pennmarc/helpers/database_spec.rb +0 -2
- data/spec/lib/pennmarc/helpers/date_spec.rb +0 -2
- data/spec/lib/pennmarc/helpers/edition_spec.rb +4 -2
- data/spec/lib/pennmarc/helpers/format_spec.rb +0 -2
- data/spec/lib/pennmarc/helpers/genre_spec.rb +0 -2
- data/spec/lib/pennmarc/helpers/identifer_spec.rb +14 -2
- data/spec/lib/pennmarc/helpers/inventory_spec.rb +0 -2
- data/spec/lib/pennmarc/helpers/language_spec.rb +0 -2
- data/spec/lib/pennmarc/helpers/link_spec.rb +0 -2
- data/spec/lib/pennmarc/helpers/location_spec.rb +0 -2
- data/spec/lib/pennmarc/helpers/note_spec.rb +22 -29
- data/spec/lib/pennmarc/helpers/production_spec.rb +121 -22
- data/spec/lib/pennmarc/helpers/relation_spec.rb +0 -2
- data/spec/lib/pennmarc/helpers/series_spec.rb +0 -2
- data/spec/lib/pennmarc/helpers/subject_spec.rb +16 -2
- data/spec/lib/pennmarc/helpers/title_spec.rb +20 -2
- data/spec/lib/pennmarc/marc_util_spec.rb +0 -2
- data/spec/lib/pennmarc/parser_spec.rb +1 -1
- data/spec/spec_helper.rb +7 -0
- data/spec/support/fixture_helpers.rb +10 -0
- metadata +4 -3
- data/spec/support/marc_spec_helpers.rb +0 -85
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b4d6a53347f4532faa566debcc59bde1fb7043cfbd4530d0a06489a36db8599
|
4
|
+
data.tar.gz: 8a92c36c80406541ac454025e6c2adc53af80dab20af5af16b8995dc5bacfe9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b1f0be0caba6a00adc8ccc5516556b2de250d93861157c49a60e17f52810b6eed7942efe8b51843d7428bb329c6dcad58a0887c17e9132004fe3d7d29729682
|
7
|
+
data.tar.gz: b06dad73899b13254391b74832d3b99745d82bc9f871801d7a617e2416f9d70039d45a9122a292377628b638c4044e692432688dbce48497cb6394fa48ba0d6e
|
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-
|
3
|
+
# on 2024-07-02 15:41:46 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
|
@@ -14,7 +14,7 @@ Gemspec/RequireMFA:
|
|
14
14
|
Exclude:
|
15
15
|
- 'pennmarc.gemspec'
|
16
16
|
|
17
|
-
# Offense count:
|
17
|
+
# Offense count: 25
|
18
18
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
19
19
|
Metrics/AbcSize:
|
20
20
|
Exclude:
|
@@ -26,18 +26,18 @@ Metrics/AbcSize:
|
|
26
26
|
- 'lib/pennmarc/helpers/location.rb'
|
27
27
|
- 'lib/pennmarc/helpers/note.rb'
|
28
28
|
- 'lib/pennmarc/helpers/production.rb'
|
29
|
-
- 'lib/pennmarc/helpers/relation.rb'
|
30
29
|
- 'lib/pennmarc/helpers/series.rb'
|
31
30
|
- 'lib/pennmarc/helpers/subject.rb'
|
32
31
|
- 'lib/pennmarc/helpers/title.rb'
|
33
32
|
- 'lib/pennmarc/util.rb'
|
34
33
|
|
35
|
-
# Offense count:
|
34
|
+
# Offense count: 8
|
36
35
|
# Configuration parameters: CountComments, Max, CountAsOne.
|
37
36
|
Metrics/ClassLength:
|
38
37
|
Exclude:
|
39
38
|
- 'lib/pennmarc/helpers/creator.rb'
|
40
39
|
- 'lib/pennmarc/helpers/format.rb'
|
40
|
+
- 'lib/pennmarc/helpers/production.rb'
|
41
41
|
- 'lib/pennmarc/helpers/series.rb'
|
42
42
|
- 'lib/pennmarc/helpers/subject.rb'
|
43
43
|
- 'lib/pennmarc/helpers/title.rb'
|
@@ -54,13 +54,12 @@ Metrics/CyclomaticComplexity:
|
|
54
54
|
- 'lib/pennmarc/helpers/language.rb'
|
55
55
|
- 'lib/pennmarc/helpers/note.rb'
|
56
56
|
- 'lib/pennmarc/helpers/production.rb'
|
57
|
-
- 'lib/pennmarc/helpers/relation.rb'
|
58
57
|
- 'lib/pennmarc/helpers/series.rb'
|
59
58
|
- 'lib/pennmarc/helpers/subject.rb'
|
60
59
|
- 'lib/pennmarc/helpers/title.rb'
|
61
60
|
- 'lib/pennmarc/util.rb'
|
62
61
|
|
63
|
-
# Offense count:
|
62
|
+
# Offense count: 28
|
64
63
|
# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
|
65
64
|
Metrics/MethodLength:
|
66
65
|
Exclude:
|
@@ -82,7 +81,7 @@ Metrics/ModuleLength:
|
|
82
81
|
Exclude:
|
83
82
|
- 'lib/pennmarc/util.rb'
|
84
83
|
|
85
|
-
# Offense count:
|
84
|
+
# Offense count: 14
|
86
85
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
87
86
|
Metrics/PerceivedComplexity:
|
88
87
|
Exclude:
|
@@ -123,7 +122,7 @@ Naming/VariableNumber:
|
|
123
122
|
Exclude:
|
124
123
|
- 'lib/pennmarc/util.rb'
|
125
124
|
|
126
|
-
# Offense count:
|
125
|
+
# Offense count: 8
|
127
126
|
# Configuration parameters: Max, CountAsOne.
|
128
127
|
RSpec/ExampleLength:
|
129
128
|
Exclude:
|
@@ -139,7 +138,7 @@ RSpec/FilePath:
|
|
139
138
|
Exclude:
|
140
139
|
- 'spec/lib/pennmarc/parser_spec.rb'
|
141
140
|
|
142
|
-
# Offense count:
|
141
|
+
# Offense count: 23
|
143
142
|
# Configuration parameters: Max, AllowedGroups.
|
144
143
|
RSpec/NestedGroups:
|
145
144
|
Exclude:
|
data/lib/pennmarc/enriched.rb
CHANGED
@@ -12,6 +12,7 @@ module PennMARC
|
|
12
12
|
PHYS_INVENTORY_TAG = 'hld'
|
13
13
|
ELEC_INVENTORY_TAG = 'prt'
|
14
14
|
ITEM_TAG = 'itm'
|
15
|
+
RELATED_RECORD_TAG = 'rel'
|
15
16
|
|
16
17
|
# Subfields for HLD tags
|
17
18
|
# Follow MARC 852 spec: https://www.loc.gov/marc/holdings/hd852.html, but names are translated into Alma parlance
|
@@ -5,14 +5,13 @@ module PennMARC
|
|
5
5
|
class Access < Helper
|
6
6
|
ONLINE = 'Online'
|
7
7
|
AT_THE_LIBRARY = 'At the library'
|
8
|
+
RESOURCE_LINK_BASE_URL = 'hdl.library.upenn.edu'
|
8
9
|
|
9
10
|
class << self
|
10
11
|
# Based on enhanced metadata fields added by Alma publishing process or API, determine if the record has
|
11
12
|
# electronic access or has physical holdings, and is therefore "Online" or "At the library". If a record is "At
|
12
13
|
# the library", but has a link to a finding aid in the 856 field (matching certain criteria), also add 'Online' as
|
13
14
|
# an access method.
|
14
|
-
# @todo What if none of these criteria match? Should we include "At the library" by default? Records with no value
|
15
|
-
# in this field would be lost if the user selects a facet value.
|
16
15
|
# @param [MARC::Record] record
|
17
16
|
# @return [Array]
|
18
17
|
def facet(record)
|
@@ -24,7 +23,7 @@ module PennMARC
|
|
24
23
|
return values if values.size == 2 # return early if all values are already present
|
25
24
|
|
26
25
|
# only check if ONLINE isn't already there
|
27
|
-
values << ONLINE if values.exclude?(ONLINE) &&
|
26
|
+
values << ONLINE if values.exclude?(ONLINE) && resource_link?(record)
|
28
27
|
values.uniq
|
29
28
|
end
|
30
29
|
|
@@ -44,20 +43,23 @@ module PennMARC
|
|
44
43
|
field.tag.in? [Enriched::Pub::PHYS_INVENTORY_TAG, Enriched::Api::PHYS_INVENTORY_TAG]
|
45
44
|
end
|
46
45
|
|
47
|
-
# Check if a record contains an 856 entry
|
46
|
+
# Check if a record contains an 856 entry with a Penn Handle server link meeting these criteria:
|
48
47
|
# 1. Indicator 1 is 4 (HTTP resource)
|
49
48
|
# 2. Indicator 2 is NOT 2 (indicating the linkage is to a "related" thing)
|
50
49
|
# 3. The URL specified in subfield u (URI) is a Penn Handle link
|
50
|
+
# 4. The subfield z does NOT include the string 'Finding aid'
|
51
51
|
# See: https://www.loc.gov/marc/bibliographic/bd856.html
|
52
|
+
# @note Some electronic records do not have Portfolios in Alma, so we rely upon the Resource Link in the 856 to
|
53
|
+
# get these records included in the Online category.
|
52
54
|
# @param [MARC::Record] record
|
53
55
|
# @return [Boolean]
|
54
|
-
def
|
56
|
+
def resource_link?(record)
|
55
57
|
record.fields('856').filter_map do |field|
|
56
58
|
next if field.indicator2 == '2' || field.indicator1 != '4'
|
57
59
|
|
58
60
|
subz = subfield_values(field, 'z')
|
59
61
|
subfield_values(field, 'u').filter_map do |value|
|
60
|
-
return true if subz.
|
62
|
+
return true if subz.exclude?('Finding aid') && value.include?(RESOURCE_LINK_BASE_URL)
|
61
63
|
end
|
62
64
|
end
|
63
65
|
false
|
@@ -7,26 +7,27 @@ module PennMARC
|
|
7
7
|
# @todo can there ever be multiple 100 fields?
|
8
8
|
# can ǂe and ǂ4 both be used at the same time? seems to result in duplicate values
|
9
9
|
class Creator < Helper
|
10
|
-
|
11
|
-
|
12
|
-
TAGS = %w[100 110].freeze
|
10
|
+
# Main tags for Author/Creator information
|
11
|
+
TAGS = %w[100 110].freeze
|
13
12
|
|
14
|
-
|
15
|
-
|
13
|
+
# Aux tags for Author/Creator information, for use in search_aux method
|
14
|
+
AUX_TAGS = %w[100 110 111 400 410 411 700 710 711 800 810 811].freeze
|
16
15
|
|
17
|
-
|
16
|
+
CONFERENCE_SEARCH_TAGS = %w[111 711 811].freeze
|
17
|
+
CORPORATE_SEARCH_TAGS = %w[110 710 810].freeze
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
# subfields NOT to join when combining raw subfield values
|
20
|
+
NAME_EXCLUDED_SUBFIELDS = %w[a 1 4 5 6 8 t].freeze
|
21
21
|
|
22
|
-
|
22
|
+
CONTRIBUTOR_TAGS = %w[700 710].freeze
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
FACET_SOURCE_MAP = {
|
25
|
+
100 => 'abcdjq', 110 => 'abcdjq', 111 => 'abcen',
|
26
|
+
700 => 'abcdjq', 710 => 'abcdjq', 711 => 'abcen',
|
27
|
+
800 => 'abcdjq', 810 => 'abcdjq', 811 => 'abcen'
|
28
|
+
}.freeze
|
29
29
|
|
30
|
+
class << self
|
30
31
|
# Author/Creator search field. Includes all subfield values (even ǂ0 URIs) from
|
31
32
|
# {https://www.oclc.org/bibformats/en/1xx/100.html 100 Main Entry--Personal Name} and
|
32
33
|
# {https://www.oclc.org/bibformats/en/1xx/110.html 110 Main Entry--Corporate Name}. Maps any relator codes found
|
@@ -35,8 +36,8 @@ module PennMARC
|
|
35
36
|
# @todo are we including too many details here and gumming up our index? consider UIRs, relator labels, dates...
|
36
37
|
# @todo shouldn't indicator1 tell us the order of the name? do we not trust the indicator?
|
37
38
|
# @note ported from get_author_creator_1_search_values
|
38
|
-
# @param [MARC::Record]
|
39
|
-
# @param [Hash]
|
39
|
+
# @param record [MARC::Record]
|
40
|
+
# @param relator_map [Hash]
|
40
41
|
# @return [Array<String>] array of author/creator values for indexing
|
41
42
|
def search(record, relator_map: Mappers.relator)
|
42
43
|
name_search_values record: record, tags: TAGS, relator_map: relator_map
|
@@ -50,7 +51,7 @@ module PennMARC
|
|
50
51
|
# and {https://www.loc.gov/marc/bibliographic/bd711.html MARC 711}. The 800, 810 and 8111 tags are similar in
|
51
52
|
# theme to the 7xx fields but apply to serial records.
|
52
53
|
# @note ported from get_author_creator_2_search_values
|
53
|
-
# @param [MARC::Record]
|
54
|
+
# @param record [MARC::Record]
|
54
55
|
# @return [Array<String>] array of extended author/creator values for indexing
|
55
56
|
def search_aux(record, relator_map: Mappers.relator)
|
56
57
|
name_search_values record: record, tags: AUX_TAGS, relator_map: relator_map
|
@@ -60,7 +61,7 @@ module PennMARC
|
|
60
61
|
# and {https://www.loc.gov/marc/bibliographic/bd110.html 110} and their linked alternates. First, joins subfields
|
61
62
|
# other than $0, $1, $4, $6, $8, $e, and w. Then, appends any encoded relators found in $4.
|
62
63
|
# If there are no valid encoded relators, uses the value found in $e.
|
63
|
-
# @param [MARC::Record]
|
64
|
+
# @param record [MARC::Record]
|
64
65
|
# @return [Array<String>] array of author/creator values for display
|
65
66
|
def show(record, relator_map: Mappers.relator)
|
66
67
|
fields = record.fields(TAGS)
|
@@ -72,8 +73,8 @@ module PennMARC
|
|
72
73
|
|
73
74
|
# Hash with main creator show values as the fields and the corresponding facet as the values.
|
74
75
|
# Does not include linked 880s.
|
75
|
-
# @param [MARC::Record]
|
76
|
-
# @param [Hash]
|
76
|
+
# @param record [MARC::Record]
|
77
|
+
# @param relator_map [Hash]
|
77
78
|
# @return [Hash]
|
78
79
|
def show_facet_map(record, relator_map: Mappers.relator)
|
79
80
|
creators = record.fields(TAGS).filter_map do |field|
|
@@ -84,11 +85,82 @@ module PennMARC
|
|
84
85
|
creators.to_h { |h| [h[:show], h[:facet]] }
|
85
86
|
end
|
86
87
|
|
88
|
+
# Returns the list of authors with name (subfield $a) only
|
89
|
+
# @param [MARC::Record] record
|
90
|
+
# @param [Boolean] main_tags_only, if true, only use TAGS; otherwise use both TAGS and CONTRIBUTOR_TAGS
|
91
|
+
# @param [Boolean] first_initial_only: true to only use the first initial instead of first name
|
92
|
+
# @return [Array<String>] names of the authors
|
93
|
+
def authors_list(record, main_tags_only: false, first_initial_only: false)
|
94
|
+
tags = if main_tags_only
|
95
|
+
TAGS
|
96
|
+
else
|
97
|
+
TAGS + CONTRIBUTOR_TAGS
|
98
|
+
end
|
99
|
+
|
100
|
+
fields = record.fields(tags)
|
101
|
+
fields.filter_map { |field|
|
102
|
+
if first_initial_only
|
103
|
+
abbreviate_name(field['a']) if field['a']
|
104
|
+
else
|
105
|
+
field['a']
|
106
|
+
end
|
107
|
+
}.uniq
|
108
|
+
end
|
109
|
+
|
110
|
+
# Show the authors and contributors grouped together by relators with only names
|
111
|
+
# @param [MARC::Record] record
|
112
|
+
# @param [Hash] relator_map
|
113
|
+
# @param [Boolean] include_authors: true to include author fields TAGS
|
114
|
+
# @param [Boolean] name_only: true to include only the name subfield $a
|
115
|
+
# @param [Boolean] vernacular: true to include field 880 with subfield $6
|
116
|
+
# @return [Hash]
|
117
|
+
def contributors_list(record, relator_map: Mappers.relator, include_authors: true, name_only: true,
|
118
|
+
vernacular: false)
|
119
|
+
indicator_2_options = ['', ' ', '0']
|
120
|
+
tags = CONTRIBUTOR_TAGS
|
121
|
+
|
122
|
+
fields = record.fields(tags)
|
123
|
+
fields += record.fields('880').select { |field| subfield_value_in?(field, '6', CONTRIBUTOR_TAGS) } if vernacular
|
124
|
+
|
125
|
+
contributors = {}
|
126
|
+
fields.each do |field|
|
127
|
+
next if indicator_2_options.exclude?(field.indicator2) && field.tag.in?(CONTRIBUTOR_TAGS)
|
128
|
+
next if subfield_defined? field, 'i'
|
129
|
+
|
130
|
+
relator = relator(field: field, relator_term_sf: 'e', relator_map: relator_map)
|
131
|
+
relator = 'Contributor' if relator.blank?
|
132
|
+
relator = trim_punctuation(relator).capitalize
|
133
|
+
|
134
|
+
name = if name_only
|
135
|
+
field['a']
|
136
|
+
else
|
137
|
+
join_subfields(field, &subfield_in?(%w[a b c d j q u 3])) + ", #{relator}"
|
138
|
+
end
|
139
|
+
|
140
|
+
if contributors.key?(relator)
|
141
|
+
contributors[relator].push(name)
|
142
|
+
else
|
143
|
+
contributors[relator] = [name]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# add the authors
|
148
|
+
if include_authors
|
149
|
+
authors = authors_list(record, main_tags_only: true)
|
150
|
+
if contributors.key?('Author')
|
151
|
+
contributors['Author'] += authors
|
152
|
+
else
|
153
|
+
contributors['Author'] = authors
|
154
|
+
end
|
155
|
+
end
|
156
|
+
contributors
|
157
|
+
end
|
158
|
+
|
87
159
|
# All author/creator values for display (like #show, but multivalued?) - no 880 linkage
|
88
160
|
# Performs additional normalization of author names
|
89
161
|
# @note ported from get_author_creator_values (indexed as author_creator_a) - shown on results page
|
90
|
-
# @param [MARC::Record]
|
91
|
-
# @param [Hash]
|
162
|
+
# @param record [MARC::Record]
|
163
|
+
# @param relator_map [Hash]
|
92
164
|
# @return [Array<String>] array of author/creator values for display
|
93
165
|
def show_aux(record, relator_map: Mappers.relator)
|
94
166
|
record.fields(TAGS).map { |field|
|
@@ -99,7 +171,7 @@ module PennMARC
|
|
99
171
|
# Author/Creator sort. Does not map and include any relator codes.
|
100
172
|
# @todo This includes any URI from ǂ0 which could help to disambiguate in sorts, but ǂ1 is excluded...
|
101
173
|
# @note ported from get_author_creator_sort_values
|
102
|
-
# @param [MARC::Record]
|
174
|
+
# @param record [MARC::Record]
|
103
175
|
# @return [String] string with author/creator value for sorting
|
104
176
|
def sort(record)
|
105
177
|
field = record.fields(TAGS).first
|
@@ -107,11 +179,11 @@ module PennMARC
|
|
107
179
|
end
|
108
180
|
|
109
181
|
# Author/Creator for faceting. Grabs values from a plethora of fields, joins defined subfields, then trims some
|
110
|
-
# punctuation (@see trim_punctuation)
|
182
|
+
# punctuation (@see Util.trim_punctuation)
|
111
183
|
# @todo should trim_punctuation apply to each subfield value, or the joined values? i think the joined values
|
112
184
|
# @note ported from author_creator_xfacet2_input - is this the best choice? check the copyField declarations -
|
113
185
|
# franklin uses author_creator_f
|
114
|
-
# @param [MARC::Record]
|
186
|
+
# @param record [MARC::Record]
|
115
187
|
# @return [Array<String>] array of author/creator values for faceting
|
116
188
|
def facet(record)
|
117
189
|
FACET_SOURCE_MAP.flat_map { |field_num, subfields|
|
@@ -123,8 +195,8 @@ module PennMARC
|
|
123
195
|
|
124
196
|
# Conference for display, intended for results display
|
125
197
|
# @note ported from get_conference_values
|
126
|
-
# @param [MARC::Record]
|
127
|
-
# @param [Hash]
|
198
|
+
# @param record [MARC::Record]
|
199
|
+
# @param relator_map [Hash]
|
128
200
|
# @return [Array<String>] array of conference values
|
129
201
|
def conference_show(record, relator_map: Mappers.relator)
|
130
202
|
record.fields('111').filter_map { |field|
|
@@ -139,7 +211,7 @@ module PennMARC
|
|
139
211
|
# using subfields $e and $w. We append any relators, preferring those defined in $4 and using $j as a fallback.
|
140
212
|
# @note ported from get_conference_values
|
141
213
|
# @todo what is ǂi for?
|
142
|
-
# @param [MARC::Record]
|
214
|
+
# @param record [MARC::Record]
|
143
215
|
# @return [Array<String>] array of conference values
|
144
216
|
def conference_detail_show(record, relator_map: Mappers.relator)
|
145
217
|
conferences = record.fields(%w[111 711]).filter_map do |field|
|
@@ -164,8 +236,8 @@ module PennMARC
|
|
164
236
|
# Return hash of detailed conference values mapped to their corresponding facets from fields
|
165
237
|
# {https://www.loc.gov/marc/bibliographic/bd111.html 111} and
|
166
238
|
# {https://www.loc.gov/marc/bibliographic/bd711.html 711}. Does not include linked 880s.
|
167
|
-
# @param [MARC::Record]
|
168
|
-
# @param [Hash]
|
239
|
+
# @param record [MARC::Record]
|
240
|
+
# @param relator_map [Hash]
|
169
241
|
# @return [Hash]
|
170
242
|
def conference_detail_show_facet_map(record, relator_map: Mappers.relator)
|
171
243
|
conferences = record.fields(%w[111 711]).filter_map do |field|
|
@@ -180,7 +252,7 @@ module PennMARC
|
|
180
252
|
end
|
181
253
|
|
182
254
|
# Conference name values for searching
|
183
|
-
# @param [MARC::Record]
|
255
|
+
# @param record [MARC::Record]
|
184
256
|
# @return [Array<String>]
|
185
257
|
def conference_search(record)
|
186
258
|
record.fields(CONFERENCE_SEARCH_TAGS).filter_map { |field|
|
@@ -188,14 +260,23 @@ module PennMARC
|
|
188
260
|
}.uniq
|
189
261
|
end
|
190
262
|
|
263
|
+
# Corporate author search values for searching
|
264
|
+
# @param record [MARC::Record]
|
265
|
+
# @return [Array<String>]
|
266
|
+
def corporate_search(record)
|
267
|
+
record.fields(CORPORATE_SEARCH_TAGS).filter_map do |field|
|
268
|
+
join_subfields(field, &subfield_in?(%w[a b c d]))
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
191
272
|
# Retrieve contributor values for display from fields {https://www.oclc.org/bibformats/en/7xx/700.html 700}
|
192
273
|
# and {https://www.oclc.org/bibformats/en/7xx/710.html 710} and their linked alternates. Joins subfields
|
193
274
|
# 'a', 'b', 'c', 'd', 'j', and 'q', 'u', and '3'. Then appends resulting string with any encoded relationships
|
194
275
|
# found in $4. If there are no valid encoded relationships, uses the value found in $e.
|
195
276
|
# @note legacy version returns array of hash objects including data for display link
|
196
277
|
# @todo is it okay to include 880 $4 here? Legacy includes $4 in main author display 880 but not here.
|
197
|
-
# @param [MARC::Record]
|
198
|
-
# @
|
278
|
+
# @param record [MARC::Record]
|
279
|
+
# @param relator_map [Hash]
|
199
280
|
# @return [Array<String>]
|
200
281
|
def contributor_show(record, relator_map: Mappers.relator)
|
201
282
|
indicator_2_options = ['', ' ', '0']
|
@@ -212,9 +293,9 @@ module PennMARC
|
|
212
293
|
|
213
294
|
private
|
214
295
|
|
215
|
-
# @param [MARC::Record]
|
216
|
-
# @param [Array]
|
217
|
-
# @param [Hash]
|
296
|
+
# @param record [MARC::Record]
|
297
|
+
# @param tags [Array] to consider
|
298
|
+
# @param relator_map [Hash]
|
218
299
|
# @return [Array<String>] name values from given tags
|
219
300
|
def name_search_values(record:, tags:, relator_map:)
|
220
301
|
acc = record.fields(tags).filter_map do |field|
|
@@ -238,30 +319,10 @@ module PennMARC
|
|
238
319
|
acc.uniq
|
239
320
|
end
|
240
321
|
|
241
|
-
# Trim punctuation method extracted from Traject macro, to ensure consistent output
|
242
|
-
# @todo move to Util?
|
243
|
-
# @param [String] string
|
244
|
-
# @return [String] string with relevant punctuation removed
|
245
|
-
def trim_punctuation(string)
|
246
|
-
return string unless string
|
247
|
-
|
248
|
-
string = string.sub(%r{ *[ ,/;:] *\Z}, '')
|
249
|
-
|
250
|
-
# trailing period if it is preceded by at least three letters (possibly preceded and followed by whitespace)
|
251
|
-
string = string.sub(/( *[[:word:]]{3,})\. *\Z/, '\1')
|
252
|
-
|
253
|
-
# single square bracket characters if they are the start and/or end chars and there are no internal square
|
254
|
-
# brackets.
|
255
|
-
string = string.sub(/\A\[?([^\[\]]+)\]?\Z/, '\1')
|
256
|
-
|
257
|
-
# trim any leading or trailing whitespace
|
258
|
-
string.strip
|
259
|
-
end
|
260
|
-
|
261
322
|
# Extract the information we care about from 1xx fields, map relator codes, and use appropriate punctuation
|
262
|
-
# @param [MARC::Field]
|
263
|
-
# @param [Hash]
|
264
|
-
# @param [Boolean]
|
323
|
+
# @param field [MARC::Field]
|
324
|
+
# @param mapping [Hash]
|
325
|
+
# @param should_convert_name_order [Boolean]
|
265
326
|
# @return [String] joined subfield values for value from field
|
266
327
|
def name_from_main_entry(field, mapping, should_convert_name_order: false)
|
267
328
|
relator_term_sf = relator_term_subfield(field)
|
@@ -284,7 +345,7 @@ module PennMARC
|
|
284
345
|
end
|
285
346
|
|
286
347
|
# Convert "Lastname, First" to "First Lastname"
|
287
|
-
# @param [String]
|
348
|
+
# @param name [String] value for processing
|
288
349
|
# @return [String]
|
289
350
|
def convert_name_order(name)
|
290
351
|
return name unless name.include? ','
|
@@ -294,17 +355,30 @@ module PennMARC
|
|
294
355
|
"#{after_comma} #{before_comma}".squish
|
295
356
|
end
|
296
357
|
|
358
|
+
# Convert "Lastname, First" to "Lastname, F"
|
359
|
+
# @param [String] name
|
360
|
+
def abbreviate_name(name)
|
361
|
+
name_parts = name.split(', ')
|
362
|
+
return '' if name_parts.empty?
|
363
|
+
|
364
|
+
first_name_parts = name_parts.last.split
|
365
|
+
temp_name = "#{name_parts.first}, #{first_name_parts.first[0, 1]}."
|
366
|
+
first_name_parts.shift
|
367
|
+
temp_name += " #{first_name_parts.join(' ')}" unless first_name_parts.empty?
|
368
|
+
temp_name
|
369
|
+
end
|
370
|
+
|
297
371
|
# Parse creator facet value from given creator field and desired subfields
|
298
|
-
# @param [MARC::Field]
|
299
|
-
# @param [Array<String>]
|
372
|
+
# @param field [MARC::Field]
|
373
|
+
# @param subfields [Array<String>]
|
300
374
|
# @return [String]
|
301
375
|
def parse_facet_value(field, subfields)
|
302
376
|
trim_punctuation(join_subfields(field, &subfield_in?(subfields)))
|
303
377
|
end
|
304
378
|
|
305
379
|
# Parse creator show value from given main creator fields (100/110).
|
306
|
-
# @param [MARC::Field]
|
307
|
-
# @param [Hash]
|
380
|
+
# @param field [MARC::Field]
|
381
|
+
# @param relator_map [Hash]
|
308
382
|
# @return [String]
|
309
383
|
def parse_show_value(field, relator_map: Mappers.relator)
|
310
384
|
creator = join_subfields(field, &subfield_not_in?(%w[0 1 4 6 8 e w]))
|
@@ -314,7 +388,7 @@ module PennMARC
|
|
314
388
|
# Parse detailed conference show value from given conference field (111/711). If there is no $i, we join subfield
|
315
389
|
# values other than $0, $4, $5, $6, $8, $e, $j, and $w to create conference value. We join subfields $e and $w to
|
316
390
|
# determine the subunit value. We append any relators, preferring those defined in $4 and using $j as a fallback.
|
317
|
-
# @param [MARC::Field]
|
391
|
+
# @param field [MARC::Field]
|
318
392
|
# @return [String]
|
319
393
|
def parse_conference_detail_show_value(field, relator_map: Mappers.relator)
|
320
394
|
conf = if subfield_undefined? field, 'i'
|
@@ -13,10 +13,12 @@ module PennMARC
|
|
13
13
|
# https://www.loc.gov/marc/bibliographic/bd250.html
|
14
14
|
# @param [MARC::Record] record
|
15
15
|
# @return [Array<String>] array of editions and their alternates
|
16
|
-
def show(record)
|
17
|
-
editions = record.fields('250').map
|
16
|
+
def show(record, with_alternate: true)
|
17
|
+
editions = record.fields('250').map do |field|
|
18
18
|
join_subfields(field, &subfield_not_in?(%w[6 8]))
|
19
|
-
|
19
|
+
end
|
20
|
+
editions += linked_alternate_not_6_or_8(record, '250') if with_alternate
|
21
|
+
|
20
22
|
editions.uniq
|
21
23
|
end
|
22
24
|
|
@@ -159,6 +159,18 @@ module PennMARC
|
|
159
159
|
}.uniq
|
160
160
|
end
|
161
161
|
|
162
|
+
# Gets any Host record MMS ID values from an Enriched::Pub::RELATED_RECORD_TAG field added during Alma enrichment.
|
163
|
+
# This aids in our handling of "bound with" records.
|
164
|
+
# @param [MARC::Record] record
|
165
|
+
# @return [Array<String>]
|
166
|
+
def host_record_id(record)
|
167
|
+
record.fields(Enriched::Pub::RELATED_RECORD_TAG).filter_map { |field|
|
168
|
+
next unless subfield_value?(field, 'c', /contains/i)
|
169
|
+
|
170
|
+
subfield_values field, :w
|
171
|
+
}.flatten.uniq
|
172
|
+
end
|
173
|
+
|
162
174
|
private
|
163
175
|
|
164
176
|
# Determine if subfield 'a' is an OCLC id.
|