pennmarc 0.0.2 → 1.0.0

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 +4 -0
  3. data/.rubocop_todo.yml +151 -0
  4. data/Gemfile +1 -1
  5. data/lib/pennmarc/helpers/creator.rb +47 -13
  6. data/lib/pennmarc/helpers/database.rb +8 -8
  7. data/lib/pennmarc/helpers/date.rb +16 -15
  8. data/lib/pennmarc/helpers/edition.rb +14 -11
  9. data/lib/pennmarc/helpers/format.rb +16 -5
  10. data/lib/pennmarc/helpers/genre.rb +12 -11
  11. data/lib/pennmarc/helpers/identifier.rb +16 -7
  12. data/lib/pennmarc/helpers/language.rb +1 -1
  13. data/lib/pennmarc/helpers/link.rb +6 -0
  14. data/lib/pennmarc/helpers/location.rb +14 -14
  15. data/lib/pennmarc/helpers/note.rb +52 -2
  16. data/lib/pennmarc/helpers/relation.rb +9 -9
  17. data/lib/pennmarc/helpers/series.rb +182 -85
  18. data/lib/pennmarc/helpers/subject.rb +11 -11
  19. data/lib/pennmarc/helpers/title.rb +1 -1
  20. data/lib/pennmarc/parser.rb +2 -99
  21. data/lib/pennmarc/util.rb +11 -11
  22. data/pennmarc.gemspec +2 -2
  23. data/spec/lib/pennmarc/helpers/citation_spec.rb +1 -2
  24. data/spec/lib/pennmarc/helpers/creator_spec.rb +46 -11
  25. data/spec/lib/pennmarc/helpers/date_spec.rb +5 -5
  26. data/spec/lib/pennmarc/helpers/edition_spec.rb +1 -4
  27. data/spec/lib/pennmarc/helpers/format_spec.rb +29 -9
  28. data/spec/lib/pennmarc/helpers/genre_spec.rb +3 -3
  29. data/spec/lib/pennmarc/helpers/identifer_spec.rb +15 -0
  30. data/spec/lib/pennmarc/helpers/location_spec.rb +9 -8
  31. data/spec/lib/pennmarc/helpers/note_spec.rb +67 -2
  32. data/spec/lib/pennmarc/helpers/series_spec.rb +54 -0
  33. data/spec/lib/pennmarc/helpers/subject_spec.rb +8 -8
  34. data/spec/lib/pennmarc/helpers/title_spec.rb +3 -1
  35. data/spec/lib/pennmarc/marc_util_spec.rb +9 -8
  36. data/spec/lib/pennmarc/parser_spec.rb +2 -2
  37. data/spec/spec_helper.rb +1 -1
  38. metadata +7 -17
@@ -19,13 +19,13 @@ module PennMARC
19
19
  # @param [MARC::Record] record
20
20
  # @return [Array<String>]
21
21
  def isxn_search(record)
22
- record.fields(%w[020 022]).filter_map do |field|
22
+ record.fields(%w[020 022]).filter_map { |field|
23
23
  if field.tag == '020'
24
24
  field.filter_map { |subfield| normalize_isbn(subfield.value) if subfield_in?(%w[a z]).call(subfield) }
25
25
  else
26
26
  field.filter_map { |subfield| subfield.value if subfield_in?(%w[a l z]).call(subfield) }
27
27
  end
28
- end.flatten.uniq
28
+ }.flatten.uniq
29
29
  end
30
30
 
31
31
  # Get ISBN values for display from the {https://www.oclc.org/bibformats/en/0xx/020.html 020 field}
@@ -37,7 +37,7 @@ module PennMARC
37
37
  def isbn_show(record)
38
38
  isbn_values = record.fields('020').filter_map do |field|
39
39
  joined_isbn = join_subfields(field, &subfield_in?(%w[a z]))
40
- joined_isbn if joined_isbn.present?
40
+ joined_isbn.presence
41
41
  end
42
42
  isbn_values += linked_alternate(record, '020', &subfield_in?(%w[a z]))
43
43
  isbn_values
@@ -51,7 +51,7 @@ module PennMARC
51
51
  def issn_show(record)
52
52
  issn_values = record.fields('022').filter_map do |field|
