pennmarc 1.0.6 → 1.0.7
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/README.md +1 -1
- data/lib/pennmarc/helpers/language.rb +3 -3
- data/lib/pennmarc/helpers/link.rb +45 -2
- data/lib/pennmarc/helpers/title.rb +92 -20
- data/lib/pennmarc/version.rb +1 -1
- data/spec/lib/pennmarc/helpers/link_spec.rb +37 -0
- data/spec/lib/pennmarc/helpers/title_spec.rb +80 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11dd403cd5a0f964db340be6258d2cc510c99ccc0fc6d43a65b236853cb5b87c
|
4
|
+
data.tar.gz: 85eed79f3e637121cce8be8b0f0509d26e3fa9b6283b7f5bc48b0b321259e3f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 90a59eaf167d985b596663d6b8d1eab0c3263724da550babfb28fa253df326b07b72bbb5aac1cf1d4150efd2eaecce84686b2de9e99801ff178bbfabc982b765
|
7
|
+
data.tar.gz: 5e0a4fdc1518af2b3a52bc137f76a30430d025f58f5cd46b9d0347a7a6a08f901e72e45917cc9a52d0352a6dbb0213725fd5a6e22650cfedb00d534fb72b44f2
|
data/README.md
CHANGED
@@ -71,7 +71,7 @@ rspec
|
|
71
71
|
|
72
72
|
## Publishing the Gem
|
73
73
|
|
74
|
-
1. Update the
|
74
|
+
1. Update the `VERSION` constant in `lib/pennmarc/version.rb`.
|
75
75
|
2. Run `gem build pennmarc.gemspec` with the latest code
|
76
76
|
3. Run `gem push pennmarc-{version number here}.gem`(e.g. `gem push pennmarc-1.0.0.gem`) to push to RubyGems. You will need access and MFA setup with RubyGems.
|
77
77
|
|
@@ -26,9 +26,9 @@ module PennMARC
|
|
26
26
|
# when no linguistic content is found.
|
27
27
|
#
|
28
28
|
# @note In franklin, we extracted the language code from the 008 control field. After engaging cataloging unit
|
29
|
-
# representatives, we decided to extract these values from the 041 field: Includes records for
|
30
|
-
# items, items that involve translation, and items where the medium of communication is a sign
|
31
|
-
# https://www.loc.gov/marc/bibliographic/bd041.html
|
29
|
+
# representatives, we decided to also extract these values from the 041 field: Includes records for
|
30
|
+
# multilingual items, items that involve translation, and items where the medium of communication is a sign
|
31
|
+
# language. https://www.loc.gov/marc/bibliographic/bd041.html
|
32
32
|
#
|
33
33
|
# @param [MARC::Record] record
|
34
34
|
# @param [Hash] iso_639_2_mapping iso-639-2 spec hash for language code translation
|
@@ -10,9 +10,52 @@ module PennMARC
|
|
10
10
|
# @return [Object]
|
11
11
|
def offsite(record); end
|
12
12
|
|
13
|
-
|
13
|
+
# Full text links from MARC 856 fields.
|
14
|
+
# @param [MARC::Record] record
|
15
|
+
# @return [Array] array of hashes
|
16
|
+
def full_text(record:)
|
17
|
+
indicator2_options = %w[0 1]
|
18
|
+
links_from_record(record, indicator2_options)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Web text links from MARC 856 fields.
|
22
|
+
# @param [MARC::Record] record
|
23
|
+
# @return [Array] array of hashes
|
24
|
+
def web(record:)
|
25
|
+
indicator2_options = ['2', ' ', '']
|
26
|
+
links_from_record(record, indicator2_options)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# Extract subfield 3 and z/y depending on the presence of either. Extract link url and assemble array
|
32
|
+
# with text and link.
|
33
|
+
# @param [MARC::Field] field
|
34
|
+
# @return [Array]
|
35
|
+
def link_text_and_url(field)
|
36
|
+
subfield3 = subfield_values(field, 3)
|
37
|
+
subfield_zy = field.find_all(&subfield_in?(%w[z y])).map(&:value)
|
38
|
+
link_text = [subfield3, subfield_zy.first].compact.join(' ')
|
39
|
+
link_url = subfield_values(field, 'u')&.first || ''
|
40
|
+
[link_text, link_url.sub(' target=_blank', '')]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Assemble array of link text, link URL values from 856 fields. Ensure indicator1 (access method)
|
44
|
+
# is always 4 (HTTP) and indicator2 (relationship) can be specified by caller method.
|
45
|
+
# @param [MARC::Record] record
|
46
|
+
# @param [Array] indicator2_options
|
47
|
+
# @return [Array]
|
48
|
+
def links_from_record(record, indicator2_options)
|
49
|
+
record.fields('856').filter_map do |field|
|
50
|
+
next unless field.indicator1 == '4' && indicator2_options.include?(field.indicator2)
|
14
51
|
|
15
|
-
|
52
|
+
link_text, link_url = link_text_and_url(field)
|
53
|
+
{
|
54
|
+
link_text: link_text.present? ? link_text : link_url,
|
55
|
+
link_url: link_url
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
16
59
|
end
|
17
60
|
end
|
18
61
|
end
|
@@ -4,46 +4,81 @@ module PennMARC
|
|
4
4
|
# This helper contains logic for parsing out Title and Title-related fields.
|
5
5
|
class Title < Helper
|
6
6
|
class << self
|
7
|
-
#
|
7
|
+
# We use these fields when retrieving auxiliary titles in the *search_aux methods:
|
8
|
+
# {https://www.loc.gov/marc/bibliographic/bd130.html 130},
|
9
|
+
# {https://www.loc.gov/marc/bibliographic/bd210.html 210},
|
10
|
+
# {https://www.loc.gov/marc/bibliographic/bd245.html 245},
|
11
|
+
# {https://www.loc.gov/marc/bibliographic/bd246.html 246},
|
12
|
+
# {https://www.loc.gov/marc/bibliographic/bd247.html 247},
|
13
|
+
# {https://www.loc.gov/marc/bibliographic/bd440.html 440},
|
14
|
+
# {https://www.loc.gov/marc/bibliographic/bd490.html 490},
|
15
|
+
# {https://www.loc.gov/marc/bibliographic/bd730.html 730},
|
16
|
+
# {https://www.loc.gov/marc/bibliographic/bd740.html 740},
|
17
|
+
# {https://www.loc.gov/marc/bibliographic/bd830.html 830},
|
18
|
+
# {https://www.loc.gov/marc/bibliographic/bd773.html 773},
|
19
|
+
# {https://www.loc.gov/marc/bibliographic/bd774.html 774},
|
20
|
+
# {https://www.loc.gov/marc/bibliographic/bd780.html 780},
|
21
|
+
# {https://www.loc.gov/marc/bibliographic/bd785.html 785},
|
22
|
+
# {https://www.loc.gov/marc/bibliographic/bd700.html 700},
|
23
|
+
# {https://www.loc.gov/marc/bibliographic/bd710.html 710},
|
24
|
+
# {https://www.loc.gov/marc/bibliographic/bd711.html 711},
|
25
|
+
# {https://www.loc.gov/marc/bibliographic/bd505.html 505}
|
8
26
|
AUX_TITLE_TAGS = {
|
9
27
|
main: %w[130 210 240 245 246 247 440 490 730 740 830],
|
10
28
|
related: %w[773 774 780 785],
|
11
|
-
entity: %w[700 710 711]
|
29
|
+
entity: %w[700 710 711],
|
30
|
+
note: %w[505]
|
12
31
|
}.freeze
|
13
32
|
|
14
|
-
# Main Title Search field. Takes from 245 and linked 880.
|
33
|
+
# Main Title Search field. Takes from {https://www.loc.gov/marc/bibliographic/bd245.html 245} and linked 880.
|
15
34
|
# @note Ported from get_title_1_search_values.
|
16
35
|
# @param [MARC::Record] record
|
17
36
|
# @return [Array<String>] array of title values for search
|
18
37
|
def search(record)
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
titles + record.fields('880').filter_map do |field|
|
23
|
-
next unless subfield_value?(field, '6', /245/)
|
38
|
+
record.fields(%w[245 880]).filter_map do |field|
|
39
|
+
next if field.tag == '880' && subfield_value_not_in?(field, '6', %w[245])
|
24
40
|
|
25
41
|
join_subfields(field, &subfield_not_in?(%w[c 6 8 h]))
|
26
42
|
end
|
27
43
|
end
|
28
44
|
|
29
|
-
# Auxiliary Title Search field. Takes from many fields that contain title-like
|
30
|
-
#
|
31
|
-
# @todo port this, it is way complicated but essential for relevance
|
45
|
+
# Auxiliary Title Search field. Takes from many fields defined in {AUX_TITLE_TAGS} that contain title-like
|
46
|
+
# information.
|
32
47
|
# @param [MARC::Record] record
|
33
|
-
# @return [Array<String>] array of title values for search
|
34
|
-
def search_aux(record)
|
48
|
+
# @return [Array<String>] array of auxiliary title values for search
|
49
|
+
def search_aux(record)
|
50
|
+
search_aux_values(record: record, title_type: :main, &subfield_not_in?(%w[c 6 8])) +
|
51
|
+
search_aux_values(record: record, title_type: :related, &subfield_not_in?(%w[s t])) +
|
52
|
+
search_aux_values(record: record, title_type: :entity, &subfield_in?(%w[t])) +
|
53
|
+
search_aux_values(record: record, title_type: :note, &subfield_in?(%w[t]))
|
54
|
+
end
|
35
55
|
|
36
|
-
# Journal Title Search field.
|
37
|
-
#
|
56
|
+
# Journal Title Search field. Takes from {https://www.loc.gov/marc/bibliographic/bd245.html 245} and linked 880.
|
57
|
+
# We do not return any values if the {https://www.loc.gov/marc/bibliographic/bdleader.html MARC leader}
|
58
|
+
# indicates that the record is not a serial.
|
38
59
|
# @param [MARC::Record] record
|
39
60
|
# @return [Array<String>] journal title information for search
|
40
|
-
def journal_search(record)
|
61
|
+
def journal_search(record)
|
62
|
+
return [] if not_a_serial?(record)
|
63
|
+
|
64
|
+
record.fields(%w[245 880]).filter_map do |field|
|
65
|
+
next if field.tag == '880' && subfield_value_not_in?(field, '6', %w[245])
|
66
|
+
|
67
|
+
join_subfields(field, &subfield_not_in?(%w[c 6 8 h]))
|
68
|
+
end
|
69
|
+
end
|
41
70
|
|
42
|
-
# Auxiliary Journal Title Search field.
|
43
|
-
#
|
71
|
+
# Auxiliary Journal Title Search field. Takes from many fields defined in {AUX_TITLE_TAGS} that contain title-like
|
72
|
+
# information. Does not return any titles if the {https://www.loc.gov/marc/bibliographic/bdleader.html MARC leader}
|
73
|
+
# indicates that the record is not a serial.
|
44
74
|
# @param [MARC::Record] record
|
45
|
-
# @return [Array<String>] journal title information for search
|
46
|
-
def journal_search_aux(record)
|
75
|
+
# @return [Array<String>] auxiliary journal title information for search
|
76
|
+
def journal_search_aux(record)
|
77
|
+
search_aux_values(record: record, title_type: :main, journal: true, &subfield_not_in?(%w[c 6 8])) +
|
78
|
+
search_aux_values(record: record, title_type: :related, journal: true, &subfield_not_in?(%w[s t])) +
|
79
|
+
search_aux_values(record: record, title_type: :entity, journal: true, &subfield_in?(%w[t])) +
|
80
|
+
search_aux_values(record: record, title_type: :note, journal: true, &subfield_in?(%w[t]))
|
81
|
+
end
|
47
82
|
|
48
83
|
# Single-valued Title, for use in headings. Takes the first {https://www.oclc.org/bibformats/en/2xx/245.html 245}
|
49
84
|
# value. Special consideration for
|
@@ -192,6 +227,43 @@ module PennMARC
|
|
192
227
|
{ prefix: '', filing: title.strip }
|
193
228
|
end
|
194
229
|
end
|
230
|
+
|
231
|
+
# Evaluate {https://www.loc.gov/marc/bibliographic/bdleader.html MARC leader} to determine if record is a serial.
|
232
|
+
# @param [MARC::Record] record
|
233
|
+
# @return [Boolean]
|
234
|
+
def not_a_serial?(record)
|
235
|
+
!record.leader[6..7].ends_with?('s')
|
236
|
+
end
|
237
|
+
|
238
|
+
# @param [MARC::DataField] field
|
239
|
+
# @param [String] value
|
240
|
+
# @return [Boolean]
|
241
|
+
def indicators_are_not_value?(field, value)
|
242
|
+
field.indicator1 != value && field.indicator2 != value
|
243
|
+
end
|
244
|
+
|
245
|
+
# Retrieve auxiliary title values. Returns no values if a journal is expected but the
|
246
|
+
# {https://www.loc.gov/marc/bibliographic/bdleader.html MARC leader} indicates that the record is not a serial.
|
247
|
+
# We take special consideration for the {https://www.loc.gov/marc/bibliographic/bd505.html 505 field}, extracting
|
248
|
+
# values only when indicator1 and indicator2 are both '0'.
|
249
|
+
# @param [MARC::Record] record
|
250
|
+
# @param [Symbol] title_type
|
251
|
+
# @param [Boolean] journal
|
252
|
+
# @bloc [Proc] join_selector
|
253
|
+
# @return [Array<String>]
|
254
|
+
def search_aux_values(record:, title_type:, journal: false, &join_selector)
|
255
|
+
return [] if journal && not_a_serial?(record)
|
256
|
+
|
257
|
+
tags = AUX_TITLE_TAGS[title_type] + ['880']
|
258
|
+
|
259
|
+
record.fields(tags).filter_map do |field|
|
260
|
+
next if field.tag == '505' && indicators_are_not_value?(field, '0')
|
261
|
+
|
262
|
+
next if field.tag == '880' && subfield_value_not_in?(field, '6', tags)
|
263
|
+
|
264
|
+
join_subfields(field, &join_selector)
|
265
|
+
end
|
266
|
+
end
|
195
267
|
end
|
196
268
|
end
|
197
269
|
end
|
data/lib/pennmarc/version.rb
CHANGED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe 'PennMARC::Link' do
|
4
|
+
include MarcSpecHelpers
|
5
|
+
|
6
|
+
let(:helper) { PennMARC::Link }
|
7
|
+
|
8
|
+
describe '.full_text' do
|
9
|
+
let(:record) do
|
10
|
+
marc_record fields: [marc_field(tag: '856', subfields: { '3': 'Materials specified',
|
11
|
+
z: 'Public note',
|
12
|
+
y: 'Link text',
|
13
|
+
u: 'https://www.test-uri.com/' },
|
14
|
+
indicator1: '4', indicator2: '0')]
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'returns full text link text and url' do
|
18
|
+
expect(helper.full_text(record: record)).to contain_exactly({ link_text: 'Materials specified Public note',
|
19
|
+
link_url: 'https://www.test-uri.com/' })
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.web' do
|
24
|
+
let(:record) do
|
25
|
+
marc_record fields: [marc_field(tag: '856', subfields: { '3': 'Materials specified',
|
26
|
+
z: 'Public note',
|
27
|
+
y: 'Link text',
|
28
|
+
u: 'https://www.test-uri.com/' },
|
29
|
+
indicator1: '4', indicator2: '')]
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'returns web link text and url' do
|
33
|
+
expect(helper.web(record: record)).to contain_exactly({ link_text: 'Materials specified Public note',
|
34
|
+
link_url: 'https://www.test-uri.com/' })
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -21,7 +21,86 @@ describe 'PennMARC::Title' do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
describe '.search_aux' do
|
24
|
-
|
24
|
+
let(:leader) { 'ZZZZZnaaZa22ZZZZZzZZ4500' }
|
25
|
+
let(:record) do
|
26
|
+
marc_record fields: [
|
27
|
+
marc_field(tag: '130', subfields: { a: 'Uniform Title', c: '130 not included' }),
|
28
|
+
marc_field(tag: '880', subfields: { '6': '130', a: 'Alternative Uniform Title' }),
|
29
|
+
marc_field(tag: '773', subfields: { a: 'Host Uniform Title', s: '773 not included' }),
|
30
|
+
marc_field(tag: '700', subfields: { t: 'Personal Entry Title', s: '700 not included' }),
|
31
|
+
marc_field(tag: '505', subfields: { t: 'Invalid Formatted Contents Note Title' }, indicator1: 'invalid'),
|
32
|
+
marc_field(tag: '505', subfields: { t: 'Formatted Contents Note Title', s: '505 not included' },
|
33
|
+
indicator1: '0', indicator2: '0')
|
34
|
+
], leader: leader
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'returns auxiliary titles' do
|
38
|
+
expect(helper.search_aux(record)).to contain_exactly('Uniform Title', 'Host Uniform Title',
|
39
|
+
'Alternative Uniform Title', 'Personal Entry Title',
|
40
|
+
'Formatted Contents Note Title')
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when the leader indicates the record is a serial' do
|
44
|
+
let(:leader) { 'ZZZZZnasZa22ZZZZZzZZ4500' }
|
45
|
+
|
46
|
+
it 'returns auxiliary titles' do
|
47
|
+
expect(helper.search_aux(record)).to contain_exactly('Uniform Title', 'Host Uniform Title',
|
48
|
+
'Alternative Uniform Title', 'Personal Entry Title',
|
49
|
+
'Formatted Contents Note Title')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '.journal_search' do
|
55
|
+
let(:leader) { 'ZZZZZnasZa22ZZZZZzZZ4500' }
|
56
|
+
let(:record) do
|
57
|
+
marc_record fields: [
|
58
|
+
marc_field(tag: '245', subfields: { a: 'Some Journal Title' }),
|
59
|
+
marc_field(tag: '880', subfields: { a: 'Alternative Script', '6': '245' }),
|
60
|
+
marc_field(tag: '880', subfields: { a: 'Unrelated 880', '6': 'invalid' })
|
61
|
+
], leader: leader
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'returns journal search titles' do
|
65
|
+
expect(helper.journal_search(record)).to contain_exactly('Some Journal Title', 'Alternative Script')
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'when the record is not a serial' do
|
69
|
+
let(:leader) { 'ZZZZZnaaZa22ZZZZZzZZ4500' }
|
70
|
+
|
71
|
+
it 'returns an empty array' do
|
72
|
+
expect(helper.journal_search_aux(record)).to be_empty
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '.journal_search_aux' do
|
78
|
+
let(:leader) { 'ZZZZZnasZa22ZZZZZzZZ4500' }
|
79
|
+
let(:record) do
|
80
|
+
marc_record fields: [
|
81
|
+
marc_field(tag: '130', subfields: { a: 'Uniform Title', c: '130 not included' }),
|
82
|
+
marc_field(tag: '880', subfields: { '6': '130', a: 'Alternative Uniform Title' }),
|
83
|
+
marc_field(tag: '773', subfields: { a: 'Host Uniform Title', s: '773 not included' }),
|
84
|
+
marc_field(tag: '700', subfields: { t: 'Personal Entry Title', s: '700 not included' }),
|
85
|
+
marc_field(tag: '505', subfields: { t: 'Invalid Formatted Contents Note Title' }, indicator1: 'invalid'),
|
86
|
+
marc_field(tag: '505', subfields: { t: 'Formatted Contents Note Title', s: '505 not included' },
|
87
|
+
indicator1: '0', indicator2: '0')
|
88
|
+
], leader: leader
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'returns auxiliary journal search titles' do
|
92
|
+
expect(helper.journal_search_aux(record)).to contain_exactly('Uniform Title', 'Alternative Uniform Title',
|
93
|
+
'Host Uniform Title', 'Personal Entry Title',
|
94
|
+
'Formatted Contents Note Title')
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'when the record is not a serial' do
|
98
|
+
let(:leader) { 'ZZZZZnaaZa22ZZZZZzZZ4500' }
|
99
|
+
|
100
|
+
it 'returns an empty array' do
|
101
|
+
expect(helper.journal_search_aux(record)).to be_empty
|
102
|
+
end
|
103
|
+
end
|
25
104
|
end
|
26
105
|
|
27
106
|
describe '.show' do
|
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.0.
|
4
|
+
version: 1.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Kanning
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2023-
|
13
|
+
date: 2023-12-06 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -128,6 +128,7 @@ files:
|
|
128
128
|
- spec/lib/pennmarc/helpers/genre_spec.rb
|
129
129
|
- spec/lib/pennmarc/helpers/identifer_spec.rb
|
130
130
|
- spec/lib/pennmarc/helpers/language_spec.rb
|
131
|
+
- spec/lib/pennmarc/helpers/link_spec.rb
|
131
132
|
- spec/lib/pennmarc/helpers/location_spec.rb
|
132
133
|
- spec/lib/pennmarc/helpers/note_spec.rb
|
133
134
|
- spec/lib/pennmarc/helpers/production_spec.rb
|