pennmarc 1.0.24 → 1.0.26

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +8 -9
  3. data/lib/pennmarc/enriched.rb +1 -0
  4. data/lib/pennmarc/helpers/access.rb +8 -6
  5. data/lib/pennmarc/helpers/creator.rb +139 -65
  6. data/lib/pennmarc/helpers/edition.rb +5 -3
  7. data/lib/pennmarc/helpers/identifier.rb +12 -0
  8. data/lib/pennmarc/helpers/note.rb +24 -19
  9. data/lib/pennmarc/helpers/production.rb +113 -20
  10. data/lib/pennmarc/helpers/subject.rb +10 -4
  11. data/lib/pennmarc/helpers/title.rb +39 -26
  12. data/lib/pennmarc/test/marc_helpers.rb +83 -0
  13. data/lib/pennmarc/util.rb +98 -69
  14. data/lib/pennmarc/version.rb +1 -1
  15. data/lib/pennmarc.rb +7 -0
  16. data/spec/lib/pennmarc/helpers/access_spec.rb +11 -2
  17. data/spec/lib/pennmarc/helpers/citation_spec.rb +0 -2
  18. data/spec/lib/pennmarc/helpers/classification_spec.rb +0 -2
  19. data/spec/lib/pennmarc/helpers/creator_spec.rb +103 -2
  20. data/spec/lib/pennmarc/helpers/database_spec.rb +0 -2
  21. data/spec/lib/pennmarc/helpers/date_spec.rb +0 -2
  22. data/spec/lib/pennmarc/helpers/edition_spec.rb +4 -2
  23. data/spec/lib/pennmarc/helpers/format_spec.rb +0 -2
  24. data/spec/lib/pennmarc/helpers/genre_spec.rb +0 -2
  25. data/spec/lib/pennmarc/helpers/identifer_spec.rb +14 -2
  26. data/spec/lib/pennmarc/helpers/inventory_spec.rb +0 -2
  27. data/spec/lib/pennmarc/helpers/language_spec.rb +0 -2
  28. data/spec/lib/pennmarc/helpers/link_spec.rb +0 -2
  29. data/spec/lib/pennmarc/helpers/location_spec.rb +0 -2
  30. data/spec/lib/pennmarc/helpers/note_spec.rb +22 -29
  31. data/spec/lib/pennmarc/helpers/production_spec.rb +121 -22
  32. data/spec/lib/pennmarc/helpers/relation_spec.rb +0 -2
  33. data/spec/lib/pennmarc/helpers/series_spec.rb +0 -2
  34. data/spec/lib/pennmarc/helpers/subject_spec.rb +16 -2
  35. data/spec/lib/pennmarc/helpers/title_spec.rb +20 -2
  36. data/spec/lib/pennmarc/marc_util_spec.rb +0 -2
  37. data/spec/lib/pennmarc/parser_spec.rb +1 -1
  38. data/spec/spec_helper.rb +7 -0
  39. data/spec/support/fixture_helpers.rb +10 -0
  40. metadata +4 -3
  41. data/spec/support/marc_spec_helpers.rb +0 -85
@@ -12,7 +12,7 @@ module PennMARC
12
12
  # {https://www.oclc.org/bibformats/en/5xx/580.html 580}, {https://www.oclc.org/bibformats/en/5xx/586.html 586},
13
13
  # {https://www.oclc.org/bibformats/en/5xx/588.html 588}
14
14
  # and their linked alternates.
15
- # @param [MARC::Record] record
15
+ # @param record [MARC::Record]
16
16
  # @return [Array<String>]
17
17
  def notes_show(record)
18
18
  notes_fields = %w[500 502 504 515 518 525 533 540 550 580 586 588]
@@ -27,7 +27,7 @@ module PennMARC
27
27
  # {https://www.oclc.org/bibformats/en/5xx/562.html 562}, {https://www.oclc.org/bibformats/en/5xx/563.html 563},
28
28
  # {https://www.oclc.org/bibformats/en/5xx/585.html 585}, {https://www.oclc.org/bibformats/en/5xx/590.html 590}.
