• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pulibrary / bibdata / 373ad6ff-fad2-405a-ab26-3d30fb5ceecf

24 Dec 2024 08:24PM UTC coverage: 91.938% (+0.08%) from 91.859%
373ad6ff-fad2-405a-ab26-3d30fb5ceecf

Pull #2563

circleci

maxkadel
Put attaching xml files in their own batch
Pull Request #2563: I2321 Shift SCSB full index tasks into separate background jobs

152 of 156 new or added lines in 10 files covered. (97.44%)

65 existing lines in 17 files now uncovered.

3478 of 3783 relevant lines covered (91.94%)

366.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.66
/marc_to_solr/lib/format/bib_types.rb
1
require 'traject/macros/marc21_semantics'
1✔
2
require_relative '../format/xv6xx'
1✔
3

4
# Determine the "types" of material represented by the bib record.
5
# The comments below come from the Ex Libris Aleph system and represent
6
# the logic used within it to determine types. This file is based
7
# on the logic use at the University of Michigan
8

9
class BibTypes
1✔
10
  attr_reader :bib_format, :record
1✔
11

12
  def initialize(bib_format, record)
1✔
13
    @bib_format = bib_format
188✔
14
    @record = record
188✔
15
    # Memoize values, since many of them are used several times
16
    @spec_vals = Hash.new { |h, spec_string| h[spec_string] = Traject::MarcExtractor.new(spec_string).extract(@record) }
1,713✔
17

18
    # Need these a lot -- the sub x and v from any 6XX field
19
    @xv6XX = XV6XX.new(@record)
188✔
20
  end
21

22
  def codes
1✔
23
    codes = []
188✔
24
    codes.concat self.video_types
188✔
25
    codes.concat self.audio_types
188✔
26
    codes.concat self.microform_types
188✔
27
    codes.concat self.musical_score_types
188✔
28
    codes.concat self.map_types
188✔
29
    codes.concat self.serial_types
188✔
30
    codes.concat self.mixed_types
188✔
31
    codes.concat self.software_types
188✔
32
    codes.concat self.statistics_types
188✔
33
    codes.concat self.conference_types
188✔
34
    codes.concat self.biography_types
188✔
35
    codes.concat self.reference_types
188✔
36
    codes.concat self.pp_types
188✔
37
    codes.concat self.videogame_types
188✔
38

39
    codes.uniq!
188✔
40
    codes.compact!
188✔
41

42
    codes
188✔
43
  end
44

45
  # Provide memoized values for on-the-fly created MarcExtractor
46
  # objects
47
  #
48
  # @param [String] spec_string A Traject::MarcExtractor-compatible spec string
49
  # @return [Array<String>] The strings in the specified subfields/byterange/whatever
50
  def [](spec_string)
1✔
51
    @spec_vals[spec_string]
2,087✔
52
  end
53

54
  ### Video stuff
55

56
  # TYP   VB Video (Blu-ray)                538## a          MATCH      *Blu-ray*
57
  # TYP   VB Video (Blu-ray)                007   F00-05     MATCH      v???s
58
  # TYP   VB Video (Blu-ray)                250## a          MATCH      *Blu-ray*
59
  # TYP   VB Video (Blu-ray)                852## j          MATCH      video-b*
60
  # TYP   VB Video (Blu-ray)                852## j          MATCH      bd-rom*
61
  #
62
  # TYP   VD Video (DVD)                    538## a          MATCH      DVD*
63
  # TYP   VD Video (DVD)                    007   F04-01     EQUAL      v
64
  #                                         007   F00-01     EQUAL      v
65
  # TYP   VD Video (DVD)                    007   F04-01     EQUAL      v
66
  #                                         008   F33-01     EQUAL      v
67
  # !
68
  # ! Visual material: vHs
69
  # TYP   VH Video (VHS)                    538## a          MATCH      VHS*
70
  # TYP   VH Video (VHS)                    007   F04-01     EQUAL      b
71
  #                                         007   F00-01     EQUAL      v
72
  # TYP   VH Video (VHS)                    007   F04-01     EQUAL      b
73
  #                                         008   F33-01     EQUAL      v
74
  # !
