pennmarc 1.0.24 → 1.0.26

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