29
29
  # Includes linked alternates except for 561.
30
- # @param [MARC::Record] record
30
+ # @param record [MARC::Record]
31
31
  # @return [Array<String>]
32
32
  def local_notes_show(record)
33
33
  local_notes = record.fields('561').filter_map do |field|
@@ -50,7 +50,7 @@ module PennMARC
50
50
  # prefixed subject field {https://www.oclc.org/bibformats/en/6xx/650.html 650} and its linked alternate.
51
51
  # Ignores 561 fields with subfield 'a' values that begin with 'Athenaeum copy: ' and 650 fields where subfield 'a'
52
52
  # does not have the prefix 'PRO'.
53
- # @param [MARC::Record] record
53
+ # @param record [MARC::Record]
54
54
  # @return [Array<String>]
55
55
  def provenance_show(record)
56
56
  provenance_notes = record.fields(%w[561 880]).filter_map do |field|
@@ -68,20 +68,25 @@ module PennMARC
68
68
  notes.uniq
69
69
  end
70
70
 
71
- # Retrieve contents notes for display from fields {https://www.oclc.org/bibformats/en/5xx/505.html 505} and
72
- # its linked alternate.
73
- # @param [MARC::Record] record
71
+ # Retrieve contents notes for display from fields {https://www.oclc.org/bibformats/en/5xx/505.html 505} and, if
72
+ # include_vernacular param is true, its linked alternate. Used for display and searching.
73
+ # @param record [MARC::Record]
74
+ # @param with_alternate [Boolean]
74
75
  # @return [Array<String>]
75
- def contents_show(record)
76
+ def contents_values(record, with_alternate: true)
76
77
  record.fields(%w[505 880]).filter_map { |field|
77
- next if field.tag == '880' && no_subfield_value_matches?(field, '6', /^505/)
78
+ if field.tag == '880'
79
+ next unless with_alternate
80
+
81
+ next if no_subfield_value_matches?(field, '6', /^505/)
82
+ end
78
83
 
79
84
  join_subfields(field, &subfield_not_in?(%w[6 8])).split('--')
80
85
  }.flatten.uniq
81
86
  end
82
87
 
83
88
  # Retrieve access restricted notes for display from field {https://www.oclc.org/bibformats/en/5xx/506.html 506}.
84
- # @param [MARC::Record] record
89
+ # @param record [MARC::Record]
85
90
  # @return [Array<String>]
86
91
  def access_restriction_show(record)
