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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/.rubocop_todo.yml +37 -21
- data/Gemfile.lock +3 -0
- data/README.md +12 -2
- data/lib/pennmarc/helpers/creator.rb +24 -20
- data/lib/pennmarc/helpers/edition.rb +15 -13
- data/lib/pennmarc/helpers/format.rb +3 -3
- data/lib/pennmarc/helpers/genre.rb +5 -4
- data/lib/pennmarc/helpers/helper.rb +1 -0
- data/lib/pennmarc/helpers/identifier.rb +32 -15
- data/lib/pennmarc/helpers/language.rb +3 -3
- data/lib/pennmarc/helpers/location.rb +10 -10
- data/lib/pennmarc/helpers/note.rb +0 -2
- data/lib/pennmarc/helpers/relation.rb +7 -7
- data/lib/pennmarc/helpers/series.rb +19 -31
- data/lib/pennmarc/helpers/subject.rb +11 -11
- data/lib/pennmarc/helpers/title.rb +1 -1
- data/lib/pennmarc/mappers.rb +31 -0
- data/lib/pennmarc/parser.rb +36 -62
- data/lib/pennmarc/util.rb +10 -11
- data/lib/pennmarc/version.rb +5 -0
- data/pennmarc.gemspec +5 -1
- data/spec/lib/pennmarc/helpers/creator_spec.rb +9 -9
- data/spec/lib/pennmarc/helpers/edition_spec.rb +3 -2
- data/spec/lib/pennmarc/helpers/format_spec.rb +1 -1
- data/spec/lib/pennmarc/helpers/genre_spec.rb +1 -1
- data/spec/lib/pennmarc/helpers/identifer_spec.rb +43 -14
- data/spec/lib/pennmarc/helpers/language_spec.rb +1 -1
- data/spec/lib/pennmarc/helpers/location_spec.rb +8 -8
- data/spec/lib/pennmarc/helpers/relation_spec.rb +2 -2
- data/spec/lib/pennmarc/helpers/series_spec.rb +6 -5
- data/spec/lib/pennmarc/helpers/subject_spec.rb +1 -1
- data/spec/lib/pennmarc/parser_spec.rb +22 -1
- metadata +7 -8
- data/legacy/indexer.rb +0 -568
- data/legacy/marc.rb +0 -2964
- data/legacy/test_file_output.json +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 33527bf43532170690b9b591097fb03f854130b3383debfafe931417d0394f52
|
4
|
+
data.tar.gz: a18a5be08df6d7b74d2aaa61275cdecdedec6caa4b5e8b2b81c99e91411ce093
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 627a4da06351037f520bc02b0a9fd61ce6cfdec35c563f2b29e3c1c01b4ad76766f155630cafe680b010783ea4f4c285df2d499fd784b7ee4f3cb4948cd421dd
|
7
|
+
data.tar.gz: c966233bb00009a14babc5bc92f0399e75640e886f7c32d176fea8983813aca8936d0e8fab98576a797afaf0b60c5f24268c2ae4e2d8cca31900e590db0a9bc6
|
data/.rubocop.yml
CHANGED
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-
|
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:
|
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:
|
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:
|
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/
|
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]
|
27
|
+
# @param [Hash] relator_map
|
28
28
|
# @return [Array<String>] array of author/creator values for indexing
|
29
|
-
def search(record,
|
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
|
35
|
+
elsif creator_subfields.exclude?(sf.code)
|
35
36
|
sf.value
|
36
37
|
elsif sf.code == '4'
|
37
|
-
relator = translate_relator(sf.value,
|
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
|
55
|
+
if secondary_subfields.exclude?(sf.code)
|
54
56
|
sf.value
|
55
57
|
elsif sf.code == '4'
|
56
|
-
relator = translate_relator(sf.value,
|
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]
|
93
|
+
# @param [Hash] relator_map
|
92
94
|
# @return [Array<String>] array of author/creator values for display
|
93
|
-
def values(record,
|
95
|
+
def values(record, relator_map: Mappers.relator)
|
94
96
|
record.fields(TAGS).map do |field|
|
95
|
-
name_from_main_entry(field,
|
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]
|
147
|
+
# @param [Hash] relator_map
|
147
148
|
# @return [Array<String>] array of conference values
|
148
|
-
def conference_show(record,
|
149
|
+
def conference_show(record, relator_map: Mappers.relator)
|
149
150
|
record.fields('111').filter_map do |field|
|
150
|
-
name_from_main_entry field,
|
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]
|
192
|
+
# @ param [Hash] relator_map
|
192
193
|
# @return [Array<String>]
|
193
|
-
def contributor_show(record,
|
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
|
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
|
203
|
+
next unless contributor_append_subfields.member?(subfield.code)
|
201
204
|
|
202
205
|
if subfield.code == '4'
|
203
|
-
", #{translate_relator(subfield.value,
|
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
|
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]
|
37
|
+
# @param [Hash] relator_map
|
38
38
|
# @return [Array<String>] array of other edition strings
|
39
|
-
def other_show(record,
|
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,
|
43
|
+
other_edition_value(field, relator_map)
|
44
44
|
end
|
45
|
-
values
|
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,
|
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]
|
57
|
+
# @param [Hash] relator_map
|
59
58
|
# @return [String (frozen)] assembled other version string
|
60
|
-
def other_edition_value(field,
|
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
|
64
|
+
next if excluded_subfields.member?(sf.code)
|
64
65
|
|
65
|
-
if
|
66
|
+
if other_edition_subfields.member?(sf.code)
|
66
67
|
" #{sf.value}"
|
67
68
|
elsif sf.code == 't'
|
68
|
-
relator = translate_relator(sf.value,
|
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
|
77
|
+
next if excluded_subfields.member?(sf.code)
|
76
78
|
|
77
|
-
if
|
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]
|
71
|
+
# @param [Hash] location_map
|
72
72
|
# @return [Array<String>] format values for faceting
|
73
73
|
|
74
|
-
def facet(record,
|
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,
|
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 =
|
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]
|
50
|
+
# @param [Hash] location_map
|
50
51
|
# @return [Array<String>]
|
51
|
-
def facet(record,
|
52
|
-
locations = Location.location record: record,
|
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' }
|
@@ -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
|
38
|
+
joined_isbn = join_subfields(field, &subfield_in?(%w[a]))
|
40
39
|
joined_isbn.presence
|
41
40
|
end
|
42
|
-
isbn_values
|
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
|
51
|
+
joined_issn = join_subfields(field, &subfield_in?(%w[a]))
|
54
52
|
joined_issn.presence
|
55
53
|
end
|
56
|
-
issn_values
|
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
|
-
|
94
|
-
|
95
|
-
|
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 (
|
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]
|
28
|
+
# @param [Hash] language_map hash for language code translation
|
29
29
|
# @return [String] nice value for language
|
30
|
-
def search(record,
|
30
|
+
def search(record, language_map: Mappers.language)
|
31
31
|
control_field = record['008']&.value
|
32
32
|
language_code = control_field[35..37]
|
33
|
-
|
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]
|
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,
|
16
|
-
location(record: record,
|
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]
|
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,
|
29
|
-
location(record: record,
|
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]
|
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:,
|
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
|
59
|
+
next unless location_map.key?(subfield.value.to_sym)
|
60
60
|
|
61
|
-
|
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]
|
49
|
+
# @param [Hash] relator_map
|
50
50
|
# @return [Array]
|
51
|
-
def related_work_show(record,
|
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:
|
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:
|
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]
|
74
|
+
# @param [Hash] relator_map
|
75
75
|
# @return [Array]
|
76
|
-
def contains_show(record,
|
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:
|
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'
|