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

pulibrary / marc_cleanup / 74b011cf-f26b-448a-8d80-00f5414cffdb

15 Dec 2023 02:52PM UTC coverage: 9.73% (-8.9%) from 18.593%
74b011cf-f26b-448a-8d80-00f5414cffdb

push

circleci

Beck-Davis
Additional spec tests for fix_008

202 of 2076 relevant lines covered (9.73%)

0.1 hits per line

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

8.5
/lib/marc_cleanup/record_level.rb
1
module MarcCleanup
1✔
2
  def non_repeatable_fields
1✔
3
    %w[
4
      001
×
5
      003
6
      005
7
      008
8
      010
9
      018
10
      036
11
      038
12
      040
13
      042
14
      043
15
      044
16
      045
17
      066
18
      100
19
      110
20
      111
21
      130
22
      240
23
      243
24
      245
25
      254
26
      256
27
      263
28
      306
29
      310
30
      357
31
      384
32
      507
33
      514
34
      841
35
      842
36
      844
37
      882
38
    ]
39
  end
40

41
  def non_repeatable_field_errors?(record)
1✔
42
    field_count = record.fields.group_by(&:tag).map { |key, value| { tag: key, count: value.size } }
×
43
    nr_fields = field_count.select { |item| non_repeatable_fields.include?(item[:tag]) && item[:count] > 1 }
×
44
    !nr_fields.empty?
×
45
  end
46

47
  def invalid_tag?(record)
1✔
48
    record.tags.find { |x| x =~ /[^0-9]/ } ? true : false
×
49
  end
50

51
  def bad_utf8?(record)
1✔
52
    record.to_s.scrub != record.to_s
×
53
  end
54

55
  def bad_utf8_identify(record)
1✔
56
    record.fields.each do |field|
×
57
      field_index = record.fields.index(field)
×
58
      if field.class == MARC::DataField
×
59
        field.subfields.each do |subfield|
×
60
          subfield_index = record.fields[field_index].subfields.index(subfield)
×
61
          record.fields[field_index].subfields[subfield_index].value.scrub! { |bytes| 'â–‘' + bytes.unpack('H*')[0] + 'â–‘' }.force_encoding('UTF-8')
×
62
        end
63
      else
64
        record.fields[field_index].value.scrub! { |bytes| 'â–‘' + bytes.unpack('H*')[0] + 'â–‘' }.force_encoding('UTF-8')
×
65
      end
66
    end
67
    record
×
68
  end
69

70
  def tab_newline_char?(record)
1✔
71
    pattern = /[\x09\n\r]/
×
72
    record.fields.each do |field|
×
73
      if field.class == MARC::DataField
×
74
        field.subfields.each do |subfield|
×
75
          return true if subfield.value =~ pattern
×
76
        end
77
      elsif field.value =~ pattern
×
78
        return true
×
79
      end
80
    end
81
    false
×
82
  end
83

84
  def invalid_xml_identify(record)
1✔
85
    pattern = /[\u0000-\u0008\u000B\u000C\u000E-\u001C\u007F-\u0084\u0086-\u009F\uFDD0-\uFDEF\uFFFE\uFFFF]/
×
86
    0.upto(record.fields.size - 1) do |field_num|
×
87
      next unless record.fields[field_num].to_s =~ pattern
×
88

89
      if record.fields[field_num].class == MARC::DataField
×
90
        0.upto(record.fields[field_num].subfields.size - 1) do |subf_num|
×
91
          next if record.fields[field_num].subfields[subf_num].value.nil?
×
92

93
          record.fields[field_num].subfields[subf_num].value.gsub!(pattern, 'â–‘\1â–‘')
×
94
        end
95
      else
96
        record.fields[field_num].value.gsub!(pattern, 'â–‘\1â–‘') unless record.fields[field_num].value.nil?
×
97
      end
98
    end
99
    record
×
100
  end
101

102
  def invalid_xml_chars?(record)
1✔
103
    pattern = /[\u0000-\u0008\u000B\u000C\u000E-\u001C\u007F-\u0084\u0086-\u009F\uFDD0-\uFDEF\uFFFE\uFFFF]/
×
104
    record.to_s =~ pattern ? true : false
×
105
  end
106

107
  def combining_chars_identify(record)
1✔
108
    pattern = /([^\p{L}\p{M}]\p{M}+)/
×
109
    0.upto(record.fields.size - 1) do |field_num|
×
110
      if record.fields[field_num].class == MARC::DataField
×
111
        0.upto(record.fields[field_num].subfields.size - 1) do |subf_num|