87
92
  record.fields('506').filter_map { |field|
@@ -91,7 +96,7 @@ module PennMARC
91
96
 
92
97
  # Retrieve finding aid notes for display from field {https://www.oclc.org/bibformats/en/5xx/555.html 555} and its
93
98
  # linked alternate.
94
- # @param [MARC::Record] record
99
+ # @param record [MARC::Record]
95
100
  # @return [Array<String>]
96
101
  def finding_aid_show(record)
97
102
  datafield_and_linked_alternate(record, '555')
@@ -99,7 +104,7 @@ module PennMARC
99
104
 
100
105
  # Retrieve participant notes for display from field {https://www.oclc.org/bibformats/en/5xx/511.html 511} and its
101
106
  # linked alternate.
102
- # @param [MARC::Record] record
107
+ # @param record [MARC::Record]
103
108
  # @return [Array<String>]
104
109
  def participant_show(record)
105
110
  datafield_and_linked_alternate(record, '511')
@@ -107,7 +112,7 @@ module PennMARC
107
112
 
108
113
  # Retrieve credits notes for display from field {https://www.oclc.org/bibformats/en/5xx/508.html 508} and its
109
114
  # linked alternate.
110
- # @param [MARC::Record] record
115
+ # @param record [MARC::Record]
111
116
  # @return [Array<String>]
112
117
  def credits_show(record)
113
118
  datafield_and_linked_alternate(record, '508')
@@ -115,7 +120,7 @@ module PennMARC
115
120
 
116
121
  # Retrieve biography notes for display from field {https://www.oclc.org/bibformats/en/5xx/545.html 545} and its
117
122
  # linked alternate.
118
- # @param [MARC::Record] record
123
+ # @param record [MARC::Record]
119
124
  # @return [Array<String>]
120
125
  def biography_show(record)
121
126
  datafield_and_linked_alternate(record, '545')
@@ -123,14 +128,14 @@ module PennMARC
123
128
 
124
129
  # Retrieve summary notes for display from field {https://www.oclc.org/bibformats/en/5xx/520.html 520} and its
125
130
  # linked alternate.
126
- # @param [MARC::Record] record
131
+ # @param record [MARC::Record]
127
132
  # @return [Array<String>]
128
133
  def summary_show(record)
129
134
  datafield_and_linked_alternate(record, '520')
130
135
  end
131
136
 
132
137
  # Retrieve arrangement values for display from field field {https://www.oclc.org/bibformats/en/3xx/351.html 351}.
133
- # @param [MARC::Record] record
138
+ # @param record [MARC::Record]
134
139
  # @return [Array<String>]
135
140
  def arrangement_show(record)
136
141
  datafield_and_linked_alternate(record, '351')
@@ -140,7 +145,7 @@ module PennMARC
140
145
  # {https://www.oclc.org/bibformats/en/3xx/344.html 344}, {https://www.oclc.org/bibformats/en/3xx/345.html 345},
141
146
  # {https://www.oclc.org/bibformats/en/3xx/346.html 346}, {https://www.oclc.org/bibformats/en/3xx/347.html 347},
142
147
  # and their linked alternates.
143
- # @param [MARC::Record] record
148
+ # @param record [MARC::Record]
144
149
  # @return [Array<String>]
145
150
  def system_details_show(record)
146
151
  system_details_notes = record.fields(%w[538 880]).filter_map do |field|
@@ -167,7 +172,7 @@ module PennMARC
167
172
  end
168
173
 
169
174
  # Retrieve "With" notes for display from field {https://www.loc.gov/marc/bibliographic/bd501.html 501}
170
- # @param [Marc::Record] record
175
+ # @param record [Marc::Record]
171
176
  # @return [Array<String>]
172
177
  def bound_with_show(record)
173
178
  record.fields('501').filter_map { |field| join_subfields(field, &subfield_in?(['a'])).presence }.uniq
@@ -177,8 +182,8 @@ module PennMARC
177
182
 
178
183
  # For system details: extract subfield ǂ3 plus other subfields as specified by passed-in block. Pays special
179
184
  # attention to punctuation, joining subfield ǂ3 values with a colon-space (': ').
180
- # @param [MARC::DataField] field
181
- # @param [Proc] &
185
+ # @param field [MARC::DataField]
186
+ # @param & [Proc]
182
187
  # @return [String]
183
188
  def sub3_and_other_subs(field, &)
184
189
  sub3 = field.filter_map { |sf| trim_trailing('period', sf.value) if sf.code == '3' }.join(': ')
@@ -4,31 +4,47 @@ module PennMARC
4
4
  # Extracts data related to a resource's production, distribution, manufacture, and publication.
5
5
  class Production < Helper
6
6
  class << self
7
- # Retrieve production values for display from {https://www.oclc.org/bibformats/en/2xx/264.html 264 field}.
8
- # @param [MARC::Record] record
7
+ # Retrieve production values for display from {https://www.loc.gov/marc/bibliographic/bd264.html 264 field}.
8
+ # @param record [MARC::Record]
9
9
  # @return [Array<String>]
10
10
  def show(record)
11
11
  get_264_or_880_fields(record, '0').uniq
12
12
  end
13
13
 
14
- # Retrieve distribution values for display from {https://www.oclc.org/bibformats/en/2xx/264.html 264 field}.
15
- # @param [MARC::Record] record
14
+ # Retrieve production values for searching. Includes only
15
+ # {https://www.loc.gov/marc/bibliographic/bd260.html 260} and
16
+ # {https://www.loc.gov/marc/bibliographic/bd264.html 264}.
17
+ # @param record [MARC::Record]
18
+ # @return [Array<String>]
19
+ def search(record)
20
+ values = record.fields('260').filter_map do |field|
21
+ join_subfields(field, &subfield_in?(['b']))
22
+ end
23
+ values + record.fields('264').filter_map { |field|
24
+ next unless field.indicator2 == '1'
25
+
26
+ join_subfields(field, &subfield_in?(['b']))
27
+ }.uniq
28
+ end
29
+
30
+ # Retrieve distribution values for display from {https://www.loc.gov/marc/bibliographic/bd264.html 264 field}.
31
+ # @param record [MARC::Record]
16
32
  # @return [Array<String>]
17
33
  def distribution_show(record)
18
34
  get_264_or_880_fields(record, '2').uniq
19
35
  end
20
36
 
21
- # Retrieve manufacture values for display from {https://www.oclc.org/bibformats/en/2xx/264.html 264 field}.
22
- # @param [MARC::Record] record
37
+ # Retrieve manufacture values for display from {https://www.loc.gov/marc/bibliographic/bd264.html 264 field}.
38
+ # @param record [MARC::Record]
23
39
  # @return [Array<String>]
24
40
  def manufacture_show(record)
25
41
  get_264_or_880_fields(record, '3').uniq
26
42
  end
27
43
 
28
44
  # Retrieve publication values. Return publication values from
29
- # {https://www.oclc.org/bibformats/en/2xx/264.html 264 field} only if none found
30
- # {https://www.oclc.org/bibformats/en/2xx/260.html 260}-262 fields.
31
- # @param [MARC::Record] record
45
+ # {https://www.loc.gov/marc/bibliographic/bd264.html 264 field} only if none found
46
+ # {https://www.loc.gov/marc/bibliographic/bd260.html 260}-262 fields.
47
+ # @param record [MARC::Record]
32
48
  # @return [Array<String>]
33
49
  def publication_values(record)
34
50
  # first get inclusive dates
@@ -64,10 +80,10 @@ module PennMARC
64
80
  end
65
81
 
66
82
  # Retrieve publication values for display from fields
67
- # {https://www.oclc.org/bibformats/en/2xx/245.html 245},
68
- # {https://www.oclc.org/bibformats/en/2xx/260.html 260}-262 and their linked alternates,
69
- # and {https://www.oclc.org/bibformats/en/2xx/264.html 264} and its linked alternate.
70
- # @param [MARC::Record] record
83
+ # {https://www.loc.gov/marc/bibliographic/bd245.html 245},
84
+ # {https://www.loc.gov/marc/bibliographic/bd260.html 260}-262 and their linked alternates,
85
+ # and {https://www.loc.gov/marc/bibliographic/bd264.html 264} and its linked alternate.
86
+ # @param record [MARC::Record]
71
87
  # @return [Array<String>]
72
88
  def publication_show(record)
73
89
  values = record.fields('245').first(1).flat_map { |field| subfield_values(field, 'f') }
@@ -89,10 +105,49 @@ module PennMARC
89
105
  values.compact_blank.uniq
90
106
  end
91
107
 
92
- # Retrieve place of publication for display from {https://www.oclc.org/bibformats/en/7xx/752.html 752 field} and
108
+ # Retrieve publication values for citation
109
+ # {https://www.loc.gov/marc/bibliographic/bd245.html 245},
110
+ # {https://www.loc.gov/marc/bibliographic/bd260.html 260}-262 and their linked alternates,
111
+ # and {https://www.loc.gov/marc/bibliographic/bd264.html 264} and its linked alternate.
112
+ # @param [MARC::Record] record
113
+ # @param [Boolean] with_year: return results with publication year if true
114
+ # @return [Array<String>]
115
+ def publication_citation_show(record, with_year: true)
116
+ values = record.fields('245').first(1).flat_map { |field| subfield_values(field, 'f') }
117
+
118
+ subfields = with_year ? %w[6 8] : %w[6 8 c]
119
+ values += record.fields(%w[260 261 262]).first(1).map do |field|
120
+ join_subfields(field, &subfield_not_in?(subfields))
121
+ end
122
+
123
+ subfields = with_year ? %w[a b c] : %w[a b]
124
+ values += record.fields('264').filter_map do |field|
125
+ next unless field.indicator2 == '1'
126
+
127
+ join_subfields(field, &subfield_in?(subfields))
128
+ end
129
+
130
+ values.compact_blank.uniq
131
+ end
132
+
133
+ # Returns the place of publication for RIS
134
+ # @param [MARC::Record] record
135
+ # @return [Array<String>]
136
+ def publication_ris_place_of_pub(record)
137
+ get_publication_ris_values(record, 'a')
138
+ end
139
+
140
+ # Returns the publisher for RIS
141
+ # @param [MARC::Record] record
142
+ # @return [Array<String>]
143
+ def publication_ris_publisher(record)
144
+ get_publication_ris_values(record, 'b')
145
+ end
146
+
147
+ # Retrieve place of publication for display from {https://www.loc.gov/marc/bibliographic/bd752.html 752 field} and
93
148
  # its linked alternate.
94
149
  # @note legacy version returns array of hash objects including data for display link
95
- # @param [MARC::Record] record
150
+ # @param record [MARC::Record]
96
151
  # @return [Array<String>]
97
152
  def place_of_publication_show(record)
98
153
  record.fields(%w[752 880]).filter_map { |field|
@@ -104,13 +159,32 @@ module PennMARC
104
159
  }.uniq
105
160
  end
106
161
 
162
+ # Retrieves place of publication values for searching. Includes
163
+ # {https://www.loc.gov/marc/bibliographic/bd752.html 752} as well as sf a from
164
+ # {https://www.loc.gov/marc/bibliographic/bd260.html 260} and
165
+ # {https://www.loc.gov/marc/bibliographic/bd264.html 264} with an indicator2 of 1.
166
+ # @param record [MARC::Record]
167
+ # @return [Array<String>]
168
+ def place_of_publication_search(record)
169
+ values = record.fields('260').filter_map do |field|
170
+ join_subfields(field, &subfield_in?(['a']))
171
+ end
172
+ values += record.fields('264').filter_map do |field|
173
+ next unless field.indicator2 == '1'
174
+
175
+ join_subfields(field, &subfield_in?(['a']))
176
+ end
177
+ values + record.fields('752').filter_map { |field|
178
+ join_subfields(field, &subfield_in?(%w[a b c d f g h]))
179
+ }.uniq
180
+ end
181
+
107
182
  private
108
183
 
109
- # base method to retrieve production values from {https://www.oclc.org/bibformats/en/2xx/264.html 264 field} based
110
- # on indicator2.
111
- # distribution and manufacture share the same logic except for indicator2
112
- # @param [MARC::Record] record
113
- # @param [String] indicator2
184
+ # base method to retrieve production values from {https://www.loc.gov/marc/bibliographic/bd264.html 264 field}
185
+ # based on indicator2. "Distribution" and "manufacture" share the same logic except for indicator2.
186
+ # @param record [MARC::Record]
187
+ # @param indicator2 [String]
114
188
  # @return [Array<String>]
115
189
  def get_264_or_880_fields(record, indicator2)
116
190
  values = record.fields('264').filter_map do |field|
@@ -126,6 +200,25 @@ module PennMARC
126
200
  join_subfields(field, &subfield_in?(%w[a b c]))
127
201
  end
128
202
  end
203
+
204
+ # Returns the publication value of the given subfield
205
+ # @param [MARC::Record] record
206
+ # @param [String] subfield
207
+ def get_publication_ris_values(record, subfield)
208
+ values = record.fields('245').first(1).flat_map { |field| subfield_values(field, 'f') }
209
+
210
+ values += record.fields(%w[260 261 262]).first(1).map do |field|
211
+ join_subfields(field, &subfield_in?([subfield]))
212
+ end
213
+
214
+ values += record.fields('264').filter_map do |field|
215
+ next unless field.indicator2 == '1'
216
+
217
+ join_subfields(field, &subfield_in?([subfield]))
218
+ end
219
+
220
+ values.compact_blank.uniq
221
+ end
129
222
  end
130
223
  end
131
224
  end
@@ -18,7 +18,7 @@ module PennMARC
18
18
  # - 2: MeSH
19
19
  # - 4: Source not specified (local?)
20
20
  # - 7: Source specified in ǂ2
21
- SEARCH_SOURCE_INDICATORS = %w[0 1 2 4 7].freeze
21
+ VALID_SOURCE_INDICATORS = %w[0 1 2 4 7].freeze
22
22
 
23
23
  # Tags that serve as sources for Subject facet values
24
24
  DISPLAY_TAGS = %w[600 610 611 630 650 651].freeze
@@ -27,7 +27,7 @@ module PennMARC
27
27
  LOCAL_TAGS = %w[690 691 697].freeze
28
28
 
29
29
  # All Subjects for searching. This includes most subfield content from any field contained in {SEARCH_TAGS} or
30
- # 69X, including any linked 880 fields. Fields must have an indicator2 value in {SEARCH_SOURCE_INDICATORS}.
30
+ # 69X, including any linked 880 fields. Fields must have an indicator2 value in {VALID_SOURCE_INDICATORS}.
31
31
  # @todo this includes subfields that may not be desired like 1 (uri) and 2 (source code) but this might be OK for
32
32
  # a search (non-display) field?
33
33
  # @param [Hash] relator_map
@@ -179,12 +179,18 @@ module PennMARC
179
179
  end
180
180
  end
181
181
 
182
- # Is a field intended for display in a general subject field
182
+ # Is a field intended for display in a general subject field? To be included, the field tag is in either
183
+ # {DISPLAY_TAGS} or {LOCAL_TAGS}, and has an indicator 2 value that is in {VALID_SOURCE_INDICATORS}. If
184
+ # indicator 2 is '7' - indicating "source specified", the specified source must be in our approved source code
185
+ # list.
186
+ # @see Util.valid_subject_genre_source_code?
183
187
  # @param [MARC::DataField] field
184
188
  # @return [Boolean] whether a MARC field is intended for display under general "Subjects"
185
189
  def subject_general_display_field?(field)
186
190
  return false unless field.tag.in?(DISPLAY_TAGS + LOCAL_TAGS) && field.respond_to?(:indicator2)
187
191
 
192
+ return false if field.indicator2.present? && !field.indicator2.in?(VALID_SOURCE_INDICATORS)
193
+
188
194
  return false if field.indicator2 == '7' && !valid_subject_genre_source_code?(field)
189
195
 
190
196
  true
@@ -278,7 +284,7 @@ module PennMARC
278
284
  # @param [MARC::DataField] field
279
285
  # @return [Boolean]
280
286
  def subject_search_field?(field)
281
- return false unless field.respond_to?(:indicator2) && SEARCH_SOURCE_INDICATORS.include?(field.indicator2)
287
+ return false unless field.respond_to?(:indicator2) && VALID_SOURCE_INDICATORS.include?(field.indicator2)
282
288
 
283
289
  tag = if field.tag == '880'
284
290
  subfield_values(field, '6').first
@@ -3,33 +3,36 @@
3
3
  module PennMARC
4
4
  # This helper contains logic for parsing out Title and Title-related fields.
5
5
  class Title < Helper
6
- class << self
7
- # We use these fields when retrieving auxiliary titles in the *search_aux methods:
8
- # {https://www.loc.gov/marc/bibliographic/bd130.html 130},
9
- # {https://www.loc.gov/marc/bibliographic/bd210.html 210},
10
- # {https://www.loc.gov/marc/bibliographic/bd245.html 245},
11
- # {https://www.loc.gov/marc/bibliographic/bd246.html 246},
12
- # {https://www.loc.gov/marc/bibliographic/bd247.html 247},
13
- # {https://www.loc.gov/marc/bibliographic/bd440.html 440},
14
- # {https://www.loc.gov/marc/bibliographic/bd490.html 490},
15
- # {https://www.loc.gov/marc/bibliographic/bd730.html 730},
16
- # {https://www.loc.gov/marc/bibliographic/bd740.html 740},
17
- # {https://www.loc.gov/marc/bibliographic/bd830.html 830},
18
- # {https://www.loc.gov/marc/bibliographic/bd773.html 773},
19
- # {https://www.loc.gov/marc/bibliographic/bd774.html 774},
20
- # {https://www.loc.gov/marc/bibliographic/bd780.html 780},
21
- # {https://www.loc.gov/marc/bibliographic/bd785.html 785},
22
- # {https://www.loc.gov/marc/bibliographic/bd700.html 700},
23
- # {https://www.loc.gov/marc/bibliographic/bd710.html 710},
24
- # {https://www.loc.gov/marc/bibliographic/bd711.html 711},
25
- # {https://www.loc.gov/marc/bibliographic/bd505.html 505}
26
- AUX_TITLE_TAGS = {
27
- main: %w[130 210 240 245 246 247 440 490 730 740 830],
28
- related: %w[773 774 780 785],
29
- entity: %w[700 710 711],
30
- note: %w[505]
31
- }.freeze
6
+ # We use these fields when retrieving auxiliary titles in the *search_aux methods:
7
+ # {https://www.loc.gov/marc/bibliographic/bd130.html 130},
8
+ # {https://www.loc.gov/marc/bibliographic/bd210.html 210},
9
+ # {https://www.loc.gov/marc/bibliographic/bd245.html 245},
10
+ # {https://www.loc.gov/marc/bibliographic/bd246.html 246},
11
+ # {https://www.loc.gov/marc/bibliographic/bd247.html 247},
12
+ # {https://www.loc.gov/marc/bibliographic/bd440.html 440},
13
+ # {https://www.loc.gov/marc/bibliographic/bd490.html 490},
14
+ # {https://www.loc.gov/marc/bibliographic/bd730.html 730},
15
+ # {https://www.loc.gov/marc/bibliographic/bd740.html 740},
16
+ # {https://www.loc.gov/marc/bibliographic/bd830.html 830},
17
+ # {https://www.loc.gov/marc/bibliographic/bd773.html 773},
18
+ # {https://www.loc.gov/marc/bibliographic/bd774.html 774},
19
+ # {https://www.loc.gov/marc/bibliographic/bd780.html 780},
20
+ # {https://www.loc.gov/marc/bibliographic/bd785.html 785},
21
+ # {https://www.loc.gov/marc/bibliographic/bd700.html 700},
22
+ # {https://www.loc.gov/marc/bibliographic/bd710.html 710},
23
+ # {https://www.loc.gov/marc/bibliographic/bd711.html 711},
24
+ # {https://www.loc.gov/marc/bibliographic/bd505.html 505}
25
+ AUX_TITLE_TAGS = {
26
+ main: %w[130 210 240 245 246 247 440 490 730 740 830],
27
+ related: %w[773 774 780 785],
28
+ entity: %w[700 710 711],
29
+ note: %w[505]
30
+ }.freeze
31
+
32
+ # This text is used in Alma to indicate a Bib record is a "Host" record for other bibs (bound-withs)
33
+ HOST_BIB_TITLE = 'Host bibliographic record for boundwith'
32
34
 
35
+ class << self
33
36
  # Main Title Search field. Takes from {https://www.loc.gov/marc/bibliographic/bd245.html 245} and linked 880.
34
37
  # @note Ported from get_title_1_search_values.
35
38
  # @param [MARC::Record] record
@@ -217,6 +220,16 @@ module PennMARC
217
220
  }.uniq