75
  # ! Visual materials: fiLm/video
76
  # TYP   VL Motion Picture                 007   F00-01     EQUAL      m
77
  # TYP   VL Motion Picture                 FMT   F00-02     EQUAL      VM
78
  #                                         008   F33-01     EQUAL      m
79

80
  def video_types
1✔
81
    types = []
188✔
82

83
    types << 'VB' if self['538a:250a'].grep(/blu-ray/i).size > 0
188✔
84
    types << 'VB' if self['007[0-5]'].grep(/v...s/i).size > 0
188✔
85
    types << 'VB' if self['852j'].grep(/\A(?:bd-rom|video-b)/i).size > 0
188✔
86

87
    @record.fields('007').map { |f| f.value }.each do |f|
215✔
88
      if (f[0] == 'v') || self['008[33]'].include?('v')
27✔
89
        types << 'VD' if f[4] == 'v'
2✔
90
        types << 'VH' if f[4] == 'b'
2✔
91
      end
92
    end
93

94
    types << 'VD' if self['538a'].grep(/\Advd(?!\-rom)/i).size > 0
188✔
95

96
    types << 'VH' if self['538a'].grep(/\AVHS/i).size > 0
188✔
97

98
    types << 'VL' if self['007[0]'].include?('m')
188✔
99
    types << 'VL' if (self.bib_format == 'VM') && self['008[33]'].include?('m')
188✔
100

101
    types.uniq!
188✔
102
    return types
188✔
103
  end
104

105
  # Audio/music
106
  # ! Recording: Compact disc
107
  # TYP   RC Audio CD                       LDR   F06-01     EQUAL      [i,j]
108
  #                                         FMT   F00-02     EQUAL      MU
109
  #                                         007   F01-01     EQUAL      d
110
  #                                         007   F12-01     EQUAL      e
111
  # TYP   RC Audio CD                       8524  j          MATCH      CD*
112
  #                                         8524  b          EQUAL      MUSIC
113
  # !
114
  # ! Recording: LP record
115
  # TYP   RL Audio LP                       LDR   F06-01     EQUAL      [i,j]
116
  #                                         FMT   F00-02     EQUAL      MU
117
  #                                         007   F01-01     EQUAL      d
118
  #                                         300   a          MATCH      *SOUND DISC*
119
  #                                         300   b          MATCH      *33 1/3 RPM*
120
  #
121
  # TYP   RL Audio LP                       8524  j          MATCH      LP*
122
  #                                         8524  c          EQUAL      MUSI
123
  # TYP   RL Audio LP                       8524  j          MATCH      LP*
124
  #                                         8524  b          EQUAL      MUSIC
125
  # !
126
  # ! Recording: Music
127
  # TYP   RM Audio (music)                  LDR   F06-01     EQUAL      j
128
  #                                         FMT   F00-02     EQUAL      MU
129
  # !
130
  # ! Recording: Spoken word
131
  # TYP   RS Audio (spoken word)            LDR   F06-01     EQUAL      i
132
  #                                         FMT   F00-02     EQUAL      MU
133
  # !
134
  # ! Recording: Undefined
135
  # TYP   RU Audio                          LDR   F06-01     EQUAL      [i,j]
136
  #                                         FMT   F00-02     EQUAL      MU
137
  #
138

139
  def audio_types
1✔
140
    ldr6 = record.leader[6]
188✔
141

142
    types = []
188✔
143

144
    # Get the 8524* fields
145
    f8524 = record.fields('852').select { |f| f.indicator1 == '4' }
575✔
146

147
    # RC
148
    if %w[i j].include?(ldr6) && (bib_format == 'MU')
188✔
149
      @record.fields('007').map { |f| f.value }.each do |f|
×
150
        if f[1] == 'd' && f[12] == 'e'
×
151
          types << 'RC'
×
152
          break
×
153
        end
154
      end
155
    end
156

157
    f8524.each do |f|
188✔
158
      if (f['b']&.upcase == 'MUSIC') && (f['j'] =~ /\ACD/i)
×
159
        types << 'RC'
×
160
        break
×
161
      end
162
    end
163

164
    # RL
165

