pennmarc 1.0.0 → 1.0.2

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/.rubocop_todo.yml +37 -21
  4. data/Gemfile.lock +3 -0
  5. data/README.md +12 -2
  6. data/lib/pennmarc/helpers/creator.rb +24 -20
  7. data/lib/pennmarc/helpers/edition.rb +15 -13
  8. data/lib/pennmarc/helpers/format.rb +3 -3
  9. data/lib/pennmarc/helpers/genre.rb +5 -4
  10. data/lib/pennmarc/helpers/helper.rb +1 -0
  11. data/lib/pennmarc/helpers/identifier.rb +32 -15
  12. data/lib/pennmarc/helpers/language.rb +3 -3
  13. data/lib/pennmarc/helpers/location.rb +10 -10
  14. data/lib/pennmarc/helpers/note.rb +0 -2
  15. data/lib/pennmarc/helpers/relation.rb +7 -7
  16. data/lib/pennmarc/helpers/series.rb +19 -31
  17. data/lib/pennmarc/helpers/subject.rb +11 -11
  18. data/lib/pennmarc/helpers/title.rb +1 -1
  19. data/lib/pennmarc/mappers.rb +31 -0
  20. data/lib/pennmarc/parser.rb +36 -62
  21. data/lib/pennmarc/util.rb +10 -11
  22. data/lib/pennmarc/version.rb +5 -0
  23. data/pennmarc.gemspec +5 -1
  24. data/spec/lib/pennmarc/helpers/creator_spec.rb +9 -9
  25. data/spec/lib/pennmarc/helpers/edition_spec.rb +3 -2
  26. data/spec/lib/pennmarc/helpers/format_spec.rb +1 -1
  27. data/spec/lib/pennmarc/helpers/genre_spec.rb +1 -1
  28. data/spec/lib/pennmarc/helpers/identifer_spec.rb +43 -14
  29. data/spec/lib/pennmarc/helpers/language_spec.rb +1 -1
  30. data/spec/lib/pennmarc/helpers/location_spec.rb +8 -8
  31. data/spec/lib/pennmarc/helpers/relation_spec.rb +2 -2
  32. data/spec/lib/pennmarc/helpers/series_spec.rb +6 -5
  33. data/spec/lib/pennmarc/helpers/subject_spec.rb +1 -1
  34. data/spec/lib/pennmarc/parser_spec.rb +22 -1
  35. metadata +7 -8
  36. data/legacy/indexer.rb +0 -568
  37. data/legacy/marc.rb +0 -2964
  38. data/legacy/test_file_output.json +0 -49
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84864756f38d54ec58b75b355931ba9b4310f7f880245c2c437ecebb63fee447
4
- data.tar.gz: ee807c262dc0f5e2117b779b44a47cf10012c8e019340a789ac4c60d21223842
3
+ metadata.gz: 33527bf43532170690b9b591097fb03f854130b3383debfafe931417d0394f52
4
+ data.tar.gz: a18a5be08df6d7b74d2aaa61275cdecdedec6caa4b5e8b2b81c99e91411ce093
5
5
  SHA512:
6
- metadata.gz: fee3c852594dcdbb871e093f0bd45efb4043e14bfe323f6da3d48bab3dc75eb58f968b26a24e3ae786742c112f3a9ebf7ae43fb1688f33011d4b89c4ded7af1c
7
- data.tar.gz: 1192019b7f5b79c90a2d68fa46d7aa6ce7b8a2cea55f78072db3191401a4109c8d96fc5eb47ff86d05805a4cabb3409d4d90062c57ff96bdcbd9d987037160fd
6
+ metadata.gz: 627a4da06351037f520bc02b0a9fd61ce6cfdec35c563f2b29e3c1c01b4ad76766f155630cafe680b010783ea4f4c285df2d499fd784b7ee4f3cb4948cd421dd
7
+ data.tar.gz: c966233bb00009a14babc5bc92f0399e75640e886f7c32d176fea8983813aca8936d0e8fab98576a797afaf0b60c5f24268c2ae4e2d8cca31900e590db0a9bc6
data/.rubocop.yml CHANGED
@@ -2,3 +2,6 @@ inherit_from: .rubocop_todo.yml
2
2
 
3
3
  inherit_gem:
4
4
  upennlib-rubocop: upennlib_rubocop_defaults.yml
