pennmarc 1.0.33 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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