166
    if (bib_format == 'MU') && %w[i j].include?(ldr6) && self['007[1]'].include?('d')
188✔
167
      record.fields('300').each do |f|
×
168
        str = f.subfields.collect { |s| s.value }.join(' ')
×
169
        if (str =~ /DISC/i) && str =~ /33 1\/3 RPM/i
×
170
          types << 'RL'
×
171
          break
×
172
        end
173
      end
174
    end
175

176
    f8524.each do |f|
188✔
177
      if  (f['j'] =~ /\ALP/i) &&
×
178
          ((f['b'].upcase == 'MUSIC') || (f['c'].upcase == 'MUSI'))
×
179
        types << 'RL'
×
180
        break
×
181
      end
182
    end
183

184
    # RM
185
    types << 'RM' if (ldr6 == 'j') && (bib_format == 'MU')
188✔
186

187
    # RS
188
    types << 'RS' if (ldr6 == 'i') && (bib_format == 'MU')
188✔
189

190
    # RU
191
    types << 'RU' if %w[i j].include?(ldr6) && (bib_format == 'MU')
188✔
192

193
    types.uniq!
188✔
194
    return types
188✔
195
  end
196

197
  # Microform
198
  # ! MicroForms
199
  # TYP   WM Microform                      FMT   F00-02     EQUAL      BK
200
  #                                         008   F23-01     EQUAL      [a,b,c]
201
  # TYP   WM Microform                      FMT   F00-02     EQUAL      MU
202
  #                                         008   F23-01     EQUAL      [a,b,c]
203
  # TYP   WM Microform                      FMT   F00-02     EQUAL      SE
204
  #                                         008   F23-01     EQUAL      [a,b,c]
205
  # TYP   WM Microform                      FMT   F00-02     EQUAL      MX
206
  #                                         008   F23-01     EQUAL      [a,b,c]
207

208
  # TYP   WM Microform                      245## h          MATCH      *micro*
209

210
  # TYP   WM Microform                      FMT   F00-02     EQUAL      MP
211
  #                                         008   F29-01     EQUAL      [a,b,c]
212
  # TYP   WM Microform                      FMT   F00-02     EQUAL      VM
213
  #                                         008   F29-01     EQUAL      [a,b,c]
214

215
  def microform_types
1✔
216
    return [] unless record['008']
188✔
217
    types = ['WM']
121✔
218
    f8_23 = record['008'].value[23]
121✔
219
    return types if %w[BK MU SE MX].include?(bib_format) && %w[a b c].include?(f8_23)
121✔
220

221
    f8_29 = record['008'].value[29]
121✔
222
    return types if %w[MP VM].include?(bib_format) && %w[a b c].include?(f8_29)
121✔
223

224
    return types if record['245'] && (record['245']['h'] =~ /micro/i)
121✔
225

226
    # Nope. Not microform
227
    return []
121✔
228
  end
229

230
  # ! Musical Score
231
  # TYP   MS Musical Score                  LDR   F06-01     EQUAL      [c,d]
232

233
  def musical_score_types
1✔
234
    types = []
188✔
235
    types << 'MS' if %w[c d].include?(record.leader[6])
188✔
236
    return types
188✔
237
  end
238

239
  # ! Maps: Numerous
240
  # TYP   MN Maps-Atlas                     FMT   F00-02     EQUAL      MP
241
  # TYP   MN Maps-Atlas                     LDR   F06-01     EQUAL      [e,f]
242
  # TYP   MN Maps-Atlas                     007   F00-01     EQUAL      a
243
  # !
244
  # ! Maps: One (commented out as per Judy Ahronheim as this TYP duplicates MN)
245
  # !TYP   MO Map                            FMT   F00-02     EQUAL      MP
246
  # !TYP   MO Map                            007   F00-01     EQUAL      a
247

248
  def map_types
1✔
249
    types = []
188✔
250
    types << 'MN' if (bib_format == 'MP') || %w[e f].include?(record.leader[6]) || self['007[0]'].include?('a')
188✔
251
    return types
188✔
252
  end
253

254
  # Serials
255
  # ! serial: A Journal
256
  # TYP   AJ Journal                        FMT   F00-02     EQUAL      SE