×
112
          record.fields[field_num].subfields[subf_num].value.gsub!(pattern, 'â–‘\1â–‘')
×
113
        end
114
      else
115
        record.fields[field_num].value.gsub!(pattern, 'â–‘\1â–‘')
×
116
      end
117
    end
118
    record
×
119
  end
120

121
  def combining_char_errors?(record)
1✔
122
    pattern = /[^\p{L}\p{M}]\p{M}+/
×
123
    record.to_s =~ pattern ? true : false
×
124
  end
125

126
  def invalid_chars?(record)
1✔
127
    good_chars = CHARSET
×
128
    record.fields.each do |field|
×
129
      if field.class == MARC::DataField
×
130
        field.subfields.each do |subfield|
×
131
          next if subfield.value.nil?
×
132

133
          subfield.value.each_char do |c|
×
134
            return true unless good_chars.include?(c.ord)
×
135
          end
136
        end
137
      else
138
        field.value.each_char do |c|
×
139
          return true unless good_chars.include?(c.ord)
×
140
        end
141
      end
142
    end
143
    false
×
144
  end
145

146
  def invalid_chars_identify(record)
1✔
147
    good_chars = CHARSET
×
148
    0.upto(record.fields.size - 1) do |field_num|
×
149
      if record.fields[field_num].class == MARC::DataField
×
150
        0.upto(record.fields[field_num].subfields.size - 1) do |subf_num|
×
151
          next if record.fields[field_num].subfields[subf_num].value.nil?
×
152

153
          temp_value = ''
×
154
          record.fields[field_num].subfields[subf_num].value.each_char do |c|
×
155
            good_chars.include?(c.ord) ? (temp_value << c) : (temp_value << 'â–‘' + c + 'â–‘')
×
156
          end
157
          record.fields[field_num].subfields[subf_num].value = temp_value
×
158
        end
159
      elsif record.fields[field_num].value
×
160
        temp_value = ''
×
161
        record.fields[field_num].value.each_char do |c|
×
162
          good_chars.include?(c.ord) ? (temp_value << c) : (temp_value << 'â–‘' + c + 'â–‘')
×
163
        end
164
        record.fields[field_num].value = temp_value
×
165
      end
166
    end
167
    record
×
168
  end
169

170
  def composed_chars_errors?(record)
1✔
171
    record.fields.each do |field|
×
172
      if field.class == MARC::DataField
×
173
        field.subfields.each do |subfield|
×
174
          subfield.value.each_codepoint do |c|
×
175
            next unless c < 1570 || (7680..10_792).cover?(c)
×
176

177
            return true unless c.chr(Encoding::UTF_8).unicode_normalized?(:nfd)
×
178
          end
179
          if subfield.value =~ /^.*[\u0653\u0654\u0655].*$/
×
180
            return true unless subfield.value.unicode_normalized?(:nfc)
×
181
          end
182
        end
183
      else
184
        field.value.each_codepoint do |c|
×
185
          next unless c < 1570 || (7680..10_792).cover?(c)
×
186

187
          return true unless c.chr(Encoding::UTF_8).unicode_normalized?(:nfd)
×
188
        end
189
        if field.value =~ /^.*[\u0653\u0654\u0655].*$/
×
190
          return true unless field.value.unicode_normalized?(:nfc)
×
191
        end
192
      end
193
    end
194
    false
×
195
  end
196

197
  ### Count fields in a record; set :subfields to True to drill down to subfields
198
  def field_count(record, opts = {})
1✔
199
    results = {}
×
200
    if opts[:subfields]
×
201
      record.fields.each do |field|
×
202
        tag = field.tag.scrub('')
×
203
        case tag
×
204
        when /^00/
205
          results[tag] = 0 unless results[tag]
×
206
          results[tag] += 1
×
207
        else
208
          field.subfields.each do |subfield|
×
209
            key = tag + subfield.code.to_s.scrub('')
×
210
            results[key] = 0 unless results[key]
×
211
            results[key] += 1
×
212
          end
213
        end
214
      end
215
    else
216
      record.fields.each do |field|
×
217
        tag = field.tag.scrub('')
×
218
        results[tag] = 0 unless results[tag]
×
219
        results[tag] += 1
×
220
      end
221
    end
222
    results
×
223
  end
224

225
  def extra_space_gsub(string)
1✔
226
    string.gsub!(/([[:blank:]]){2,}/, '\1')
×
227
    string.gsub!(/^(.*)[[:blank:]]+$/, '\1')
×
228
    string.gsub(/^[[:blank:]]+(.*)$/, '\1')
×
229
  end
230

231
  ### Remove extra spaces from all fields that are not positionally defined
