pennmarc 1.0.33 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f26c7e473bed7b22bd7aa63257b9647dd808f79a02aa1aab21e965f264d545a
4
- data.tar.gz: f793a9945291b9b66ee6c4155446c9270fc6e2f994c0754fa6dc0b4ba887cebc
3
+ metadata.gz: 9003d5a58efd2cbef83a220bd0d609edfdc2bfb883378c003d0bafa2d85e520e
4
+ data.tar.gz: d8f841dbba9e412848b31a7a11284b14e2bbb772fbb98762b827ab9e2baf6355
5
5
  SHA512:
6
- metadata.gz: b3b5296a1f285562ed9c2fd88e5f06f3c3127fd988ad7066298fcbc3cbb3b143678ac1da9c2e63e1fcf5df3075ea763197928712db0221042164525a6191a635
7
- data.tar.gz: 3201a8f615d58871620081112eb663d7526911a68f1eae4a561e3216d77ada399cc10164be0532fdf7d2992a9cc964a829abfeb9272d64fabaa263ddb8f2f31c
6
+ metadata.gz: a45d1e909a7a9efad1aec8047d79f3358b1ee3b523958661459c27b397f3a0f33c00deffeae2bdd30fad14156b8f348171639375677e6f600086e1b592fe2c51
7
+ data.tar.gz: ba609fef49f12f9341328fc292cc510fab6ab298174791afc99ec802ecd1c62448c9ccc009a7f01c6aefef7be2c56d794cc5f2e0bddf01c72fc4e9db11ce6961
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-07-02 15:41:46 UTC using RuboCop version 1.51.0.
3
+ # on 2024-08-20 20:46:53 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: 25
17
+ # Offense count: 26
18
18
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
19
19
  Metrics/AbcSize:
20
20
  Exclude:
@@ -31,7 +31,7 @@ Metrics/AbcSize:
31
31
  - 'lib/pennmarc/helpers/title.rb'
32
32
  - 'lib/pennmarc/util.rb'
33
33
 
34
- # Offense count: 8
34
+ # Offense count: 9
35
35
  # Configuration parameters: CountComments, Max, CountAsOne.
36
36
  Metrics/ClassLength:
37
37
  Exclude:
@@ -138,9 +138,10 @@ RSpec/FilePath:
138
138
  Exclude:
139
139
  - 'spec/lib/pennmarc/parser_spec.rb'
140
140
 
141
- # Offense count: 23
141
+ # Offense count: 26
142
142
  # Configuration parameters: Max, AllowedGroups.
143
143
  RSpec/NestedGroups:
144
144
  Exclude:
145
145
  - 'spec/lib/pennmarc/helpers/access_spec.rb'
146
146
  - 'spec/lib/pennmarc/helpers/format_spec.rb'
147
+ - 'spec/lib/pennmarc/helpers/location_spec.rb'
@@ -42,6 +42,24 @@ module PennMARC
42
42
  }.uniq
43
43
  end
44
44
 
45
+ # Parse call number values from inventory fields, including both hld and itm fields from publishing enrichment.
46
+ # Return only unique values.
47
+ # @param record [MARC::Record]
48
+ # @return [Array<String>] array of call numbers from inventory fields
49
+ def call_number_search(record)
50
+ call_nums = record.fields(TAGS).filter_map do |field|
51
+ subfield_values(field, call_number_sf(field))
52
+ end
53
+
54
+ # Ensure we get call numbers for records with no `itm` tags by also checking `hld` and de-duping
55
+ call_nums += record.fields([Enriched::Pub::PHYS_INVENTORY_TAG]).filter_map do |field|
56
+ first = subfield_values(field, Enriched::Pub::HOLDING_CLASSIFICATION_PART)&.first
57
+ last = subfield_values(field, Enriched::Pub::HOLDING_ITEM_PART)&.first
58
+ "#{first} #{last}".squish.presence
59
+ end
60
+ call_nums.flatten.uniq
61
+ end
62
+
45
63
  private
46
64
 
47
65
  # Retrieve subfield code that stores the call number on enriched marc field
@@ -3,7 +3,6 @@
3
3
  module PennMARC
4
4
  # Methods that return Library and Location values from Alma enhanced MARC fields
5
5
  class Location < Helper
6
- ONLINE_LIBRARY = 'Online library'
7
6
  WEB_LOCATION_CODE = 'web'
8
7
 
9
8
  class << self
@@ -38,14 +37,14 @@ module PennMARC
38
37
  # @see https://developers.exlibrisgroup.com/alma/apis/docs/bibs/R0VUIC9hbG1hd3MvdjEvYmlicy97bW1zX2lkfQ==/
39
38
  # Alma documentation for these added fields
40
39
  # @param record [MARC::Record]
41
- # @param display_value [Symbol | String] field in location hash to retrieve
40
+ # @param display_value [Symbol,String] field in location hash to retrieve
42
41
  # @param location_map [Hash] hash with location_code as key and location hash as value
43
42
  # @return [Array<String>]
44
43
  def location(record:, display_value:, location_map:)
45
44
  # get enriched marc location tag and relevant subfields
46
- enriched_location_tag_and_subfields(record) => {tag:, location_code_sf:, call_num_sf:}
45
+ enriched_location_tag_and_subfields(record) => {tag:, location_code_sf:, call_num_sf:, call_num_type_sf:}
47
46
 