257
  #                                         008   F21-01     EQUAL      p
258
  #                                         008   F22-01     EQUAL      [^,a,b,c,d,f,g,h,i,s,x,z,|]
259
  #                                         008   F29-01     EQUAL      [0,|]
260
  # TYP   AJ Journal                        FMT   F00-02     EQUAL      SE
261
  #                                         008   F21-01     EQUAL      [^,d,l,m,p,w,|]
262
  #                                         008   F22-01     EQUAL      [^,a,b,c,d,f,g,h,i,s,x,z,|]
263
  #                                         008   F24-01     EQUAL      [a,b,g,m,n,o,p,s,w,x,y,^]
264
  #                                         008   F29-01     EQUAL      [0,|]
265
  # !
266
  # ! serial: A Newspaper
267
  # TYP   AN Newspaper                      FMT   F00-02     EQUAL      SE
268
  #                                         008   F21-01     EQUAL      n
269
  # TYP   AN Newspaper                      FMT   F00-02     EQUAL      SE
270
  #                                         008   F22-01     EQUAL      e
271
  #
272
  # ! serial: All, including serials with other FMT codes
273
  # TYP   SX All Serials                    LDR   F07-01     EQUAL      [b,s]
274

275
  # Wrap it all up in serial_types
276
  def serial_types
1✔
277
    types = []
188✔
278
    types << 'SX' if %w[b s].include?(record.leader[7])
188✔
279
    types.concat journal_types
188✔
280
    types.concat newspaper_types
188✔
281
    types.uniq!
188✔
282
    return types
188✔
283
  end
284

285
  def journal_types
1✔
286
    types = []
188✔
287
    # gotta be SE and have a 008
288
    return types unless (bib_format == 'SE') && record['008']
188✔
289

290
    # We need lots of chars from the 008
UNCOV
291
    f8 = record['008'].value
×
292

UNCOV
293
    if  (f8[21] == 'p') &&
×
294
        [' ', 'a', 'b', 'c', 'd', 'f', 'g', 'h', 'i', 's', 'x', 'z', '|'].include?(f8[22]) &&
295
        ['0', '|'].include?(f8[29])
UNCOV
296
      types << 'AJ'
×
297
    end
298

UNCOV
299
    if  [' ', 'd', 'l', 'm', 'p', 'w', '|'].include?(f8[21]) &&
×
300
        [' ', 'a', 'b', 'c', 'd', 'f', 'g', 'h', 'i', 's', 'x', 'z', '|'].include?(f8[22]) &&
301
        ['a', 'b', 'g', 'm', 'n', 'o', 'p', 's', 'w', 'x', 'y', ' '].include?(f8[24]) &&
302
        ['0', '|'].include?(f8[29])
UNCOV
303
      types << 'AJ'
×
304
    end
305

UNCOV
306
    types.uniq!
×
307
    return types
×
308
  end
309

310
  def newspaper_types
1✔
311
    types = []
188✔
312
    types << 'AN' if (bib_format == 'SE') && record['008'] &&
188✔
UNCOV
313
                     ((record['008'].value[21] == 'n') || (record['008'].value[22] == 'e'))
×
314
    return types
188✔
315
  end
316

317
  # ! Mixed material: archi-V-e
318
  # TYP   MV Archive                        FMT   F00-02     EQUAL      MX
319
  # TYP   MV Archive                        LDR   F08-01     EQUAL      a
320
  # !
321
  # ! Mixed material: manuscript
322
  # TYP   MW Manuscript                     LDR   F06-01     EQUAL      [d,f,p,t]
323

324
  def mixed_types
1✔
325
    types = []
188✔
326
    types << 'MV' if (bib_format == 'MX') || (record.leader[8] == 'a')
188✔
327
    types << 'MW' if %w[d f p t].include?(record.leader[6])
188✔
328
    return types
188✔
329
  end
330

331
  # TYP   CR CDROM                          852## j          MATCH      cd-rom*
332
  # TYP   CR CDROM                          852## j          MATCH      cdrom*
333
  # TYP   CR CDROM                          852## j          MATCH      cd-rom*
