pennmarc 0.0.2 → 1.0.1

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -0
  3. data/.rubocop_todo.yml +143 -0
  4. data/Gemfile +1 -1
  5. data/README.md +12 -2
  6. data/lib/pennmarc/helpers/creator.rb +59 -21
  7. data/lib/pennmarc/helpers/database.rb +8 -8
  8. data/lib/pennmarc/helpers/date.rb +16 -15
  9. data/lib/pennmarc/helpers/edition.rb +25 -20
  10. data/lib/pennmarc/helpers/format.rb +15 -4
  11. data/lib/pennmarc/helpers/genre.rb +13 -11
  12. data/lib/pennmarc/helpers/helper.rb +1 -0
  13. data/lib/pennmarc/helpers/identifier.rb +16 -7
  14. data/lib/pennmarc/helpers/language.rb +3 -3
  15. data/lib/pennmarc/helpers/link.rb +6 -0
  16. data/lib/pennmarc/helpers/location.rb +8 -8
  17. data/lib/pennmarc/helpers/note.rb +52 -2
  18. data/lib/pennmarc/helpers/relation.rb +4 -4
  19. data/lib/pennmarc/helpers/series.rb +171 -85
  20. data/lib/pennmarc/helpers/subject.rb +16 -17
  21. data/lib/pennmarc/helpers/title.rb +1 -1
  22. data/lib/pennmarc/mappers.rb +31 -0
  23. data/lib/pennmarc/parser.rb +34 -157
  24. data/lib/pennmarc/util.rb +15 -16
  25. data/pennmarc.gemspec +2 -2
  26. data/spec/lib/pennmarc/helpers/citation_spec.rb +1 -2
  27. data/spec/lib/pennmarc/helpers/creator_spec.rb +54 -19
  28. data/spec/lib/pennmarc/helpers/date_spec.rb +5 -5
  29. data/spec/lib/pennmarc/helpers/edition_spec.rb +4 -6
  30. data/spec/lib/pennmarc/helpers/format_spec.rb +30 -10
  31. data/spec/lib/pennmarc/helpers/genre_spec.rb +4 -4
  32. data/spec/lib/pennmarc/helpers/identifer_spec.rb +15 -0
  33. data/spec/lib/pennmarc/helpers/language_spec.rb +1 -1
  34. data/spec/lib/pennmarc/helpers/location_spec.rb +2 -1
  35. data/spec/lib/pennmarc/helpers/note_spec.rb +67 -2
  36. data/spec/lib/pennmarc/helpers/relation_spec.rb +2 -2
  37. data/spec/lib/pennmarc/helpers/series_spec.rb +54 -0
  38. data/spec/lib/pennmarc/helpers/subject_spec.rb +9 -9
  39. data/spec/lib/pennmarc/helpers/title_spec.rb +3 -1
  40. data/spec/lib/pennmarc/marc_util_spec.rb +9 -8
  41. data/spec/lib/pennmarc/parser_spec.rb +24 -3
  42. data/spec/spec_helper.rb +1 -1
  43. metadata +8 -20
  44. data/legacy/indexer.rb +0 -568
  45. data/legacy/marc.rb +0 -2964
  46. data/legacy/test_file_output.json +0 -49
@@ -11,9 +11,9 @@ module PennMARC
11
11
  # @param [MARC::Record] record
12
12
  # @return [Array<String>] array of genre values for search
13
13
  def search(record)
14
- record.fields('655').map do |field|
14
+ record.fields('655').map { |field|
15
15
  join_subfields(field, &subfield_not_in?(%w[0 2 5 c]))
16
- end.uniq
16
+ }.uniq
17
17
  end
18
18
 
19
19
  # Genre values for display. We display Genre/Term values if they fulfill the following criteria:
@@ -29,17 +29,18 @@ module PennMARC
29
29
  # @param [MARC::Record] record
30
30
  # @return [Array<String>] array of genre values for display
31
31
  def show(record)
