pennmarc 1.0.25 → 1.0.27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +8 -9
  3. data/Gemfile +1 -0
  4. data/Gemfile.lock +2 -0
  5. data/README.md +16 -1
  6. data/lib/pennmarc/heading_control.rb +22 -4
  7. data/lib/pennmarc/helpers/creator.rb +139 -65
  8. data/lib/pennmarc/helpers/edition.rb +5 -3
  9. data/lib/pennmarc/helpers/note.rb +24 -19
  10. data/lib/pennmarc/helpers/production.rb +113 -20
  11. data/lib/pennmarc/helpers/subject.rb +32 -22
  12. data/lib/pennmarc/mappers.rb +22 -10
  13. data/lib/pennmarc/mappings/headings_override.yml +8 -0
  14. data/lib/pennmarc/mappings/headings_remove.yml +2 -0
  15. data/lib/pennmarc/test/marc_helpers.rb +83 -0
  16. data/lib/pennmarc/util.rb +98 -69
  17. data/lib/pennmarc/version.rb +1 -1
  18. data/lib/pennmarc.rb +7 -0
  19. data/pennmarc.gemspec +2 -1
  20. data/spec/lib/pennmarc/heading_control_spec.rb +45 -0
  21. data/spec/lib/pennmarc/helpers/access_spec.rb +0 -2
  22. data/spec/lib/pennmarc/helpers/citation_spec.rb +0 -2
  23. data/spec/lib/pennmarc/helpers/classification_spec.rb +0 -2
  24. data/spec/lib/pennmarc/helpers/creator_spec.rb +103 -2
  25. data/spec/lib/pennmarc/helpers/database_spec.rb +0 -2
  26. data/spec/lib/pennmarc/helpers/date_spec.rb +0 -2
  27. data/spec/lib/pennmarc/helpers/edition_spec.rb +4 -2
  28. data/spec/lib/pennmarc/helpers/format_spec.rb +0 -2
  29. data/spec/lib/pennmarc/helpers/genre_spec.rb +0 -2
  30. data/spec/lib/pennmarc/helpers/identifer_spec.rb +0 -2
  31. data/spec/lib/pennmarc/helpers/inventory_spec.rb +0 -2
  32. data/spec/lib/pennmarc/helpers/language_spec.rb +0 -2
  33. data/spec/lib/pennmarc/helpers/link_spec.rb +0 -2
  34. data/spec/lib/pennmarc/helpers/location_spec.rb +0 -2
  35. data/spec/lib/pennmarc/helpers/note_spec.rb +22 -29
  36. data/spec/lib/pennmarc/helpers/production_spec.rb +121 -22
  37. data/spec/lib/pennmarc/helpers/relation_spec.rb +0 -2
  38. data/spec/lib/pennmarc/helpers/series_spec.rb +0 -2
  39. data/spec/lib/pennmarc/helpers/subject_spec.rb +19 -2
  40. data/spec/lib/pennmarc/helpers/title_spec.rb +0 -2
  41. data/spec/lib/pennmarc/marc_util_spec.rb +0 -2
  42. data/spec/lib/pennmarc/parser_spec.rb +1 -1
  43. data/spec/spec_helper.rb +7 -0
  44. data/spec/support/fixture_helpers.rb +10 -0
  45. metadata +23 -3
  46. data/spec/support/marc_spec_helpers.rb +0 -85
data/lib/pennmarc/util.rb CHANGED
@@ -13,16 +13,16 @@ module PennMARC
13
13
  period: /\.\s*$/ }.freeze # TODO: revise to exclude "etc."
14
14
 
15
15
  # Check if a given record has a field present by tag (e.g., '041')
16
- # @param [MARC::Record] record
17
- # @param [String] marc_field
16
+ # @param record [MARC::Record]
17
+ # @param marc_field [String]
18
18
  # @return [Boolean]
19
19
  def field_defined?(record, marc_field)
20
20
  record.select { |field| field.tag == marc_field }.any?
21
21
  end
22
22
 
23
23
  # Join subfields from a field selected based on a provided proc
24
- # @param [MARC::DataField, nil] field
25
- # @param [Proc] selector
24
+ # @param field [MARC::DataField, nil]
25
+ # @param selector [Proc]
26
26
  # @return [String]
27
27
  def join_subfields(field, &selector)