48
- locations = record.fields(tag).flat_map { |field|
47
+ record.fields(tag).flat_map { |field|
49
48
  field.filter_map { |subfield|
50
49
  # skip unless subfield matches enriched marc tag subfield code
51
50
  next unless subfield.code == location_code_sf
@@ -54,28 +53,27 @@ module PennMARC
54
53
 
55
54
  next if location_code_to_ignore?(location_map, location_code)
56
55
 
57
- override = specific_location_override(display_value: display_value, location_code: location_code,
58
- field: field, call_num_sf: call_num_sf)
56
+ override = if display_value.to_sym == :specific_location
57
+ specific_location_override(location_code: location_code, field: field,
58
+ call_num_sf: call_num_sf, call_num_type_sf: call_num_type_sf)
59
+ end
59
60
 
60
61
  override || location_map[location_code.to_sym][display_value.to_sym]
61
62
  }.flatten.compact_blank
62
63
  }.uniq
63
- if record.tags.intersect?([Enriched::Pub::ELEC_INVENTORY_TAG, Enriched::Api::ELEC_INVENTORY_TAG])
64
- locations << ONLINE_LIBRARY
65
- end
66
-
67
- locations
68
64
  end
69
65
 
70
66
  private
71
67
 
72
68
  # Determine enriched marc location tag, location code subfield, and call number subfield,
73
- # giving priority to using 'itm', 'AVA', or 'AVE' fields.
69
+ # giving priority to using 'itm', 'AVA', or 'hld' fields.
74
70
  # @param record [MARC::Record]
75
71
  # @return [Hash<String, String>] containing location tag and subfield code
76
72
  # - `:tag` (String): The enriched marc location tag
77
73
  # - `:location_code_sf` (String): The subfield code where location code is stored
78
74
  # - `:call_num_sf` (String): The subfield code where call number is stored
75
+ # - `:call_num_type_sf` (String, nil): The subfield code where call number type is stored. nil if unavailable in a
76
+ # MARC field and we need to look for an indicator.
79
77
  def enriched_location_tag_and_subfields(record)
80
78
  # in holdings records, the shelving location is always the permanent location.
81
79
  # in item records, the current location takes into account
@@ -90,19 +88,22 @@ module PennMARC
90
88
  tag = Enriched::Pub::ITEM_TAG
91
89
  location_code_sf = Enriched::Pub::ITEM_CURRENT_LOCATION
92
90
  call_num_sf = Enriched::Pub::ITEM_CALL_NUMBER
91
+ call_num_type_sf = Enriched::Pub::ITEM_CALL_NUMBER_TYPE
93
92
  # if the record has API inventory tags, use them
94
93
  elsif field_defined?(record, Enriched::Api::PHYS_INVENTORY_TAG)
95
94
  tag = Enriched::Api::PHYS_INVENTORY_TAG
96
95
  location_code_sf = Enriched::Api::PHYS_LOCATION_CODE
97
96
  call_num_sf = Enriched::Api::PHYS_CALL_NUMBER
97
+ call_num_type_sf = Enriched::Api::PHYS_CALL_NUMBER_TYPE
98
98
  # otherwise use Pub holding tags
99
99
  else
100
100
  tag = Enriched::Pub::PHYS_INVENTORY_TAG
101
101
  location_code_sf = Enriched::Pub::PHYS_LOCATION_CODE
102
102
  call_num_sf = Enriched::Pub::HOLDING_CLASSIFICATION_PART
103
+ call_num_type_sf = nil # for hld tags, the call num type is indicator0
103
104
  end
104
105
 
105
- { tag: tag, location_code_sf: location_code_sf, call_num_sf: call_num_sf }
106
+ { tag: tag, location_code_sf: location_code_sf, call_num_sf: call_num_sf, call_num_type_sf: call_num_type_sf }
106
107
  end
107
108
 
108
109
  # Determines whether to ignore a location code.
@@ -111,32 +112,55 @@ module PennMARC
111
112
  # map, we ignore it, for faceting purposes. We also ignore the location code 'web'. We don't facet for 'web'
112
113
  # which is the 'Penn Library Web' location used in Voyager. This location should eventually go away completely
113
114
  # with data cleanup in Alma.
114
- # @param location_map [location_map] hash with location_code as key and location hash as value
115
- # @param location_code [location_code] retrieved from record
115
+ # @param location_map [Hash] hash with location_code as key and location hash as value
116
+ # @param location_code [String] retrieved from record
116
117
  # @return [Boolean]
117
118
  def location_code_to_ignore?(location_map, location_code)
118
- location_map.key?(location_code.to_sym) == false || location_code == WEB_LOCATION_CODE
119
+ !location_map.key?(location_code.to_sym) || location_code == WEB_LOCATION_CODE
119
120
  end
120
121
 
121
122
  # Retrieves a specific location override based on location code and call number. Specific location overrides are
122
123
  # located in `location_overrides.yml`.
123
- # @param display_value [String | Symbol]
124
124
  # @param location_code [String]
125
125
  # @param field [MARC::Field]
126
126
  # @param call_num_sf [String]
127
+ # @param call_num_type_sf [String, nil]
127
128
  # @return [String, Nil]
128
- def specific_location_override(display_value:, location_code:, field:, call_num_sf:)
129
- return unless display_value.to_sym == :specific_location
129
+ def specific_location_override(location_code:, field:, call_num_sf:, call_num_type_sf:)
130
+ callnum_type = callnum_type(field: field, call_num_type_sf: call_num_type_sf)
131
+ return unless callnum_type
130
132
 
131
- locations_overrides = Mappers.location_overrides
133
+ override = Mappers.location_overrides.find do |_key, override_data|
134
+ override_matching?(override_data: override_data, location_code: location_code, callnum_type: callnum_type,
135
+ call_numbers: subfield_values(field, call_num_sf))
136
+ end
132
137
 
133
- call_numbers = subfield_values(field, call_num_sf)
138
+ override&.last&.dig(:specific_location)
139
+ end
134
140
 
135
- override = locations_overrides.find do |_key, value|
136
- value[:location_code] == location_code && call_numbers.any? { |num| num.match?(value[:call_num_pattern]) }
141
+ # Check override_data hash for a matching location name override
142
+ # @param override_data [Hash]
143
+ # @param location_code [String]
144
+ # @param call_numbers [Array]
145
+ # @param callnum_type [String]
146
+ # @return [Boolean]
147
+ def override_matching?(override_data:, location_code:, call_numbers:, callnum_type:)
148
+ call_numbers.any? do |call_number|
149
+ override_data[:location_code] == location_code &&
150
+ override_data[:call_num_type] == callnum_type &&
151
+ call_number.match?(override_data[:call_num_pattern])
137
152
  end
153
+ end
138
154
 
139
- override&.last&.dig(:specific_location)
155
+ # Return call num type value for a given field. If no call number subfield is expected (publishing holding
156
+ # inventory case), the first indicator is checked.
157
+ # @param field [MARC::Field]
158
+ # @param call_num_type_sf [String, nil]
159
+ # @return [String, nil]
160
+ def callnum_type(field:, call_num_type_sf:)
161
+ return field.indicator1 if call_num_type_sf.nil?
162
+
163
+ subfield_values(field, call_num_type_sf).first
140
164
  end
141
165
  end
142
166
  end
@@ -90,7 +90,7 @@ module PennMARC
90
90
  # @return [Array<String>]
91
91
  def access_restriction_show(record)
92
92
  record.fields('506').filter_map { |field|
93
- join_subfields(field, &subfield_not_in?(%w[5 6]))
93
+ join_subfields(field, &subfield_not_in?(%w[2 5 6]))
94
94
  }.uniq
95
95
  end
96
96
 
@@ -93,22 +93,46 @@ module PennMARC
93
93
  # @param record [MARC::Record]
94
94
  # @return [String] single title for display
95
95
  def show(record)
96
+ field = record.fields('245')&.first
97
+ values = title_values(field)
98
+ [format_title(values[:title_or_form]), values[:punctuation], values[:other_info]].compact_blank.join(' ')
99
+ end
100
+
101
+ # Same as show, but with inclusive dates appended. For use on show page.
102
+ # @param record [MARC::Record]
103
+ # @return [String] detailed title for display
104
+ def detailed_show(record)
105
+ field = record.fields('245')&.first
106
+ values = title_values(field)
107
+ title = [format_title(values[:title_or_form]), values[:punctuation],
108
+ trim_trailing(:period, values[:other_info])].compact_blank.join(' ')
109
+ values[:inclusive_dates].present? ? [title, values[:inclusive_dates]].compact_blank.join(', ') : title
110
+ end
111
+
112
+ # Same structure as show, but linked alternate title.
113
+ # @param record [MARC::Record]
114
+ # @return [String, nil] alternate title for display
115
+ def alternate_show(record)
116
+ field = record.fields('880').filter_map { |alternate_field|
117
+ next unless subfield_value?(alternate_field, '6', /^245/)
118
+
119
+ alternate_field
120
+ }.first
121
+ return unless field
122
+
123
+ values = title_values(field)
124
+ [format_title(values[:title_or_form]), values[:punctuation], values[:other_info]].compact_blank.join(' ')
125
+ end
126
+
127
+ # Title statement of responsibility (field 245, subfield c) and linked alternate for display.
128
+ # See https://www.oclc.org/bibformats/en/2xx/245.html#subfieldc for examples
129
+ # @param [MARC::Record] record
130
+ # @return [Array<String>] statement of responsibility and linked alternate
131
+ def statement_of_responsibility_show(record)
96
132
  field = record.fields('245').first
97
- title_or_form = field.find_all(&subfield_in?(%w[a k]))
98
- .map { |sf| trim_trailing(:comma, trim_trailing(:slash, sf.value).rstrip) }
99
- .first || ''
100
- other_info = field.find_all(&subfield_in?(%w[b n p]))
101
- .map { |sf| trim_trailing(:slash, sf.value) }
102
- .join(' ')
103
- hpunct = field.find_all { |sf| sf.code == 'h' }.map { |sf| sf.value.last }.first
104
- punctuation = if [title_or_form.last, hpunct].include?('=')
105
- '='
106
- else
107
- [title_or_form.last, hpunct].include?(':') ? ':' : nil
108
- end
109
- [trim_trailing(:colon, trim_trailing(:equal, title_or_form)).strip,
110
- punctuation,
111
- other_info].compact_blank.join(' ')
133
+ statement = field&.find { |sf| sf.code == 'c' }&.value
134
+ alternate_statement = linked_alternate(record, '245', &subfield_in?(%w[c]))&.first
135
+ [statement, alternate_statement].compact_blank
112
136
  end
113
137
 
114
138
  # Canonical title with non-filing characters relocated to the end.
@@ -212,12 +236,13 @@ module PennMARC
212
236
  def former_show(record)
213
237
  record.fields
214
238
  .filter_map { |field|
215
- next unless field.tag == '247' || (field.tag == '880' && subfield_value?(field, '6', /^247/))
239
+ next unless field.tag == '247' || (field.tag == '880' && subfield_value?(field, '6', /^247/))
216
240
 
217
- former_title = join_subfields field, &subfield_not_in?(%w[6 8 e w]) # 6 and 8 are not meaningful for display
218
- former_title_append = join_subfields field, &subfield_in?(%w[e w])
219
- "#{former_title} #{former_title_append}".strip
220
- }.uniq
241
+ # 6 and 8 are not meaningful for display
242
+ former_title = join_subfields field, &subfield_not_in?(%w[6 8 e w])
243
+ former_title_append = join_subfields field, &subfield_in?(%w[e w])
244
+ "#{former_title} #{former_title_append}".strip
245
+ }.uniq
221
246
  end
