pennmarc 1.0.30 → 1.0.32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -1
- data/Gemfile.lock +0 -2
- data/lib/pennmarc/heading_control.rb +9 -5
- data/lib/pennmarc/helpers/access.rb +4 -4
- data/lib/pennmarc/helpers/citation.rb +2 -2
- data/lib/pennmarc/helpers/classification.rb +10 -7
- data/lib/pennmarc/helpers/creator.rb +27 -25
- data/lib/pennmarc/helpers/database.rb +8 -8
- data/lib/pennmarc/helpers/date.rb +5 -5
- data/lib/pennmarc/helpers/edition.rb +7 -7
- data/lib/pennmarc/helpers/format.rb +36 -40
- data/lib/pennmarc/helpers/genre.rb +5 -5
- data/lib/pennmarc/helpers/identifier.rb +18 -18
- data/lib/pennmarc/helpers/inventory.rb +7 -7
- data/lib/pennmarc/helpers/inventory_entry/base.rb +2 -2
- data/lib/pennmarc/helpers/language.rb +4 -4
- data/lib/pennmarc/helpers/link.rb +6 -6
- data/lib/pennmarc/helpers/location.rb +14 -14
- data/lib/pennmarc/helpers/note.rb +2 -2
- data/lib/pennmarc/helpers/production.rb +7 -6
- data/lib/pennmarc/helpers/relation.rb +14 -14
- data/lib/pennmarc/helpers/series.rb +19 -19
- data/lib/pennmarc/helpers/subject.rb +28 -28
- data/lib/pennmarc/helpers/title.rb +18 -18
- data/lib/pennmarc/mappings/headings_override.yml +12 -8
- data/lib/pennmarc/parser.rb +5 -5
- data/lib/pennmarc/test/marc_helpers.rb +11 -11
- data/lib/pennmarc/util.rb +18 -18
- data/lib/pennmarc/version.rb +1 -1
- data/pennmarc.gemspec +0 -1
- data/spec/lib/pennmarc/heading_control_spec.rb +17 -10
- data/spec/lib/pennmarc/helpers/creator_spec.rb +15 -12
- data/spec/lib/pennmarc/marc_util_spec.rb +12 -0
- data/spec/support/fixture_helpers.rb +1 -1
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 529930d44585a1ba459c533cd6906bbc910a3b73c2a09bc57c0eb1f2739772b7
|
4
|
+
data.tar.gz: 1570743e970c564ece0d3eefa40fd51a720cf920f44cf97fca866770e21785bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97e6db5b2bccfde42421db0276b890b9ec0ea81bd9862679b1b948ba692d44f0dd23bd54dde788f042908c4dfb6c22f1016109f3ae449711a9c09fba98729aa8
|
7
|
+
data.tar.gz: 8dc0c53f5f491f2c403b392fb0edf69ed61fd193e131a118c0ea2f4b3f2d33b24eca1412207d2791320f69475f57fd08e74928d888b5fafba6907f9a6e5251b1
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -19,7 +19,6 @@ GEM
|
|
19
19
|
scrub_rb (>= 1.0.1, < 2)
|
20
20
|
unf
|
21
21
|
minitest (5.18.0)
|
22
|
-
multi_string_replace (2.0.2)
|
23
22
|
nokogiri (1.15.2-arm64-darwin)
|
24
23
|
racc (~> 1.4)
|
25
24
|
nokogiri (1.15.2-x64-mingw-ucrt)
|
@@ -114,7 +113,6 @@ DEPENDENCIES
|
|
114
113
|
activesupport (~> 7)
|
115
114
|
library_stdnums (~> 1.6)
|
116
115
|
marc (~> 1.2)
|
117
|
-
multi_string_replace (~> 2.0)
|
118
116
|
nokogiri (~> 1.15)
|
119
117
|
rake (~> 13.0)
|
120
118
|
rspec (~> 3.12)
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'multi_string_replace'
|
4
|
-
|
5
3
|
module PennMARC
|
6
4
|
# Shared tools and values for controlling handling of subject or genre headings
|
7
5
|
class HeadingControl
|
@@ -10,6 +8,9 @@ module PennMARC
|
|
10
8
|
ALLOWED_SOURCE_CODES = %w[aat cct fast ftamc gmgpc gsafd homoit jlabsh lcgft lcsh lcstt lctgm
|
11
9
|
local/osu mesh ndlsh nli nlksh rbbin rbgenr rbmscv rbpap rbpri rbprov rbpub rbtyp].freeze
|
12
10
|
|
11
|
+
REMOVE_TERM_REGEX = /#{Mappers.headings_to_remove&.join('|')}/i
|
12
|
+
REPLACE_TERM_REGEX = /(#{Mappers.heading_overrides.keys.join('|')})/i
|
13
|
+
|
13
14
|
class << self
|
14
15
|
# Replace or remove any terms in provided values pursuant to the configuration in remove and override mappers.
|
15
16
|
# Used to remove or replace offensive or otherwise undesirable subject headings.
|
@@ -18,10 +19,13 @@ module PennMARC
|
|
18
19
|
def term_override(values)
|
19
20
|
values.filter_map do |value|
|
20
21
|
# Remove values if they contain a remove term
|
21
|
-
next nil if value.match?(
|
22
|
+
next nil if value.match?(REMOVE_TERM_REGEX)
|
23
|
+
|
24
|
+
# return early if theres no terms to replace
|
25
|
+
next value if value.match(REPLACE_TERM_REGEX).nil?
|
22
26
|
|
23
|
-
#
|
24
|
-
|
27
|
+
# lookup and perform replacement
|
28
|
+
value.sub(::Regexp.last_match.to_s, Mappers.heading_overrides[::Regexp.last_match.to_s.downcase])
|
25
29
|
end
|
26
30
|
end
|
27
31
|
end
|
@@ -12,7 +12,7 @@ module PennMARC
|
|
12
12
|
# electronic access or has physical holdings, and is therefore "Online" or "At the library". If a record is "At
|
13
13
|
# the library", but has a link to a finding aid in the 856 field (matching certain criteria), also add 'Online' as
|
14
14
|
# an access method.
|
15
|
-
# @param [MARC::Record]
|
15
|
+
# @param record [MARC::Record]
|
16
16
|
# @return [Array]
|
17
17
|
def facet(record)
|
18
18
|
values = record.filter_map do |field|
|
@@ -30,14 +30,14 @@ module PennMARC
|
|
30
30
|
private
|
31
31
|
|
32
32
|
# Does the record have added electronic holding info?
|
33
|
-
# @param [MARC::Field]
|
33
|
+
# @param field [MARC::Field]
|
34
34
|
# @return [Boolean]
|
35
35
|
def electronic_holding_tag?(field)
|
36
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
|
-
# @param [MARC::Field]
|
40
|
+
# @param field [MARC::Field]
|
41
41
|
# @return [Boolean]
|
42
42
|
def physical_holding_tag?(field)
|
43
43
|
field.tag.in? [Enriched::Pub::PHYS_INVENTORY_TAG, Enriched::Api::PHYS_INVENTORY_TAG]
|
@@ -51,7 +51,7 @@ module PennMARC
|
|
51
51
|
# See: https://www.loc.gov/marc/bibliographic/bd856.html
|
52
52
|
# @note Some electronic records do not have Portfolios in Alma, so we rely upon the Resource Link in the 856 to
|
53
53
|
# get these records included in the Online category.
|
54
|
-
# @param [MARC::Record]
|
54
|
+
# @param record [MARC::Record]
|
55
55
|
# @return [Boolean]
|
56
56
|
def resource_link?(record)
|
57
57
|
record.fields('856').filter_map do |field|
|
@@ -10,7 +10,7 @@ module PennMARC
|
|
10
10
|
# abbreviations, etc.). The actual text of a published description is not recorded in field 510 but rather in
|
11
11
|
# field 520 (Summary, Etc. Note).
|
12
12
|
# https://www.loc.gov/marc/bibliographic/bd510.html
|
13
|
-
# @param [MARC::Record]
|
13
|
+
# @param record [MARC::Record]
|
14
14
|
# @return [Array<String>] array of citations and any linked alternates
|
15
15
|
def cited_in_show(record)
|
16
16
|
datafield_and_linked_alternate(record, '510').uniq
|
@@ -21,7 +21,7 @@ module PennMARC
|
|
21
21
|
# each is recorded in a separate occurrence of field 524. The note is sometimes displayed and/or printed with an
|
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
|
-
# @param [MARC::Record]
|
24
|
+
# @param record [MARC::Record]
|
25
25
|
# @return [Array<String>] array of citation of described materials note and any linked alternates
|
26
26
|
def cite_as_show(record)
|
27
27
|
datafield_and_linked_alternate(record, '524').uniq
|
@@ -25,7 +25,7 @@ module PennMARC
|
|
25
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
|
-
# @param [MARC::Record]
|
28
|
+
# @param record [MARC::Record]
|
29
29
|
# @return [Array<String>] array of classifications
|
30
30
|
def facet(record)
|
31
31
|
record.fields(TAGS).flat_map { |field|
|
@@ -45,7 +45,7 @@ module PennMARC
|
|
45
45
|
private
|
46
46
|
|
47
47
|
# Retrieve subfield code that stores the call number on enriched marc field
|
48
|
-
# @param [MARC::DataField]
|
48
|
+
# @param field [MARC::DataField]
|
49
49
|
# @return [String]
|
50
50
|
def call_number_sf(field)
|
51
51
|
return Enriched::Pub::ITEM_CALL_NUMBER if field.tag == Enriched::Pub::ITEM_TAG
|
@@ -54,7 +54,7 @@ module PennMARC
|
|
54
54
|
end
|
55
55
|
|
56
56
|
# Retrieve subfield code that stores call number type on enriched marc field
|
57
|
-
# @param [MARC::DataField]
|
57
|
+
# @param field [MARC::DataField]
|
58
58
|
# @return [String]
|
59
59
|
def call_number_type_sf(field)
|
60
60
|
return Enriched::Pub::ITEM_CALL_NUMBER_TYPE if field.tag == Enriched::Pub::ITEM_TAG
|
@@ -63,9 +63,9 @@ module PennMARC
|
|
63
63
|
end
|
64
64
|
|
65
65
|
# retrieve title of classification based on single char classification code and call number type
|
66
|
-
# @param[String]
|
67
|
-
# @param[String]
|
68
|
-
# @return [String,
|
66
|
+
# @param class_code [String] classification code
|
67
|
+
# @param call_number_type [String] value from call number type subfield
|
68
|
+
# @return [String, nil]
|
69
69
|
def translate_classification(class_code, call_number_type)
|
70
70
|
map = CLASSIFICATION_MAPS[call_number_type]
|
71
71
|
|
@@ -77,6 +77,9 @@ module PennMARC
|
|
77
77
|
# format classification facet by joining single character classification code with its corresponding title.
|
78
78
|
# Our Dewey mapping codes are single digit, so we must concatenate '00' to the class code to accurately reflect
|
79
79
|
# Dewey class codes.
|
80
|
+
# @param class_code [String]
|
81
|
+
# @param call_number_type [String]
|
82
|
+
# @param title [String]
|
80
83
|
# @return [String]
|
81
84
|
def format_facet(class_code, call_number_type, title)
|
82
85
|
return [class_code, title].join(' - ') if loc_call_number_type?(call_number_type)
|
@@ -85,7 +88,7 @@ module PennMARC
|
|
85
88
|
end
|
86
89
|
|
87
90
|
# Determine whether call number type is library of congress
|
88
|
-
# @param [String]
|
91
|
+
# @param call_number_type [String] value from call number type subfield
|
89
92
|
# @return [Boolean]
|
90
93
|
def loc_call_number_type?(call_number_type)
|
91
94
|
call_number_type == '0'
|
@@ -86,9 +86,9 @@ module PennMARC
|
|
86
86
|
end
|
87
87
|
|
88
88
|
# Returns the list of authors with name (subfield $a) only
|
89
|
-
# @param [MARC::Record]
|
90
|
-
# @param [Boolean]
|
91
|
-
# @param [Boolean]
|
89
|
+
# @param record [MARC::Record]
|
90
|
+
# @param main_tags_only [Boolean] only use TAGS; otherwise use both TAGS and CONTRIBUTOR_TAGS
|
91
|
+
# @param first_initial_only [Boolean] only use the first initial instead of first name
|
92
92
|
# @return [Array<String>] names of the authors
|
93
93
|
def authors_list(record, main_tags_only: false, first_initial_only: false)
|
94
94
|
tags = if main_tags_only
|
@@ -99,20 +99,19 @@ module PennMARC
|
|
99
99
|
|
100
100
|
fields = record.fields(tags)
|
101
101
|
fields.filter_map { |field|
|
102
|
-
if
|
103
|
-
|
104
|
-
|
105
|
-
field['a']
|
102
|
+
if field['a'].present?
|
103
|
+
name = trim_trailing(:comma, field['a'])
|
104
|
+
first_initial_only ? abbreviate_name(name) : name
|
106
105
|
end
|
107
106
|
}.uniq
|
108
107
|
end
|
109
108
|
|
110
109
|
# Show the authors and contributors grouped together by relators with only names
|
111
|
-
# @param [MARC::Record]
|
112
|
-
# @param [Hash]
|
113
|
-
# @param [Boolean]
|
114
|
-
# @param [Boolean]
|
115
|
-
# @param [Boolean]
|
110
|
+
# @param record [MARC::Record]
|
111
|
+
# @param relator_map [Hash]
|
112
|
+
# @param include_authors [Boolean] include author fields TAGS
|
113
|
+
# @param name_only [Boolean] include only the name subfield $a
|
114
|
+
# @param vernacular [Boolean] include field 880 with subfield $6
|
116
115
|
# @return [Hash]
|
117
116
|
def contributors_list(record, relator_map: Mappers.relator, include_authors: true, name_only: true,
|
118
117
|
vernacular: false)
|
@@ -131,10 +130,11 @@ module PennMARC
|
|
131
130
|
relator = 'Contributor' if relator.blank?
|
132
131
|
relator = trim_punctuation(relator).capitalize
|
133
132
|
|
133
|
+
name = trim_trailing(:comma, field['a'])
|
134
134
|
name = if name_only
|
135
|
-
|
135
|
+
name
|
136
136
|
else
|
137
|
-
join_subfields(field, &subfield_in?(%w[
|
137
|
+
"#{name} #{join_subfields(field, &subfield_in?(%w[b c d j q u 3]))}, #{relator}"
|
138
138
|
end
|
139
139
|
|
140
140
|
if contributors.key?(relator)
|
@@ -294,7 +294,7 @@ module PennMARC
|
|
294
294
|
private
|
295
295
|
|
296
296
|
# @param record [MARC::Record]
|
297
|
-
# @param tags [Array] to consider
|
297
|
+
# @param tags [Array] tags to consider
|
298
298
|
# @param relator_map [Hash]
|
299
299
|
# @return [Array<String>] name values from given tags
|
300
300
|
def name_search_values(record:, tags:, relator_map:)
|
@@ -328,7 +328,7 @@ module PennMARC
|
|
328
328
|
relator_term_sf = relator_term_subfield(field)
|
329
329
|
name = field.filter_map { |sf|
|
330
330
|
if sf.code == 'a'
|
331
|
-
should_convert_name_order ? convert_name_order(sf.value) : sf.value
|
331
|
+
should_convert_name_order ? convert_name_order(sf.value) : trim_trailing(:comma, sf.value)
|
332
332
|
elsif sf.code == relator_term_sf
|
333
333
|
next
|
334
334
|
elsif NAME_EXCLUDED_SUBFIELDS.exclude?(sf.code)
|
@@ -348,6 +348,7 @@ module PennMARC
|
|
348
348
|
# @param name [String] value for processing
|
349
349
|
# @return [String]
|
350
350
|
def convert_name_order(name)
|
351
|
+
name = trim_trailing(:comma, name)
|
351
352
|
return name unless name.include? ','
|
352
353
|
|
353
354
|
after_comma = join_and_squish([trim_trailing(:comma, substring_after(name, ', '))])
|
@@ -356,16 +357,17 @@ module PennMARC
|
|
356
357
|
end
|
357
358
|
|
358
359
|
# Convert "Lastname, First" to "Lastname, F"
|
359
|
-
# @param [String]
|
360
|
+
# @param name [String]
|
361
|
+
# @return [String]
|
360
362
|
def abbreviate_name(name)
|
361
|
-
|
362
|
-
return
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
363
|
+
name = trim_trailing(:comma, name)
|
364
|
+
return name unless name.include? ','
|
365
|
+
|
366
|
+
after_comma = join_and_squish([trim_trailing(:comma, substring_after(name, ','))])
|
367
|
+
before_comma = substring_before(name, ',')
|
368
|
+
abbrv = "#{before_comma},"
|
369
|
+
abbrv += " #{after_comma.first.upcase}." if after_comma.present?
|
370
|
+
abbrv
|
369
371
|
end
|
370
372
|
|
371
373
|
# Parse creator facet value from given creator field and desired subfields
|
@@ -16,8 +16,8 @@ module PennMARC
|
|
16
16
|
# Retrieves database subtype (subfield 'b') from
|
17
17
|
# {https://upennlibrary.atlassian.net/wiki/spaces/ALMA/pages/323912493/Local+9XX+Field+Use+in+Almalocal
|
18
18
|
# local field 944}. Only returns database subtype if Penn's Database facet value is present in subfield 'a'.
|
19
|
-
# @param [
|
20
|
-
# @return [Array<
|
19
|
+
# @param record [MARC::Record]
|
20
|
+
# @return [Array<String>] Array of types
|
21
21
|
def type_facet(record)
|
22
22
|
record.fields('944').filter_map { |field|
|
23
23
|
# skip unless specified database format type present
|
@@ -32,8 +32,8 @@ module PennMARC
|
|
32
32
|
# {https://upennlibrary.atlassian.net/wiki/spaces/ALMA/pages/323912493/Local+9XX+Field+Use+in+Almalocal
|
33
33
|
# local field 943}. Only returns database subject category if Penn's Community of Interest code is present in
|
34
34
|
# subfield '2'.
|
35
|
-
# @param [
|
36
|
-
# @return [Array<
|
35
|
+
# @param record [MARC::Record]
|
36
|
+
# @return [Array<String>] Array of categories
|
37
37
|
def category_facet(record)
|
38
38
|
return [] unless curated_db?(record)
|
39
39
|
|
@@ -53,8 +53,8 @@ module PennMARC
|
|
53
53
|
# local field 943}. Only returns subcategory if Penn's Community of Interest code is present in subfield '2'.
|
54
54
|
# @note return value differs from legacy implementation. This version only returns ["category--subcategory"] or
|
55
55
|
# an empty array.
|
56
|
-
# @param [
|
57
|
-
# @return [Array<
|
56
|
+
# @param record [MARC::Record]
|
57
|
+
# @return [Array<String>] Array of "category--subcategory"
|
58
58
|
def subcategory_facet(record)
|
59
59
|
return [] unless curated_db?(record)
|
60
60
|
|
@@ -79,8 +79,8 @@ module PennMARC
|
|
79
79
|
private
|
80
80
|
|
81
81
|
# Determines if Database format type is format type used to facet databases
|
82
|
-
# @param [
|
83
|
-
# @return [
|
82
|
+
# @param record [MARC::Record]
|
83
|
+
# @return [Boolean]
|
84
84
|
def curated_db?(record)
|
85
85
|
record.fields('944').any? { |field| subfield_value?(field, 'a', /#{DATABASES_FACET_VALUE}/o) }
|
86
86
|
end
|
@@ -7,7 +7,7 @@ module PennMARC
|
|
7
7
|
# Retrieve publication date (Date 1) from {https://www.loc.gov/marc/bibliographic/bd008a.html 008 field}.
|
8
8
|
# Publication date is a four-digit year found in position 7-10 and may contain 'u' characters to represent
|
9
9
|
# partially known dates. We replace any occurrences of 'u' with '0' before converting to DateTime object.
|
10
|
-
# @param [MARC::Record]
|
10
|
+
# @param record [MARC::Record]
|
11
11
|
# @return [Time, nil] The publication date, or nil if date found in record is invalid
|
12
12
|
def publication(record)
|
13
13
|
record.fields('008').filter_map { |field|
|
@@ -22,7 +22,7 @@ module PennMARC
|
|
22
22
|
# Retrieve date added (subfield 'q') from enriched marc 'itm' field.
|
23
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
|
-
# @param [MARC::Record]
|
25
|
+
# @param record [MARC::Record]
|
26
26
|
# @return [Time, nil] The date added, or nil if date found in record is invalid
|
27
27
|
def added(record)
|
28
28
|
record.fields(Enriched::Pub::ITEM_TAG).flat_map { |field|
|
@@ -46,7 +46,7 @@ module PennMARC
|
|
46
46
|
# Retrieve date last updated from {https://www.loc.gov/marc/bibliographic/bd005.html 005 field}.
|
47
47
|
# Date last updated is a sixteen character String recorded in
|
48
48
|
# {https://www.iso.org/iso-8601-date-and-time-format.html ISO 8601} format.
|
49
|
-
# @param [MARC::Record]
|
49
|
+
# @param record [MARC::Record]
|
50
50
|
# @return [Time, nil] The date last updated, or nil if date found in record is invalid
|
51
51
|
def last_updated(record)
|
52
52
|
record.fields('005').filter_map { |field|
|
@@ -69,8 +69,8 @@ module PennMARC
|
|
69
69
|
private
|
70
70
|
|
71
71
|
# Sanitizes a partially known date string by replacing any 'u' occurrences with a specified replacement value.
|
72
|
-
# @param [String]
|
73
|
-
# @param [String]
|
72
|
+
# @param date [String] The date string in '%Y' format, potentially containing 'u' characters.
|
73
|
+
# @param replacement [String] The value with which to replace 'u' occurrences in the date string.
|
74
74
|
# @return [String, nil] The sanitized date string with 'u' characters replaced by the replacement value,
|
75
75
|
# or nil if the date string does not match the expected format.
|
76
76
|
def sanitize_partially_known_date(date, replacement)
|
@@ -11,7 +11,7 @@ module PennMARC
|
|
11
11
|
# sequential edition statements such as 1st- ed. This type of information is contained in field 362 (Dates of
|
12
12
|
# Publication and/or Volume Designation).
|
13
13
|
# https://www.loc.gov/marc/bibliographic/bd250.html
|
14
|
-
# @param [MARC::Record]
|
14
|
+
# @param record [MARC::Record]
|
15
15
|
# @return [Array<String>] array of editions and their alternates
|
16
16
|
def show(record, with_alternate: true)
|
17
17
|
editions = record.fields('250').map do |field|
|
@@ -23,8 +23,8 @@ module PennMARC
|
|
23
23
|
end
|
24
24
|
|
25
25
|
# Edition values for display in search results. Just grab the first 250 field.
|
26
|
-
# @param [MARC::Record]
|
27
|
-
# @return [String,
|
26
|
+
# @param record [MARC::Record]
|
27
|
+
# @return [String, nil] string of all first 250 subfields, excluding 6 and 8
|
28
28
|
def values(record)
|
29
29
|
edition = record.fields('250').first
|
30
30
|
return if edition.blank?
|
@@ -36,8 +36,8 @@ module PennMARC
|
|
36
36
|
# from this field, the introductory phrase Other editions available: may be generated based on the field tag for
|
37
37
|
# display.
|
38
38
|
# https://www.loc.gov/marc/bibliographic/bd775.html
|
39
|
-
# @param [MARC::Record]
|
40
|
-
# @param [Hash]
|
39
|
+
# @param record [MARC::Record]
|
40
|
+
# @param relator_map [Hash]
|
41
41
|
# @return [Array<String>] array of other edition strings
|
42
42
|
def other_show(record, relator_map: Mappers.relator)
|
43
43
|
values = record.fields('775').filter_map do |field|
|
@@ -57,8 +57,8 @@ module PennMARC
|
|
57
57
|
private
|
58
58
|
|
59
59
|
# Assemble a string of relevant edition information.
|
60
|
-
# @param [MARC::DataField]
|
61
|
-
# @param [Hash]
|
60
|
+
# @param field [MARC::DataField]
|
61
|
+
# @param relator_map [Hash]
|
62
62
|
# @return [String (frozen)] assembled other version string
|
63
63
|
def other_edition_value(field, relator_map)
|
64
64
|
subi = remove_paren_value_from_subfield_i(field) || ''
|
@@ -33,7 +33,7 @@ module PennMARC
|
|
33
33
|
# 254, 255, 310, 342, 352, 362 or {https://www.oclc.org/bibformats/en/3xx/340.html 340} field. based on the source
|
34
34
|
# field, different subfields are used.
|
35
35
|
# @note ported from get_format_display
|
36
|
-
# @param [MARC::Record]
|
36
|
+
# @param record [MARC::Record]
|
37
37
|
# @return [Array<String>] format values for display
|
38
38
|
def show(record)
|
39
39
|
results = record.fields('300').map { |f| join_subfields(f, &subfield_not_in?(%w[3 6 8])) }
|
@@ -70,13 +70,9 @@ module PennMARC
|
|
70
70
|
# 5. Media Type values from {https://www.oclc.org/bibformats/en/3xx/337.html#subfielda 337 ǂa}
|
71
71
|
# Additional fields are considered for many of the formats. Much of this logic has been moved to private methods
|
72
72
|
# to keep this method from becoming too unwieldy.
|
73
|
-
# @todo is the conditional structure here still best practice? see the "Thesis on Microfilm" case in the specs
|
74
|
-
# for this helper method
|
75
73
|
# @note ported from get_format
|
76
|
-
# @param [MARC::Record]
|
77
|
-
# @param [Hash] location_map
|
74
|
+
# @param record [MARC::Record]
|
78
75
|
# @return [Array<String>] format values for faceting
|
79
|
-
|
80
76
|
def facet(record)
|
81
77
|
formats = []
|
82
78
|
format_code = leader_format(record.leader)
|
@@ -113,7 +109,7 @@ module PennMARC
|
|
113
109
|
|
114
110
|
# Show "Other Format" values from {https://www.oclc.org/bibformats/en/7xx/776.html 776} and any 880 linkage.
|
115
111
|
# @todo is 774 an error in the linked field in legacy? i changed to 776 here
|
116
|
-
# @param [MARC::Record]
|
112
|
+
# @param record [MARC::Record]
|
117
113
|
# @return [Array<String>] other format values for display
|
118
114
|
def other_show(record)
|
119
115
|
values = record.fields('776').filter_map do |field|
|
@@ -130,7 +126,7 @@ module PennMARC
|
|
130
126
|
|
131
127
|
# Retrieve cartographic reference data for map/atlas formats for display from
|
132
128
|
# {https://www.oclc.org/bibformats/en/2xx/255.html 255} and {https://www.oclc.org/bibformats/en/3xx/342.html 342}
|
133
|
-
# @param [MARC::Record]
|
129
|
+
# @param record [MARC::Record]
|
134
130
|
# @return [Array<String>]
|
135
131
|
def cartographic_show(record)
|
136
132
|
record.fields(%w[255 342]).map { |field|
|
@@ -139,7 +135,7 @@ module PennMARC
|
|
139
135
|
end
|
140
136
|
|
141
137
|
# Check if leader format code is either 't', 'f', or 'd'
|
142
|
-
# @param [String]
|
138
|
+
# @param format_code [String]
|
143
139
|
# @return [Boolean]
|
144
140
|
def include_manuscripts?(format_code)
|
145
141
|
format_code.first.in? %w[t f d]
|
@@ -149,7 +145,7 @@ module PennMARC
|
|
149
145
|
|
150
146
|
# Get Call Numbers for holdings using the 'Classification part' which can contain strings like
|
151
147
|
# 'Microfilm'. Look in enriched tags used by both Alma Publishing and API.
|
152
|
-
# @param [MARC::Record]
|
148
|
+
# @param record [MARC::Record]
|
153
149
|
# @return [Array]
|
154
150
|
def call_nums(record)
|
155
151
|
if field_defined?(record, Enriched::Pub::PHYS_INVENTORY_TAG)
|
@@ -169,7 +165,7 @@ module PennMARC
|
|
169
165
|
# Get 'Curated' format from.
|
170
166
|
# {https://upennlibrary.atlassian.net/wiki/spaces/ALMA/pages/323912493/Local+9XX+Field+Use+in+Alma local field
|
171
167
|
# 944} ǂa, as long as it is not a numerical value.
|
172
|
-
# @param [MARC::Record]
|
168
|
+
# @param record [MARC::Record]
|
173
169
|
# @return [Array]
|
174
170
|
def curated_format(record)
|
175
171
|
record.fields('944').filter_map { |field|
|
@@ -180,57 +176,57 @@ module PennMARC
|
|
180
176
|
}.uniq
|
181
177
|
end
|
182
178
|
|
183
|
-
# @param [String]
|
179
|
+
# @param format_code [String]
|
184
180
|
# @return [Boolean]
|
185
181
|
def image?(format_code)
|
186
182
|
format_code.in?(%w[km kd])
|
187
183
|
end
|
188
184
|
|
189
|
-
# @param [String]
|
185
|
+
# @param format_code [String]
|
190
186
|
# @return [Boolean]
|
191
187
|
def datafile?(format_code)
|
192
188
|
format_code == 'mm'
|
193
189
|
end
|
194
190
|
|
195
|
-
# @param [String]
|
191
|
+
# @param format_code [String]
|
196
192
|
# @return [Boolean]
|
197
193
|
def journal_periodical?(format_code)
|
198
194
|
format_code.in?(%w[as gs])
|
199
195
|
end
|
200
196
|
|
201
|
-
# @param [String]
|
197
|
+
# @param format_code [String]
|
202
198
|
# @return [Boolean]
|
203
199
|
def three_d_object?(format_code)
|
204
200
|
format_code.start_with?('r')
|
205
201
|
end
|
206
202
|
|
207
|
-
# @param [String]
|
203
|
+
# @param format_code [String]
|
208
204
|
# @return [Boolean]
|
209
205
|
def sound_recording?(format_code)
|
210
206
|
format_code.in?(%w[im jm jc jd js])
|
211
207
|
end
|
212
208
|
|
213
|
-
# @param [String]
|
209
|
+
# @param format_code [String]
|
214
210
|
# @return [Boolean]
|
215
211
|
def graphical_media?(format_code)
|
216
212
|
format_code == 'gm'
|
217
213
|
end
|
218
214
|
|
219
|
-
# @param [String]
|
215
|
+
# @param format_code [String]
|
220
216
|
# @return [Boolean]
|
221
217
|
def map_atlas?(format_code)
|
222
218
|
format_code&.start_with?('e') || format_code == 'fm'
|
223
219
|
end
|
224
220
|
|
225
|
-
# @param [String]
|
221
|
+
# @param format_code [String]
|
226
222
|
# @return [Boolean]
|
227
223
|
def musical_score?(format_code)
|
228
224
|
format_code.in?(%w[ca cb cc cd cm cs dc dm])
|
229
225
|
end
|
230
226
|
|
231
|
-
# @param [String]
|
232
|
-
# @param [Array<String>]
|
233
|
-
# @param [MARC::Record]
|
227
|
+
# @param format_code [String]
|
228
|
+
# @param media_type [Array<String>]
|
229
|
+
# @param record [MARC::Record]
|
234
230
|
# @return [Boolean]
|
235
231
|
def book?(format_code, media_type, record)
|
236
232
|
title_forms = subfield_values_for tag: '245', subfield: :k, record: record
|
@@ -239,17 +235,17 @@ module PennMARC
|
|
239
235
|
media_type.none? { |val| val =~ /micro/i }
|
240
236
|
end
|
241
237
|
|
242
|
-
# @param [Array<String>]
|
243
|
-
# @param [String]
|
238
|
+
# @param f006_forms [Array<String>]
|
239
|
+
# @param format_code [String]
|
244
240
|
# @return [Boolean]
|
245
241
|
def website_database?(f006_forms, format_code)
|
246
242
|
format_code&.end_with?('i') ||
|
247
243
|
(format_code == 'am' && f006_forms.include?('m') && f006_forms.include?('s'))
|
248
244
|
end
|
249
245
|
|
250
|
-
# @param [String]
|
251
|
-
# @param [MARC::Record]
|
252
|
-
# @param [String]
|
246
|
+
# @param f008 [String]
|
247
|
+
# @param record [MARC::Record]
|
248
|
+
# @param format_code [String]
|
253
249
|
# @return [Boolean]
|
254
250
|
def government_document?(f008, record, format_code)
|
255
251
|
# is a 260 entry present, and does it have a b that matches 'press'
|
@@ -259,31 +255,31 @@ module PennMARC
|
|
259
255
|
%w[c d i j].exclude?(format_code[0]) && f008[28].in?(%w[f i o]) && !f260press
|
260
256
|
end
|
261
257
|
|
262
|
-
# @param [String]
|
263
|
-
# @param [String]
|
258
|
+
# @param f008 [String]
|
259
|
+
# @param format_code [String]
|
264
260
|
# @return [Boolean]
|
265
261
|
def newspaper?(f008, format_code)
|
266
262
|
format_code == 'as' && (f008[21] == 'n' || f008[22] == 'e')
|
267
263
|
end
|
268
264
|
|
269
|
-
# @param [MARC::Record]
|
265
|
+
# @param record [MARC::Record]
|
270
266
|
# @return [Boolean]
|
271
267
|
def conference_event?(record)
|
272
268
|
record.fields('111').any? || record.fields('711').any? # TODO: use field_present helper here and below?
|
273
269
|
end
|
274
270
|
|
275
|
-
# @param [MARC::Record]
|
276
|
-
# @param [String]
|
271
|
+
# @param record [MARC::Record]
|
272
|
+
# @param format_code [String]
|
277
273
|
# @return [Boolean]
|
278
274
|
def thesis_or_dissertation?(format_code, record)
|
279
275
|
record.fields('502').any? && format_code.in?(%w[am tm dm])
|
280
276
|
end
|
281
277
|
|
282
|
-
# @param [Array<String>]
|
283
|
-
# @param [Array<String>]
|
284
|
-
# @param [String]
|
285
|
-
# @param [Array<String>]
|
286
|
-
# @param [Array<String>]
|
278
|
+
# @param call_nums [Array<String>]
|
279
|
+
# @param f007 [Array<String>]
|
280
|
+
# @param f008 [String]
|
281
|
+
# @param title_medium [Array<String>]
|
282
|
+
# @param media_type [Array<String>]
|
287
283
|
# @return [Boolean]
|
288
284
|
def micro_or_microform?(call_nums, f007, f008, media_type, title_medium)
|
289
285
|
[f008[23], f008[29]].any? { |v| v.in?(%w[a b c]) } ||
|
@@ -296,7 +292,7 @@ module PennMARC
|
|
296
292
|
# Determine archive format by checking if {https://www.loc.gov/marc/bibliographic/hd852.html 852} and
|
297
293
|
# {PennMARC::Enriched} Publishing Tag 'ITM' have values that match any of the following archive locations:
|
298
294
|
# archarch, musearch, scfreed, univarch, archivcoll
|
299
|
-
# @param [MARC::Record]
|
295
|
+
# @param record [MARC::Record]
|
300
296
|
# @return [Boolean]
|
301
297
|
def archive?(record)
|
302
298
|
enriched_tag = Enriched::Pub::ITEM_TAG
|
@@ -311,7 +307,7 @@ module PennMARC
|
|
311
307
|
end
|
312
308
|
|
313
309
|
# Consider {https://www.loc.gov/marc/bibliographic/bd007g.html 007} to determine graphical media format
|
314
|
-
# @param [Array<String>]
|
310
|
+
# @param f007 [Array<String>]
|
315
311
|
# @return [String (frozen)]
|
316
312
|
def graphical_media_type(f007)
|
317
313
|
if f007.any? { |v| v.start_with?('g') }
|
@@ -321,7 +317,7 @@ module PennMARC
|
|
321
317
|
end
|
322
318
|
end
|
323
319
|
|
324
|
-
# @param [String]
|
320
|
+
# @param leader [String]
|
325
321
|
# @return [String]
|
326
322
|
def leader_format(leader)
|
327
323
|
leader[6..7] || ' '
|