28
28
  return '' unless field
@@ -37,77 +37,75 @@ module PennMARC
37
37
 
38
38
  # returns true if field has a value that matches
39
39
  # passed-in regex and passed in subfield
40
- # @todo example usage
41
- # @param [MARC::DataField] field
42
- # @param [String|Integer|Symbol] subfield
43
- # @param [Regexp] regex
44
- # @return [TrueClass, FalseClass]
40
+ # @param field [MARC::DataField]
41
+ # @param subfield [String|Integer|Symbol]
42
+ # @param regex [Regexp]
43
+ # @return [Boolean, nil]
45
44
  def subfield_value?(field, subfield, regex)
46
45
  field&.any? { |sf| sf.code == subfield.to_s && sf.value =~ regex }
47
46
  end
48
47
 
49
48
  # returns true if field has no value that matches
50
49
  # passed-in regex and passed in subfield
51
- # @param [MARC::DataField] field
52
- # @param [String|Integer|Symbol] subfield
53
- # @param [Regexp] regex
54
- # @return [TrueClass, FalseClass, nil]
50
+ # @param field [MARC::DataField]
51
+ # @param subfield [String|Integer|Symbol]
52
+ # @param regex [Regexp]
53
+ # @return [Boolean, nil]
55
54
  def no_subfield_value_matches?(field, subfield, regex)
56
55
  field&.none? { |sf| sf.code == subfield.to_s && sf.value =~ regex }
57
56
  end
58
57
 
59
58
  # returns true if a given field has a given subfield value in a given array
60
- # TODO: example usage
61
- # @param [MARC:DataField] field
62
- # @param [String|Integer|Symbol] subfield
63
- # @param [Array] array
64
- # @return [TrueClass, FalseClass]
59
+ # @param field [MARC:DataField]
60
+ # @param subfield [String|Integer|Symbol]
61
+ # @param array [Array]
62
+ # @return [Boolean]
65
63
  def subfield_value_in?(field, subfield, array)
66
64
  field.any? { |sf| sf.code == subfield.to_s && sf.value.in?(array) }
67
65
  end
68
66
 
69
67
  # returns true if a given field does not have a given subfield value in a given array
70
- # @param [MARC:DataField] field
71
- # @param [String|Integer|Symbol] subfield
72
- # @param [Array] array
73
- # @return [TrueClass, FalseClass
68
+ # @param field [MARC:DataField]
69
+ # @param subfield [String|Integer|Symbol]
70
+ # @param array [Array]
71
+ # @return [Boolean]
74
72
  def subfield_value_not_in?(field, subfield, array)
75
73
  field.none? { |sf| sf.code == subfield.to_s && sf.value.in?(array) }
76
74
  end
77
75
 
78
76
  # returns a lambda checking if passed-in subfield's code is a member of array
79
- # @param [Array] array
77
+ # @param array [Array]
80
78
  # @return [Proc]
81
79
  def subfield_in?(array)
82
80
  ->(subfield) { array.member?(subfield.code) }
83
81
  end
84
82
 
85
83
  # returns a lambda checking if passed-in subfield's code is NOT a member of array
86
- # @param [Array] array
84
+ # @param array [Array]
87
85
  # @return [Proc]
88
86
  def subfield_not_in?(array)
89
87
  ->(subfield) { !array.member?(subfield.code) }
90
88
  end
91
89
 
92
90
  # Check if a field has a given subfield defined
93
- # @param [MARC::DataField] field
94
- # @param [String|Symbol|Integer] subfield
95
- # @return [TrueClass, FalseClass]
91
+ # @param field [MARC::DataField]
92
+ # @param subfield [String|Symbol|Integer]
93
+ # @return [Boolean]
96
94
  def subfield_defined?(field, subfield)
97
95
  field.any? { |sf| sf.code == subfield.to_s }
98
96
  end
99
97
 
100
98
  # Check if a field does not have a given subfield defined
101
- # @param [MARC::DataField] field
102
- # @param [String|Symbol|Integer] subfield
103
- # @return [TrueClass, FalseClass]
99
+ # @param field [MARC::DataField]
100
+ # @param subfield [String|Symbol|Integer]
101
+ # @return [Boolean]
104
102
  def subfield_undefined?(field, subfield)