53
53
  joined_issn = join_subfields(field, &subfield_in?(%w[a z]))
54
- joined_issn if joined_issn.present?
54
+ joined_issn.presence
55
55
  end
56
56
  issn_values += linked_alternate(record, '022', &subfield_in?(%w[a z]))
57
57
  issn_values
@@ -92,21 +92,30 @@ module PennMARC
92
92
  def publisher_number_show(record)
93
93
  publisher_numbers = record.fields(%w[024 028]).filter_map do |field|
94
94
  joined_identifiers = join_subfields(field, &subfield_not_in?(%w[5 6]))
95
- joined_identifiers if joined_identifiers.present?
95
+ joined_identifiers.presence
96
96
  end
97
97
  publisher_numbers += linked_alternate(record, %w[024 028], &subfield_not_in?(%w[5 6]))
98
98
  publisher_numbers
99
99
  end
100
100
 
101
101
  # Get publisher issued identifiers for searching of a record. Values extracted from fields
102
- # {https://www.oclc.org/bibformats/en/0xx/024.html 024} and {https://www.oclc.org/bibformats/en/0xx/024.html 028}.
102
+ # {https://www.oclc.org/bibformats/en/0xx/024.html 024} and {https://www.oclc.org/bibformats/en/0xx/028.html 028}.
103
103
  #
104
104
  # @param [MARC::Record] record
105
105
  # @return [Array<String>]
106
106
  def publisher_number_search(record)
107
107
  record.fields(%w[024 028]).filter_map do |field|
108
108
  joined_identifiers = join_subfields(field, &subfield_in?(%w[a]))
109
- joined_identifiers if joined_identifiers.present?
109
+ joined_identifiers.presence
110
+ end
111
+ end
112
+
113
+ # Retrieve fingerprint for display from the {https://www.oclc.org/bibformats/en/0xx/026.html 026} field
114
+ # @param [MARC::Record] record
115
+ # @return [Array<String>]
116
+ def fingerprint_show(record)
117
+ record.fields('026').map do |field|
118
+ join_subfields(field, &subfield_not_in?(%w[2 5 6 8]))
110
119
  end
111
120
  end
112
121
 
@@ -27,7 +27,7 @@ module PennMARC
27
27
  # @param [MARC::Record] record
28
28
  # @param [Hash] mapping hash for language code translation
29
29
  # @return [String] nice value for language
30
- def search(record, mapping)
30
+ def search(record, mapping = language_map)
31
31
  control_field = record['008']&.value
32
32
  language_code = control_field[35..37]
33
33
  mapping[language_code.to_sym || UNDETERMINED_CODE]
@@ -4,6 +4,12 @@ module PennMARC
4
4
  # Do Link-y stuff
5
5
  class Link < Helper
6
6
  class << self
7
+ # @todo the legacy code here is a hot mess for a number of reasons, what do we need this field to do?
8
+ # @note port the needed parts from get_offsite_display, don't return HTML
9
+ # @param [MARC::Record] record
10
+ # @return [Object]
11
+ def offsite(record); end
12
+
7
13
  def full_text(record:); end
8
14
 
9
15
  def web(record:); 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_map hash with location_code as key and location hash as value