222
247
 
223
248
  # Determine if the record is a "Host" bibliographic record for other bib records ("bound-withs")
@@ -232,6 +257,44 @@ module PennMARC
232
257
 
233
258
  private
234
259
 
260
+ # Extract title values from provided 245 subfields. Main title components are the following:
261
+ # - title_or_form: subfields a and k
262
+ # - inclusive_dates: subfield c
263
+ # - other_info: subfields b, n, and p
264
+ # https://www.oclc.org/bibformats/en/2xx/245.html
265
+ #
266
+ # @param field [MARC::Field]
267
+ # @return [Hash] title values
268
+ def title_values(field)
269
+ title_or_form = field.find_all(&subfield_in?(%w[a k]))
270
+ .map { |sf| trim_trailing(:comma, trim_trailing(:slash, sf.value).rstrip) }
271
+ .first || ''
272
+ inclusive_dates = field.find { |sf| sf.code == 'f' }&.value
273
+ other_info = field.find_all(&subfield_in?(%w[b n p]))
274
+ .map { |sf| trim_trailing(:slash, sf.value) }
275
+ .join(' ')
276
+ title_punctuation = title_or_form.last
277
+ medium_punctuation = field.find_all { |sf| sf.code == 'h' }
278
+ .map { |sf| sf.value.last }
279
+ .first
280
+ punctuation = if [title_punctuation, medium_punctuation].include?('=')
281
+ '='
282
+ else
283
+ [title_punctuation, medium_punctuation].include?(':') ? ':' : nil
284
+ end
285
+ { title_or_form: title_or_form,
286
+ inclusive_dates: inclusive_dates,
287
+ other_info: other_info,
288
+ punctuation: punctuation }
289
+ end
290
+
291
+ # Remove trailing equal from title, then remove trailing colon.
292
+ # @param title [String]
293
+ # @return [String]
294
+ def format_title(title)
295
+ trim_trailing(:colon, trim_trailing(:equal, title)).strip
296
+ end
297
+
235
298
  # Create prefix/filing hash for representing a title value with filing characters removed, with special