105
103
  field.none? { |sf| sf.code == subfield.to_s }
106
104
  end
107
105
 
108
106
  # Gets all subfield values for a subfield in a given field
109
- # @param [MARC::DataField] field
110
- # @param [String|Symbol] subfield as a string or symbol
107
+ # @param field [MARC::DataField]
108
+ # @param subfield [String|Symbol] as a string or symbol
111
109
  # @return [Array] subfield values for given subfield code
112
110
  def subfield_values(field, subfield)
113
111
  field.filter_map do |sf|
@@ -120,9 +118,9 @@ module PennMARC
120
118
  end
121
119
 
122
120
  # Get all subfield values for a provided subfield from any occurrence of a provided tag/tags
123
- # @param [String|Array] tag tags to consider
124
- # @param [String|Symbol] subfield to take the values from
125
- # @param [MARC::Record] record source
121
+ # @param tag [String|Array] tags to consider
122
+ # @param subfield [String|Symbol] to take the values from
123
+ # @param record [MARC::Record]
126
124
  # @return [Array] array of subfield values
127
125
  def subfield_values_for(tag:, subfield:, record:)
128
126
  record.fields(tag).flat_map do |field|
@@ -130,24 +128,43 @@ module PennMARC
130
128
  end
131
129
  end
132
130
 
133
- # @param [Symbol|String] trailer to target for removal
134
- # @param [String] string to modify
131
+ # Trim punctuation method extracted from Traject macro, to ensure consistent output
132
+ # @param string [String]
133
+ # @return [String] string with relevant punctuation removed
134
+ def trim_punctuation(string)
135
+ return string unless string
136
+
137
+ string = string.sub(%r{ *[ ,/;:] *\Z}, '')
138
+
139
+ # trailing period if it is preceded by at least three letters (possibly preceded and followed by whitespace)
140
+ string = string.sub(/( *[[:word:]]{3,})\. *\Z/, '\1')
141
+
142
+ # single square bracket characters if they are the start and/or end chars and there are no internal square
143
+ # brackets.
144
+ string = string.sub(/\A\[?([^\[\]]+)\]?\Z/, '\1')
145
+
146
+ # trim any leading or trailing whitespace
147
+ string.strip
148
+ end
149
+
150
+ # @param trailer [Symbol|String] to target for removal
151
+ # @param string [String] to modify
135
152
  # @return [String]
136
153
  def trim_trailing(trailer, string)
137
154
  string.sub TRAILING_PUNCTUATIONS_PATTERNS[trailer.to_sym], ''
138
155
  end
139
156
 
140
157
  # trim trailing punctuation, manipulating string in place
141
- # @param [Symbol|String] trailer to target for removal
142
- # @param [String] string to modify
158
+ # @param trailer [Symbol|String] to target for removal
159
+ # @param string [String] to modify
143
160
  # @return [String, Nil] string to modify
144
161
  def trim_trailing!(trailer, string)
145
162
  string.sub! TRAILING_PUNCTUATIONS_PATTERNS[trailer.to_sym], ''
146
163
  end
147
164
 
148
165
  # Intelligently append given punctuation to the end of a string
149
- # @param [Symbol] trailer
150
- # @param [String] string
166
+ # @param trailer [Symbol]
167
+ # @param string [String]
151
168
  # @return [String]
152
169
  def append_trailing(trailer, string)
153
170
  return string if string.end_with?('.', '-')
@@ -165,9 +182,9 @@ module PennMARC
165
182
  # translations of title values. A common need is to extract subfields as selected by
166
183
  # passed-in block from 880 datafield that has a particular subfield 6 value.
167
184
  # See: https://www.loc.gov/marc/bibliographic/bd880.html
168
- # @param [MARC::Record] record
169
- # @param [String|Array] subfield6_value either a string to look for in sub6 or an array of them
170
- # @param [Proc] selector takes a subfield as argument, returns a boolean
185
+ # @param record [MARC::Record]
186
+ # @param subfield6_value [String|Array] either a string to look for in sub6 or an array of them
187
+ # @param selector [Proc] takes a subfield as argument, returns a boolean
171
188
  # @return [Array] array of linked alternates
172
189
  def linked_alternate(record, subfield6_value, &selector)
173
190
  record.fields('880').filter_map do |field|
