pennmarc 0.0.2 → 1.0.1

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