236
299
  # consideration for bracketed titles
237
300
  # @todo Is this still useful?
@@ -1,5 +1,6 @@
1
1
  albrecht:
2
2
  location_code: 'vanp'
3
3
  call_num_pattern: '^M.*'
4
+ call_num_type: '0'
4
5
  specific_location: 'Van Pelt - Albrecht Music Library'
5
6
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PennMARC
4
- VERSION = '1.0.33'
4
+ VERSION = '1.1.1'
5
5
  end
@@ -2,22 +2,26 @@
2
2
 
3
3
  describe 'PennMARC::Classification' do
4
4
  let(:helper) { PennMARC::Classification }
5
- let(:record) do
6
- marc_record fields: [marc_field(tag: tag,
7
- subfields: { call_number_type_sf => '0', call_number_sf => 'TA683 .B3 1909b' }),
8
- marc_field(tag: tag,
9
- subfields: { call_number_type_sf => '0', call_number_sf => 'QL756 .S643' }),
10
- marc_field(tag: tag,
11
- subfields: { call_number_type_sf => '1', call_number_sf => '691.3 B2141' }),
12
- marc_field(tag: tag,
13
- subfields: { call_number_type_sf => '1', call_number_sf => '378.748 POS1952.29' })]
14
- end
5
+ let(:record) { marc_record fields: fields }
15
6
 
16
7
  describe '.facet' do
17
- context 'with enrichment via the Alma publishing process' do
18
- let(:tag) { PennMARC::Enriched::Pub::ITEM_TAG }
19
- let(:call_number_type_sf) { PennMARC::Enriched::Pub::ITEM_CALL_NUMBER_TYPE }
20
- let(:call_number_sf) { PennMARC::Enriched::Pub::ITEM_CALL_NUMBER }
8
+ let(:fields) do
9
+ [marc_field(tag: config[:tag],
10
+ subfields: { config[:call_number_type_sf] => '0', config[:call_number_sf] => 'TA683 .B3 1909b' }),
11
+ marc_field(tag: config[:tag],
12
+ subfields: { config[:call_number_type_sf] => '0', config[:call_number_sf] => 'QL756 .S643' }),
13
+ marc_field(tag: config[:tag],
14
+ subfields: { config[:call_number_type_sf] => '1', config[:call_number_sf] => '691.3 B2141' }),
15
+ marc_field(tag: config[:tag],
16
+ subfields: { config[:call_number_type_sf] => '1', config[:call_number_sf] => '378.748 POS1952.29' })]
17
+ end
18
+
19
+ context 'with enrichment via the Alma publishing process and itm fields' do
20
+ let(:config) do
21
+ { tag: PennMARC::Enriched::Pub::ITEM_TAG,
22
+ call_number_type_sf: PennMARC::Enriched::Pub::ITEM_CALL_NUMBER_TYPE,
23
+ call_number_sf: PennMARC::Enriched::Pub::ITEM_CALL_NUMBER }
24
+ end
21
25
 