5
+
6
+ Rails:
7
+ Enabled: false
data/.rubocop_todo.yml CHANGED
@@ -1,12 +1,36 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 10000`
3
- # on 2023-07-28 16:23:59 UTC using RuboCop version 1.51.0.
3
+ # on 2023-08-25 13:55:25 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
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 21
9
+ # Offense count: 2
10
+ # This cop supports safe autocorrection (--autocorrect).
11
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
12
+ # SupportedStyles: with_first_argument, with_fixed_indentation
13
+ Layout/ArgumentAlignment:
14
+ Exclude:
15
+ - 'spec/lib/pennmarc/helpers/series_spec.rb'
16
+
17
+ # Offense count: 1
18
+ # This cop supports safe autocorrection (--autocorrect).
19
+ # Configuration parameters: EnforcedStyle.
20
+ # SupportedStyles: empty_lines, no_empty_lines
21
+ Layout/EmptyLinesAroundBlockBody:
22
+ Exclude:
23
+ - 'spec/lib/pennmarc/helpers/identifer_spec.rb'
24
+
25
+ # Offense count: 1
26
+ # This cop supports safe autocorrection (--autocorrect).
27
+ # Configuration parameters: EnforcedStyle.
28
+ # SupportedStyles: final_newline, final_blank_line
29
+ Layout/TrailingEmptyLines:
30
+ Exclude:
31
+ - 'spec/lib/pennmarc/helpers/identifer_spec.rb'
32
+
33
+ # Offense count: 22
10
34
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
11
35
  Metrics/AbcSize:
12
36
  Exclude:
@@ -50,7 +74,7 @@ Metrics/CyclomaticComplexity:
50
74
  - 'lib/pennmarc/helpers/title.rb'
51
75
  - 'lib/pennmarc/util.rb'
52
76
 
53
- # Offense count: 22
77
+ # Offense count: 24
54
78
  # Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
55
79
  Metrics/MethodLength:
56
80
  Exclude:
@@ -86,6 +110,14 @@ Metrics/PerceivedComplexity:
86
110
  - 'lib/pennmarc/helpers/title.rb'
87
111
  - 'lib/pennmarc/util.rb'
88
112
 
113
+ # Offense count: 4
114
+ # This cop supports safe autocorrection (--autocorrect).
115
+ # Configuration parameters: EnforcedStyle, BlockForwardingName.
116
+ # SupportedStyles: anonymous, explicit
117
+ Naming/BlockForwarding:
118
+ Exclude:
119
+ - 'lib/pennmarc/util.rb'
120
+
89
121
  # Offense count: 1
90
122
  # Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros.
91
123
  # NamePrefix: is_, has_, have_
@@ -96,7 +128,7 @@ Naming/PredicateName:
96
128
  Exclude:
97
129
  - 'lib/pennmarc/helpers/relation.rb'
98
130
 
99
- # Offense count: 2
131
+ # Offense count: 1
100
132
  # Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns.
101
133
  # SupportedStyles: snake_case, normalcase, non_integer
102
134
  # AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64
@@ -104,14 +136,6 @@ Naming/VariableNumber:
104
136
  Exclude:
105
137
  - 'lib/pennmarc/util.rb'
106
138
 
107
- # Offense count: 7
108
- # Configuration parameters: MinSize.
109
- Performance/CollectionLiteralInLoop:
110
- Exclude:
111
- - 'lib/pennmarc/helpers/creator.rb'
112
- - 'lib/pennmarc/helpers/edition.rb'
113
- - 'lib/pennmarc/helpers/series.rb'
114
-
115
139
  # Offense count: 6
116
140
  # Configuration parameters: Max, CountAsOne.
117
141
  RSpec/ExampleLength:
@@ -135,17 +159,9 @@ RSpec/NestedGroups:
135
159
  - 'spec/lib/pennmarc/helpers/format_spec.rb'
136
160
 
137
161
  # Offense count: 2
138
- # This cop supports unsafe autocorrection (--autocorrect-all).
139
- # Configuration parameters: Include.
140
- # Include: app/**/*.rb, config/**/*.rb, db/**/*.rb, lib/**/*.rb
141
- Rails/Output:
142
- Exclude:
143
- - 'lib/pennmarc/helpers/date.rb'
144
-
145
- # Offense count: 1
146
162
  # This cop supports safe autocorrection (--autocorrect).
147
163
  # Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
148
164
  # URISchemes: http, https
149
165
  Layout/LineLength:
150
166
  Exclude:
151
- - 'lib/pennmarc/helpers/subject.rb'
167
+ - 'spec/lib/pennmarc/helpers/creator_spec.rb'
data/Gemfile.lock CHANGED
@@ -21,6 +21,8 @@ GEM
21
21
  minitest (5.18.0)
22
22
  nokogiri (1.15.2-arm64-darwin)
23
23
  racc (~> 1.4)
24
+ nokogiri (1.15.2-x64-mingw-ucrt)
25
+ racc (~> 1.4)
24
26
  nokogiri (1.15.2-x86_64-linux)
25
27
  racc (~> 1.4)
26
28
  parallel (1.23.0)
@@ -101,6 +103,7 @@ GEM
101
103
  PLATFORMS
102
104
  arm64-darwin-21
103
105
  arm64-darwin-22
106
+ x64-mingw-ucrt
104
107
  x86_64-linux
105
108
 
106
109
  DEPENDENCIES
data/README.md CHANGED
@@ -53,6 +53,12 @@ To run rubocop with the configuration:
53
53
  rubocop
54
54
  ```
