traject_umich_format 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a7113842cf09274c14d8075df5530382af465333
4
+ data.tar.gz: 5fa241fa4d01b9b43ca3afa25eb4f58f6b5e3ea4
5
+ SHA512:
6
+ metadata.gz: 10293427c26a8821321d51e3dfa616aba7651dadd2f3e03c9063b998e28db4938470e74faed48a98a25ecd31763e723fc10a6bb252e0ae5f7a7bcf51ce98191a
7
+ data.tar.gz: 84d6dead962758738a725b522137862aa5b7dc648e03d3a793380bf11f3d26b37407881f7541f7d29801d454339e195f950d6458b35f08056d3193b35e4837e6
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ -
2
+ ChangeLog.md
3
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ Gemfile.lock
2
+ doc/
3
+ pkg/
4
+ vendor/cache/*.gem
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - jruby-19mode
4
+ jdk:
5
+ - openjdk7
6
+ - openjdk6
7
+ bundler_args: --without debug
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown --title "traject_umich_format Documentation" --protected
data/ChangeLog.md ADDED
@@ -0,0 +1,4 @@
1
+ ### 0.1.0 / 2013-10-07
2
+
3
+ * Initial release:
4
+
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ gem 'traject'
5
+ gem 'yell'
6
+
7
+ group :development do
8
+ gem 'kramdown'
9
+ gem 'minitest'
10
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Bill Dueber
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # traject_umich_format
2
+ * [Homepage](https://github.com/billdueber/traject_umich_format#readme)
3
+ * [Issues](https://github.com/billdueber/traject_umich_format/issues)
4
+ * [Documentation](http://rubydoc.info/gems/traject_umich_format/frames)
5
+ * [Email](mailto:bill at dueber.com)
6
+
7
+
8
+ Opnionated macros to provide bibliographic format/types based on information in the
9
+ MARC bibliographic record, in the manner of the University of Michigan
10
+ University Library.
11
+
12
+ We at UMich use ths to populate facets in our discovery layer.
13
+
14
+
15
+ *Note* This code is designed to be used with the [traject](http://github.com/jrochkind/traject)
16
+ indexing system, and relies on it to run.
17
+
18
+
19
+ ## Description
20
+
21
+ Looks at the values in a MARC record to determine a format and set of types for the object represented by the record.
22
+
23
+ ### Bib Formats
24
+
25
+ Each record is assigned exactly one format. Raw, untranslated codes are provided in brackets.
26
+
27
+ * Book [BK]
28
+ * Data File [CF]
29
+ * Visual Material [VM]
30
+ * Music [MU]
31
+ * Map [MP]
32
+ * Serial [SE]
33
+ * Mixed Materials [MX]
34
+ * No match [XX]
35
+
36
+ ### Bib Types
37
+
38
+ Additionally, each record may have one or more of the following more specific types associated with it.
39
+
40
+ * Archive [MV]
41
+ * Audio (music) [RM]
42
+ * Audio (spoken word) [RS]
43
+ * Audio [RU]
44
+ * Audio CD [RC]
45
+ * Audio LP [RL]
46
+ * Biography [BI]
47
+ * CDROM [CR]
48
+ * Conference [XC]
49
+ * Dictionaries [DI]
50
+ * Directories [DR]
51
+ * Encyclopedias [EN]
52
+ * Journal [AJ]
53
+ * Manuscript [MW]
54
+ * Maps-Atlas [MN]
55
+ * Microform [WM]
56
+ * Motion Picture [VL]
57
+ * Music [MU]
58
+ * Musical Score [MS]
59
+ * Newspaper [AN]
60
+ * Photographs & Pictorial Works [PP]
61
+ * Serial [SX]
62
+ * Software [CS]
63
+ * Statistics [XS]
64
+ * Unknown [XX]
65
+ * Video (Blu-ray) [VB]
66
+ * Video (DVD) [VD]
67
+ * Video (VHS) [VH]
68
+ * Video Games [VG]
69
+
70
+
71
+ ## A sample traject configuration file
72
+
73
+ ```ruby
74
+ require 'traject'
75
+ require 'traject_umich_format'
76
+ extend Traject::UMichFormat::Macros
77
+
78
+ to_field 'id', extract_marc('001', :first=>true)
79
+ to_field 'bib_format', umich_format
80
+ to_field 'bib_types', umich_types
81
+ to_field 'bib_formats_and_types', umich_format_and_types
82
+
83
+ ```
84
+
85
+
86
+ ## Install
87
+
88
+ $ gem install traject_umich_format
89
+
90
+ ## Copyright
91
+
92
+ Copyright (c) 2013 Bill Dueber
93
+
94
+ See [LICENSE.txt](LICENSE.txt) for details.
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+
5
+ begin
6
+ require 'bundler'
7
+ rescue LoadError => e
8
+ warn e.message
9
+ warn "Run `gem install bundler` to install Bundler."
10
+ exit -1
11
+ end
12
+
13
+ begin
14
+ Bundler.setup(:development)
15
+ rescue Bundler::BundlerError => e
16
+ warn e.message
17
+ warn "Run `bundle install` to install missing gems."
18
+ exit e.status_code
19
+ end
20
+
21
+ require 'rake'
22
+
23
+ require "bundler/gem_tasks"
24
+
25
+ require 'yard'
26
+ YARD::Rake::YardocTask.new
27
+ task :doc => :yard
28
+
29
+ require 'rake/testtask'
30
+ Rake::TestTask.new do |t|
31
+ t.libs.push 'lib'
32
+ t.libs.push 'spec'
33
+ t.test_files = Dir.glob('spec/**/*_spec.rb')
34
+ end
35
+
36
+ task :spec => :test
37
+
38
+ task(:default => :test)
@@ -0,0 +1,40 @@
1
+ require 'traject/umich_format/version'
2
+ require 'traject/umich_format/bib_format'
3
+ require 'traject/umich_format/bib_types'
4
+ require 'traject/umich_format/macros'
5
+
6
+ # Encapsulates logic that uses University of Michigan University Library
7
+ # rules to determine both bib format (book, serial, visual
8
+ # material, etc.) and type, a more expansive list including both format
9
+ # (blu-ray, microform) and more semantic categories (bibliography,
10
+ # conference)
11
+
12
+ class Traject::UMichFormat
13
+
14
+
15
+ # @!attribute [r] record
16
+ # The record passed into the constructor
17
+ # @!attribute [r] bib_format
18
+ # The bib format code as computed from the passed record
19
+ # @!attribute [r] types
20
+ # A (possibly empty) array of type codes as computed from record data
21
+ attr_reader :bib_format, :record, :types
22
+
23
+ # Construct a Formats object from the given record, calcuclating
24
+ # the bib_format and types
25
+ #
26
+ # @param [MARC::Record] record
27
+ def initialize(marc_record)
28
+ @record = marc_record
29
+ @bib_format = BibFormat.new(record).code
30
+ @types = BibTypes.new(@bib_format, record).codes
31
+ end
32
+
33
+ def format_and_types
34
+ types = @types.dup
35
+ types.unshift bib_format
36
+ types
37
+ end
38
+
39
+ end
40
+
@@ -0,0 +1,62 @@
1
+ # given a record, find the bib_format code
2
+ class Traject::UMichFormat::BibFormat
3
+
4
+ attr_reader :code
5
+
6
+ # Determine the bib format code
7
+ #
8
+ # @param [MARC::Record] record The record to test
9
+
10
+ def initialize(record)
11
+ ldr = record.leader
12
+
13
+ type = ldr[6]
14
+ lev = ldr[7]
15
+ @code = self.determine_bib_code(type, lev)
16
+ end
17
+
18
+ def determine_bib_code(type, lev)
19
+ return 'BK' if bibformat_bk(type, lev)
20
+ return "CF" if bibformat_cf(type, lev)
21
+ return "VM" if bibformat_vm(type, lev)
22
+ return "MU" if bibformat_mu(type, lev)
23
+ return "MP" if bibformat_mp(type, lev)
24
+ return "SE" if bibformat_se(type, lev)
25
+ return "MX" if bibformat_mx(type, lev)
26
+
27
+ # Extra check for serial
28
+ return "SE" if lev == 's'
29
+
30
+ # No match
31
+ return 'XX'
32
+
33
+ end
34
+
35
+ def bibformat_bk(type, lev)
36
+ %w[a t].include?(type) && %w[a c d m].include?(lev)
37
+ end
38
+
39
+ def bibformat_cf(type, lev)
40
+ (type == 'm') && %w[a b c d m s].include?(lev)
41
+ end
42
+
43
+ def bibformat_vm(type, lev)
44
+ %w[g k o r].include?(type) && %w[a b c d m s].include?(lev)
45
+ end
46
+
47
+ def bibformat_mu(type, lev)
48
+ %w[c d i j].include?(type) && %w[a b c d m s].include?(lev)
49
+ end
50
+
51
+ def bibformat_mp(type, lev)
52
+ %w[e f].include?(type) && %w[a b c d m s].include?(lev)
53
+ end
54
+
55
+ def bibformat_se(type, lev)
56
+ (type == 'a') && %w[b s i].include?(lev)
57
+ end
58
+
59
+ def bibformat_mx(type, lev)
60
+ %w[b p].include?(type) && %w[a b c d m s].include?(lev)
61
+ end
62
+ end
@@ -0,0 +1,540 @@
1
+ require 'traject'
2
+ require 'traject/umich_format/xv6xx'
3
+
4
+
5
+ # Determine the "types" of material represented by the bib record.
6
+ # The comments below come from the Ex Libris Aleph system and represent
7
+ # the logic used within it to determine types. This file is based
8
+ # on the logic use at the University of Michigan
9
+
10
+ class Traject::UMichFormat::BibTypes
11
+
12
+ attr_reader :codes, :bib_format, :record
13
+
14
+ def initialize(bib_format, record)
15
+ @bib_format = bib_format
16
+ @record = record
17
+ # Memoize values, since many of them are used several times
18
+ @spec_vals = Hash.new { |h, spec_string| h[spec_string] = Traject::MarcExtractor.new(spec_string).extract(@record) }
19
+
20
+ # Need these a lot -- the sub x and v from any 6XX field
21
+ @xv6XX = Traject::UMichFormat::XV6XX.new(@record)
22
+
23
+ @codes = []
24
+ @codes.concat self.video_types
25
+ @codes.concat self.audio_types
26
+ @codes.concat self.microform_types
27
+ @codes.concat self.musical_score_types
28
+ @codes.concat self.map_types
29
+ @codes.concat self.serial_types
30
+ @codes.concat self.mixed_types
31
+ @codes.concat self.software_types
32
+ @codes.concat self.statistics_types
33
+ @codes.concat self.conference_types
34
+ @codes.concat self.biography_types
35
+ @codes.concat self.reference_types
36
+ @codes.concat self.pp_types
37
+ @codes.concat self.videogame_types
38
+
39
+ @codes.uniq!
40
+ @codes.compact!
41
+
42
+ end
43
+
44
+ # Provide memoized values for on-the-fly created MarcExtractor
45
+ # objects
46
+ #
47
+ # @param [String] spec_string A Traject::MarcExtractor-compatible spec string
48
+ # @return [Array<String>] The strings in the specified subfields/byterange/whatever
49
+ def [](spec_string)
50
+ @spec_vals[spec_string]
51
+ end
52
+
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
81
+ types = []
82
+
83
+ types << 'VB' if self['538a:250a'].grep(/blu-ray/i).size > 0
84
+ types << 'VB' if self['007[0-5]'].grep(/v...s/i).size > 0
85
+ types << 'VB' if self['852j'].grep(/\A(?:bd-rom|video-b)/i).size > 0
86
+
87
+
88
+ types << 'VD' if self['007[4]'].include?('v') &&
89
+ (
90
+ self['007[0]'].include?('v') ||
91
+ self['008[33]'].include?('v')
92
+ )
93
+
94
+ types << 'VD' if self['538a'].grep(/\Advd/i).size > 0
95
+
96
+ types << 'VH' if self['538a'].grep(/\AVHS/i).size > 0
97
+
98
+ types << 'VH' if self['007[4]'].include?('b') &&
99
+ (
100
+ self['007[0]'].include?('v') ||
101
+ self['008[33]'].include?('v')
102
+ )
103
+
104
+ types << 'VL' if self['007[0]'].include?('m')
105
+ types << 'VL' if (self.bib_format == 'VM') && self['008[33]'].include?('m')
106
+
107
+ return types
108
+ end
109
+
110
+
111
+ # Audio/music
112
+ # ! Recording: Compact disc
113
+ # TYP RC Audio CD LDR F06-01 EQUAL [i,j]
114
+ # FMT F00-02 EQUAL MU
115
+ # 007 F01-01 EQUAL d
116
+ # 007 F12-01 EQUAL e
117
+ # TYP RC Audio CD 8524 j MATCH CD*
118
+ # 8524 b EQUAL MUSIC
119
+ # !
120
+ # ! Recording: LP record
121
+ # TYP RL Audio LP LDR F06-01 EQUAL [i,j]
122
+ # FMT F00-02 EQUAL MU
123
+ # 007 F01-01 EQUAL d
124
+ # 300 a MATCH *SOUND DISC*
125
+ # 300 b MATCH *33 1/3 RPM*
126
+ #
127
+ # TYP RL Audio LP 8524 j MATCH LP*
128
+ # 8524 c EQUAL MUSI
129
+ # TYP RL Audio LP 8524 j MATCH LP*
130
+ # 8524 b EQUAL MUSIC
131
+ # !
132
+ # ! Recording: Music
133
+ # TYP RM Audio (music) LDR F06-01 EQUAL j
134
+ # FMT F00-02 EQUAL MU
135
+ # !
136
+ # ! Recording: Spoken word
137
+ # TYP RS Audio (spoken word) LDR F06-01 EQUAL i
138
+ # FMT F00-02 EQUAL MU
139
+ # !
140
+ # ! Recording: Undefined
141
+ # TYP RU Audio LDR F06-01 EQUAL [i,j]
142
+ # FMT F00-02 EQUAL MU
143
+ #
144
+
145
+ def audio_types
146
+ ldr6 = record.leader[6]
147
+
148
+ types = []
149
+
150
+ # Get the 8524* fields
151
+ f8524 = record.fields('852').select{|f| f.indicator1 == '4'}
152
+
153
+ # RC
154
+ types << 'RC' if %w[i j].include?(ldr6) &&
155
+ (bib_format == 'MU') &&
156
+ self['007[1]'].include?('d') &&
157
+ self['007[12]'].include?('e')
158
+
159
+ f8524.each do |f|
160
+ if (f['b'].upcase == 'MUSIC') && (f['j'] =~ /\ACD/i)
161
+ types << 'RC'
162
+ break
163
+ end
164
+ end
165
+
166
+ # RL
167
+
168
+ if (bib_format == 'MU') && %w[i j].include?(ldr6) && self['007[1]'].include?('d')
169
+ record.fields('300').each do |f|
170
+ if (f['a'] =~ /SOUND DISC/i) && (f['b'] =~ /33 1\/3 RPM/i)
171
+ types << 'RL'
172
+ break
173
+ end
174
+ end
175
+ end
176
+
177
+
178
+ f8524.each do |f|
179
+ if (f['j'] =~ /\ALP/i) &&
180
+ ((f['b'].upcase == 'MUSIC') || (f['c'].upcase == 'MUSI'))
181
+ types << 'RL'
182
+ break
183
+ end
184
+ end
185
+
186
+ # RM
187
+ types << 'RM' if (ldr6 == 'j') && (bib_format == 'MU')
188
+
189
+ # RS
190
+ types << 'RS' if (ldr6 == 'i') && (bib_format == 'MU')
191
+
192
+ # RU
193
+ types << 'RU' if %w[i j].include?(ldr6) && (bib_format == 'MU')
194
+
195
+ return types
196
+ end
197
+
198
+
199
+ # Microform
200
+ # ! MicroForms
201
+ # TYP WM Microform FMT F00-02 EQUAL BK
202
+ # 008 F23-01 EQUAL [a,b,c]
203
+ # TYP WM Microform FMT F00-02 EQUAL MU
204
+ # 008 F23-01 EQUAL [a,b,c]
205
+ # TYP WM Microform FMT F00-02 EQUAL SE
206
+ # 008 F23-01 EQUAL [a,b,c]
207
+ # TYP WM Microform FMT F00-02 EQUAL MX
208
+ # 008 F23-01 EQUAL [a,b,c]
209
+
210
+ # TYP WM Microform 245## h MATCH *micro*
211
+
212
+ # TYP WM Microform FMT F00-02 EQUAL MP
213
+ # 008 F29-01 EQUAL [a,b,c]
214
+ # TYP WM Microform FMT F00-02 EQUAL VM
215
+ # 008 F29-01 EQUAL [a,b,c]
216
+
217
+
218
+ def microform_types
219
+ return [] unless record['008']
220
+ types = ['WM']
221
+ f8_23 = record['008'].value[23]
222
+ return types if %w[BK MU SE MX].include?(bib_format) && %w[a b c].include?(f8_23)
223
+
224
+ f8_29 = record['008'].value[29]
225
+ return types if %w[MP VM].include?(bib_format) && %w[a b c].include?(f8_29)
226
+
227
+ return types if record['245'] && (record['245']['h'] =~ /micro/i)
228
+
229
+ # Nope. Not microform
230
+ return []
231
+ end
232
+
233
+
234
+ # ! Musical Score
235
+ # TYP MS Musical Score LDR F06-01 EQUAL [c,d]
236
+
237
+ def musical_score_types
238
+ types = []
239
+ types << 'MS' if %w[c d].include?(record.leader[6])
240
+ return types
241
+ end
242
+
243
+
244
+ # ! Maps: Numerous
245
+ # TYP MN Maps-Atlas FMT F00-02 EQUAL MP
246
+ # TYP MN Maps-Atlas LDR F06-01 EQUAL [e,f]
247
+ # TYP MN Maps-Atlas 007 F00-01 EQUAL a
248
+ # !
249
+ # ! Maps: One (commented out as per Judy Ahronheim as this TYP duplicates MN)
250
+ # !TYP MO Map FMT F00-02 EQUAL MP
251
+ # !TYP MO Map 007 F00-01 EQUAL a
252
+
253
+
254
+ def map_types
255
+ types = []
256
+ if (bib_format == 'MP') || %w[e f].include?(record.leader[6]) || self['007[0]'].include?('a')
257
+ types << 'MN'
258
+ end
259
+ return types
260
+ end
261
+
262
+
263
+ # Serials
264
+ # ! serial: A Journal
265
+ # TYP AJ Journal FMT F00-02 EQUAL SE
266
+ # 008 F21-01 EQUAL p
267
+ # 008 F22-01 EQUAL [^,a,b,c,d,f,g,h,i,s,x,z,|]
268
+ # 008 F29-01 EQUAL [0,|]
269
+ # TYP AJ Journal FMT F00-02 EQUAL SE
270
+ # 008 F21-01 EQUAL [^,d,l,m,p,w,|]
271
+ # 008 F22-01 EQUAL [^,a,b,c,d,f,g,h,i,s,x,z,|]
272
+ # 008 F24-01 EQUAL [a,b,g,m,n,o,p,s,w,x,y,^]
273
+ # 008 F29-01 EQUAL [0,|]
274
+ # !
275
+ # ! serial: A Newspaper
276
+ # TYP AN Newspaper FMT F00-02 EQUAL SE
277
+ # 008 F21-01 EQUAL n
278
+ # TYP AN Newspaper FMT F00-02 EQUAL SE
279
+ # 008 F22-01 EQUAL e
280
+ #
281
+ # ! serial: All, including serials with other FMT codes
282
+ # TYP SX All Serials LDR F07-01 EQUAL [b,s]
283
+
284
+
285
+ # Wrap it all up in serial_types
286
+ def serial_types
287
+ types = []
288
+ types << 'SX' if %w[b s].include?(record.leader[7])
289
+ types.concat journal_types
290
+ types.concat newspaper_types
291
+ end
292
+
293
+
294
+ def journal_types
295
+
296
+ types = []
297
+ # gotta be SE and have a 008
298
+ return types unless (bib_format == 'SE') && record['008']
299
+
300
+
301
+ # We need lots of chars from the 008
302
+ f8 = record['008'].value
303
+
304
+ if (f8[21] == 'p') &&
305
+ [' ','a','b','c','d','f','g','h','i','s','x','z','|'].include?(f8[22]) &&
306
+ ['0', '|'].include?(f8[29])
307
+ types << 'AJ'
308
+ end
309
+
310
+ if [' ','d','l','m','p','w','|'].include?(f8[21]) &&
311
+ [' ','a','b','c','d','f','g','h','i','s','x','z','|'].include?(f8[22]) &&
312
+ ['a','b','g','m','n','o','p','s','w','x','y',' '].include?(f8[24]) &&
313
+ ['0', '|'].include?(f8[29])
314
+ types << 'AJ'
315
+ end
316
+
317
+ return types
318
+ end
319
+
320
+ def newspaper_types
321
+ types = []
322
+ types << 'AN' if (bib_format == 'SE') && record['008'] &&
323
+ ((record['008'].value[21] == 'n') || (record['008'].value[22] == 'e'))
324
+ return types
325
+ end
326
+
327
+
328
+ # ! Mixed material: archi-V-e
329
+ # TYP MV Archive FMT F00-02 EQUAL MX
330
+ # TYP MV Archive LDR F08-01 EQUAL a
331
+ # !
332
+ # ! Mixed material: manuscript
333
+ # TYP MW Manuscript LDR F06-01 EQUAL [d,f,p,t]
334
+
335
+ def mixed_types
336
+ types = []
337
+ types << 'MV' if (bib_format == 'MX') || (record.leader[8] == 'a')
338
+ types << 'MW' if %w[d f p t].include?(record.leader[6])
339
+ return types
340
+ end
341
+
342
+ # TYP CR CDROM 852## j MATCH cd-rom*
343
+ # TYP CR CDROM 852## j MATCH cdrom*
344
+ # TYP CR CDROM 852## j MATCH cd-rom*
345
+ # TYP CS Software 852## j MATCH software*
346
+
347
+ def software_types
348
+ types = []
349
+ self['852j'].each do |j|
350
+ if j =~ /\Acd-?rom/i
351
+ types << 'CR'
352
+ end
353
+ if j =~ /\Asoftware/i
354
+ types << 'CS'
355
+ end
356
+ end
357
+ return types
358
+ end
359
+
360
+ # ! X (no icon) - Conference
361
+ # TYP XC Conference 008 F29-01 EQUAL 1
362
+ # TYP XC Conference 111## EXIST
363
+ # TYP XC Conference 711## EXIST
364
+ # TYP XC Conference 811## EXIST
365
+ # TYP XC Conference FMT F00-02 EQUAL CF
366
+ # 006 F00-01 EQUAL [a,s]
367
+ # 006 F12-01 EQUAL 1
368
+ # TYP XC Conference FMT F00-02 EQUAL MU
369
+ # 008 F30-01 EQUAL c
370
+ # TYP XC Conference FMT F00-02 EQUAL MU
371
+ # 008 F31-01 EQUAL c
372
+ # ! additional types defined for vufind extract
373
+ # TYP XC Conference 6#### xv MATCH *congresses*
374
+
375
+ def conference_types
376
+ # Get the easy stuff done first
377
+
378
+ return ['XC'] if (record['008'] && (record['008'].value[29] == '1')) || record.fields(['111', '711', '811']).size > 0
379
+
380
+ if (bib_format == 'CF') &&
381
+ ((self['006[0]'] & %w[a s]).size > 0) &&
382
+ self['006[12]'].include?('1')
383
+ return ['XC']
384
+ end
385
+
386
+ if (bib_format == 'MU') &&
387
+ (record['008'].value[30-31] =~ /c/)
388
+ return ['XC']
389
+ end
390
+
391
+ return ['XC'] if @xv6XX.match? /congresses/i
392
+
393
+ # Nope.
394
+ return []
395
+ end
396
+
397
+ # ! X (no icon) - Statistics
398
+ # TYP XS Statistics 650## x MATCH Statistic*
399
+ # TYP XS Statistics 6#### x MATCH Statistic*
400
+ # TYP XS Statistics 6#### v MATCH Statistic*
401
+ # TYP XS Statistics FMT F00-02 EQUAL BK
402
+ # 008 F24-01 EQUAL s
403
+ # TYP XS Statistics FMT F00-02 EQUAL BK
404
+ # 008 F25-01 EQUAL s
405
+ # TYP XS Statistics FMT F00-02 EQUAL BK
406
+ # 008 F26-01 EQUAL s
407
+ # TYP XS Statistics FMT F00-02 EQUAL BK
408
+ # 008 F27-01 EQUAL s
409
+
410
+
411
+ def statistics_types
412
+
413
+ if bib_format == 'BK'
414
+ return ['XS'] if record['008'] && record['008'].value[24..27] =~ /s/
415
+ end
416
+
417
+ return ['XS'] if @xv6XX.match? /\AStatistic/i
418
+
419
+ # Nope
420
+ return []
421
+ end
422
+
423
+
424
+
425
+ # TYP EN Encyclopedias 6#### xv MATCH *encyclopedias*
426
+ # TYP EN Encyclopedias 008 F24-01 EQUAL e
427
+ # TYP EN Encyclopedias 006 F07-01 EQUAL e
428
+ #
429
+ # TYP DI Dictionaries 6#### xv MATCH *dictionaries*
430
+ # TYP DI Dictionaries 008 F24-01 EQUAL d
431
+ # TYP DI Dictionaries 006 F07-01 EQUAL d
432
+ #
433
+ # TYP DR Directories 6#### xv MATCH *directories*
434
+ # TYP DR Directories 008 F24-01 EQUAL r
435
+ # TYP DR Directories 006 F07-01 EQUAL d
436
+
437
+ def reference_types
438
+ types = []
439
+
440
+ # Will need the 008[24] and 006[7]
441
+ f8_24 = self['008[24]']
442
+ f6_7 = self['006[7]']
443
+
444
+
445
+
446
+ if (f8_24.include? 'e') || (f6_7.include? 'e')
447
+ types << 'EN'
448
+ end
449
+
450
+ if f6_7.include? 'd'
451
+ types << 'DI'
452
+ types << 'DR'
453
+ end
454
+
455
+ if f8_24.include? 'd'
456
+ types << 'DI'
457
+ end
458
+
459
+ if f8_24.include? 'r'
460
+ types << 'DR'
461
+ end
462
+
463
+ types << 'EN' if @xv6XX.match? /encyclopedias/i
464
+ types << 'DI' if @xv6XX.match? /dictionaries/i
465
+ types << 'DR' if @xv6XX.match? /directories/i
466
+
467
+ return types
468
+ end
469
+
470
+
471
+ # TYP BI Biography 6#### xv MATCH *biography*
472
+ # TYP BI Biography 6#### xv MATCH *diaries*
473
+ # TYP BI Biography 008 F34-01 EQUAL [a,b,c]
474
+ # TYP BI Biography 006 F17-01 EQUAL [a,b,c]
475
+
476
+ def biography_types
477
+ return ['BI'] if record['008'] && %w[a b c].include?(record['008'].value[34])
478
+ return ['BI'] if (%w[a b c ] & self['006[17]']).size > 0
479
+
480
+ return ['BI'] if @xv6XX.match? /(?:biography|diaries)/i
481
+
482
+ # Nope
483
+ return []
484
+ end
485
+
486
+
487
+ # TYP PP Photographs & Pictorial Works 6#### xv MATCH pictorial works
488
+ # TYP PP Photographs & Pictorial Works 6#### xv MATCH views
489
+ # TYP PP Photographs & Pictorial Works 6#### xv MATCH photographs
490
+ # TYP PP Photographs & Pictorial Works 6#### xv MATCH in art
491
+ # TYP PP Photographs & Pictorial Works 6#### xv MATCH aerial views
492
+ # TYP PP Photographs & Pictorial Works 6#### xv MATCH aerial photographs
493
+ # TYP PP Photographs & Pictorial Works 6#### xv MATCH art
494
+ # TYP PP Photographs & Pictorial Works 6#### xv MATCH cariacatures and cartoons
495
+ # TYP PP Photographs & Pictorial Works 6#### xv MATCH comic books
496
+ # TYP PP Photographs & Pictorial Works 6#### xv MATCH illustrations
497
+ # TYP PP Photographs & Pictorial Works 6#### xv MATCH drawings
498
+ # TYP PP Photographs & Pictorial Works 6#### xv MATCH slides
499
+
500
+ class << self
501
+ attr_accessor :pp_regexp
502
+ end
503
+
504
+ self.pp_regexp = Regexp.union [ 'pictorial works',
505
+ 'views',
506
+ 'photographs',
507
+ 'in art',
508
+ 'aerial views',
509
+ 'aerial photographs',
510
+ 'cariacatures and cartoons',
511
+ 'comic books',
512
+ 'illustrations',
513
+ 'drawings',
514
+ 'slides',
515
+ ].map{|s| Regexp.new('\b'+s+'\b', true)}
516
+ self.pp_regexp = Regexp.union(self.pp_regexp, /\bart\b/i)
517
+
518
+ def pp_types
519
+ if @xv6XX.match? self.class.pp_regexp
520
+ return ['PP']
521
+ else
522
+ return []
523
+ end
524
+ end
525
+
526
+
527
+
528
+ # TYP VG Video Games FMT F00-02 EQUAL CF
529
+ # 008 F26-01 EQUAL g
530
+
531
+ def videogame_types
532
+ if (bib_format == 'CF') && (self['008[26]'].include? 'g')
533
+ return ['VG']
534
+ else
535
+ return []
536
+ end
537
+ end
538
+
539
+
540
+ end