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

pulibrary / bibdata / 1dcebae2-3318-4e77-bc53-82276e293354

02 May 2025 04:45PM UTC coverage: 28.256% (-63.9%) from 92.189%
1dcebae2-3318-4e77-bc53-82276e293354

push

circleci

sandbergja
Add basic infrastructure for compiling rust code

* Add a rake compile task to compile
* Run the rake task in CI
* Run the rake task before rspec tests with the rust tag, to provide quick feedback on rust changes in TDD cycles

2 of 7 new or added lines in 2 files covered. (28.57%)

2467 existing lines in 97 files now uncovered.

1089 of 3854 relevant lines covered (28.26%)

0.29 hits per line

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

28.99
/marc_to_solr/lib/genre.rb
1
# This class is responsible for listing the
2
# genres present in a given MARC record
3
class Genre
1✔
4
  SUBJECT_GENRE_VOCABULARIES = %w[sk aat lcgft rbbin rbgenr rbmscv
1✔
5
                                  rbpap rbpri rbprov rbpub rbtyp homoit].freeze
6

7
  def initialize(record)
1✔
UNCOV
8
    @record = record
×
9
  end
10

11
  # 600/610/650/651 $v, $x filtered
12
  # 655 $a, $v, $x filtered
13
  def to_a
1✔
UNCOV
14
    @as_array ||= (
×
UNCOV
15
      genres_from_subfield_x + genres_from_subject_vocabularies + genres_from_subfield_v + genres_from_primary_source_mapping + genres_from_autobiography
×
16
    ).compact.uniq
17
  end
18

19
  private
1✔
20

21
    attr_reader :record
1✔
22

23
    def genres_from_subfield_x
1✔
UNCOV
24
      Traject::MarcExtractor.cached('600|*0|x:610|*0|x:611|*0|x:630|*0|x:650|*0|x:651|*0|x:655|*0|x').collect_matching_lines(record) do |field, spec, extractor|
×
UNCOV
25
        genre = extractor.collect_subfields(field, spec).first
×
UNCOV
26
        next if genre.nil?
×
27

UNCOV
28
        genre = Traject::Macros::Marc21.trim_punctuation(genre)
×
UNCOV
29
        genre if likely_genre_term(genre)
×
30
      end
31
    end
32

33
    def genres_from_subject_vocabularies
1✔
UNCOV
34
      Traject::MarcExtractor.cached('650|*7|v:655|*7|a:655|*7|v').collect_matching_lines(record) do |field, spec, extractor|
×
UNCOV
35
        should_include = field.subfields.any? do |s_field|
×
36
          # only include heading if it is part of the vocabulary
UNCOV
37
          SUBJECT_GENRE_VOCABULARIES.include?(s_field.value) if s_field.code == '2'
×
38
        end
UNCOV
39
        genre = extractor.collect_subfields(field, spec).first
×
UNCOV
40
        next if genre.nil?
×
41

UNCOV
42
        genre = Traject::Macros::Marc21.trim_punctuation(genre)
×
UNCOV
43
        if genre.match?(/^\s+$/)
×
44
          logger.error "#{record['001']} - Blank genre field"
×
45
          next
×
UNCOV
46
        elsif should_include
×
UNCOV
47
          genre
×
48
        end
49
      end
50
    end
51

52
    def genres_from_subfield_v
1✔
UNCOV
53
      Traject::MarcExtractor.cached('600|*0|v:610|*0|v:611|*0|v:630|*0|v:650|*0|v:651|*0|v:655|*0|a:655|*0|v').collect_matching_lines(record) do |field, spec, extractor|
×
UNCOV
54
        genre = extractor.collect_subfields(field, spec).first
×
UNCOV
55
        next if genre.nil?
×
56

UNCOV
57
        genre = Traject::Macros::Marc21.trim_punctuation(genre)
×
UNCOV
58
        if genre.match?(/^\s+$/)
×
59
          logger.error "#{record['001']} - Blank genre field"
×
60
          next
×
61
        end
UNCOV
62
        genre
×
63
      end
64
    end
65

66
    def genres_from_primary_source_mapping
1✔
UNCOV
67
      potential_genres = Traject::MarcExtractor.cached('600|*0|vx:610|*0|vx:611|*0|vx:630|*0|vx:650|*0|vx:651|*0|vx:655|*0|a:655|*0|vx').collect_matching_lines(record) do |field, spec, extractor|