@@ -180,8 +197,8 @@ module PennMARC
180
197
  # Common case of wanting to extract all the subfields besides 6 or 8,
181
198
  # from 880 datafield that has a particular subfield 6 value. We exclude 6 because
182
199
  # that value is the linkage ID itself and 8 because... IDK
183
- # @param [MARC::Record] record
184
- # @param [String|Array] subfield6_value either a string to look for in sub6 or an array of them
200
+ # @param record [MARC::Record]
201
+ # @param subfield6_value [String|Array] either a string to look for in sub6 or an array of them
185
202
  # @return [Array] array of linked alternates without 8 or 6 values
186
203
  def linked_alternate_not_6_or_8(record, subfield6_value)
187
204
  excluded_subfields = %w[6 8]
@@ -191,8 +208,8 @@ module PennMARC
191
208
  end
192
209
 
193
210
  # Returns the non-6,8 subfields from a datafield and its 880 link.
194
- # @param [MARC::Record] record
195
- # @param [String] tag
211
+ # @param record [MARC::Record]
212
+ # @param tag [String]
196
213
  # @return [Array<String>] values
197
214
  def datafield_and_linked_alternate(record, tag)
198
215
  record.fields(tag).filter_map { |field|
@@ -201,23 +218,23 @@ module PennMARC
201
218
  end
202
219
 
203
220
  # Get the substring of a string up to a given target character
204
- # @param [Object] string to split
205
- # @param [Object] target character to split upon
221
+ # @param string [Object] to split
222
+ # @param target [Object] character to split upon
206
223
  # @return [String (frozen)]
207
224
  def substring_before(string, target)
208
225
  string.scan(target).present? ? string.split(target, 2).first : ''
209
226
  end
210
227
 
211
228
  # Get the substring of a string after the first occurrence of a target character
212
- # @param [Object] string to split
213
- # @param [Object] target character to split upon
229
+ # @param string [Object] to split
230
+ # @param target [Object] character to split upon
214
231
  # @return [String (frozen)]
215
232
  def substring_after(string, target)
216
233
  string.scan(target).present? ? string.split(target, 2).second : ''
217
234
  end
218
235
 
219
236
  # Join array and normalizing extraneous spaces
220
- # @param [Array] array
237
+ # @param array [Array]
221
238
  # @return [String]
222
239
  def join_and_squish(array)
223
240
  array.join(' ').squish
@@ -225,7 +242,7 @@ module PennMARC
225
242
 
226
243
  # If there's a subfield i, extract its value, and if there's something
227
244
  # in parentheses in that value, extract that.
228
- # @param [MARC::Field] field
245
+ # @param field [MARC::Field]
229
246
  # @return [String] subfield i without parentheses value
230
247
  def remove_paren_value_from_subfield_i(field)
231
248
  val = field.filter_map { |sf|
@@ -243,19 +260,19 @@ module PennMARC
243
260
 
244
261
  # Translate a relator code using mapping
245
262
  # @todo handle case of receiving a URI? E.g., http://loc.gov/relator/aut
246
- # @param [String, NilClass] relator_code
247
- # @param [Hash] mapping
263
+ # @param relator_code [String, NilClass]
264
+ # @param mapping [Hash]
248
265
  # @return [String, NilClass] full relator string
249
266
  def translate_relator(relator_code, mapping)
250
267
  return if relator_code.blank?
251
268
 
252
- mapping[relator_code.to_sym]
269
+ mapping[relator_code&.to_sym]
253
270
  end
254
271
 
255
272
  # Get 650 & 880 for Provenance and Chronology: prefix should be 'PRO' or 'CHR' and may be preceded by a '%'
256
273
  # @note 11/2018: do not display $5 in PRO or CHR subjs
257
- # @param [MARC::Record] record
258
- # @param [String] prefix to select from subject field
274
+ # @param record [MARC::Record]
275
+ # @param prefix [String] to select from subject field
259
276
  # @return [Array] array of values
260
277
  def prefixed_subject_and_alternate(record, prefix)
261
278
  record.fields(%w[650 880]).filter_map { |field|
@@ -273,16 +290,16 @@ module PennMARC
273
290
 
274
291
  # Does the given field specify an allowed source code?
275
292
  #
276
- # @param [MARC::DataField] field
293
+ # @param field [MARC::DataField]
277
294
  # @return [Boolean]
278
295
  def valid_subject_genre_source_code?(field)
279
296
  subfield_value_in?(field, '2', PennMARC::HeadingControl::ALLOWED_SOURCE_CODES)
280
297
  end
281
298
 
282
299
  # Does a field or its linked alternate match any of the specified tags?
283
- # @param [MARC::Field] field
284
- # @param [Array<String>] tags
285
- # @return [TrueClass, FalseClass]
300
+ # @param field [MARC::Field]
301
+ # @param tags [Array<String>]
302
+ # @return [Boolean]
286
303
  def field_or_its_linked_alternate?(field, tags)
287
304
  return true if field.tag.in? tags
288
305
  return true if field.tag == '880' && subfield_value?(field, '6', /^(#{tags.join('|')})/)
@@ -291,7 +308,7 @@ module PennMARC
291
308
  end
292
309
 
293
310
  # Match any open dates ending a given string to determine join separator for relator term in 1xx/7xx fields.
294
- # @param [String] str
311
+ # @param str [String]
295
312
  # @return [String (frozen)]
296
313
  def relator_join_separator(str)
297
314
  /\b\d+-\z/.match?(str) ? ' ' : ', '
@@ -302,7 +319,7 @@ module PennMARC
302
319
  # {https://www.loc.gov/marc/bibliographic/bd111.html 111}, {https://www.loc.gov/marc/bibliographic/bd411.html 411},
303
320
  # {https://www.loc.gov/marc/bibliographic/bd611.html 611}, {https://www.loc.gov/marc/bibliographic/bd711.html 711},
304
321
  # {https://www.loc.gov/marc/bibliographic/bd811.html 811}
305
- # @param [MARC:Field] field
322
+ # @param field [MARC:Field]
306
323
  # @return [String (frozen)]
307
324
  def relator_term_subfield(field)
308
325
  field_or_its_linked_alternate?(field, %w[111 411 611 711 811]) ? 'j' : 'e'
@@ -311,10 +328,10 @@ module PennMARC
311
328
  # Appends a relator value to the given string. It prioritizes relator codes found in subfield $4
312
329
  # and falls back to the specified relator term subfield (defaulting to 'e') if no valid codes are found in $4.
313
330
  # Use with 1xx/7xx fields.
314
- # @param [MARC::Field] field where relator values are stored
315
- # @param [String] joined_subfields the string to which the relator is appended
316
- # @param [String] relator_term_sf MARC subfield that stores relator term
317
- # @param [Hash] relator_map
331
+ # @param field [MARC::Field] where relator values are stored
332
+ # @param joined_subfields [String] the string to which the relator is appended
333
+ # @param relator_term_sf [String] MARC subfield that stores relator term
334
+ # @param relator_map [Hash]
318
335
  # @return [String]
319
336
  def append_relator(field:, joined_subfields:, relator_term_sf:, relator_map: Mappers.relator)
320
337
  joined_subfields = trim_trailing(:comma, joined_subfields)
@@ -329,5 +346,17 @@ module PennMARC
329
346
 
330
347
  [joined_subfields, relator].compact_blank.join(join_separator).squish
331
348
  end
349
+
350
+ # Returns a relator value of the given field. Like append_relator, it prioritizes relator codes found in subfileld
351
+ # $4 and falls back to the specified relator term subfield relator_term_sf if no valid codes are found in $4
352
+ # @param [MARC::Field] field where relator values are stored
353
+ # @param [String] relator_term_sf MARC subfield that stores relator term
354
+ # @param [Hash] relator_map
355
+ # @return [String]
356
+ def relator(field:, relator_term_sf:, relator_map: Mappers.relator)
357
+ relator = subfield_values(field, '4').filter_map { |code| translate_relator(code, relator_map) }
358
+ relator = subfield_values(field, relator_term_sf) if relator.blank?
359
+ relator.join
360
+ end
332
361
  end
333
362
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PennMARC
4
- VERSION = '1.0.25'
4
+ VERSION = '1.0.27'
5
5
  end
data/lib/pennmarc.rb CHANGED
@@ -2,5 +2,12 @@
2
2
 
3
3
  $LOAD_PATH.unshift(__dir__) unless $LOAD_PATH.include?(__dir__)
4
4
 
5
+ module PennMARC
6
+ # Autoload MARC helpers
7
+ module Test
8
+ autoload :MarcHelpers, 'pennmarc/test/marc_helpers'
9
+ end
10
+ end
11
+
5
12
  require_relative 'pennmarc/parser'
6
13
  require 'library_stdnums'
data/pennmarc.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.summary = 'Penn Libraries Catalog MARC parsing wisdom for cross-project usage'
11
11
  s.description = 'This gem provides methods for parsing a Penn Libraries MARCXML record into string, array and date
12
12
  objects for use in discovery or preservation applications.'
13
- s.authors = ['Mike Kanning', 'Amrey Mathurin', 'Patrick Perkins']
13
+ s.authors = ['Mike Kanning', 'Amrey Mathurin', 'Patrick Perkins', 'Katherine Schultz', 'Baowei Wei']
14
14
  s.email = 'mkanning@upenn.edu'
15
15
  s.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
16
16
  s.homepage = 'https://gitlab.library.upenn.edu/dld/catalog/pennmarc'
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
21
21
  s.add_dependency 'activesupport', '~> 7'
22
22
  s.add_dependency 'library_stdnums', '~> 1.6'
23
23
  s.add_dependency 'marc', '~> 1.2'
24
+ s.add_dependency 'multi_string_replace', '~> 2.0'
24
25
  s.add_dependency 'nokogiri', '~> 1.15'
25
26
 
26
27
  s.metadata['rubygems_mfa_required'] = 'false'
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'PennMARC::HeadingControl' do
4
+ let(:replace_term) { PennMARC::Mappers.heading_overrides.first[0] }
5
+ let(:replaced_term) { PennMARC::Mappers.heading_overrides.first[1] }
6
+ let(:remove_term) { PennMARC::Mappers.headings_to_remove.first }
7
+
8
+ describe '.process' do
9
+ context 'with a term for removal' do
10
+ it 'removes the term if found in isolation' do
11
+ values = [remove_term]
12
+ expect(PennMARC::HeadingControl.term_override(values)).to eq []
13
+ end
14
+
15
+ it 'removes the term regardless of case' do
16
+ values = [remove_term.downcase]
17
+ expect(PennMARC::HeadingControl.term_override(values)).to eq []
18
+ end
19
+
20
+ it 'removes the term if it is included as a substring' do
21
+ values = ["#{remove_term}--History"]
22
+ expect(PennMARC::HeadingControl.term_override(values)).to eq []
23
+ end
24
+ end
25
+
26
+ context 'with a term for replacement' do
27
+ it 'replaces the term in isolation' do
28
+ values = [replace_term]
29
+ expect(PennMARC::HeadingControl.term_override(values)).to eq [replaced_term]
30
+ end
31
+
32
+ it 'replaces the term when used with other headings' do
33
+ values = ["#{replace_term}--History"]
34
+ expect(PennMARC::HeadingControl.term_override(values)).to eq ["#{replaced_term}--History"]
35
+ end
36
+ end
37
+
38
+ context 'with a variety of terms' do
39
+ it 'removes and replaces terms as needed' do
40
+ values = [remove_term, replace_term, 'History']
41
+ expect(PennMARC::HeadingControl.term_override(values)).to contain_exactly 'History', replaced_term
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe 'PennMARC::Access' do
4
- include MarcSpecHelpers
5
-
6
4
  let(:helper) { PennMARC::Access }
7
5
 
8
6
  describe '.facet' do
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe 'PennMARC::Citation' do
4
- include MarcSpecHelpers
5
-
6
4
  let(:helper) { PennMARC::Citation }
7
5
 
8
6
  describe '.cited_in_show' do
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe 'PennMARC::Classification' do
4
- include MarcSpecHelpers
5
-
6
4
  let(:helper) { PennMARC::Classification }
7
5
  let(:record) do
8
6
  marc_record fields: [marc_field(tag: tag,
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe 'PennMARC::Creator' do
4
- include MarcSpecHelpers
5
-
6
4
  let(:helper) { PennMARC::Creator }
7
5
  let(:mapping) { { aut: 'Author' } }
8
6
 
@@ -95,6 +93,91 @@ describe 'PennMARC::Creator' do
95
93
  end
96
94
  end
97
95
 
96
+ describe '.authors_list' do
97
+ let(:record) { marc_record fields: fields }
98
+
99
+ context 'with two author records' do
100
+ let(:fields) do
101
+ [marc_field(tag: '100', subfields: { a: 'Surname, Name', '0': 'http://cool.uri/12345', d: '1900-2000',
102
+ e: 'author.', '4': 'http://cool.uri/vocabulary/relators/aut' }),
103
+ marc_field(tag: '700', subfields: { a: 'Surname, Alternative', '6': '100', d: '1970-' })]
104
+ end
105
+
106
+ it 'returns single author values with no URIs anywhere' do
107
+ values = helper.authors_list(record)
108
+ expect(values).to contain_exactly 'Surname, Name', 'Surname, Alternative'
109
+ end
110
+ end
111
+
112
+ context 'with three author records - abbreviated names' do
113
+ let(:fields) do
114
+ [marc_field(tag: '100', subfields: { a: 'Surname, Alex', '0': 'http://cool.uri/12345', d: '1900-2000',
115
+ e: 'author.', '4': 'http://cool.uri/vocabulary/relators/aut' }),
116
+ marc_field(tag: '110', subfields: { a: 'Second, NameX', '0': 'http://cool.uri/12345', d: '1901-2010',
117
+ e: 'author.', '4': 'http://cool.uri/vocabulary/relators/aut' }),
118
+ marc_field(tag: '700', subfields: { a: 'Alt, Alternative', '6': '100', d: '1970-' })]
119
+ end
120
+
121
+ it 'returns single author values with no URIs anywhere' do
122
+ values = helper.authors_list(record, first_initial_only: true)
123
+ expect(values).to contain_exactly 'Surname, A.', 'Second, N.', 'Alt, A.'
124
+ end
125
+ end
126
+ end
127
+
128
+ describe '.contributors_list' do
129
+ let(:record) { marc_record fields: fields }
130
+
131
+ context 'with two authors and four contributors records, names only' do
132
+ let(:fields) do
133
+ [marc_field(tag: '100', subfields: { a: 'Hamilton, Alex', '0': 'http://cool.uri/12345', d: '1900-2000',
134
+ e: 'author.' }),
135
+ marc_field(tag: '100', subfields: { a: 'Lincoln, Abraham', b: 'I', c: 'laureate', d: '1968', e: 'author',
136
+ j: 'pseud', q: 'Fuller Name', u: 'affiliation', '3': 'materials',
137
+ '4': 'aut' }),
138
+ marc_field(tag: '700', subfields: { a: 'Einstein, Albert', '6': '100', d: '1970-', '4': 'trl',
139
+ e: 'translator' }),
140
+ marc_field(tag: '700', subfields: { a: 'Franklin, Ben', '6': '100', d: '1970-', '4': 'edt' }),
141
+ marc_field(tag: '710', subfields: { a: 'Jefferson, Thomas', '6': '100', d: '1870-', '4': 'edt' }),
142
+ marc_field(tag: '700', subfields: { a: 'Dickens, Charles', '6': '100', d: '1970-', '4': 'com' })]
143
+ end
144
+
145
+ it 'returns two authors and four contributors' do
146
+ values = helper.contributors_list(record)
147
+ expect(values).to contain_exactly ['Author', ['Hamilton, Alex', 'Lincoln, Abraham']],
148
+ ['Compiler', ['Dickens, Charles']],
149
+ ['Editor', ['Franklin, Ben', 'Jefferson, Thomas']],
150
+ ['Translator', ['Einstein, Albert']]
151
+ end
152
+ end
153
+
154
+ context 'with two authors and four contributors records, with full information and relator' do
155
+ let(:fields) do
156
+ [marc_field(tag: '100', subfields: { a: 'Hamilton, Alex', '0': 'http://cool.uri/12345', d: '1900-2000',
157
+ e: 'author.', '4': 'aut' }),
158
+ marc_field(tag: '100', subfields: { a: 'Lincoln, Abraham', b: 'I', c: 'laureate', d: '1968', e: 'author',
159
+ j: 'pseud', q: 'Fuller Name', u: 'affiliation', '3': 'materials',
160
+ '4': 'aut' }),
161
+ marc_field(tag: '700', subfields: { a: 'Einstein, Albert', '6': '100', d: '1970-', '4': 'trl',
162
+ e: 'translator' }),
163
+ marc_field(tag: '700', subfields: { a: 'Franklin, Ben', '6': '100', d: '1970-', '4': 'edt' }),
164
+ marc_field(tag: '710', subfields: { a: 'Jefferson, Thomas', '6': '100', d: '1870-', '4': 'edt' }),
165
+ marc_field(tag: '700', subfields: { a: 'Dickens, Charles', '6': '100', d: '1970-', '4': 'com' }),
166
+ marc_field(tag: '880', subfields: { a: '狄更斯', '6': '700', d: '1970-', '4': 'com' }),
167
+ marc_field(tag: '700', subfields: { a: 'Twain, Mark', '6': '100', d: '1870-' })]
168
+ end
169
+
170
+ it 'returns four contributors' do
171
+ values = helper.contributors_list(record, include_authors: false, name_only: false, vernacular: true)
172
+ expect(values).to contain_exactly ['Compiler', ['Dickens, Charles 1970-, Compiler', '狄更斯 1970-, Compiler']],
173
+ ['Contributor', ['Twain, Mark 1870-, Contributor']],
174
+ ['Editor',
175
+ ['Franklin, Ben 1970-, Editor', 'Jefferson, Thomas 1870-, Editor']],
176
+ ['Translator', ['Einstein, Albert 1970-, Translator']]
177
+ end
178
+ end
179
+ end
180
+
98
181
  describe '.show_facet_map' do
99
182
  let(:record) do
100
183
  marc_record fields: [
@@ -302,6 +385,24 @@ describe 'PennMARC::Creator' do
302
385
  end
303
386
  end
304
387
 
388
+ describe '.corporate_search' do
389
+ let(:record) do
390
+ marc_record fields: [
391
+ marc_field(tag: '110', subfields: { a: 'Penn Libraries', b: 'Digital Library Development' }),
392
+ marc_field(tag: '710', subfields: { a: 'Working Group on Digital Repository Infrastructure' }),
393
+ marc_field(tag: '810', subfields: { a: 'Constellation of Repositories Strategic Team' })
394
+ ]
395
+ end
396
+
397
+ it 'returns expected values' do
398
+ expect(helper.corporate_search(record)).to contain_exactly(
399
+ 'Constellation of Repositories Strategic Team',
400
+ 'Penn Libraries Digital Library Development',
401
+ 'Working Group on Digital Repository Infrastructure'
402
+ )
403
+ end
404
+ end
405
+
305
406
  describe '.contributor_show' do
306
407
  let(:record) { marc_record fields: fields }
307
408
 
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe 'PennMARC::Database' do
4
- include MarcSpecHelpers
5
-
6
4
  let(:helper) { PennMARC::Database }
7
5
  let(:record) do
8
6
  marc_record(fields: [
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe 'PennMARC::Date' do
4
- include MarcSpecHelpers
5
-
6
4
  let(:helper) { PennMARC::Date }
7
5
  let(:record) { marc_record fields: fields }
8
6
 
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe 'PennMARC::Edition' do
4
- include MarcSpecHelpers
5
-
6
4
  let(:helper) { PennMARC::Edition }
7
5
  let(:mapping) { { aut: 'Author' } }
8
6
  let(:record) do
@@ -18,6 +16,10 @@ describe 'PennMARC::Edition' do
18
16
  it 'returns the editions' do
19
17
  expect(helper.show(record)).to contain_exactly('5th Edition Remastered', 'رمستر')
20
18
  end
19
+
20
+ it 'returns the editions without alternate' do
21
+ expect(helper.show(record, with_alternate: false)).to contain_exactly('5th Edition Remastered')
22
+ end
21
23
  end
22
24
 
23
25
  describe '.values' do
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe 'PennMARC::Format' do
4
- include MarcSpecHelpers
5
-
6
4
  let(:helper) { PennMARC::Format }
7
5
 
8
6
  describe '.facet' do
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe 'PennMARC::Genre' do
4
- include MarcSpecHelpers
5
-
6
4
  let(:helper) { PennMARC::Genre }
7
5
  let(:record) { marc_record fields: fields }
8
6
 
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe 'PennMARC::Identifier' do
4
- include MarcSpecHelpers
5
-
6
4
  let(:helper) { PennMARC::Identifier }
7
5
 
8
6
  describe '.mmsid' do