13
+ # @param [Hash] location_mapping 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_map)
16
- location(record: record, location_map: location_map, display_value: 'library')
15
+ def library(record, location_mapping = location_map)
16
+ location(record: record, location_mapping: location_mapping, 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_map hash with location_code as key and location hash as value
26
+ # @param [Hash] location_mapping 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_map)
29
- location(record: record, location_map: location_map, display_value: 'specific_location')
28
+ def specific_location(record, location_mapping = location_map)
29
+ location(record: record, location_mapping: location_mapping, 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
@@ -35,15 +35,15 @@ module PennMARC
35
35
  # @see https://developers.exlibrisgroup.com/alma/apis/docs/bibs/R0VUIC9hbG1hd3MvdjEvYmlicy97bW1zX2lkfQ==/
36
36
  # Alma documentation for these added fields
37
37
  # @param [MARC::Record] record
38
- # @param [Hash] location_map hash with location_code as key and location hash as value
39
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
40
40
  # @return [Array<String>]
41
- def location(record:, location_map:, display_value:)
41
+ def location(record:, display_value:, location_mapping: 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
 
45
- locations = record.fields(tag).flat_map do |field|
46
- field.filter_map do |subfield|
45
+ locations = record.fields(tag).flat_map { |field|
46
+ field.filter_map { |subfield|
47
47
  # skip unless subfield code does not match enriched marc tag subfield code
48
48
  next unless subfield.code == subfield_code
49
49
 
@@ -56,11 +56,11 @@ 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_map.key?(subfield.value.to_sym)
59
+ next unless location_mapping.key?(subfield.value.to_sym)
60
60
 
61
- location_map[subfield.value.to_sym][display_value.to_sym]
62
- end.flatten.compact_blank
63
- end.uniq
61
+ location_mapping[subfield.value.to_sym][display_value.to_sym]
62
+ }.flatten.compact_blank
63
+ }.uniq
64
64
  locations << 'Online library' if record.fields(PennMARC::EnrichedMarc::TAG_ELECTRONIC_INVENTORY).any?
65
65
  locations
66
66
  end
@@ -72,11 +72,11 @@ module PennMARC
72
72
  # @param [MARC::Record] record
73
73
  # @return [Array<String>]
74
74
  def contents_show(record)
75
- record.fields(%w[505 880]).filter_map do |field|
75
+ record.fields(%w[505 880]).filter_map { |field|
76
76
  next if field.tag == '880' && subfield_value_not_in?(field, '6', %w[505])
77
77
 
78
78
  join_subfields(field, &subfield_not_in?(%w[6 8])).split('--')
79
- end.flatten
79
+ }.flatten
80
80
  end
81
81
 
82
82
  # Retrieve access restricted notes for display from field {https://www.oclc.org/bibformats/en/5xx/506.html 506}.
@@ -127,6 +127,56 @@ module PennMARC
127
127
  def summary_show(record)
128
128
  datafield_and_linked_alternate(record, '520')
129
129
  end
130
+
131
+ # Retrieve arrangement values for display from field field {https://www.oclc.org/bibformats/en/3xx/351.html 351}.
132
+ # @param [MARC::Record] record
133
+ # @return [Array<String>]
134
+ def arrangement_show(record)
135
+ datafield_and_linked_alternate(record, '351')
136
+ end
137
+
138
+ # Retrieve system details notes for display from fields {https://www.oclc.org/bibformats/en/5xx/538.html 538},
139
+ # {https://www.oclc.org/bibformats/en/3xx/344.html 344}, {https://www.oclc.org/bibformats/en/3xx/345.html 345},
140
+ # {https://www.oclc.org/bibformats/en/3xx/346.html 346}, {https://www.oclc.org/bibformats/en/3xx/347.html 347},
141
+ # and their linked alternates.
142
+ # @param [MARC::Record] record
143
+ # @return [Array<String>]
144
+ def system_details_show(record)
145
+ system_details_notes = record.fields(%w[538 880]).filter_map do |field|
146
+ next if field.tag == '880' && subfield_value_not_in?(field, '6', ['538'])
147
+
148
+ sub3_and_other_subs(field, &subfield_in?(%w[a i u]))
149
+ end
150
+ system_details_notes += record.fields(%w[344 880]).filter_map do |field|
151
+ next if field.tag == '880' && subfield_value_not_in?(field, '6', ['344'])
152
+
153
+ sub3_and_other_subs(field, &subfield_in?(%w[a b c d e f g h]))
154
+ end
155
+ system_details_notes += record.fields(%w[345 346 880]).filter_map do |field|
156
+ next if field.tag == '880' && subfield_value_not_in?(field, '6', %w[345 346])
157
+
158
+ sub3_and_other_subs(field, &subfield_in?(%w[a b]))
159
+ end
160
+ system_details_notes += record.fields(%w[347 880]).filter_map do |field|
161
+ next if field.tag == '880' && subfield_value_not_in?(field, '6', ['347'])
162
+
163
+ sub3_and_other_subs(field, &subfield_in?(%w[a b c d e f]))
164
+ end
165
+ system_details_notes
166
+ end
167
+
168
+ private
169
+
170
+ # For system details: extract subfield ǂ3 plus other subfields as specified by passed-in block. Pays special
171
+ # attention to punctuation, joining subfield ǂ3 values with a colon-space (': ').
172
+ # @param [MARC::DataField] field
173
+ # @param [Proc] selector
174
+ # @return [String]
175
+ def sub3_and_other_subs(field, &)
176
+ sub3 = field.filter_map { |sf| trim_trailing('period', sf.value) if sf.code == '3' }.join(': ')
177
+ oth_subs = join_subfields(field, &)
178
+ [sub3, trim_trailing('semicolon', oth_subs)].join(' ')
179
+ end
130
180
  end
131
181
  end
132
182
  end
@@ -46,24 +46,24 @@ 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_map
49
+ # @param [Hash] relator_mapping
50
50
  # @return [Array]
51
- def related_work_show(record, relator_map)
51
+ def related_work_show(record, relator_mapping = relator_map)
52
52
  values = record.fields(RELATED_WORK_FIELDS).filter_map do |field|
53
- next unless field.indicator2.blank?
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_map)
57
+ values_with_title_prefix(field, sf_exclude: %w[0 4 6 8 i], relator_map: relator_mapping)
58
58
  end
59
59
  values + record.fields('880').filter_map do |field|
60
- next unless field.indicator2.blank?
60
+ next if field.indicator2.present?
61
61
 
62
62
  next unless subfield_value?(field, '6', /^(#{RELATED_WORK_FIELDS.join('|')})/)
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_map)
66
+ values_with_title_prefix(field, sf_exclude: %w[0 4 6 8 i], relator_map: relator_mapping)
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_map
74
+ # @param [Hash] relator_mapping
75
75
  # @return [Array]
76
- def contains_show(record, relator_map)
76
+ def contains_show(record, relator_mapping = relator_map)
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_map)
80
+ values_with_title_prefix(field, sf_exclude: %w[0 4 5 6 8 i], relator_map: relator_mapping)
81
81
  end
82
82
  acc + record.fields('880').filter_map do |field|
83
83
  next unless field.indicator2 == '2'
@@ -1,116 +1,213 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PennMARC
4
- # Do Series-y stuff
4
+ # Do Series and series-related field processing. Many of these fields are added entries that are justified by
5
+ # corresponding series statements (usually 490). These fields provide information about the published series in which
6
+ # a book, encoded finding aid, or other published work has appeared
7
+ # @todo We may want to include 410 in the display tags, since it is included in references below.
5
8
  class Series < Helper
6
9
  class << self
7
- def show(record)
8
- acc = []
9
-
10
- tags_present = series_tags.select { |tag| record[tag].present? }
11
-
12
- if %w[800 810 811 400 410 411].member?(tags_present.first)
13
- record.fields(tags_present.first).each do |field|
14
- # added 2017/04/10: filter out 0 (authority record numbers) added by Alma
15
- series = join_subfields(field, &subfield_not_in(%w[0 5 6 8 e t w v n]))
16
- pairs = field.map do |sf|
17
- if %w[e w v n t].member?(sf.code)
18
- [' ', sf.value]
19
- elsif sf.code == '4'
20
- [', ', relator_codes[sf.value]]
21
- end
22
- end
23
- series_append = pairs.flatten.join.strip
24
- acc << { value: series, value_append: series_append, link_type: 'author_search' }
25
- end
26
- elsif %w[830 440 490].member?(tags_present.first)
27
- record.fields(tags_present.first).each do |field|
28
- # added 2017/04/10: filter out 0 (authority record numbers) added by Alma
29
- series = join_subfields(field, &subfield_not_in(%w[0 5 6 8 c e w v n]))
30
- series_append = join_subfields(field, &subfield_in(%w[c e w v n]))
31
- acc << { value: series, value_append: series_append, link_type: 'title_search' }
32
- end
33
- end
10
+ # 800 - Series Added Entry-Personal Name - https://www.loc.gov/marc/bibliographic/bd800.html
11
+ # 810 - Series Added Entry-Corporate Name - https://www.loc.gov/marc/bibliographic/bd810.html
12
+ # 410 - Series Statement/Added Entry-Corporate Name - https://www.loc.gov/marc/bibliographic/bd410.html
13
+ # 811 - Series Added Entry-Meeting Name - https://www.loc.gov/marc/bibliographic/bd811.html
14
+ # 830 - Series Added Entry-Uniform Title - https://www.loc.gov/marc/bibliographic/bd830.html
15
+ # 400 - Series Statement/Added Entry-Personal Name - https://www.loc.gov/marc/bibliographic/bd400.html
16
+ # 411 - Series Statement/Added Entry Meeting Name - https://www.loc.gov/marc/bibliographic/bd411.html
17
+ # 440 - Series Statement/Added Entry-Title - https://www.loc.gov/marc/bibliographic/bd440.html
18
+ # 490 - Series Statement - https://www.loc.gov/marc/bibliographic/bd490.html
19
+ DISPLAY_TAGS = %w[800 810 811 830 400 411 440 490].freeze
34
20
 
35
- record.fields(tags_present.drop(1)).each do |field|
36
- # added 2017/04/10: filter out 0 (authority record numbers) added by Alma
37
- series = join_subfields(field, &subfield_not_in(%w[0 5 6 8]))
38
- acc << { value: series, link: false }
39
- end
21
+ # Fields for display that pertain to series information.
22
+ # @param [MARC::Record] record
23
+ # @param [Hash] relator_mapping
24
+ # @return [Array<String>] array of series information
25
+ def show(record, relator_mapping = relator_map)
26
+ tags_present = DISPLAY_TAGS.select { |tag| record[tag].present? }
40
27
 
41
- record.fields('880')
42
- .select { |f| has_subfield6_value(f, /^(800|810|811|830|400|410|411|440|490)/) }
43
- .each do |field|
44
- series = join_subfields(field, &subfield_not_in(%w[5 6 8]))
45
- acc << { value: series, link: false }
46
- end
28
+ values = if %w[800 810 811 400 410 411].member?(tags_present.first)
29
+ author_show_entries(record, tags_present.first, relator_mapping)
30
+ elsif %w[830 440 490].member?(tags_present.first)
31
+ title_show_entries(record, tags_present.first)
32
+ end || []
47
33
 
48
- acc
34
+ values += remaining_show_entries(record, tags_present)
35
+ values + series_880_fields(record)
49
36
  end
50
37
 
51
- def values(record)
52
- acc = []
53
- added_8xx = false
54
- record.fields(%w[800 810 811 830]).take(1).each do |field|
55
- acc << get_series_8xx_field(field)
56
- added_8xx = true
57
- end
58
- unless added_8xx
59
- record.fields(%w[400 410 411 440 490]).take(1).map do |field|
60
- acc << get_series_4xx_field(field)
61
- end
62
- end
63
- acc
38
+ # Values from series fields for display.
39
+ # @param [MARC::Record] record
40
+ # @param [Hash] relator_mapping
41
+ # @return [Array<String>] array of series values
42
+ def values(record, relator_mapping = relator_map)
43
+ series_8x = record.fields(%w[800 810 811 830]).first
44
+ return Array.wrap(series_8xx_field(series_8x, relator_mapping)) if series_8x
45
+
46
+ series_4x = record.fields(%w[400 410 411 440 490]).first
47
+ return Array.wrap(series_4xx_field(series_4x, relator_mapping)) if series_4x
64
48
  end
65
49
 
50
+ # Series fields for search.
51
+ # @param [MARC::Record] record
52
+ # @return [Array<String>] array of series values
66
53
  def search(record)
67
- acc += record.fields(%w[400 410 411])
68
- .select { |f| f.indicator2 == '0' }
69
- .map do |field|
70
- join_subfields(field, &subfield_not_in(%w[4 6 8]))
54
+ values = record.fields(%w[400 410 411]).filter_map do |field|
55
+ subfields = if field.indicator2 != '0'
56
+ %w[4 6 8]
57
+ elsif field.indicator2 != '1'
58
+ %w[4 6 8 a]
59
+ else
60
+ next
61
+ end
62
+ join_subfields(field, &subfield_not_in?(subfields))
71
63
  end
72
- acc += record.fields(%w[400 410 411])
73
- .select { |f| f.indicator2 == '1' }
74
- .map do |field|
75
- join_subfields(field, &subfield_not_in(%w[4 6 8 a]))
64
+ values += record.fields(%w[440]).filter_map do |field|
65
+ join_subfields(field, &subfield_not_in?(%w[0 5 6 8 w]))
76
66
  end
77
- acc += record.fields(%w[440])
78
- .map do |field|
79
- join_subfields(field, &subfield_not_in(%w[0 5 6 8 w]))
67
+ values += record.fields(%w[800 810 811]).filter_map do |field|
68
+ join_subfields(field, &subfield_not_in?(%w[0 4 5 6 7 8 w]))
80
69
  end
81
- acc += record.fields(%w[800 810 811])
82
- .map do |field|
83
- join_subfields(field, &subfield_not_in(%w[0 4 5 6 7 8 w]))
70
+ values += record.fields(%w[830]).filter_map do |field|
71
+ join_subfields(field, &subfield_not_in?(%w[0 5 6 7 8 w]))
84
72
  end
85
- acc += record do |field|
86
- join_subfields(field, &subfield_not_in(%w[0 5 6 7 8 w]))
73
+ values += record.fields(%w[533]).filter_map do |field|
74
+ filtered_values = field.filter_map { |sf| sf.value if sf.code == 'f' }
75
+ next if filtered_values.empty?
76
+
77
+ filtered_values.map { |v| v.gsub(/\(|\)/, '') }.join(' ')
87
78
  end
88
- acc + record.fields(%w[533])
89
- .map do |field|
90
- field.find_all { |sf| sf.code == 'f' }
91
- .map(&:value)
92
- .map { |v| v.gsub(/\(|\)/, '') }
93
- .join(' ')
94
- end
79
+ values
95
80
  end
96
81
 
82
+ # Information concerning the immediate predecessor of the target item (chronological relationship). When a note
83
+ # is generated from this field, the introductory term or phrase may be generated based on the value in the second
84
+ # indicator position for display.
85
+ # https://www.loc.gov/marc/bibliographic/bd780.html
86
+ # @param [MARC::Record] record
87
+ # @return [String] continues fields string
97
88
  def get_continues_display(record)
98
- get_continues(record, '780')
89
+ continues(record, '780')
99
90
  end
100
91
 
92
+ # Information concerning the immediate successor to the target item (chronological relationship). When a note is
93
+ # generated from this field, the introductory phrase may be generated based on the value in the second indicator
94
+ # position for display.
95
+ # https://www.loc.gov/marc/bibliographic/bd785.html
96
+ # @param [MARC::Record] record
97
+ # @return [String] continued by fields string
101
98
  def get_continued_by_display(record)
102
- get_continues(record, '785')
99
+ continues(record, '785')
103
100
  end
104
101
 
105
102
  private
106
103
 
107
- # logic for 'Continues' and 'Continued By' is very similar
108
- def get_continues(record, tag)
109
- record.fields
110
- .select { |f| f.tag == tag || (f.tag == '880' && has_subfield6_value(f, /^#{tag}/)) }
111
- .select { |f| f.any?(&subfield_in(%w[i a s t n d])) }
112
- .map do |field|
113
- join_subfields(field, &subfield_in(%w[i a s t n d]))
104
+ # If any of these values: 800 810 811 400 410 411 are present, return a string with series information and
105
+ # appended values.
106
+ # @note added 2017/04/10: filter out 0 (authority record numbers) added by Alma
107
+ # @param [MARC::Record] record
108
+ # @param [String] first_tag
109
+ # @param [Hash] relator_mapping
110
+ # @return [Array<Hash>] array of author show entry hashes
111
+ def author_show_entries(record, first_tag, relator_mapping)
112
+ record.fields(first_tag).map do |field|
113
+ series = join_subfields(field, &subfield_not_in?(%w[0 5 6 8 e t w v n]))
114
+ pairs = field.map do |sf|
115
+ if %w[e w v n t].member?(sf.code)
116
+ [' ', sf.value]
117
+ elsif sf.code == '4'
118
+ [', ', translate_relator(sf.value, relator_mapping)]
119
+ end
120
+ end
121
+ series_append = pairs.flatten.join.strip
122
+ "#{series} #{series_append}".squish
123
+ end || []
124
+ end
125
+
126
+ # If any of these values: 830 440 490 are present, return a string with series information and appended values.
127
+ # @note added 2017/04/10: filter out 0 (authority record numbers) added by Alma
128
+ # @param [MARC::Record] record
129
+ # @param [String] first_tag
130
+ # @return [Array<Hash>] array of author show entry hashes
131
+ def title_show_entries(record, first_tag)
132
+ record.fields(first_tag).map do |field|
133
+ series = join_subfields(field, &subfield_not_in?(%w[0 5 6 8 c e w v n]))
134
+ series_append = join_subfields(field, &subfield_in?(%w[c e w v n]))
135
+ "#{series} #{series_append}".squish
136
+ end || []
137
+ end
138
+
139
+ # Assemble an array of hashes that includes the remaining show entries.
140
+ # @note added 2017/04/10: filter out 0 (authority record numbers) added by Alma
141
+ # @param [MARC::Record] record
142
+ # @param [Array<String>] tags_present
143
+ # @return [Array<Hash>] array of remaining show entry hashes
144
+ def remaining_show_entries(record, tags_present)
145
+ record.fields(tags_present.drop(1)).map do |field|
146
+ join_subfields(field, &subfield_not_in?(%w[0 5 6 8]))
147
+ end || []
148
+ end
149
+
150
+ # TODO: use linked alternate in place of this function
151
+ # @note There are multiple locations in these helpers where we should be able to use the linked_alternate util.
152
+ # @note This requires a more comprehensive evaluation and refactor of the linked_alternate utility.
153
+ #
154
+ # Fully content-designated representation, in a different script, of another field in the same record. Field 880
155
+ # is linked to the associated regular field by subfield $6 (Linkage). A subfield $6 in the associated field also
156
+ # links that field to the 880 field. The data in field 880 may be in more than one script. This function exists
157
+ # because it differs than the tradition use of linked_alternate.
158
+ # @param [MARC::Record] record
159
+ def series_880_fields(record)
160
+ record.fields('880').filter_map do |field|
161
+ next unless subfield_value?(field, '6', /^(800|810|811|830|400|410|411|440|490)/)
162
+
163
+ join_subfields(field, &subfield_not_in?(%w[5 6 8]))
164
+ end || []
165
+ end
166
+
167
+ # Assemble a formatted string of a given 8xx field.
168
+ # @note added 2017/04/10: filter out 0 (authority record numbers) added by Alma
169
+ # @param [String] field
170
+ # @param [Hash] relator_mapping
171
+ # @return [String] series 8xx field
172
+ def series_8xx_field(field, relator_mapping)
173
+ s = field.filter_map { |sf|
174
+ if %w[0 4 5 6 8].exclude?(sf.code)
175
+ " #{sf.value}"
176
+ elsif sf.code == '4'
177
+ ", #{translate_relator(sf.value, relator_mapping)}"
178
+ end
179
+ }.join
180
+ s2 = s + (%w[. -].exclude?(s[-1]) ? '.' : '')
181
+ s2.squish
182
+ end
183
+
184
+ # Assemble a formatted string of a given 4xx field.
185
+ # @note added 2017/04/10: filter out 0 (authority record numbers) added by Alma
186
+ # @param [String] field
187
+ # @param [Hash] relator_mapping
188
+ # @return [String] series 4xx field
189
+ def series_4xx_field(field, relator_mapping)
190
+ s = field.filter_map { |sf|
191
+ if %w[0 4 6 8].exclude?(sf.code)
192
+ " #{sf.value}"
193
+ elsif sf.code == '4'
194
+ ", #{translate_relator(sf.value, relator_mapping)}"
195
+ end
196
+ }.join
197
+ s2 = s + (%w[. -].exclude?(s[-1]) ? '.' : '')
198
+ s2.squish
199
+ end
200
+
201
+ # Get subfields from a given field (continues or continued_by).
202
+ # @param [MARC::Record] record
203
+ # @param [String] tag
204
+ # @return [String] joined subfields
205
+ def continues(record, tag)
206
+ record.fields.filter_map do |field|
207
+ next unless field.tag == tag || (field.tag == '880' && subfield_value?(field, '6', /^#{tag}/))
208
+ next unless field.any?(&subfield_in?(%w[i a s t n d]))
209
+
210
+ join_subfields(field, &subfield_in?(%w[i a s t n d]))
114
211
  end
115
212
  end
116
213
  end