×
UNCOV
68
        extractor.collect_subfields(field, spec)
×
69
      end
UNCOV
70
      if potential_genres.any? { |genre| genre_term_indicates_primary_source? genre } && !literary_work?
×
UNCOV
71
        ['Primary sources']
×
72
      else
UNCOV
73
        []
×
74
      end
75
    end
76

77
    def genres_from_autobiography
1✔
UNCOV
78
      if biography? && author_matches_subject? && !literary_work?
×
UNCOV
79
        ['Primary sources']
×
80
      else
UNCOV
81
        []
×
82
      end
83
    end
84

85
    def genre_term_indicates_primary_source?(genre)
1✔
UNCOV
86
      normalized_genre = genre.downcase.strip.delete_suffix('.')
×
UNCOV
87
      primary_source_genres.any? { |primary_source_genre| normalized_genre.match?(/(^|\W)#{primary_source_genre}($|\W)/) }
×
88
    end
89

90
    def biography?
1✔
UNCOV
91
      potential_genres = Traject::MarcExtractor.cached('600|*0|vx:610|*0|vx:611|*0|vx:630|*0|vx:650|*0|avx:651|*0|vx:655|*0|avx').collect_matching_lines(record) do |field, spec, extractor|
×
UNCOV
92
        extractor.collect_subfields(field, spec)
×
93
      end
UNCOV
94
      potential_genres.include?('Biography')
×
95
    end
96

97
    def author_matches_subject?
1✔
UNCOV
98
      authors = Traject::MarcExtractor.cached('100abcdjq').extract(record).uniq.map { |name| Traject::Macros::Marc21.trim_punctuation name.downcase.strip }
×
UNCOV
99
      name_subjects = Traject::MarcExtractor.cached('600abcdjq').extract(record).uniq.map { |name| Traject::Macros::Marc21.trim_punctuation name.downcase.strip }
×
UNCOV
100
      authors.any? { |author| name_subjects.include? author }
×
101
    end
102

103
    def likely_genre_term term
1✔
UNCOV
104
      genre_terms.include?(term) || genre_starting_terms.any? { |potential| term.start_with? potential }
×
105
    end
106

107
    def genre_terms
1✔
108
      [
UNCOV
109
        'Bibliography',
×
110
        'Biography',
111
        'Catalogs',
112
        'Catalogues raisonnes',
113
        'Commentaries',
114
        'Congresses',
115
        'Diaries',
116
        'Dictionaries',
117
        'Drama',
118
        'Encyclopedias',
119
        'Exhibitions',
120
        'Fiction',
121
        'Guidebooks',
122
        'In art',
123
        'Indexes',
124
        'Librettos',
125
        'Manuscripts',
126
        'Newspapers',
127
        'Periodicals',
128
        'Pictorial works',
129
        'Poetry',
130
        'Portraits',
131
        'Scores',
132
        'Songs and music',
133
        'Sources',
134
        'Statistics',
135
        'Texts',
136
        'Translations'
137
      ]
138
    end
139

140
    def genre_starting_terms
1✔
141
      [
UNCOV
142
        'Census',
×
143
        'Maps',
144
        'Methods',
145
        'Parts',
146
        'Personal narratives',
147
        'Scores and parts',
148
        'Study and teaching',
149
        'Translations into '
150
      ]
151
    end
152

153
    def primary_source_genres
1✔
154
      [
UNCOV
155
        'atlases',
×
156
        'charters',
157
        'correspondence',
158
        'diaries',
159
        'documents',
160
        'interview',
161
        'interviews',
162
        'letters',
163
        'manuscripts',
164
        'maps',
165
        'notebooks, sketchbooks, etc',
166
        'oral history',
167
        'pamphlets',
168
        'personal narratives',
169
        'photographs',
170
        'pictorial works',
171
        'sources',
172
        'speeches',
173
        'statistics'
174
      ]
175
    end
176

177
    def literary_work?
1✔
UNCOV
178
      book? && record.fields('008').any? { |litf| %w[1 d e f j p].include? litf.value[33] }
×
179
    end
180

181
    def book?
1✔
UNCOV
182
      record.leader && record.leader[6..7]&.match?(/a[acdim]/)
×
183
    end
184
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