334
  # TYP   CS Software                       852## j          MATCH      software*
335

336
  def software_types
1✔
337
    types = []
188✔
338
    self['852j'].each do |j|
188✔
339
      types << 'CR' if /\Acd-?rom/i.match?(j)
3✔
340
      types << 'CS' if /\Asoftware/i.match?(j)
3✔
341
    end
342
    types.uniq!
188✔
343
    return types
188✔
344
  end
345

346
  # ! X (no icon) - Conference
347
  # TYP   XC Conference                     008   F29-01     EQUAL      1
348
  # TYP   XC Conference                     111##            EXIST
349
  # TYP   XC Conference                     711##            EXIST
350
  # TYP   XC Conference                     811##            EXIST
351
  # TYP   XC Conference                     FMT   F00-02     EQUAL      CF
352
  #                                         006   F00-01     EQUAL      [a,s]
353
  #                                         006   F12-01     EQUAL      1
354
  # TYP   XC Conference                     FMT   F00-02     EQUAL      MU
355
  #                                         008   F30-01     EQUAL      c
356
  # TYP   XC Conference                     FMT   F00-02     EQUAL      MU
357
  #                                         008   F31-01     EQUAL      c
358
  # ! additional types defined for vufind extract
359
  # TYP   XC Conference                     6#### xv         MATCH      *congresses*
360

361
  def conference_types
1✔
362
    # Get the easy stuff done first
363

364
    return ['XC'] if (record['008'] && (record['008'].value[29] == '1')) || record.fields(['111', '711', '811']).size > 0
188✔
365

366
    if (bib_format == 'CF')
182✔
UNCOV
367
      @record.fields('006').map { |f| f.value }.each do |f|
×
368
        return ['XC'] if %w[a s].include?(f[0]) && (f[12] == '1')
×
369
      end
370
    end
371

372
    if  (bib_format == 'MU') && record['008'] &&
182✔
UNCOV
373
        (record['008'].value[30..31] =~ /c/)
×
374
      return ['XC']
×
375
    end
376

377
    return ['XC'] if @xv6XX.match? /congresses/i
182✔
378

379
    # Nope.
380
    return []
182✔
381
  end
382

383
  # ! X (no icon) - Statistics
384
  # TYP   XS Statistics                     650## x          MATCH      Statistic*
385
  # TYP   XS Statistics                     6#### x          MATCH      Statistic*
386
  # TYP   XS Statistics                     6#### v          MATCH      Statistic*
387
  # TYP   XS Statistics                     FMT   F00-02     EQUAL      BK
388
  #                                         008   F24-01     EQUAL      s
389
  # TYP   XS Statistics                     FMT   F00-02     EQUAL      BK
390
  #                                         008   F25-01     EQUAL      s
391
  # TYP   XS Statistics                     FMT   F00-02     EQUAL      BK
392
  #                                         008   F26-01     EQUAL      s
393
  # TYP   XS Statistics                     FMT   F00-02     EQUAL      BK
394
  #                                         008   F27-01     EQUAL      s
395

396
  def statistics_types
1✔
397
    if bib_format == 'BK'
188✔
UNCOV
398
      return ['XS'] if record['008'] && record['008'].value[24..27] =~ /s/
×
399
    end
400

401
    return ['XS'] if @xv6XX.match? /\AStatistic/i
188✔
402

403
    # Nope
404
    return []
187✔
405
  end
406

407
  # TYP   EN Encyclopedias                  6#### xv         MATCH      *encyclopedias*
408
  # TYP   EN Encyclopedias                  008   F24-01     EQUAL      e
409
  # TYP   EN Encyclopedias                  006   F07-01     EQUAL      e
410
  #
411
  # TYP   DI Dictionaries                   6#### xv         MATCH      *dictionaries*
412
  # TYP   DI Dictionaries                   008   F24-01     EQUAL      d
413
  # TYP   DI Dictionaries                   006   F07-01     EQUAL      d
414
  #
415
  # TYP   DR Directories                    6#### xv         MATCH      *directories*
416
  # TYP   DR Directories                    008   F24-01     EQUAL      r
417
  # TYP   DR Directories                    006   F07-01     EQUAL      d