32
- record.fields(%w[655 880]).filter_map do |field|
32
+ record.fields(%w[655 880]).filter_map { |field|
33
33
  next unless allowed_genre_field?(field)
34
34
 
35
35
  next if field.tag == '880' && subfield_values(field, '6').exclude?('655')
36
36
 
37
- sub_with_hyphens = field.find_all(&subfield_not_in?(%w[0 2 5 6 8 c e w])).map do |sf|
38
- sep = %w[a b].exclude?(sf.code) ? ' -- ' : ' '
37
+ subfields = %w[a b]
38
+ sub_with_hyphens = field.find_all(&subfield_not_in?(%w[0 2 5 6 8 c e w])).map { |sf|
39
+ sep = subfields.exclude?(sf.code) ? ' -- ' : ' '
39
40
  sep + sf.value
40
- end.join.lstrip
41
+ }.join.lstrip
41
42
  "#{sub_with_hyphens} #{field.find_all(&subfield_in?(%w[e w])).join(' -- ')}".strip
42
- end.uniq
43
+ }.uniq
43
44
  end
44
45
 
45
46
  # Genre values for faceting. We only set Genre facet values for movies (videos) and manuscripts(?)
@@ -48,15 +49,16 @@ module PennMARC
48
49
  # @param [MARC::Record] record
49
50
  # @param [Hash] location_map
50
51
  # @return [Array<String>]
51
- def facet(record, location_map)
52
- locations = Location.location record: record, location_map: location_map, display_value: :specific_location
52
+ def facet(record, location_map: Mappers.location)
53
+ locations = Location.location record: record, location_map: location_map,
54
+ display_value: :specific_location
53
55
  manuscript = Format.include_manuscripts?(locations)
54
56
  video = record.fields('007').any? { |field| field.value.starts_with? 'v' }
55
57
  return [] unless manuscript || video
56
58
 
57
- record.fields('655').filter_map do |field|
59
+ record.fields('655').filter_map { |field|
58
60
  join_subfields field, &subfield_not_in?(%w[0 2 5 c])
59
- end.uniq
61
+ }.uniq
60
62
  end
61
63
 
62
64
  private
@@ -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
@@ -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
 
@@ -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)
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
@@ -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
@@ -12,7 +12,7 @@ module PennMARC
12
12
  # @param [MARC::Record] record
13
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_map)
15
+ def library(record, location_map: Mappers.location)
16
16
  location(record: record, location_map: location_map, display_value: 'library')
17
17
  end
18
18
 
@@ -25,7 +25,7 @@ module PennMARC
25
25
  # @param [MARC::Record] record
26
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_map)
28
+ def specific_location(record, location_map: Mappers.location)
29
29
  location(record: record, location_map: location_map, display_value: 'specific_location')
30
30
  end
31
31
 
@@ -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_map 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_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
 
@@ -59,8 +59,8 @@ module PennMARC
59
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
- end.flatten.compact_blank
63
- end.uniq
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
@@ -48,16 +48,16 @@ module PennMARC
48
48
  # @param [MARC::Record] record
49
49
  # @param [Hash] relator_map
50
50
  # @return [Array]