22
26
  it 'returns expected values' do
23
27
  expect(helper.facet(record)).to contain_exactly('T - Technology', '600 - Technology',
@@ -26,9 +30,11 @@ describe 'PennMARC::Classification' do
26
30
  end
27
31
 
28
32
  context 'with enrichment with availability info via Alma Api' do
29
- let(:tag) { PennMARC::Enriched::Api::PHYS_INVENTORY_TAG }
30
- let(:call_number_type_sf) { PennMARC::Enriched::Api::PHYS_CALL_NUMBER_TYPE }
31
- let(:call_number_sf) { PennMARC::Enriched::Api::PHYS_CALL_NUMBER }
33
+ let(:config) do
34
+ { tag: PennMARC::Enriched::Api::PHYS_INVENTORY_TAG,
35
+ call_number_type_sf: PennMARC::Enriched::Api::PHYS_CALL_NUMBER_TYPE,
36
+ call_number_sf: PennMARC::Enriched::Api::PHYS_CALL_NUMBER }
37
+ end
32
38
 
33
39
  it 'returns expected values' do
34
40
  expect(helper.facet(record)).to contain_exactly('T - Technology', '600 - Technology',
@@ -36,4 +42,63 @@ describe 'PennMARC::Classification' do
36
42
  end
37
43
  end
38
44
  end
45
+
46
+ describe '.call_number_search' do
47
+ let(:fields) do
48
+ [marc_field(tag: config[:tag],
49
+ subfields: { config[:call_number_type_sf] => '0', config[:call_number_sf] => 'QL756 .S643' }),
50
+ marc_field(tag: config[:tag],
51
+ subfields: { config[:call_number_type_sf] => '1', config[:call_number_sf] => '691.3 B2141' })]
52
+ end
53
+
54
+ context 'with enrichment via the Alma publishing process' do
55
+ let(:config) do
56
+ { tag: PennMARC::Enriched::Pub::ITEM_TAG,
57
+ call_number_type_sf: PennMARC::Enriched::Pub::ITEM_CALL_NUMBER_TYPE,
58
+ call_number_sf: PennMARC::Enriched::Pub::ITEM_CALL_NUMBER }
59
+ end
60
+
61
+ it 'returns expected values' do
62
+ expect(helper.call_number_search(record)).to contain_exactly '691.3 B2141', 'QL756 .S643'
63
+ end
64
+ end
65
+
66
+ context 'with enrichment via the Alma publishing process and no itm fields' do
67
+ let(:fields) do
68
+ [marc_field(tag: PennMARC::Enriched::Pub::PHYS_INVENTORY_TAG,
69
+ subfields: { PennMARC::Enriched::Pub::HOLDING_CLASSIFICATION_PART => 'KF6450',
70
+ PennMARC::Enriched::Pub::HOLDING_ITEM_PART => '.C59 1989' })]
71
+ end
72
+
73
+ it 'returns expected values from the hld tag' do
74
+ expect(helper.call_number_search(record)).to contain_exactly('KF6450 .C59 1989')
75
+ end
76
+ end
77
+
78
+ context 'with enrichment via the Alma publishing process and values from both hld and itm fields' do
79
+ let(:fields) do
80
+ [marc_field(tag: PennMARC::Enriched::Pub::PHYS_INVENTORY_TAG,
81
+ subfields: { PennMARC::Enriched::Pub::HOLDING_CLASSIFICATION_PART => 'KF6450',
82
+ PennMARC::Enriched::Pub::HOLDING_ITEM_PART => '.C59 1989' }),
83
+ marc_field(tag: PennMARC::Enriched::Pub::ITEM_TAG,
84
+ subfields: { PennMARC::Enriched::Pub::ITEM_CALL_NUMBER => 'KF6450 .C59 1989' })]
85
+ end
86
+
87
+ it 'returns a single call number' do
88
+ expect(helper.call_number_search(record)).to contain_exactly('KF6450 .C59 1989')
89
+ end
90
+ end
91
+
92
+ context 'with enrichment with availability info via Alma Api' do
93
+ let(:config) do
94
+ { tag: PennMARC::Enriched::Api::PHYS_INVENTORY_TAG,
95
+ call_number_type_sf: PennMARC::Enriched::Api::PHYS_CALL_NUMBER_TYPE,
96
+ call_number_sf: PennMARC::Enriched::Api::PHYS_CALL_NUMBER }
97
+ end
98
+
99
+ it 'returns expected values' do
100
+ expect(helper.call_number_search(record)).to contain_exactly '691.3 B2141', 'QL756 .S643'
101
+ end
102
+ end
103
+ end
39
104
  end
@@ -4,12 +4,13 @@ describe 'PennMARC::Location' do
4
4
  let(:helper) { PennMARC::Location }
5
5
  let(:enriched_marc) { PennMARC::Enriched }
6
6
  let(:mapping) { location_map }
7
+ let(:record) { marc_record(fields: fields) }
7
8
 
8
9
  describe 'location' do
9
10
  context "with only 'itm' field present" do
10
- let(:record) do
11
- marc_record(fields: [marc_field(tag: enriched_marc::Pub::ITEM_TAG,
12
- subfields: { enriched_marc::Pub::ITEM_CURRENT_LOCATION => 'stor' })])
11
+ let(:fields) do
12
+ [marc_field(tag: enriched_marc::Pub::ITEM_TAG,
13
+ subfields: { enriched_marc::Pub::ITEM_CURRENT_LOCATION => 'stor' })]
13
14
  end
14
15
 
15
16
  it 'returns expected value' do
@@ -21,9 +22,9 @@ describe 'PennMARC::Location' do
21
22
  end
22
23
 
23
24
  context "with only 'hld' field present" do
24
- let(:record) do
25
- marc_record(fields: [marc_field(tag: enriched_marc::Pub::PHYS_INVENTORY_TAG,
26
- subfields: { enriched_marc::Pub::PHYS_LOCATION_CODE => 'stor' })])
25
+ let(:fields) do
26
+ [marc_field(tag: enriched_marc::Pub::PHYS_INVENTORY_TAG,
27
+ subfields: { enriched_marc::Pub::PHYS_LOCATION_CODE => 'stor' })]
27
28
  end
28
29
 
29
30
  it 'returns expected value' do
@@ -35,11 +36,11 @@ describe 'PennMARC::Location' do
35
36
  end
36
37
 
37
38
  context 'with both holding and item tag fields present=' do
38
- let(:record) do
39
- marc_record(fields: [marc_field(tag: enriched_marc::Pub::ITEM_TAG,
40
- subfields: { enriched_marc::Pub::ITEM_CURRENT_LOCATION => 'stor' }),
41
- marc_field(tag: enriched_marc::Pub::PHYS_INVENTORY_TAG,
42
- subfields: { enriched_marc::Pub::PHYS_LOCATION_CODE => 'dent' })])
39
+ let(:fields) do
40
+ [marc_field(tag: enriched_marc::Pub::ITEM_TAG,
41
+ subfields: { enriched_marc::Pub::ITEM_CURRENT_LOCATION => 'stor' }),
42
+ marc_field(tag: enriched_marc::Pub::PHYS_INVENTORY_TAG,
43
+ subfields: { enriched_marc::Pub::PHYS_LOCATION_CODE => 'dent' })]
43
44
  end
44
45
 
45
46
  it 'returns item location' do
@@ -49,7 +50,7 @@ describe 'PennMARC::Location' do
49
50
  end
50
51
 
51
52
  context 'with multiple library locations' do
52
- let(:record) { marc_record(fields: [marc_field(tag: enriched_marc::Pub::ITEM_TAG, subfields: { g: %w[dent] })]) }
53
+ let(:fields) { [marc_field(tag: enriched_marc::Pub::ITEM_TAG, subfields: { g: %w[dent] })] }
53
54
 
54
55
  it 'returns expected value' do
55
56
  expect(helper.location(record: record, location_map: mapping,
@@ -59,34 +60,19 @@ describe 'PennMARC::Location' do
59
60
  end
60
61
 
61
62
  context 'without enriched marc location tag' do
62
- let(:record) { marc_record(fields: [marc_field(tag: '852', subfields: { g: 'stor' })]) }
63
+ let(:fields) { [marc_field(tag: '852', subfields: { g: 'stor' })] }
63
64
 
64
65
  it 'returns expected value' do
65
66
  expect(helper.location(record: record, location_map: mapping, display_value: :library)).to be_empty
66
67
  end
67
68
  end
68
69
 
69
- context 'with electronic inventory tag' do
70
- let(:record) do
71
- marc_record(fields: [marc_field(tag: enriched_marc::Pub::ITEM_TAG,
72
- subfields: { enriched_marc::Pub::ITEM_CURRENT_LOCATION => 'stor' }),
73
- marc_field(tag: enriched_marc::Pub::ELEC_INVENTORY_TAG)])
74
- end
75
-
76
- it 'returns expected value' do
77
- expect(helper.location(record: record, location_map: mapping,
78
- display_value: :library)).to contain_exactly('LIBRA', helper::ONLINE_LIBRARY)
79
- end
80
- end
81
-
82
70
  context 'with AVA fields' do
83
- let(:record) do
84
- marc_record(fields: [marc_field(tag: enriched_marc::Api::PHYS_INVENTORY_TAG,
85
- subfields: {
86
- enriched_marc::Api::PHYS_LIBRARY_CODE => 'Libra',
87
- enriched_marc::Api::PHYS_LOCATION_NAME => 'LIBRA',
88
- enriched_marc::Api::PHYS_LOCATION_CODE => 'stor'
89
- })])
71
+ let(:fields) do
72
+ [marc_field(tag: enriched_marc::Api::PHYS_INVENTORY_TAG,
73
+ subfields: { enriched_marc::Api::PHYS_LIBRARY_CODE => 'Libra',
74
+ enriched_marc::Api::PHYS_LOCATION_NAME => 'LIBRA',
75
+ enriched_marc::Api::PHYS_LOCATION_CODE => 'stor' })]
90
76
  end
91
77
 
92
78
  it 'returns expected values' do
@@ -96,37 +82,83 @@ describe 'PennMARC::Location' do
96
82
  end
97
83
  end
98
84
 
99
- context 'with AVE fields' do
100
- let(:record) do
101
- marc_record(fields: [marc_field(tag: enriched_marc::Api::ELEC_INVENTORY_TAG,
102
- subfields: { enriched_marc::Api::ELEC_COLLECTION_NAME => 'Nature' })])
103
- end
104
-
105
- it 'returns expected values' do
106
- expect(helper.location(record: record, location_map: mapping, display_value: :library)).to(
107
- contain_exactly(helper::ONLINE_LIBRARY)
108
- )
109
- end
110
- end
111
-
112
85
  context 'with a specific location override' do
113
- let(:record) do
114
- marc_record(fields: [marc_field(tag: enriched_marc::Pub::ITEM_TAG,
115
- subfields: { enriched_marc::Pub::ITEM_CURRENT_LOCATION => 'vanp',
116
- enriched_marc::Pub::ITEM_CALL_NUMBER => 'ML3534 .D85 1984' }),
117
- marc_field(tag: enriched_marc::Pub::ITEM_TAG,
118
- subfields: { enriched_marc::Pub::ITEM_CURRENT_LOCATION => 'stor',
119
- enriched_marc::Pub::ITEM_CALL_NUMBER => 'L3534 .D85 1984' })])
120
- end
121
-
122
- it 'returns expected values' do
123
- expect(helper.location(record: record, display_value: :specific_location, location_map: mapping))
124
- .to(contain_exactly(PennMARC::Mappers.location_overrides[:albrecht][:specific_location], 'LIBRA'))
125
- end
126
-
127
- it 'returns expected values when receiving a string for display_value' do
128
- expect(helper.location(record: record, display_value: 'specific_location', location_map: mapping))
129
- .to(contain_exactly(PennMARC::Mappers.location_overrides[:albrecht][:specific_location], 'LIBRA'))
86
+ context 'with item fields and LC call nums' do
87
+ let(:fields) do
88
+ [marc_field(tag: enriched_marc::Pub::ITEM_TAG,
89
+ subfields: { enriched_marc::Pub::ITEM_CURRENT_LOCATION => 'vanp',
90
+ enriched_marc::Pub::ITEM_CALL_NUMBER_TYPE =>
91
+ PennMARC::Classification::LOC_CALL_NUMBER_TYPE,
92
+ enriched_marc::Pub::ITEM_CALL_NUMBER => 'ML3534 .D85 1984' }),
93
+ marc_field(tag: enriched_marc::Pub::ITEM_TAG,
94
+ subfields: { enriched_marc::Pub::ITEM_CURRENT_LOCATION => 'stor',
95
+ enriched_marc::Pub::ITEM_CALL_NUMBER_TYPE => '8',
96
+ enriched_marc::Pub::ITEM_CALL_NUMBER => 'L3534 .D85 1984' })]
97
+ end
98
+
99
+ it 'returns expected values' do
100
+ expect(helper.location(record: record, display_value: :specific_location, location_map: mapping))
101
+ .to(contain_exactly(PennMARC::Mappers.location_overrides[:albrecht][:specific_location], 'LIBRA'))
102
+ end
103
+
104
+ it 'returns expected values when receiving a string for display_value' do
105
+ expect(helper.location(record: record, display_value: 'specific_location', location_map: mapping))
106
+ .to(contain_exactly(PennMARC::Mappers.location_overrides[:albrecht][:specific_location], 'LIBRA'))
107
+ end
108
+ end
109
+
110
+ context 'with item fields and microfilm call nums' do
111
+ let(:fields) do
112
+ [marc_field(tag: enriched_marc::Pub::ITEM_TAG, indicator1: ' ',
113
+ subfields: { enriched_marc::Pub::ITEM_CURRENT_LOCATION => 'vanp',
114
+ enriched_marc::Pub::ITEM_CALL_NUMBER_TYPE => '8',
115
+ enriched_marc::Pub::ITEM_CALL_NUMBER => 'Microfilm 3140 item 8' })]
116
+ end
117
+
118
+ it 'returns expected values' do
119
+ expect(helper.location(record: record, display_value: :specific_location, location_map: mapping))
120
+ .to(contain_exactly(PennMARC::Mappers.location[:vanp][:specific_location]))
121
+ end
122
+ end
123
+
124
+ context 'with holding fields and both LC and non-LC call num type' do
125
+ let(:fields) do
126
+ [marc_field(indicator1: '8', tag: enriched_marc::Pub::PHYS_INVENTORY_TAG,
127
+ subfields: { enriched_marc::Pub::PHYS_LOCATION_CODE => 'vanp' }),
128
+ marc_field(indicator1: '0', tag: enriched_marc::Pub::PHYS_INVENTORY_TAG,
129
+ subfields: { enriched_marc::Pub::PHYS_LOCATION_CODE => 'vanp',
130
+ enriched_marc::Pub::HOLDING_CLASSIFICATION_PART => 'ML3534' })]
131
+ end
132
+
133
+ it 'returns expected values' do
134
+ expect(helper.location(record: record, display_value: :specific_location, location_map: mapping))
135
+ .to(contain_exactly(PennMARC::Mappers.location[:vanp][:specific_location],
136
+ PennMARC::Mappers.location_overrides[:albrecht][:specific_location]))
137
+ end
138
+ end
139
+
140
+ context 'with a variety of holding fields from the Alma API enrichment' do
141
+ let(:fields) do
142
+ [marc_field(tag: enriched_marc::Api::PHYS_INVENTORY_TAG,
143
+ subfields: { enriched_marc::Api::PHYS_CALL_NUMBER => 'Locked Closet Floor',
144
+ enriched_marc::Api::PHYS_CALL_NUMBER_TYPE => '8' }),
145
+ marc_field(tag: enriched_marc::Api::PHYS_INVENTORY_TAG,
146
+ subfields: { enriched_marc::Api::PHYS_LOCATION_CODE => 'vanp',
147
+ enriched_marc::Api::PHYS_CALL_NUMBER => ['ML123 .P567 1875', 'ML123'],
148
+ enriched_marc::Api::PHYS_CALL_NUMBER_TYPE =>
149
+ PennMARC::Classification::LOC_CALL_NUMBER_TYPE }),
150
+ marc_field(tag: enriched_marc::Api::PHYS_INVENTORY_TAG,
151
+ subfields: { enriched_marc::Api::PHYS_LOCATION_CODE => 'vanp',
152
+ enriched_marc::Api::PHYS_CALL_NUMBER => 'P789 .D123 2012',
153
+ enriched_marc::Api::PHYS_CALL_NUMBER_TYPE =>
154
+ PennMARC::Classification::LOC_CALL_NUMBER_TYPE })]
155
+ end
156
+
157
+ it 'returns expected values' do
158
+ expect(helper.location(record: record, display_value: :specific_location, location_map: mapping))
159
+ .to(contain_exactly(PennMARC::Mappers.location[:vanp][:specific_location],
160
+ PennMARC::Mappers.location_overrides[:albrecht][:specific_location]))
161
+ end
130
162
  end
131
163
  end
132
164
  end
@@ -136,7 +136,7 @@ describe 'PennMARC::Note' do
136
136
  it 'returns expected values from 506' do
137
137
  expect(values).to contain_exactly(
138
138
  'Open to users with valid PennKey Donor Appointment Only estate executors Some Policy No online access
139
- 20300101 Van Pelt URI star'.squish
139
+ 20300101 Van Pelt URI'.squish
140
140
  )
141
141
  end
142
142
  end
@@ -138,6 +138,66 @@ describe 'PennMARC::Title' do
138
138
  end
139
139
  end
140
140
 
141
+ describe '.detailed_show' do
142
+ let(:record) do
143
+ marc_record fields: [
144
+ marc_field(tag: '245', subfields: { k: 'Letters', f: '1972-1982', b: 'to Lewis Mumford.' })
145
+ ]
146
+ end
147
+
148
+ context 'with subfields ǂk, ǂf and ǂc' do
149
+ it 'returns detailed title values' do
150
+ expect(helper.detailed_show(record)).to eq 'Letters to Lewis Mumford, 1972-1982'
151
+ end
152
+ end
153
+ end
154
+
155
+ describe '.alternate_show' do
156
+ let(:record) do
157
+ marc_record fields: [
158
+ marc_field(tag: '245', subfields: { k: 'Letters', b: 'to Lewis Mumford. ' }),
159
+ marc_field(tag: '880', subfields: { '6': '245', k: 'Lettres', b: 'à Lewis Mumford.' })
160
+ ]
161
+ end
162
+
163
+ context 'with subfields ǂk and ǂb' do
164
+ it 'returns alternate title values' do
165
+ expect(helper.alternate_show(record)).to eq 'Lettres à Lewis Mumford.'
166
+ end
167
+ end
168
+
169
+ context 'when 880 field is not present' do
170
+ let(:record) do
171
+ marc_record fields: [
172
+ marc_field(tag: '245', subfields: { k: 'Letters', b: 'to Lewis Mumford. ' })
173
+ ]
174
+ end
175
+
176
+ it 'returns nil' do
177
+ expect(helper.alternate_show(record)).to be_nil
178
+ end
179
+ end
180
+ end
181
+
182
+ describe '.statement_of_responsibility_show' do
183
+ let(:record) do
184
+ marc_record fields: [marc_field(tag: '245', subfields: { c: 'statement of responsibility' }),
185
+ marc_field(tag: '880', subfields: { '6': '245', c: 'déclaration de responsabilité' })]
186
+ end
187
+
188
+ context 'with ǂc defined' do
189
+ it 'returns statement of responsibility' do
190
+ expect(helper.statement_of_responsibility_show(record)).to include 'statement of responsibility'
191
+ end
192
+ end
193
+
194
+ context 'with linked alternate of 245 ǂc defined' do
195
+ it 'returns alternate statement of responsibility' do
196
+ expect(helper.statement_of_responsibility_show(record)).to include 'déclaration de responsabilité'
197
+ end
198
+ end
199
+ end
200
+
141
201
  describe '.sort' do
142
202
  context 'with a record with a valid indicator2 value' do
143
203
  let(:record) 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.33
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Kanning
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2024-08-12 00:00:00.000000000 Z
15
+ date: 2024-08-23 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: activesupport