pennmarc 1.0.0 → 1.0.2

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