218
221
  end
219
222
 
223
+ # Determine if the record is a "Host" bibliographic record for other bib records ("bound-withs")
224
+ # @param [MARC::Record] record
225
+ # @return [Boolean]
226
+ def host_bib_record?(record)
227
+ record.fields('245').any? do |f|
228
+ title = join_subfields(f, &subfield_in?(%w[a]))
229
+ title.include?(HOST_BIB_TITLE)
230
+ end
231
+ end
232
+
220
233
  private
221
234
 
222
235
  # Create prefix/filing hash for representing a title value with filing characters removed, with special
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'nokogiri'
4
+ require 'marc'
5
+
6
+ module PennMARC
7
+ module Test
8
+ # Helper methods for use in constructing MARC objects for testing
9
+ module MarcHelpers
10
+ # Return a MARC::XMLReader that will parse a given file and return MARC::Record objects
11
+ # @param [String] filename of MARCXML fixture
12
+ # @return [MARC::Record, NilClass]
13
+ def record_from(filename)
14
+ MARC::XMLReader.new(marc_xml_path(filename)).first
15
+ end
16
+
17
+ # Create an isolated MARC::Subfield object for use in specs or as part of a MARC::Field
18
+ # @param [String] code
19
+ # @param [String] value
20
+ # @return [MARC::Subfield]
21
+ def marc_subfield(code, value)
22
+ MARC::Subfield.new code.to_s, value
23
+ end
24
+
25
+ # Return a new ControlField (000-009)
26
+ # @param [String] tag
27
+ # @param [String] value
28
+ # @return [MARC::ControlField]
29
+ def marc_control_field(tag:, value:)
30
+ MARC::ControlField.new tag, value
31
+ end
32
+
33
+ # Create an isolated MARC::DataField object for use in specs
34
+ # Can pass in tag, indicators and subfields (using simple hash structure). E.g.,
35
+ # marc_field(tag: '650', indicator2: '7'),
36
+ # subfields: { a: 'Tax planning',
37
+ # m: ['Multiple', 'Subfields']
38
+ # z: 'United States.',
39
+ # '0': http://id.loc.gov/authorities/subjects/sh2008112546 }
40
+ # )
41
+ # @param [String (frozen)] tag MARC tag, e.g., 001, 665
42
+ # @param [String (frozen)] indicator1 MARC indicator, e.g., 0
43
+ # @param [String (frozen)] indicator2
44
+ # @param [Hash] subfields hash of subfield values as code => value or code => [value, value]
45
+ # @return [MARC::DataField]
46
+ def marc_field(tag: 'TST', indicator1: ' ', indicator2: ' ', subfields: {})
47
+ subfield_objects = subfields.each_with_object([]) do |(code, value), array|
48
+ Array.wrap(value).map { |v| array << marc_subfield(code, v) }
49
+ end
50
+ MARC::DataField.new tag, indicator1, indicator2, *subfield_objects
51
+ end
52
+
53
+ # Return a MARC::Record containing passed in DataFields
54
+ # @param [Array<MARC::DataField>] fields
55
+ # @param [String, nil] leader
56
+ # @return [MARC::Record]
57
+ def marc_record(fields: [], leader: nil)
58
+ record = MARC::Record.new
59
+ fields.each { |field| record << field }
60
+ record.leader = leader if leader
61
+ record
62
+ end
63
+
64
+ # Mock map for location lookup using Location helper
65
+ # The location codes :dent and :stor are the two outermost keys
66
+ # :specific_location, :library, :display are the inner keys that store location values
67
+ # @example
68
+ # location_map[:stor][:library] #=> 'LIBRA'
69
+ # @return [Hash]
70
+ def location_map
71
+ { dent: { specific_location: 'Levy Dental Medicine Library - Stacks',
72
+ library: ['Health Sciences Libraries', 'Levy Dental Medicine Library'],
73
+ display: 'Levy Dental Medicine Library - Stacks' },
74
+ stor: { specific_location: 'LIBRA',
75
+ library: 'LIBRA',
76
+ display: 'LIBRA' },
77
+ vanp: { specific_location: 'Van Pelt - Stacks',
78
+ library: 'Van Pelt-Dietrich Library Center',
79
+ display: 'Van Pelt Library' } }
80
+ end
81
+ end
82
+ end
83
+ end