51
- def related_work_show(record, 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
- next unless field.indicator2.blank?
53
+ next if field.indicator2.present?
54
54
 
55
55
  next unless subfield_defined?(field, 't')
56
56
 
57
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
- 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
 
@@ -73,7 +73,7 @@ module PennMARC
73
73
  # @param [MARC::Record] record
74
74
  # @param [Hash] relator_map
75
75
  # @return [Array]
76
- def contains_show(record, 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
 
@@ -1,116 +1,202 @@
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_map
24
+ # @return [Array<String>] array of series information
25
+ def show(record, relator_map: Mappers.relator)
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_map)
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_map
41
+ # @return [Array<String>] array of series values
42
+ def values(record, relator_map: Mappers.relator)
43
+ series_8x = record.fields(%w[800 810 811 830]).first
44
+ return Array.wrap(series_field(series_8x, relator_map)) if series_8x
45
+
46
+ series_4x = record.fields(%w[400 410 411 440 490]).first
47
+ Array.wrap(series_field(series_4x, relator_map)) 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
+ author_show_subfields = %w[e w v n t]
115
+ pairs = field.map do |sf|
116
+ if author_show_subfields.member?(sf.code)
117
+ [' ', sf.value]
118
+ elsif sf.code == '4'
119
+ [', ', translate_relator(sf.value, relator_mapping)]
120
+ end
121
+ end
122
+ series_append = pairs.flatten.join.strip
123
+ "#{series} #{series_append}".squish
124
+ end || []
125
+ end
126
+
127
+ # If any of these values: 830 440 490 are present, return a string with series information and appended values.
128
+ # @note added 2017/04/10: filter out 0 (authority record numbers) added by Alma
129
+ # @param [MARC::Record] record
130
+ # @param [String] first_tag
131
+ # @return [Array<Hash>] array of author show entry hashes
132
+ def title_show_entries(record, first_tag)
133
+ record.fields(first_tag).map do |field|
134
+ series = join_subfields(field, &subfield_not_in?(%w[0 5 6 8 c e w v n]))
135
+ series_append = join_subfields(field, &subfield_in?(%w[c e w v n]))
136
+ "#{series} #{series_append}".squish
137
+ end || []
138
+ end
139
+
140
+ # Assemble an array of hashes that includes the remaining show entries.
141
+ # @note added 2017/04/10: filter out 0 (authority record numbers) added by Alma
142
+ # @param [MARC::Record] record
143
+ # @param [Array<String>] tags_present
144
+ # @return [Array<Hash>] array of remaining show entry hashes
145
+ def remaining_show_entries(record, tags_present)
146
+ record.fields(tags_present.drop(1)).map do |field|
147
+ join_subfields(field, &subfield_not_in?(%w[0 5 6 8]))
148
+ end || []
149
+ end
150
+
151
+ # TODO: use linked alternate in place of this function
152
+ # @note There are multiple locations in these helpers where we should be able to use the linked_alternate util.
153
+ # @note This requires a more comprehensive evaluation and refactor of the linked_alternate utility.
154
+ #
155
+ # Fully content-designated representation, in a different script, of another field in the same record. Field 880
156
+ # is linked to the associated regular field by subfield $6 (Linkage). A subfield $6 in the associated field also
157
+ # links that field to the 880 field. The data in field 880 may be in more than one script. This function exists
158
+ # because it differs than the tradition use of linked_alternate.
159
+ # @param [MARC::Record] record
160
+ def series_880_fields(record)
161
+ record.fields('880').filter_map do |field|
162
+ next unless subfield_value?(field, '6', /^(800|810|811|830|400|410|411|440|490)/)
163
+
164
+ join_subfields(field, &subfield_not_in?(%w[5 6 8]))
165
+ end || []
166
+ end
167
+
168
+ # Assemble a formatted string of a given field.
169
+ # @note added 2017/04/10: filter out 0 (authority record numbers) added by Alma
170
+ # @param [MARC::Field] field
171
+ # @param [Hash] relator_mapping
172
+ # @return [String] series 4xx field
173
+ def series_field(field, relator_mapping)
174
+ subfields = if field.tag.start_with? '4'
175
+ %w[0 4 6 8]
176
+ else
177
+ %w[0 4 5 6 8]
178
+ end
179
+ s = field.filter_map { |sf|
180
+ if subfields.exclude?(sf.code)
181
+ " #{sf.value}"
182
+ elsif sf.code == '4'
183
+ ", #{translate_relator(sf.value, relator_mapping)}"
184
+ end
185
+ }.join
186
+ s2 = s + (%w[. -].exclude?(s[-1]) ? '.' : '')
187
+ s2.squish
188
+ end
189
+
190
+ # Get subfields from a given field (continues or continued_by).
191
+ # @param [MARC::Record] record
192
+ # @param [String] tag
193
+ # @return [String] joined subfields
194
+ def continues(record, tag)
195
+ record.fields.filter_map do |field|
196
+ next unless field.tag == tag || (field.tag == '880' && subfield_value?(field, '6', /^#{tag}/))
197
+ next unless field.any?(&subfield_in?(%w[i a s t n d]))
198
+
199
+ join_subfields(field, &subfield_in?(%w[i a s t n d]))
114
200
  end
115
201
  end
116
202
  end