232
  def extra_space_fix(record)
1✔
233
    record.fields.each do |field|
×
234
      next unless field.class == MARC::DataField && field.tag != '010'
×
235

236
      field_index = record.fields.index(field)
×
237
      curr_subfield = -1
×
238
      case field.tag
×
239
      when /^[1-469]..|0[2-9].|01[1-9]|7[0-5].|5[0-24-9].|53[0-24-9]/
240
        field.subfields.each do |subfield|
×
241
          curr_subfield += 1
×
242
          next if subfield.value.nil?
×
243

244
          record.fields[field_index].subfields[curr_subfield].value = extra_space_gsub(subfield.value)
×
245
        end
246
      when '533'
247
        field.subfields.each do |subfield|
×
248
          curr_subfield += 1
×
249
          next if subfield.code == '7' || subfield.value.nil?
×
250

251
          record.fields[field_index].subfields[curr_subfield].value = extra_space_gsub(subfield.value)
×
252
        end
253
      when /^7[6-8]./
254
        field.subfields.each do |subfield|
×
255
          curr_subfield += 1
×
256
          next if subfield.code =~ /[^a-v3-8]/ || subfield.value.nil?
×
257

258
          record.fields[field_index].subfields[curr_subfield].value = extra_space_gsub(subfield.value)
×
259
        end
260
      when /^8../
261
        field.subfields.each do |subfield|
×
262
          curr_subfield += 1
×
263
          next if %w[w 7].include?(subfield.code) || subfield.value.nil?
×
264

265
          record.fields[field_index].subfields[curr_subfield].value = extra_space_gsub(subfield.value)
×
266
        end
267
      end
268
    end
269
    record
×
270
  end
271

272
  ### Scrub invalid UTF-8 byte sequences within field values,
273
  #     replacing with nothing; indicators, subfield codes, and tags must be
274
  #     handled separately
275
  def bad_utf8_fix(record)
1✔
276
    record.fields.each do |field|
×
277
      field_index = record.fields.index(field)
×
278
      if field.class == MARC::DataField
×
279
        field.subfields.each do |subfield|
×
280
          subfield_index = record.fields[field_index].subfields.index(subfield)
×
281
          record.fields[field_index].subfields[subfield_index].value.scrub!('').force_encoding('UTF-8')
×
282
        end
283
      else
284
        record.fields[field_index].value.scrub!('').force_encoding('UTF-8')
×
285
      end
286
    end
287
    record
×
288
  end
289

290
  ### Replace invalid XML 1.0 characters with a space
291
  def invalid_xml_fix(record)
1✔
292
    bad_xml_range = /[\u0000-\u0008\u000B\u000C\u000E-\u001C\u007F-\u0084\u0086-\u009F\uFDD0-\uFDEF\uFFFE\uFFFF]/
×
293
    record.leader.gsub!(bad_xml_range, ' ')
×
294
    record.fields.each do |field|
×
295
      field_index = record.fields.index(field)
×
296
      if field.class == MARC::DataField
×
297
        curr_subfield = 0
×
298
        final_subfield = field.subfields.length
×
299
        while curr_subfield < final_subfield
×
300
          record.fields[field_index].subfields[curr_subfield].value.gsub!(bad_xml_range, ' ')
×
301
          curr_subfield += 1
×
302
        end
303
      else
304
        record.fields[field_index].value.gsub!(bad_xml_range, ' ')
×
305
      end
306
    end
307
    record
×
308
  end
309

310
  ### Replace tab and newline characters with a space
311
  def tab_newline_fix(record)
1✔
312
    regex = /[\x09\n\r]/
×
313
    record.leader.gsub!(regex, ' ')
×
314
    record.fields.each do |field|
×
315
      field_index = record.fields.index(field)
×
316
      if field.class == MARC::DataField
×
317
        curr_subfield = 0
×
318
        final_subfield = field.subfields.length
×
319
        field.indicator1.gsub!(regex, ' ') if field.indicator1
×
320
        field.indicator2.gsub!(regex, ' ') if field.indicator2
×
321
        while curr_subfield < final_subfield
×
322
          record.fields[field_index].subfields[curr_subfield].value.gsub!(regex, ' ')
×
323
          curr_subfield += 1
×
324
        end
325
      else
326
        record.fields[field_index].value.gsub!(regex, ' ')
×
327
      end
328
    end
329
    record
×
330
  end
331

332
  ## Can delete fields based on tags alone, or with
333
  ## optional indicator values provided in arrays
334
  def field_delete(tags, record, indicators = {})
1✔
335
    if indicators.empty?
×
336
      record.fields.delete_if { |field| tags.include? field.tag }
×
337
    else
338
      ind_1 = indicators[:ind_1]
×
339
      ind_2 = indicators[:ind_2]
×
340
      if ind_1 && ind_2
×
341
        record.fields.delete_if { |field| (tags.include? field.tag) && (ind_1.include? field.indicator1) && (ind_2.include? field.indicator2) }
×
342
      elsif ind_1
×
343
        record.fields.delete_if { |field| (tags.include? field.tag) && (ind_1.include? field.indicator1) }
×
344
      else
345
        record.fields.delete_if { |field| (tags.include? field.tag) && (ind_2.include? field.indicator2) }
×
346
      end
347
    end
348
    record
×
349
  end
350

351
  def recap_fixes(record)
1✔
352
    record = bad_utf8_fix(record)
×
353
    record = field_delete(['959'], record)
×
354
    record = field_delete(['856'], record)
×
355
    record = leaderfix(record)
×
356
    record = extra_space_fix(record)
×
357
    record = invalid_xml_fix(record)
×
358
    record = composed_chars_normalize(record)
×
359
    record = tab_newline_fix(record)
×
360
    empty_subfield_fix(record)
×
361
  end
362

363
  ### Remove field from a record that matches a string version of the field
364
  ###   generated by ruby-marc (ex.: '655  0 $a Electronic books')
365
  def remove_field(field_string, record)
1✔
366
    orig_string = field_string.dup
×
367
    orig_string.scrub!('')
×
368
    orig_string.strip!
×
369
    field_tag = orig_string[0..2]
×
370
    target_fields = record.fields(field_tag)
×
371
    return record if target_fields.empty?
×
372

373
    target_fields.each do |field|
×
374
      string = field.to_s
×
375
      string.scrub!('')
×
376
      string.strip!
×
377
      next unless string == orig_string
×
378

379
      field_index = record.fields.index(field)
×
380
      record.fields.delete_at(field_index)
×
381
    end
382
    record
×
383
  end
384

385
  ### Replace field from a record that matches a string version of the field
386
  ###   with the supplied field object, which can be either a ControlField
387
  ###   or a DataField
388
  def replace_field(field_string:, replacement_field:, record:)
1✔
389
    orig_string = field_string.dup
×
390
    orig_string.scrub!('')
×
391
    orig_string.strip!
×
392
    field_tag = orig_string[0..2]
×
393
    target_fields = record.fields(field_tag)
×
394
    return record if target_fields.empty?
×
395

396
    target_fields.each do |field|
×
397
      string = field.to_s
×
398
      string.scrub!('')
×
399
      string.strip!
×
400
      next unless string == orig_string
×
401

402
      field_index = record.fields.index(field)
×
403
      record.fields[field_index] = replacement_field
×
404
    end
405
    record
×
406
  end
407

408
  ### Perform multiple field replacements on a record;
409
  ###   input is a hash with field strings as keys
410
  ###   and replacement fields as values
411
  def replace_fields(field_hash:, record:)
1✔
412
    field_hash.each do |field_string, replacement_field|
×
413
      record = replace_field(field_string: field_string,
×
414
                             replacement_field: replacement_field,
415
                             record: record)
416
    end
417
    record
×
418
  end
419

420
  ### Default field sort: sort fixed fields numerically, then sort the rest
421
  ###   in groups, leaving the order of fields within the group alone
422
  def field_sort(record)
1✔
423
    new_rec = MARC::Record.new
×
424
    new_rec.leader = record.leader
×
425
    record.fields('001'..'009').sort_by { |field| field.tag }.each do |field|
×
426
      new_rec.append(field)
×
427
    end
428
    record.fields('010'..'099').each do |field|
×
429
      new_rec.append(field)
×
430
    end
431
    record.fields('100'..'199').each do |field|
×
432
      new_rec.append(field)
×
433
    end
434
    record.fields('200'..'299').each do |field|
×
435
      new_rec.append(field)
×
436
    end
437
    record.fields('300'..'399').each do |field|
×
438
      new_rec.append(field)
×
439
    end
440
    record.fields('400'..'499').each do |field|
×
441
      new_rec.append(field)
×
442
    end
443
    record.fields('500'..'599').each do |field|
×
444
      new_rec.append(field)
×
445
    end
446
    record.fields('600'..'699').each do |field|
×
447
      new_rec.append(field)
×
448
    end
449
    record.fields('700'..'799').each do |field|
×
450
      new_rec.append(field)
×
451
    end
452
    record.fields('800'..'899').each do |field|
×
453
      new_rec.append(field)
×
454
    end
455
    record.fields('900'..'999').each do |field|
×
456
      new_rec.append(field)
×
457
    end
458
    new_rec
×
459
  end
460

461
  def remove_duplicate_fields(record)
1✔
462
    field_array = []
×
463
    record.fields.reverse_each do |field|
×
464
      field_index = record.fields.index(field)
×
465
      string = field.to_s
×
466
      if field_array.include?(string)
×
467
        record.fields.delete_at(field_index)
×
468
      else
469
        field_array << string
×
470
      end
471
    end
472
    record
×
473
  end
474

475
  ### Duplicate record to preserve original when making modifications
476
  def duplicate_record(record)
1✔
477
    raw_marc = ''
×
478
    writer = MARC::Writer.new(StringIO.new(raw_marc, 'w'))
×
479
    writer.write(record)
×
480
    writer.close
×
481
    reader = MARC::Reader.new(StringIO.new(raw_marc, 'r'),
×
482
                              external_encoding: 'UTF-8',
483
                              invalid: :replace,
484
                              replace: '')
485
    reader.first
×
486
  end
487

488
  def blvl_ab_valid?(record)
1✔
489
    record['773'] ? true : false
×
490
  end
491

492
  def ftype_ac_cdm_valid?(record)
1✔
493
    present_fields1 = record.fields(
×
494
      %w[
495
        020
496
        024
497
        027
498
        088
499
        100
500
        110
501
        111
502
        300
503
        533
504
        700
505
        710
506
        711
507
        800
508
        810
509
        811
510
        830
511
      ]
512
    )
513
    present_fields2 = record.fields(%w[260 264 533])
×
514
    return false if present_fields1.empty?
×
515
    return false if present_fields2.empty?
×
516

517
    f1_criteria = false
×
518
    present_fields1.each do |field|
×
519
      f1_criteria = true if field['a']
×
520
    end
521
    present_fields2.each do |field|
×
522
      case field.tag
×
523
      when '260'
524
        return true if field['a'] || field['b']
×
525
      when '264'
526
        return true if field['b']
×
527
      when '533'
528
        return true if field['c']
×
529
      end
530
    end
531
    false
×
532
  end
533

534
  def ftype_ac_is_valid?(record)
1✔
535
    present_fields = record.fields(%w[260 264 533])
×
536
    return false if present_fields.empty?
×
537

538
    present_fields.each do |field|
×
539
      case field.tag
×
540
      when '260'
541
        return true if field['a'] || field['b']
×
542
      when '264'
543
        return true if field['b']
×
544
      when '533'
545
        return true if field['c']
×
546
      end
547
    end
548
    false
×
549
  end
550

551
  def ftype_dt_cdm_valid?(record)
1✔
552
    present_fields = record.fields(
×
553
      %w[
554
        020
555
        024
556
        027
557
        028
558
        088
559
        100
560
        110
561
        111
562
        300
563
        533
564
        700
565
        710
566
        711
567
        800
568
        810
569
        811
570
        830
571
      ]
572
    )
573
    return false if present_fields.empty?
×
574

575
    present_fields.each do |field|
×
576
      case field.tag
×
577
      when '300'
578
        return true if field['a'] || field['f']
×
579
      when '533'
580
        return true if field['e']
×
581
      else
582
        return true if field['a']
×
583
      end
584
    end
585
    false
×
586
  end
587

588
  def ftype_e_cdims_valid?(record)
1✔
589
    present_fields1 = record.fields(%w[007 300 338])
×
590
    present_fields2 = record.fields(%w[260 264 533])
×
591
    return false if present_fields1.empty?
×
592
    return false if present_fields2.empty?
×
593

594
    f1_criteria = false
×
595
    present_fields1.each do |field|
×
596
      case field.tag
×
597
      when '007'
598
        f1_criteria = true if %w[a d r].include? field.value[0]
×
599
      when '300'
600
        f1_criteria = true if field['a']
×
601
      when '338'
602
        f1_criteria = true if field['a'] || field['b']
×
603
      when 533
604
        f1_criteria = true if field['e']
×
605
      end
606
    end
607
    return false unless f1_criteria
×
608

609
    present_fields2.each do |field|
×
610
      case field.tag
×
611
      when '260'
612
        return true if field['a'] || field['b']
×
613
      when '264'
614
        return true if field['b']
×
615
      when '533'
616
        return true if field['c']
×
617
      end
618
    end
619
    false
×
620
  end
621

622
  def ftype_f_cdm_valid?(record)
1✔
623
    present_fields = record.fields(
×
624
      %w[
625
        007
626
        300
627
        338
628
        533
629
      ]
630
    )
631
    return false if present_fields.empty?
×
632

633
    present_fields.each do |field|
×
634
      case field.tag
×
635
      when '007'
636
        return true if %w[a d r].include? field.value[0]
×
637
      when '300'
638
        return true if field['a'] || field['f']
×
639
      when '338'
640
        return true if field['a'] || field['b']
×
641
      when 533
642
        return true if field['e']
×
643
      end
644
    end
645
    false
×
646
  end
647

648
  def ftype_g_cdm_valid?(record)
1✔
649
    present_fields = record.fields(
×
650
      %w[
651
        007
652
        008
653
        300
654
        338
655
        345
656
        346
657
        538
658
      ]
659
    )
660
    return false if present_fields.empty?
×
661

662
    present_fields.each do |field|
×
663
      case field.tag
×
664
      when '007'
665
        return true if %w[a d r].include? field.value[0]
×
666
      when '008'
667
        return true if %w[g k o r].include?(record.leader[6]) && %w[f m p s t v].include?(field.value[33])
×
668
      when '300'
669
        return true if field['a']
×
670
      when '345'
671
        return true
×
672
      when '346'
673
        return true
×
674
      when '538'
675
        return true if field['a']
×
676
      end
677
    end
678
    false
×
679
  end
680

681
  def ftype_g_is_valid?(record)
1✔
682
    present_fields1 = record.fields(
×
683
      %w[
684
        007
685
        008
686
        300
687
        338
688
        345
689
        346
690
        538
691
      ]
692
    )
693
    present_fields2 = record.fields(%w[260 264 533])
×
694
    return false if present_fields1.empty?
×
695
    return false if present_fields2.empty?
×
696

697
    f1_criteria = false
×
698
    present_fields1.each do |field|
×
699
      case field.tag
×
700
      when '007'
701
        f1_criteria = true if %w[g m v].include? field.value[0]
×
702
      when '008'
703
        f1_criteria = true if %w[g k o r].include?(record.leader[6]) && %w[f m p s t v].include?(field.value[33])
×
704
      when '300'
705
        f1_criteria = true if field['a']
×
706
      when '338'
707
        f1_criteria = true if field['a'] || field['b']
×
708
      when '345'
709
        f1_criteria = true
×
710
      when '346'
711
        f1_criteria = true
×
712
      when 538
713
        f1_criteria = true if field['a']
×
714
      end
715
    end
716
    return false unless f1_criteria
×
717

718
    present_fields2.each do |field|
×
719
      case field.tag
×
720
      when '260'
721
        return true if field['a'] || field['b']
×
722
      when '264'
723
        return true if field['b']
×
724
      when '533'
725
        return true if field['c']
×
726
      end
727
    end
728
    false
×
729
  end
730

731
  def ftype_ij_cdm_valid?(record)
1✔
732
    present_fields = record.fields(
×
733
      %w[
734
        007
735
        300
736
        338
737
        344
738
        538
739
      ]
740
    )
741
    return false if present_fields.empty?
×
742

743
    present_fields.each do |field|
×
744
      case field.tag
×
745
      when '007'
746
        return true if field.value[0] == 's'
×
747
      when '300'
748
        return true if field['a']
×
749
      when '338'
750
        return true if field['a'] || field['b']
×
751
      when '344'
752
        return true
×
753
      when '538'
754
        return true if field['a']
×
755
      end
756
    end
757
    false
×
758
  end
759

760
  def ftype_ij_is_valid?(record)
1✔
761
    present_fields1 = record.fields(
×
762
      %w[
763
        007
764
        300
765
        338
766
        344
767
        538
768
      ]
769
    )
770
    present_fields2 = record.fields(%w[260 264 533])
×
771
    return false if present_fields1.empty?
×
772
    return false if present_fields2.empty?
×
773

774
    f1_criteria = false
×
775
    present_fields1.each do |field|
×
776
      case field.tag
×
777
      when '007'
778
        f1_criteria = true if field.value[0] == 's'
×
779
      when '300'
780
        f1_criteria = true if field['a']
×
781
      when '338'
782
        f1_criteria = true if field['a'] || field['b']
×
783
      when '344'
784
        f1_criteria = true
×
785
      when 538
786
        f1_criteria = true if field['a']
×
787
      end
788
    end
789
    return false unless f1_criteria
×
790

791
    present_fields2.each do |field|
×
792
      case field.tag
×
793
      when '260'
794
        return true if field['a'] || field['b']
×
795
      when '264'
796
        return true if field['b']
×
797
      when '533'
798
        return true if field['c']
×
799
      end
800
    end
801
    false
×
802
  end
803

804
  def ftype_k_cdm_valid?(record)
1✔
805
    present_fields = record.fields(
×
806
      %w[
807
        007
808
        008
809
        300
810
        338
811
      ]
812
    )
813
    return false if present_fields.empty?
×
814

815
    present_fields.each do |field|
×
816
      case field.tag
×
817
      when '007'
818
        return true if field.value[0] == 'k'
×
819
      when '008'
820
        return true if %w[g k o r].include?(record.leader[6]) && %w[a c k l n o p].include?(field.value[33])
×
821
      when '300'
822
        return true if field['a']
×
823
      when '338'
824
        return true if field['a'] || field['b']
×
825
      end
826
    end
827
    false
×
828
  end
829

830
  def ftype_k_is_valid?(record)
1✔
831
    present_fields1 = record.fields(
×
832
      %w[
833
        007
834
        008
835
        300
836
        338
837
      ]
838
    )
839
    present_fields2 = record.fields(%w[260 264 533])
×
840
    return false if present_fields1.empty?
×
841
    return false if present_fields2.empty?
×
842

843
    f1_criteria = false
×
844
    present_fields1.each do |field|
×
845
      case field.tag
×
846
      when '007'
847
        f1_criteria = true if field.value[0] == 'k'
×
848
      when '008'
849
        return true if %w[g k o r].include?(record.leader[6]) && %w[a c k l n o p].include?(field.value[33])
×
850
      when '300'
851
        f1_criteria = true if field['a']
×
852
      when '338'
853
        f1_criteria = true if field['a'] || field['b']
×
854
      end
855
    end
856
    return false unless f1_criteria
×
857

858
    present_fields2.each do |field|
×
859
      case field.tag
×
860
      when '260'
861
        return true if field['a'] || field['b']
×
862
      when '264'
863
        return true if field['b']
×
864
      when '533'
865
        return true if field['c']
×
866
      end
867
    end
868
    false
×
869
  end
870

871
  def ftype_m_cdm_valid?(record)
1✔
872
    present_fields = record.fields(
×
873
      %w[
874
        007
875
        300
876
        338
877
        347
878
        538
879
      ]
880
    )
881
    return false if present_fields.empty?
×
882

883
    present_fields.each do |field|
×
884
      case field.tag
×
885
      when '007'
886
        return true if field.value[0] == 'c'
×
887
      when '300'
888
        return true if field['a']
×
889
      when '338'
890
        return true if field['a'] || field['b']
×
891
      when '347'
892
        return true
×
893
      when '538'
894
        return true if field['a']
×
895
      end
896
    end
897
    false
×
898
  end
899

900
  def ftype_m_is_valid?(record)
1✔
901
    present_fields1 = record.fields(
×
902
      %w[
903
        007
904
        300
905
        338
906
        347
907
        538
908
      ]
909
    )
910
    present_fields2 = record.fields(%w[260 264 533])
×
911
    return false if present_fields1.empty?
×
912
    return false if present_fields2.empty?
×
913

914
    f1_criteria = false
×
915
    present_fields1.each do |field|
×
916
      case field.tag
×
917
      when '007'
918
        f1_criteria = true if field.value[0] == 'c'
×
919
      when '300'
920
        f1_criteria = true if field['a']
×
921
      when '338'
922
        f1_criteria = true if field['a'] || field['b']
×
923
      when '347'
924
        f1_criteria = true
×
925
      when '538'
926
        f1_criteria = true if field['a']
×
927
      end
928
    end
929
    return false unless f1_criteria
×
930

931
    present_fields2.each do |field|
×
932
      case field.tag
×
933
      when '260'
934
        return true if field['a'] || field['b']
×
935
      when '264'
936
        return true if field['b']
×
937
      when '533'
938
        return true if field['c']
×
939
      end
940
    end
941
    false
×
942
  end
943

944
  def ftype_or_cdm_valid?(record)
1✔
945
    present_fields = record.fields(
×
946
      %w[
947
        008
948
        300
949
        338
950
      ]
951
    )
952
    return false if present_fields.empty?
×
953

954
    present_fields.each do |field|
×
955
      case field.tag
×
956
      when '008'
957
        return true if %w[g k o r].include?(record.leader[6]) && %w[a b c d g q r w].include?(field.value[33])
×
958
      when '300'
959
        return true if field['a']
×
960
      when '338'
961
        return true if field['a'] || field['b']
×
962
      end
963
    end
964
    false
×
965
  end
966

967
  def ftype_or_is_valid?(record)
1✔
968
    present_fields1 = record.fields(
×
969
      %w[
970
        008
971
        300
972
        338
973
      ]
974
    )
975
    present_fields2 = record.fields(%w[260 264 533])
×
976
    return false if present_fields1.empty?
×
977
    return false if present_fields2.empty?
×
978

979
    f1_criteria = false
×
980
    present_fields1.each do |field|
×
981
      case field.tag
×
982
      when '008'
983
        return true if %w[g k o r].include?(record.leader[6]) && %w[a b c d g q r w].include?(field.value[33])
×
984
      when '300'
985
        f1_criteria = true if field['a']
×
986
      when '338'
987
        f1_criteria = true if field['a'] || field['b']
×
988
      end
989
    end
990
    return false unless f1_criteria
×
991

992
    present_fields2.each do |field|
×
993
      case field.tag
×
994
      when '260'
995
        return true if field['a'] || field['b']
×
996
      when '264'
997
        return true if field['b']
×
998
      when '533'
999
        return true if field['c']
×
1000
      end
1001
    end
1002
    false
×
1003
  end
1004

1005
  def ftype_p_cd_valid?(record)
1✔
1006
    present_fields = record.fields(
×
1007
      %w[
1008
        100
1009
        110
1010
        111
1011
        300
1012
        338
1013
        700
1014
        710
1015
        711
1016
      ]
1017
    )
1018
    return false if present_fields.empty?
×
1019

1020
    present_fields.each do |field|
×
1021
      case field.tag
×
1022
      when '300'
1023
        return true if field['a'] || field['f']
×
1024
      when '338'
1025
        return true if field['a'] || field['b']
×
1026
      else
1027
        return true if field['a']
×
1028
      end
1029
    end
1030
    false
×
1031
  end
1032

1033
  def sparse_record?(record)
1✔
1034
    type = record.leader[6]
×
1035
    blvl = record.leader[7]
×
1036
    form = bib_form(record)
×
1037
    return true unless %w[\  a b c d f o q r s].include?(form)
×
1038

1039
    f245 = record['245']
×
1040
    return true unless f245 && (f245['a'] || f245['k'])
×
1041
    return true unless record['008']
×
1042

1043
    valid =
1044
      if %w[a b].include?(blvl)
×
1045
        blvl_ab_valid?(record)
×
1046
      elsif %w[a c].include?(type) && %w[c d m].include?(blvl)
×
1047
        ftype_ac_cdm_valid?(record)
×
1048
      elsif %w[a c].include?(type) && %w[i s].include?(blvl)
×
1049
        ftype_ac_is_valid?(record)
×
1050
      elsif %w[d t].include?(type) && %w[c d m].include?(blvl)
×
1051
        ftype_dt_cdm_valid?(record)
×
1052
      elsif %w[e].include?(type) && %w[c d i m s].include?(blvl)
×
1053
        ftype_e_cdims_valid?(record)
×
1054
      elsif %w[f].include?(type) && %w[c d m].include?(blvl)
×
1055
        ftype_f_cdm_valid?(record)
×
1056
      elsif %w[g].include?(type) && %w[c d m].include?(blvl)
×
1057
        ftype_g_cdm_valid?(record)
×
1058
      elsif %w[g].include?(type) && %w[i s].include?(blvl)
×
1059
        ftype_g_is_valid?(record)
×
1060
      elsif %w[i j].include?(type) && %w[c d m].include?(blvl)
×
1061
        ftype_ij_cdm_valid?(record)
×
1062
      elsif %w[i j].include?(type) && %w[i s].include?(blvl)
×
1063
        ftype_ij_is_valid?(record)
×
1064
      elsif %w[k].include?(type) && %w[c d m].include?(blvl)
×
1065
        ftype_k_cdm_valid?(record)
×
1066
      elsif %w[k].include?(type) && %w[i s].include?(blvl)
×
1067
        ftype_k_is_valid?(record)
×
1068
      elsif %w[m].include?(type) && %w[c d m].include?(blvl)
×
1069
        ftype_m_cdm_valid?(record)
×
1070
      elsif %w[m].include?(type) && %w[i s].include?(blvl)
×
1071
        ftype_m_is_valid?(record)
×
1072
      elsif %w[o r].include?(type) && %w[c d m].include?(blvl)
×
1073
        ftype_or_cdm_valid?(record)
×
1074
      elsif %w[o r].include?(type) && %w[i s].include?(blvl)
×
1075
        ftype_or_is_valid?(record)
×
1076
      elsif %w[p].include?(type) && %w[c d].include?(blvl)
×
1077
        ftype_p_cd_valid?(record)
×
1078
      else
1079
        true
×
1080
      end
1081
    valid ? false : true
×
1082
  end
1083
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