55
55
 
56
+ #### To regenerate `.rubocop_todo.yml`:
57
+ ```shell
58
+ bundle exec rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 10000
59
+ ```
60
+
61
+
56
62
  ### Testing
57
63
 
58
64
  Testing is done with `rspec`. Test coverage should approach 100% given the relative simplicity of this gem.
@@ -63,6 +69,12 @@ To run the test suite:
63
69
  rspec
64
70
  ```
65
71
 
72
+ ## Publishing the Gem
73
+
74
+ 1. Update the version in `pennmarc.gemspec`
75
+ 2. Run `gem build pennmarc.gemspec` with the latest code
76
+ 3. Run `gem push pennmarc-{version number here}`(e.g. `gem push pennmarc-1.0.0`) to push to RubyGems. You will need access and MFA setup with RubyGems.
77
+
66
78
  ## QA
67
79
 
68
80
  ### Checking output of an arbitrary MARC XML file
@@ -75,8 +87,6 @@ MARC_FILE=path/to/marc.xml bundle exec rake pennmarc:parse
75
87
 
76
88
  ## TODO
77
89
  - rake task or some similar command to return a full set of values extracted from a specified marcxml file
78
- - hosting of yard output files?
79
- - mappings (locations, call number, languages)
80
90
  - Pipeline to run tests and publish to Rubygems
81
91
  - rubocop check
82
92
  - rdoc/yard coverage checks?
@@ -24,17 +24,18 @@ module PennMARC
24
24
  # indicator1 tell us the order of the name?
25
25
  # @note ported from get_author_creator_1_search_values
26
26
  # @param [MARC::Record] record
27
- # @param [Hash] relator_mapping
27
+ # @param [Hash] relator_map
28
28
  # @return [Array<String>] array of author/creator values for indexing
29
- def search(record, relator_mapping = relator_map)
29
+ def search(record, relator_map: Mappers.relator)
30
+ creator_subfields = %w[a 1 4 6 8]
30
31
  acc = record.fields(TAGS).map do |field|
31
32
  pieces = field.filter_map do |sf|
32
33
  if sf.code == 'a'
33
34
  convert_name_order(sf.value)
34
- elsif %w[a 1 4 6 8].exclude?(sf.code)
35
+ elsif creator_subfields.exclude?(sf.code)
35
36
  sf.value
36
37
  elsif sf.code == '4'
37
- relator = translate_relator(sf.value, relator_mapping)
38
+ relator = translate_relator(sf.value, relator_map)
38
39
  next if relator.blank?
39
40
 
40
41
  relator
@@ -48,12 +49,13 @@ module PennMARC
48
49
  end
49
50
  end
50
51
  # a second iteration over the same fields produces name entries with the names not reordered
52
+ secondary_subfields = %w[4 6 8]
51
53
  acc += record.fields(TAGS).map do |field|
52
54
  pieces = field.filter_map do |sf|
53
- if !%w[4 6 8].member?(sf.code)
55
+ if secondary_subfields.exclude?(sf.code)
54
56
  sf.value
55
57
  elsif sf.code == '4'
56
- relator = translate_relator(sf.value, relator_mapping)
58
+ relator = translate_relator(sf.value, relator_map)
57
59
  next if relator.blank?
58
60
 
59
61
  relator
@@ -88,11 +90,11 @@ module PennMARC
88
90
  # All author/creator values for display (like #show, but multivalued?) - no 880 linkage
89
91
  # @note ported from get_author_creator_values (indexed as author_creator_a) - shown on results page
90
92
  # @param [MARC::Record] record
91
- # @param [Hash] relator_mapping
93
+ # @param [Hash] relator_map
92
94
  # @return [Array<String>] array of author/creator values for display
93
- def values(record, relator_mapping = relator_map)
95
+ def values(record, relator_map: Mappers.relator)
94
96
  record.fields(TAGS).map do |field|
95
- name_from_main_entry(field, relator_mapping)
97
+ name_from_main_entry(field, relator_map)
96
98
  end
97
99
  end
98
100
 
@@ -109,8 +111,7 @@ module PennMARC
109
111
  end
110
112
  end
111
113
 
112
- # Author/Creator sort. Does not map and include any relator
113
- # codes.
114
+ # Author/Creator sort. Does not map and include any relator codes.
114
115
  # @todo This includes any URI from ǂ0 which could help to disambiguate in sorts, but ǂ1 is excluded...
115
116
  # @note ported from get_author_creator_sort_values
116
117
  # @param [MARC::Record] record
@@ -143,11 +144,11 @@ module PennMARC
143
144
  # Conference for display, intended for results display
144
145
  # @note ported from get_conference_values
145
146
  # @param [MARC::Record] record
146
- # @param [Hash] relator_mapping
147
+ # @param [Hash] relator_map
147
148
  # @return [Array<String>] array of conference values
148
- def conference_show(record, relator_mapping = relator_map)
149
+ def conference_show(record, relator_map: Mappers.relator)
149
150
  record.fields('111').filter_map do |field|
150
- name_from_main_entry field, relator_mapping
151
+ name_from_main_entry field, relator_map
151
152
  end
152
153
  end
153
154
 
@@ -188,19 +189,21 @@ module PennMARC
188
189
  # 'a', 'b', 'c', 'd', 'j', and 'q'. Then appends resulting string with joined subfields 'e', 'u', '3', and '4'.
189
190
  # @note legacy version returns array of hash objects including data for display link
190
191
  # @param [MARC::Record] record
191
- # @ param [Hash] relator_mapping
192
+ # @ param [Hash] relator_map
192
193
  # @return [Array<String>]
193
- def contributor_show(record, relator_mapping = relator_map)
194
+ def contributor_show(record, relator_map: Mappers.relator)
195
+ indicator_2_options = ['', ' ', '0']
194
196
  contributors = record.fields(%w[700 710]).filter_map do |field|
195
- next unless ['', ' ', '0'].member?(field.indicator2)
197
+ next unless indicator_2_options.member?(field.indicator2)
196
198
  next if subfield_defined? field, 'i'
197
199
 
198
200
  contributor = join_subfields(field, &subfield_in?(%w[a b c d j q]))
201
+ contributor_append_subfields = %w[e u 3 4]
199
202
  contributor_append = field.filter_map { |subfield|
200
- next unless %w[e u 3 4].member?(subfield.code)
203
+ next unless contributor_append_subfields.member?(subfield.code)
201
204
 
202
205
  if subfield.code == '4'
203
- ", #{translate_relator(subfield.value, relator_mapping)}"
206
+ ", #{translate_relator(subfield.value, relator_map)}"
204
207
  else
205
208
  " #{subfield.value}"
206
209
  end
@@ -243,8 +246,9 @@ module PennMARC
243
246
  # @param [MARC::Field] field
244
247
  # @return [String] joined subfield values for value from field
245
248
  def name_from_main_entry(field, mapping)
249
+ name_subfields = %w[0 1 4 6 8]
246
250
  s = field.filter_map { |sf|
247
- if %w[0 1 4 6 8].exclude?(sf.code)
251
+ if name_subfields.exclude?(sf.code)
248
252
  " #{sf.value}"
249
253
  elsif sf.code == '4'
250
254
  relator = translate_relator(sf.value, mapping)
@@ -34,47 +34,49 @@ module PennMARC
34
34
  # display.
35
35
  # https://www.loc.gov/marc/bibliographic/bd775.html
36
36
  # @param [MARC::Record] record
37
- # @param [Hash] relator_mapping
37
+ # @param [Hash] relator_map
38
38
  # @return [Array<String>] array of other edition strings
39
- def other_show(record, relator_mapping = relator_map)
39
+ def other_show(record, relator_map: Mappers.relator)
40
40
  values = record.fields('775').filter_map do |field|
41
41
  next unless subfield_defined?(field, :i)
42
42
 
43
- other_edition_value(field, relator_mapping)
43
+ other_edition_value(field, relator_map)
44
44
  end
45
- values += record.fields('880').filter_map do |field|
45
+ values + record.fields('880').filter_map do |field|
46
46
  next unless field.indicator2.blank? && subfield_value_in?(field, '6', %w[775]) &&
47
47
  subfield_defined?(field, 'i')
48
48
 
49
- other_edition_value(field, relator_mapping)
49
+ other_edition_value(field, relator_map)
50
50
  end
51
- values
52
51
  end
53
52
 
54
53
  private
55
54
 
56
55
  # Assemble a string of relevant edition information.
57
56
  # @param [MARC::DataField] field
58
- # @param [Hash] relator_mapping
57
+ # @param [Hash] relator_map
59
58
  # @return [String (frozen)] assembled other version string
60
- def other_edition_value(field, relator_mapping)
59
+ def other_edition_value(field, relator_map)
61
60
  subi = remove_paren_value_from_subfield_i(field) || ''
61
+ excluded_subfields = %w[6 8]
62
+ other_edition_subfields = %w[s x z]
62
63
  other_editions = field.filter_map { |sf|
63
- next if %w[6 8].member?(sf.code)
64
+ next if excluded_subfields.member?(sf.code)
64
65
 
65
- if %w[s x z].member?(sf.code)
66
+ if other_edition_subfields.member?(sf.code)
66
67
  " #{sf.value}"
67
68
  elsif sf.code == 't'
68
- relator = translate_relator(sf.value, relator_mapping)
69
+ relator = translate_relator(sf.value, relator_map)
69
70
  next if relator.blank?
70
71
 
71
72
  " #{relator}. "
72
73
  end
73
74
  }.join
75
+ other_editions_append_subfields = %w[i h s t x z e f o r w y 7]
74
76
  other_editions_append = field.filter_map { |sf|
75
- next if %w[6 8].member?(sf.code)
77
+ next if excluded_subfields.member?(sf.code)
76
78
 
77
- if %w[i h s t x z e f o r w y 7].exclude?(sf.code)
79
+ if other_editions_append_subfields.exclude?(sf.code)
78
80
  " #{sf.value}"
79
81
  elsif sf.code == 'h'
80
82
  " (#{sf.value}) "
@@ -68,10 +68,10 @@ module PennMARC
68
68
  # for this helper method
69
69
  # @note ported from get_format
70
70
  # @param [MARC::Record] record
71
- # @param [Hash] location_mapping
71
+ # @param [Hash] location_map
72
72
  # @return [Array<String>] format values for faceting
73
73
 
74
- def facet(record, location_mapping = location_map)
74
+ def facet(record, location_map: Mappers.location)
75
75
  formats = []
76
76
  format_code = leader_format(record.leader)
77
77
  f007 = record.fields('007').map(&:value)
@@ -88,7 +88,7 @@ module PennMARC
88
88
  end
89
89
 
90
90
  # get all specific_location values from inventory info
91
- locations = Location.location record: record, location_mapping: location_mapping,
91
+ locations = Location.location record: record, location_map: location_map,
92
92
  display_value: :specific_location
93
93
 
94
94
  if include_manuscripts?(locations)
@@ -34,8 +34,9 @@ module PennMARC
34
34
 
35
35
  next if field.tag == '880' && subfield_values(field, '6').exclude?('655')
36
36
 
37
+ subfields = %w[a b]
37
38
  sub_with_hyphens = field.find_all(&subfield_not_in?(%w[0 2 5 6 8 c e w])).map { |sf|
38
- sep = %w[a b].exclude?(sf.code) ? ' -- ' : ' '
39
+ sep = subfields.exclude?(sf.code) ? ' -- ' : ' '
39
40
  sep + sf.value
40
41
  }.join.lstrip
41
42
  "#{sub_with_hyphens} #{field.find_all(&subfield_in?(%w[e w])).join(' -- ')}".strip
@@ -46,10 +47,10 @@ module PennMARC
46
47
  # @todo the Genre facet in Franklin is pretty ugly. It could be cleaned up by limiting the subfields included
47
48
  # here and cleaning up punctuation.
48
49
  # @param [MARC::Record] record
49
- # @param [Hash] location_mapping
50
+ # @param [Hash] location_map
50
51
  # @return [Array<String>]
51
- def facet(record, location_mapping = location_map)
52
- locations = Location.location record: record, location_mapping: location_mapping,
52
+ def facet(record, location_map: Mappers.location)
53
+ locations = Location.location record: record, location_map: location_map,
53
54
  display_value: :specific_location
54
55
  manuscript = Format.include_manuscripts?(locations)
55
56
  video = record.fields('007').any? { |field| field.value.starts_with? 'v' }
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../enriched_marc'
4
+ require_relative '../mappers'
4
5
  require_relative '../util'
5
6
 
6
7
  module PennMARC
@@ -33,14 +33,12 @@ module PennMARC
33
33
  #
34
34
  # @param [MARC::Record] record
35
35
  # @return [Array<String>]
36
- # @todo look into z subfield for 020 field, should we show cancelled isbn?
37
36
  def isbn_show(record)
38
37
  isbn_values = record.fields('020').filter_map do |field|
39
- joined_isbn = join_subfields(field, &subfield_in?(%w[a z]))
38
+ joined_isbn = join_subfields(field, &subfield_in?(%w[a]))
40
39
  joined_isbn.presence
41
40
  end
42
- isbn_values += linked_alternate(record, '020', &subfield_in?(%w[a z]))
43
- isbn_values
41
+ isbn_values + linked_alternate(record, '020', &subfield_in?(%w[a]))
44
42
  end
45
43
 
46
44
  # Get ISSN values for display from the {https://www.oclc.org/bibformats/en/0xx/022.html 022 field} and related
@@ -50,11 +48,10 @@ module PennMARC
50
48
  # @return [Array<String>]
51
49
  def issn_show(record)
52
50
  issn_values = record.fields('022').filter_map do |field|
53
- joined_issn = join_subfields(field, &subfield_in?(%w[a z]))
51
+ joined_issn = join_subfields(field, &subfield_in?(%w[a]))
54
52
  joined_issn.presence
55
53
  end
56
- issn_values += linked_alternate(record, '022', &subfield_in?(%w[a z]))
57
- issn_values
54
+ issn_values + linked_alternate(record, '022', &subfield_in?(%w[a]))
58
55
  end
59
56
 
60
57
  # Get numeric OCLC ID of first {https://www.oclc.org/bibformats/en/0xx/035.html 035 field}
@@ -85,17 +82,22 @@ module PennMARC
85
82
 
86
83
  # Get publisher issued identifiers from fields {https://www.oclc.org/bibformats/en/0xx/024.html 024},
87
84
  # {https://www.oclc.org/bibformats/en/0xx/024.html 028}, and related
88
- # {https://www.oclc.org/bibformats/en/8xx/880.html 880 field}.
85
+ # {https://www.oclc.org/bibformats/en/8xx/880.html 880 field}. We do not return DOI values stored in 024 ǂ2,
86
+ # see {PennMARC::Identifier.doi_show} for parsing DOI values.
89
87
  #
90
88
  # @param [MARC::Record] record
91
89
  # @return [Array<string>]
92
90
  def publisher_number_show(record)
93
- publisher_numbers = record.fields(%w[024 028]).filter_map do |field|
94
- joined_identifiers = join_subfields(field, &subfield_not_in?(%w[5 6]))
95
- joined_identifiers.presence
91
+ record.fields(%w[024 028 880]).filter_map do |field|
92
+ next if field.tag == '880' && subfield_value_not_in?(field, '6', %w[024 028])
93
+
94
+ # do not return doi values from 024 ǂ2
95
+ if field.tag == '024' && subfield_value_in?(field, '2', %w[doi])
96
+ join_subfields(field, &subfield_not_in?(%w[a 2 5 6])).presence
97
+ else
98
+ join_subfields(field, &subfield_not_in?(%w[5 6])).presence
99
+ end
96
100
  end
97
- publisher_numbers += linked_alternate(record, %w[024 028], &subfield_not_in?(%w[5 6]))
98
- publisher_numbers
99
101
  end
100
102
 
101
103
  # Get publisher issued identifiers for searching of a record. Values extracted from fields
@@ -119,6 +121,21 @@ module PennMARC
119
121
  end
120
122
  end
121
123
 
124
+ # Retrieve DOI values stored in {https://www.oclc.org/bibformats/en/0xx/024.html 024}.
125
+ # Penn MARC records give the first indicator a value of '7' and ǂ2 a value of 'doi' to denote that ǂa is a doi.
126
+ # @param [MARC::Record] record
127
+ # @return [Array<String>]
128
+ def doi_show(record)
129
+ record.fields('024').filter_map do |field|
130
+ # skip unless indicator1 is '7'
131
+ next unless field.indicator1.in?(%w[7])
132
+ # skip unless ǂ2 is the string literal 'doi'
133
+ next unless subfield_value_in?(field, '2', %w[doi])
134
+
135
+ join_subfields(field, &subfield_in?(%w[a]))
136
+ end
137
+ end
138
+
122
139
  private
123
140
 
124
141
  # Determine if subfield 'a' is an OCLC id.
@@ -126,11 +143,11 @@ module PennMARC
126
143
  # @param [MARC::Subfield]
127
144
  # @return [TrueClass, FalseClass]
128
145
  def subfield_a_is_oclc?(subfield)
129
- subfield.code == 'a' && subfield.value =~ /^\(OCoLC\).*/
146
+ subfield.code == 'a' && (subfield.value =~ /^\(OCoLC\).*/).present?
130
147
  end
131
148
 
132
149
  # Normalize isbn value using {https://github.com/billdueber/library_stdnums library_stdnums gem}.
133
- # Converts ISBN10 (ten-digit) to validated ISBN13 (thriteen-digit) and returns both values. If passed
150
+ # Converts ISBN10 (ten-digit) to validated ISBN13 (thirteen-digit) and returns both values. If passed
134
151
  # ISBN13 parameter, only returns validated ISBN13 value.
135
152
  #
136
153
  # @param [String] isbn
@@ -25,12 +25,12 @@ module PennMARC
25
25
  # the 008 control field. Language facet and search values will typically be the same.
26
26
  #
27
27
  # @param [MARC::Record] record
28
- # @param [Hash] mapping hash for language code translation
28
+ # @param [Hash] language_map hash for language code translation
29
29
  # @return [String] nice value for language
30
- def search(record, mapping = language_map)
30
+ def search(record, language_map: Mappers.language)
31
31
  control_field = record['008']&.value
32
32
  language_code = control_field[35..37]
33
- mapping[language_code.to_sym || UNDETERMINED_CODE]
33
+ language_map[language_code.to_sym || UNDETERMINED_CODE]
34
34
  end
35
35
  end
36
36
  end
@@ -10,10 +10,10 @@ module PennMARC
10
10
  # @see https://developers.exlibrisgroup.com/alma/apis/docs/bibs/R0VUIC9hbG1hd3MvdjEvYmlicy97bW1zX2lkfQ==/
11
11
  # Alma documentation for these added fields
12
12
  # @param [MARC::Record] record
13
- # @param [Hash] location_mapping hash with location_code as key and location hash as value
13
+ # @param [Hash] location_map hash with location_code as key and location hash as value
14
14
  # @return [Array<String>] Array of library locations retrieved from location_map
15
- def library(record, location_mapping = location_map)
16
- location(record: record, location_mapping: location_mapping, display_value: 'library')
15
+ def library(record, location_map: Mappers.location)
16
+ location(record: record, location_map: location_map, display_value: 'library')
17
17
  end
18
18
 
19
19
  # Retrieves the specific location from enriched marc 'itm' or 'hld' fields, giving priority to the item location
@@ -23,10 +23,10 @@ module PennMARC
23
23
  # @see https://developers.exlibrisgroup.com/alma/apis/docs/bibs/R0VUIC9hbG1hd3MvdjEvYmlicy97bW1zX2lkfQ==/
24
24
  # Alma documentation for these added fields
25
25
  # @param [MARC::Record] record
26
- # @param [Hash] location_mapping hash with location_code as key and location hash as value
26
+ # @param [Hash] location_map hash with location_code as key and location hash as value
27
27
  # @return [Array<String>] Array of specific locations retrieved from location_map
28
- def specific_location(record, location_mapping = location_map)
29
- location(record: record, location_mapping: location_mapping, display_value: 'specific_location')
28
+ def specific_location(record, location_map: Mappers.location)
29
+ location(record: record, location_map: location_map, display_value: 'specific_location')
30
30
  end
31
31
 
32
32
  # Base method to retrieve location data from enriched marc 'itm' or 'hld' fields, giving priority to the item
@@ -36,9 +36,9 @@ module PennMARC
36
36
  # Alma documentation for these added fields
37
37
  # @param [MARC::Record] record
38
38
  # @param [Symbol | String] display_value field in location hash to retrieve
39
- # @param [Hash] location_mapping hash with location_code as key and location hash as value
39
+ # @param [Hash] location_map hash with location_code as key and location hash as value
40
40
  # @return [Array<String>]
41
- def location(record:, display_value:, location_mapping: location_map)
41
+ def location(record:, display_value:, location_map:)
42
42
  # get enriched marc location tag and subfield code
43
43
  location_tag_and_subfield_code(record) => {tag:, subfield_code:}
44
44
 
@@ -56,9 +56,9 @@ module PennMARC
56
56
  # sometimes "happening locations" are mistakenly used in holdings records.
57
57
  # that's a data problem that should be fixed.
58
58
  # here, if we encounter a code we can't map, we ignore it, for faceting purposes
59
- next unless location_mapping.key?(subfield.value.to_sym)
59
+ next unless location_map.key?(subfield.value.to_sym)
60
60
 
61
- location_mapping[subfield.value.to_sym][display_value.to_sym]
61
+ location_map[subfield.value.to_sym][display_value.to_sym]
62
62
  }.flatten.compact_blank
63
63
  }.uniq
64
64
  locations << 'Online library' if record.fields(PennMARC::EnrichedMarc::TAG_ELECTRONIC_INVENTORY).any?
@@ -11,8 +11,6 @@ module PennMARC
11
11
  # {https://www.oclc.org/bibformats/en/5xx/550.html 550}, {https://www.oclc.org/bibformats/en/5xx/580.html 580},
12
12
  # {https://www.oclc.org/bibformats/en/5xx/586.html 586}, {https://www.oclc.org/bibformats/en/5xx/588.html 588},
13
13
  # and their linked alternates.
14
- # @todo legacy implementation used conditional to separate join logic for 588 field. However, this doesn't seem
15
- # necessary because 588 only has subfields 'a', '5', '6', and '8'. Do we need to look into this?
16
14
  # @param [MARC::Record] record
17
15
  # @return [Array<String>]
18
16
  def notes_show(record)
@@ -46,15 +46,15 @@ module PennMARC
46
46
  # Get related work from {RELATED_WORK_FIELDS} in the 7XX range. Require presence of sf t (title) and absence of
47
47
  # an indicator2 value. Prefix returned values with sf i value. Also map relator codes found in sf 4. Ignore sf 0.
48
48
  # @param [MARC::Record] record
49
- # @param [Hash] relator_mapping
49
+ # @param [Hash] relator_map
50
50
  # @return [Array]
51
- def related_work_show(record, relator_mapping = relator_map)
51
+ def related_work_show(record, relator_map: Mappers.relator)
52
52
  values = record.fields(RELATED_WORK_FIELDS).filter_map do |field|
53
53
  next if field.indicator2.present?
54
54
 
55
55
  next unless subfield_defined?(field, 't')
56
56
 
57
- values_with_title_prefix(field, sf_exclude: %w[0 4 6 8 i], relator_map: relator_mapping)
57
+ values_with_title_prefix(field, sf_exclude: %w[0 4 6 8 i], relator_map: relator_map)
58
58
  end
59
59
  values + record.fields('880').filter_map do |field|
60
60
  next if field.indicator2.present?
@@ -63,7 +63,7 @@ module PennMARC
63
63
 
64
64
  next unless subfield_defined?(field, 't')
65
65
 
66
- values_with_title_prefix(field, sf_exclude: %w[0 4 6 8 i], relator_map: relator_mapping)
66
+ values_with_title_prefix(field, sf_exclude: %w[0 4 6 8 i], relator_map: relator_map)
67
67
  end
68
68
  end
69
69
 
@@ -71,13 +71,13 @@ module PennMARC
71
71
  # "Analytical Entry" meaning that the record is contained by the matching field. Map relator codes in sf 4. Ignore
72
72
  # values in sf 0, 5, 6, and 8.
73
73
  # @param [MARC::Record] record
74
- # @param [Hash] relator_mapping
74
+ # @param [Hash] relator_map
75
75
  # @return [Array]
76
- def contains_show(record, relator_mapping = relator_map)
76
+ def contains_show(record, relator_map: Mappers.relator)
77
77
  acc = record.fields(CONTAINS_FIELDS).filter_map do |field|
78
78
  next unless field.indicator2 == '2'
79
79
 
80
- values_with_title_prefix(field, sf_exclude: %w[0 4 5 6 8 i], relator_map: relator_mapping)
80
+ values_with_title_prefix(field, sf_exclude: %w[0 4 5 6 8 i], relator_map: relator_map)
81
81
  end
82
82
  acc + record.fields('880').filter_map do |field|
83
83
  next unless field.indicator2 == '2'