418

419
  def reference_types
1✔
420
    types = []
188✔
421

422
    # Will need the 008[24] and 006[7]
423
    f8_24 = self['008[24]']
188✔
424
    f6_7 = self['006[7]']
188✔
425

426
    types << 'EN' if (f8_24.include? 'e') || (f6_7.include? 'e')
188✔
427

428
    if f6_7.include? 'd'
188✔
429
      types << 'DI'
1✔
430
      types << 'DR'
1✔
431
    end
432

433
    types << 'DI' if f8_24.include? 'd'
188✔
434

435
    types << 'DR' if f8_24.include? 'r'
188✔
436

437
    types << 'EN' if @xv6XX.match? /encyclopedias/i
188✔
438
    types << 'DI' if @xv6XX.match? /dictionaries/i
188✔
439
    types << 'DR' if @xv6XX.match? /directories/i
188✔
440

441
    types.uniq!
188✔
442
    return types
188✔
443
  end
444

445
  # TYP   BI Biography                      6#### xv         MATCH      *biography*
446
  # TYP   BI Biography                      6#### xv         MATCH      *diaries*
447
  # TYP   BI Biography                      008   F34-01     EQUAL      [a,b,c]
448
  # TYP   BI Biography                      006   F17-01     EQUAL      [a,b,c]
449

450
  def biography_types
1✔
451
    return ['BI'] if record['008'] && %w[a b c].include?(record['008'].value[34])
188✔
452
    return ['BI'] if (%w[a b c] & self['006[17]']).size > 0
185✔
453

454
    return ['BI'] if @xv6XX.match? /(?:biography|diaries)/i
185✔
455

456
    # Nope
457
    return []
182✔
458
  end
459

460
  # TYP   PP Photographs & Pictorial Works  6#### xv         MATCH      pictorial works
461
  # TYP   PP Photographs & Pictorial Works  6#### xv         MATCH      views
462
  # TYP   PP Photographs & Pictorial Works  6#### xv         MATCH      photographs
463
  # TYP   PP Photographs & Pictorial Works  6#### xv         MATCH      in art
464
  # TYP   PP Photographs & Pictorial Works  6#### xv         MATCH      aerial views
465
  # TYP   PP Photographs & Pictorial Works  6#### xv         MATCH      aerial photographs
466
  # TYP   PP Photographs & Pictorial Works  6#### xv         MATCH      art
467
  # TYP   PP Photographs & Pictorial Works  6#### xv         MATCH      cariacatures and cartoons
468
  # TYP   PP Photographs & Pictorial Works  6#### xv         MATCH      comic books
469
  # TYP   PP Photographs & Pictorial Works  6#### xv         MATCH      illustrations
470
  # TYP   PP Photographs & Pictorial Works  6#### xv         MATCH      drawings
471
  # TYP   PP Photographs & Pictorial Works  6#### xv         MATCH      slides
472

473
  class << self
1✔
474
    attr_accessor :pp_regexp
1✔
475
  end
476

477
  self.pp_regexp = Regexp.union ['pictorial works',
1✔
478
                                 'views',
479
                                 'photographs',
480
                                 'in art',
481
                                 'aerial views',
482
                                 'aerial photographs',
483
                                 'cariacatures and cartoons',
484
                                 'comic books',
485
                                 'illustrations',
486
                                 'drawings',
487
                                 'slides',].map { |s| Regexp.new('\b' + s + '\b', true) }
11✔
488
  self.pp_regexp = Regexp.union(self.pp_regexp, /\bart\b/i)
1✔
489

490
  def pp_types
1✔
491
    if @xv6XX.match? self.class.pp_regexp
188✔
492
      return ['PP']
1✔
493
    else
494
      return []
187✔
495
    end
496
  end
497

498
  # TYP   VG Video Games                    FMT   F00-02     EQUAL      CF
499
  #                                         008   F26-01     EQUAL      g
500

501
  def videogame_types
1✔
502
    if (bib_format == 'CF') && (self['008[26]'].include? 'g')
188✔
UNCOV
503
      return ['VG']
×
504
    else
505
      return []
188✔
506
    end
507
  end
508
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc