pennmarc 0.0.2 → 1.0.0

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 +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