marc4j4r 0.1.6 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +17 -0
- data/Rakefile +26 -13
- data/VERSION +1 -1
- data/jars/marc4j.jar +0 -0
- data/lib/marc4j4r/controlfield.rb +32 -0
- data/lib/marc4j4r/datafield.rb +196 -0
- data/lib/marc4j4r/reader.rb +71 -0
- data/lib/marc4j4r/record.rb +214 -0
- data/lib/marc4j4r/writer.rb +29 -0
- data/lib/marc4j4r.rb +26 -485
- data/lib/original_monolithic_file.rb +518 -0
- data/spec/batch.dat +1 -0
- data/spec/batch.txt +193 -0
- data/spec/batch.xml +13 -0
- data/spec/controlfield_spec.rb +40 -0
- data/spec/datafield_spec.rb +56 -0
- data/spec/one.dat +1 -0
- data/spec/one.txt +17 -0
- data/spec/one.xml +4 -0
- data/spec/reader_spec.rb +49 -0
- data/spec/record_spec.rb +101 -0
- data/{test/helper.rb → spec/spec_helper.rb} +9 -5
- metadata +74 -80
- data/.document +0 -5
- data/.gitignore +0 -21
- data/README.markdown +0 -41
- data/doc/ControlFieldImpl.html +0 -314
- data/doc/DataFieldImpl.html +0 -875
- data/doc/Java/OrgMarc4j/MarcReader.html +0 -184
- data/doc/MARC4J4R/Reader.html +0 -245
- data/doc/MARC4J4R.html +0 -281
- data/doc/RecordImpl.html +0 -686
- data/doc/SubfieldImpl.html +0 -252
- data/doc/_index.html +0 -153
- data/doc/class_list.html +0 -36
- data/doc/css/common.css +0 -1
- data/doc/css/full_list.css +0 -50
- data/doc/css/style.css +0 -268
- data/doc/file.README.html +0 -90
- data/doc/file_list.html +0 -38
- data/doc/frames.html +0 -13
- data/doc/index.html +0 -90
- data/doc/js/app.js +0 -99
- data/doc/js/full_list.js +0 -106
- data/doc/js/jquery.js +0 -19
- data/doc/method_list.html +0 -219
- data/doc/top-level-namespace.html +0 -87
- data/jars/MarcImporter.jar +0 -0
- data/test/batch.seq +0 -118
- data/test/bench.rb +0 -63
- data/test/one.dat +0 -1
- data/test/one.seq +0 -30
- data/test/one.xml +0 -55
- data/test/test_marc4j4r.rb +0 -76
@@ -0,0 +1,518 @@
|
|
1
|
+
unless defined? JRUBY_VERSION
|
2
|
+
raise "Only works under JRUBY"
|
3
|
+
end
|
4
|
+
|
5
|
+
begin
|
6
|
+
include_class Java::org.marc4j.marc.impl.RecordImpl
|
7
|
+
rescue NameError => e
|
8
|
+
jardir = File.join(File.dirname(__FILE__), '..', 'jars')
|
9
|
+
require "#{jardir}/marc4j.jar"
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'set'
|
13
|
+
|
14
|
+
|
15
|
+
# Re-open the MarcReader interface, define #each and include Enumerable
|
16
|
+
#
|
17
|
+
# We also automatically call #hashify on the records that stream through
|
18
|
+
# #each in order to speed up RecordImpl#[] when (a) doing many operations on a single
|
19
|
+
# record, and (b) we're not worried about interleaved tags (e.g., a 520 followed by a 510 followed
|
20
|
+
# by another 520)
|
21
|
+
|
22
|
+
module Java::OrgMarc4j::MarcReader
|
23
|
+
include Enumerable
|
24
|
+
|
25
|
+
# Return the next record, after calling #hashify on it
|
26
|
+
def each(hashify=true)
|
27
|
+
while self.hasNext
|
28
|
+
r = self.next
|
29
|
+
r.hashify if hashify
|
30
|
+
yield r
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
module MARC4J4R
|
37
|
+
|
38
|
+
# Do some simple substitutions to make things prettier. After this,
|
39
|
+
# we can use MARC4J4R::Record instead of Java::org.marc4j.marc.impl::RecordImpl
|
40
|
+
|
41
|
+
Record = Java::org.marc4j.marc.impl::RecordImpl
|
42
|
+
ControlField = Java::org.marc4j.marc.impl::ControlFieldImpl
|
43
|
+
DataField = Java::org.marc4j.marc.impl::DataFieldImpl
|
44
|
+
SubField = Java::org.marc4j.marc.impl::SubfieldImpl
|
45
|
+
|
46
|
+
|
47
|
+
# Add some sugar to the MarcReader interface
|
48
|
+
#
|
49
|
+
# Adjust the interface so that a #new call to any implementations that
|
50
|
+
# implement it can take a java.io.InputStream, ruby IO obejct, or String
|
51
|
+
# (that will be interpreted as a filename) without complaining.
|
52
|
+
#
|
53
|
+
# The mechanism -- running module_eval on a string-representation of the
|
54
|
+
# new method in each of the hard-coded implementations of MarcReader
|
55
|
+
# (MarcStreamReader,MarcPermissiveStreamReader,MarcXmlReader) -- is ugly
|
56
|
+
# and deeply unsettling.
|
57
|
+
#
|
58
|
+
# @author Bill Dueber
|
59
|
+
#
|
60
|
+
# A string used to override the initializer for each stream reader
|
61
|
+
# Need to do it this ugly way because of the way java and ruby interact;
|
62
|
+
# can't just add it to the MarcReader interface the way I wanted to.
|
63
|
+
|
64
|
+
NEWINIT = <<-ENDBINDER
|
65
|
+
include Enumerable
|
66
|
+
alias_method :oldinit, :initialize
|
67
|
+
def initialize(fromwhere)
|
68
|
+
stream = nil
|
69
|
+
if fromwhere.is_a? Java::JavaIO::InputStream or fromwhere.is_a? Java::JavaIO::ByteArrayInputStream
|
70
|
+
stream = fromwhere
|
71
|
+
elsif fromwhere.is_a? IO
|
72
|
+
stream = fromwhere.to_inputstream
|
73
|
+
else
|
74
|
+
stream = java.io.FileInputStream.new(fromwhere.to_java_string)
|
75
|
+
end
|
76
|
+
if self.class == Java::org.marc4j.MarcPermissiveStreamReader
|
77
|
+
self.oldinit(stream, true, true)
|
78
|
+
else
|
79
|
+
self.oldinit(stream)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
ENDBINDER
|
83
|
+
|
84
|
+
Java::org.marc4j.MarcStreamReader.module_eval(NEWINIT)
|
85
|
+
Java::org.marc4j.MarcPermissiveStreamReader.module_eval(NEWINIT)
|
86
|
+
Java::org.marc4j.MarcXmlReader.module_eval(NEWINIT)
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
# Get a marc reader of the appropriate type
|
91
|
+
# @param [String, IO, java.io.InputStream] input The IO stream (or filename) from which you want to read
|
92
|
+
# @param [:strictmarc, :permissivemarc, :marcxml] The type of MARC reader you want.
|
93
|
+
# @return [MarcReader] A MarcReader object with the syntactic sugar added in this file (e.g, each)
|
94
|
+
#
|
95
|
+
# @example Get a strict binary MARC reader for the file 'test.mrc'
|
96
|
+
# reader = MARC4J4R.reader('test.mrc')
|
97
|
+
#
|
98
|
+
# @example Get a permissive binary MARC reader
|
99
|
+
# reader = MARC4J4R.reader('test.mrc', :permissivemarc)
|
100
|
+
#
|
101
|
+
# @example Get a reader for an xml file
|
102
|
+
# reader = MARC4J4R.reader('test.xml', :marcxml)
|
103
|
+
#
|
104
|
+
# @example Get a reader based on an existing IO object
|
105
|
+
# require 'open-uri'
|
106
|
+
# infile = open('http://my.machine.com/test.mrc')
|
107
|
+
# reader = MARC4J4R.reader(infile)
|
108
|
+
|
109
|
+
def reader(input, type = :strictmarc)
|
110
|
+
case type
|
111
|
+
when :strictmarc then
|
112
|
+
return Java::org.marc4j.MarcStreamReader.new(input)
|
113
|
+
when :permissivemarc then
|
114
|
+
return Java::org.marc4j.MarcPermissiveStreamReader.new(input)
|
115
|
+
when :marcxml then
|
116
|
+
return Java::org.marc4j.MarcXmlReader.new(input)
|
117
|
+
when :alephsequential then
|
118
|
+
return MARC4J4R::AlephSequentialReader.new(input)
|
119
|
+
else
|
120
|
+
raise ArgumentError, "Reader type #{type} illegal: must be :strictmarc, :permissivemarc, :marcxml, or :alephsequential"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
module_function :reader
|
124
|
+
|
125
|
+
|
126
|
+
# Implement an AlephSequential reader
|
127
|
+
class AlephSequentialReader
|
128
|
+
include Enumerable
|
129
|
+
def initialize(fromwhere)
|
130
|
+
stream = nil
|
131
|
+
if fromwhere.is_a? Java::JavaIO::InputStream
|
132
|
+
stream = fromwhere.to_io
|
133
|
+
elsif fromwhere.is_a? IO
|
134
|
+
stream = fromwhere
|
135
|
+
else
|
136
|
+
stream = File.new(fromwhere)
|
137
|
+
end
|
138
|
+
|
139
|
+
@handle = stream
|
140
|
+
end
|
141
|
+
|
142
|
+
def each
|
143
|
+
record = nil
|
144
|
+
currentID = nil
|
145
|
+
|
146
|
+
@handle.each_line do |l|
|
147
|
+
l.chomp!
|
148
|
+
next unless l =~ /\S/
|
149
|
+
vals = l.unpack('a9 a a3 c c a3 a*')
|
150
|
+
id, tag, ind1, ind2, data = vals[0], vals[2], vals[3], vals[4], vals[6]
|
151
|
+
# id, tag, ind1, ind2, junk, data = *(l.unpack('A10 a3 c c a3 A*'))
|
152
|
+
if id != currentID
|
153
|
+
if record
|
154
|
+
yield record
|
155
|
+
end
|
156
|
+
record = RecordImpl.new
|
157
|
+
currentID = id
|
158
|
+
end
|
159
|
+
if tag == 'LDR'
|
160
|
+
record.setLeader(Java::org.marc4j.marc.impl.LeaderImpl.new(data))
|
161
|
+
else
|
162
|
+
record << buildField(tag,ind1,ind2,data)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
yield record
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
SUBREGEXP = /\$\$(.)/
|
170
|
+
def buildField (tag, ind1, ind2, data)
|
171
|
+
if Java::org.marc4j.marc.impl.Verifier.isControlField tag
|
172
|
+
return Java::org.marc4j.marc.impl.ControlFieldImpl.new(tag, data)
|
173
|
+
else
|
174
|
+
f = Java::org.marc4j.marc.impl.DataFieldImpl.new(tag, ind1, ind2)
|
175
|
+
data.split(SUBREGEXP)[1..-1].each_slice(2) do |code, value|
|
176
|
+
f.addSubfield Java::org.marc4j.marc.impl.SubfieldImpl.new(code[0].ord, value)
|
177
|
+
end
|
178
|
+
return f
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
end # End of class AlephSequentialReader
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
# Open up RecordImpl to add some sugar, including Enumberable as well
|
188
|
+
# @author Bill Dueber
|
189
|
+
|
190
|
+
class Record
|
191
|
+
include Enumerable
|
192
|
+
|
193
|
+
alias_method :<<, :addVariableField
|
194
|
+
alias_method :append, :addVariableField
|
195
|
+
alias_method :fields, :getVariableFields
|
196
|
+
|
197
|
+
# Export as a MARC-Hash, as described at
|
198
|
+
# http://robotlibrarian.billdueber.com/marc-hash-the-saga-continues-now-with-even-less-structure/
|
199
|
+
# @return A marc-hash representation of the record, suitable for calling .to_json on or whatever
|
200
|
+
def to_marchash
|
201
|
+
h = {}
|
202
|
+
h['type'] = 'marc-hash'
|
203
|
+
h['version'] = [1,0]
|
204
|
+
h['leader'] = self.leader
|
205
|
+
|
206
|
+
fields = []
|
207
|
+
|
208
|
+
self.getVariableFields.each do |f|
|
209
|
+
if f.controlField?
|
210
|
+
fields << [f.tag, f.value]
|
211
|
+
else
|
212
|
+
farray = [f.tag, f.indicator1 || ' ', f.indicator2 || ' ']
|
213
|
+
subs = []
|
214
|
+
f.each do |subfield|
|
215
|
+
subs << [subfield.code, subfield.value]
|
216
|
+
end
|
217
|
+
farray.push subs
|
218
|
+
fields << farray
|
219
|
+
end
|
220
|
+
end
|
221
|
+
h['fields'] = fields
|
222
|
+
return h
|
223
|
+
end
|
224
|
+
|
225
|
+
# Create a local hash by tag number; makes some stuff faster
|
226
|
+
# Called automatically if you use reader.each
|
227
|
+
|
228
|
+
def hashify
|
229
|
+
return if @hashedtags # don't do it more than once
|
230
|
+
@hashedtags = {}
|
231
|
+
self.getVariableFields.each do |f|
|
232
|
+
@hashedtags[f.tag] ||= []
|
233
|
+
@hashedtags[f.tag].push f
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# Create a nice string of the record
|
238
|
+
def to_s
|
239
|
+
arr = ['LEADER ' + self.leader]
|
240
|
+
self.each do |f|
|
241
|
+
arr.push f.to_s
|
242
|
+
end
|
243
|
+
return arr.join("\n")
|
244
|
+
end
|
245
|
+
|
246
|
+
# Get the leader as a string (marc4j would otherwise return Leader object)
|
247
|
+
def leader
|
248
|
+
self.get_leader.toString
|
249
|
+
end
|
250
|
+
|
251
|
+
|
252
|
+
# Cycle through the fields in the order the appear in the record
|
253
|
+
def each
|
254
|
+
self.getVariableFields.each do |f|
|
255
|
+
yield f
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
# Get the first field associated with a tag
|
260
|
+
# @param [String] tag The tag
|
261
|
+
# @return [Field] The first matching field, or nil if none. Note that
|
262
|
+
# to mirror ruby-marc, this returns a single field
|
263
|
+
|
264
|
+
def [] tag
|
265
|
+
if defined? @hashedtags
|
266
|
+
if @hashedtags[tag]
|
267
|
+
return @hashedtags[tag][0]
|
268
|
+
else
|
269
|
+
return nil
|
270
|
+
end
|
271
|
+
else
|
272
|
+
return self.getVariableField(tag)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
# Get a (possibly empty) list of fields with the given tag(s)
|
278
|
+
#
|
279
|
+
# @param [String, Array<String>] tags A string (or Array of strings) with the tags you're interested in
|
280
|
+
# @param [Boolean] originalorder Whether or not results should be presented in the original order within the
|
281
|
+
# record or with a two-column sort of (a) Order of the tag in the list of tags sent, (b) order within that tag
|
282
|
+
# in the record
|
283
|
+
# @return [Array<Field>] Either an empty list or a list of one or more matched fields will be returned.
|
284
|
+
#
|
285
|
+
# originalorder == false will use an internal hash and be faster in many cases (see #hashify)
|
286
|
+
#
|
287
|
+
# @example originalorder == false
|
288
|
+
# # Given a record that looks like
|
289
|
+
# # 010 $a 68027371
|
290
|
+
# # 035 $a (RLIN)MIUG0001728-B
|
291
|
+
# # 035 $a (CaOTULAS)159818044
|
292
|
+
# # 035 $a (OCoLC)ocm00001728
|
293
|
+
#
|
294
|
+
# r.find_by_tag(['035', '010']).each {|f| puts f.to_s}
|
295
|
+
# # 035 $a (RLIN)MIUG0001728-B
|
296
|
+
# # 035 $a (CaOTULAS)159818044
|
297
|
+
# # 035 $a (OCoLC)ocm00001728
|
298
|
+
# # 010 $a 68027371
|
299
|
+
#
|
300
|
+
# # The results are ordered first by tag as passed in, then by original order within the tag
|
301
|
+
#
|
302
|
+
# @example Just get all fields for a single tag
|
303
|
+
# ohThirtyFives = r.find_by_tag('035')
|
304
|
+
#
|
305
|
+
# @example Get a bunch of standard identifiers
|
306
|
+
# standardIDs = r.find_by_tag(['022', '020', '010'])
|
307
|
+
#
|
308
|
+
# @example originalorder == true
|
309
|
+
# r.find_by_tag(['035', '010'], true).each {|f| puts f.to_s}
|
310
|
+
# # 010 $a 68027371
|
311
|
+
# # 035 $a (RLIN)MIUG0001728-B
|
312
|
+
# # 035 $a (CaOTULAS)159818044
|
313
|
+
# # 035 $a (OCoLC)ocm00001728
|
314
|
+
|
315
|
+
def find_by_tag(tags, originalorder = false)
|
316
|
+
self.hashify unless @hashedtags and !originalorder
|
317
|
+
if !tags.is_a? Array
|
318
|
+
return @hashedtags[tags] || []
|
319
|
+
end
|
320
|
+
if originalorder
|
321
|
+
return self.find_all {|f| tags.include? f.tag}
|
322
|
+
else
|
323
|
+
# puts "Tags is #{tags}: got #{@hashedtags.values_at(*tags)}"
|
324
|
+
return @hashedtags.values_at(*tags).flatten.compact
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
|
329
|
+
|
330
|
+
# Return the record as valid MARC-XML
|
331
|
+
# @return String A MARC-XML representation of the record, including the XML header
|
332
|
+
def to_xml
|
333
|
+
return @xml if @xml
|
334
|
+
begin
|
335
|
+
@xml = java.io.StringWriter.new
|
336
|
+
res = javax.xml.transform.stream.StreamResult.new(@xml)
|
337
|
+
writer = org.marc4j.MarcXmlWriter.new(res)
|
338
|
+
writer.write(self)
|
339
|
+
writer.writeEndDocument
|
340
|
+
return @xml.toString
|
341
|
+
rescue
|
342
|
+
"Woops! to_xml failed for record #{self['001'].data}: #{$!}"
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
def to_marc
|
347
|
+
begin
|
348
|
+
s = Java::java.io.ByteArrayOutputStream.new
|
349
|
+
writer = org.marc4j.MarcStreamWriter.new(s)
|
350
|
+
writer.write(self)
|
351
|
+
@marcbinary = s.to_string
|
352
|
+
puts @marcbinary
|
353
|
+
return @marcbinary
|
354
|
+
rescue
|
355
|
+
# "Woops! to_marc failed for record #{self['001'].data}: #{$!}"
|
356
|
+
"Whoops! Failed: #{$!}"
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
|
361
|
+
end
|
362
|
+
|
363
|
+
class ControlField
|
364
|
+
def value
|
365
|
+
return self.data
|
366
|
+
end
|
367
|
+
|
368
|
+
def controlField?
|
369
|
+
return true
|
370
|
+
end
|
371
|
+
|
372
|
+
def self.control_tag? tag
|
373
|
+
return Java::org.marc4j.marc.impl.Verifier.isControlField tag
|
374
|
+
end
|
375
|
+
|
376
|
+
# Pretty-print
|
377
|
+
# @param [String] joiner What string to use to join the subfields
|
378
|
+
# @param [String] The pretty string
|
379
|
+
def to_s
|
380
|
+
return self.tag + " " + self.value
|
381
|
+
end
|
382
|
+
|
383
|
+
def == other
|
384
|
+
self.tag == other.tag && self.value == other.value
|
385
|
+
end
|
386
|
+
|
387
|
+
end
|
388
|
+
|
389
|
+
class DataField
|
390
|
+
include Enumerable
|
391
|
+
|
392
|
+
alias_method :<<, :addSubfield
|
393
|
+
|
394
|
+
|
395
|
+
def controlField?
|
396
|
+
return false
|
397
|
+
end
|
398
|
+
|
399
|
+
# Broken. Need to check subs as well
|
400
|
+
def == other
|
401
|
+
self.tag == other.tag and
|
402
|
+
self.indicator1 == other.indicator1 and
|
403
|
+
self.indicator2 == other.indicator2
|
404
|
+
end
|
405
|
+
|
406
|
+
# Pretty-print
|
407
|
+
# @param [String] joiner What string to use to join the subfields
|
408
|
+
# @param [String] The pretty string
|
409
|
+
def to_s (joiner = ' ')
|
410
|
+
arr = [self.tag + ' ' + self.indicator1 + self.indicator2]
|
411
|
+
self.each do |s|
|
412
|
+
arr.push s.to_s
|
413
|
+
end
|
414
|
+
return arr.join(joiner)
|
415
|
+
end
|
416
|
+
|
417
|
+
# Get the value of the first subfield of this field with the given code
|
418
|
+
# @param [String] code 1-character string of the subfield code
|
419
|
+
# @return [String] The value of the first matched subfield
|
420
|
+
def [] code
|
421
|
+
raise ArgumentError, "Code must be a one-character string, not #{code}" unless code.is_a? String and code.size == 1
|
422
|
+
# need to send a char value that the underlying java can deal with
|
423
|
+
sub = self.getSubfield(code[0].ord)
|
424
|
+
if (sub)
|
425
|
+
return sub.getData
|
426
|
+
else
|
427
|
+
return nil
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
|
432
|
+
# Get all values from the subfields for the given code or array of codes
|
433
|
+
# @param [String, Array<String>] code (Array of?) 1-character string(s) of the subfield code
|
434
|
+
# @param [Boolean] myorder Use the order of subfields that I gave instead of the order they're in the record
|
435
|
+
# @return [Array<String>] A possibly-empty array of Strings made up of the values in the subfields whose
|
436
|
+
# code is included in the given codes. If myorder == true, use the order in which they are passed in; if a code is repeated
|
437
|
+
# (ocassionally legal) subfield values will appear first ordered by the passed array, then by order within
|
438
|
+
# the document.
|
439
|
+
#
|
440
|
+
# If myorder is false, just return the values for matching subfields in the order they appear in the field.
|
441
|
+
#
|
442
|
+
# @example Quick examples:
|
443
|
+
# # 260 $a New York, $b Van Nostrand Reinhold Co. $c 1969
|
444
|
+
# rec['260'].sub_values('a') #=> ["New York,"]
|
445
|
+
# rec['260'].sub_values(['a', 'c']) #=> ["New York,", "1969"]
|
446
|
+
# rec['260'].sub_values(['c', 'a']) #=> ["New York,", "1969"]
|
447
|
+
# rec['260'].sub_values(['c', 'a'], true) #=> ["1969", "New York"]
|
448
|
+
|
449
|
+
def sub_values(code, myorder = false)
|
450
|
+
|
451
|
+
# Do a little razzle-dazzle for the common case when a single code is given
|
452
|
+
if not [Set, Array].include? code.class
|
453
|
+
c = code
|
454
|
+
elsif code.size == 1
|
455
|
+
c = code.first
|
456
|
+
end
|
457
|
+
if c
|
458
|
+
return self.find_all { |s| c == s.code}.map {|s| s.data}
|
459
|
+
end
|
460
|
+
|
461
|
+
# unless [Set, Array].include? code.class
|
462
|
+
# code = [code]
|
463
|
+
# # puts "Arrayified for code #{code} / #{code.class}"
|
464
|
+
# end
|
465
|
+
if myorder
|
466
|
+
subs = []
|
467
|
+
code.each do |c|
|
468
|
+
subs << self.find_all {|s| c == s.code}
|
469
|
+
end
|
470
|
+
return subs.flatten.map {|s| s.data}
|
471
|
+
else
|
472
|
+
return self.find_all{|s| code.include? s.code}.map {|s| s.data}
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
# Get first indicator as a one-character string
|
477
|
+
def indicator1
|
478
|
+
return self.getIndicator1.chr
|
479
|
+
end
|
480
|
+
|
481
|
+
# Get second indicator as a one-character string
|
482
|
+
def indicator2
|
483
|
+
return self.getIndicator2.chr
|
484
|
+
end
|
485
|
+
|
486
|
+
# Iterate over the subfields
|
487
|
+
def each
|
488
|
+
self.getSubfields.each do |s|
|
489
|
+
yield s
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
# Get the concatentated values of the subfields in order the appear in the field
|
494
|
+
# @param [String] joiner The string used to join the subfield values
|
495
|
+
def value joiner=' '
|
496
|
+
data = self.getSubfields.map {|s| s.data}
|
497
|
+
return data.join(joiner)
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
class SubField
|
502
|
+
|
503
|
+
def == other
|
504
|
+
return ((self.code == other.code) and (self.data == other.data))
|
505
|
+
end
|
506
|
+
|
507
|
+
def value
|
508
|
+
return self.data
|
509
|
+
end
|
510
|
+
|
511
|
+
def code
|
512
|
+
return self.getCode.chr
|
513
|
+
end
|
514
|
+
|
515
|
+
def to_s
|
516
|
+
return '$' + self.code + " " + self.data
|
517
|
+
end
|
518
|
+
end
|
data/spec/batch.dat
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
00755cam 22002414a 4500001001300000003000600013005001700019008004100036010001700077020004300094040001800137042000800155050002600163082001700189100003100206245005400237260004200291300007200333500003300405650003700438630002500475630001300500fol05731351 IMchF20000613133448.0000107s2000 nyua 001 0 eng a 00020737 a0471383147 (paper/cd-rom : alk. paper) aDLCcDLCdDLC apcc00aQA76.73.P22bM33 200000a005.13/32211 aMartinsson, Tobias,d1976-10aActivePerl with ASP and ADO /cTobias Martinsson. aNew York :bJohn Wiley & Sons,c2000. axxi, 289 p. :bill. ;c23 cm. +e1 computer laser disc (4 3/4 in.) a"Wiley Computer Publishing." 0aPerl (Computer program language)00aActive server pages.00aActiveX.00647pam 2200241 a 4500001001300000003000600013005001700019008004100036010001700077020001500094040001800109042000800127050002600135082001500161100002600176245006700202260003800269263000900307300001100316650003700327650002500364700001600389fol05754809 IMchF20000601115601.0000203s2000 mau 001 0 eng a 00022023 a1565926994 aDLCcDLCdDLC apcc00aQA76.73.P22bD47 200000a005.742211 aDescartes, Alligator.10aProgramming the Perl DBI /cAlligator Descartes and Tim Bunce. aCmabridge, MA :bO'Reilly,c2000. a1111 ap. cm. 0aPerl (Computer program language) 0aDatabase management.1 aBunce, Tim.00605cam 22002054a 4500001001300000003000600013005001700019008004100036010001700077040001800094042000800112050002700120082001700147100002100164245005500185260004500240300002600285504005100311650003700362fol05843555 IMchF20000525142739.0000318s1999 cau b 001 0 eng a 00501349 aDLCcDLCdDLC apcc00aQA76.73.P22bB763 199900a005.13/32211 aBrown, Martin C.10aPerl :bprogrammer's reference /cMartin C. Brown. aBerkeley :bOsborne/McGraw-Hill,cc1999. axix, 380 p. ;c22 cm. aIncludes bibliographical references and index. 0aPerl (Computer program language)00579cam 22002054a 4500001001300000003000600013005001700019008004100036010001700077020001500094040001800109042000800127050002700135082001700162100002100179245005500200260004500255300003600300650003700336fol05843579 IMchF20000525142716.0000318s1999 caua 001 0 eng a 00502116 a0072120002 aDLCcDLCdDLC apcc00aQA76.73.P22bB762 199900a005.13/32211 aBrown, Martin C.10aPerl :bthe complete reference /cMartin C. Brown. aBerkeley :bOsborne/McGraw-Hill,cc1999. axxxv, 1179 p. :bill. ;c24 cm. 0aPerl (Computer program language)00801nam 22002778a 4500001001300000003000600013005001700019008004100036010001700077020001500094040001300109042000800122050002600130082001800156100002000174245008800194250003200282260004100314263000900355300001100364650003700375650003600412650002600448700002500474700002400499fol05848297 IMchF20000524125727.0000518s2000 mau 001 0 eng a 00041664 a1565924193 aDLCcDLC apcc00aQA76.73.P22bG84 200000a005.2/7622211 aGuelich, Scott.10aCGI programming with Perl /cScott Guelich, Shishir Gundavaram & Gunther Birznieks. a2nd ed., expanded & updated aCambridge, Mass. :bO'Reilly,c2000. a0006 ap. cm. 0aPerl (Computer program language) 0aCGI (Computer network protocol) 0aInternet programming.1 aGundavaram, Shishir.1 aBirznieks, Gunther.00665nam 22002298a 4500001001300000003000600013005001700019008004100036010001700077020001500094040001300109042000800122050002700130082001700157111005200174245008600226250001200312260004100324263000900365300001100374650005000385fol05865950 IMchF20000615103017.0000612s2000 mau 100 0 eng a 00055759 a0596000138 aDLCcDLC apcc00aQA76.73.P22bP475 200000a005.13/32212 aPerl Conference 4.0d(2000 :cMonterey, Calif.)10aProceedings of the Perl Conference 4.0 :bJuly 17-20, 2000, Monterey, California. a1st ed. aCambridge, Mass. :bO'Reilly,c2000. a0006 ap. cm. 0aPerl (Computer program language)vCongresses.00579nam 22002178a 4500001001300000003000600013005001700019008004100036010001700077020001500094040001300109042000800122050002600130082001700156100002800173245006200201260004100263263000900304300001100313650003700324fol05865956 IMchF20000615102948.0000612s2000 mau 000 0 eng a 00055770 a1565926099 aDLCcDLC apcc00aQA76.73.P22bB43 200000a005.13/32211 aBlank-Edelman, David N.10aPerl for system administration /cDavid N. Blank-Edelman. aCambridge, Mass. :bO'Reilly,c2000. a0006 ap. cm. 0aPerl (Computer program language)00661nam 22002538a 4500001001300000003000600013005001700019008004100036010001700077020001500094040001300109042000800122050002600130082001700156100001700173245006700190250001200257260004100269263000900310300001100319650003700330700002300367700001700390fol05865967 IMchF20000615102611.0000614s2000 mau 000 0 eng a 00055799 a0596000278 aDLCcDLC apcc00aQA76.73.P22bW35 200000a005.13/32211 aWall, Larry.10aProgramming Perl /cLarry Wall, Tom Christiansen & Jon Orwant. a3rd ed. aCambridge, Mass. :bO'Reilly,c2000. a0007 ap. cm. 0aPerl (Computer program language)1 aChristiansen, Tom.1 aOrwant, Jon.00603cam 22002054a 4500001001300000003000600013005001700019008004100036010001700077020001500094040001800109042000800127050002600135082001700161100003200178245006000210260005700270300003300327650003700360fol05872355 IMchF20000706095105.0000315s1999 njua 001 0 eng a 00500678 a013020868X aDLCcDLCdDLC apcc00aQA76.73.P22bL69 199900a005.13/32211 aLowe, Vincentq(Vincent D.)10aPerl programmer's interactive workbook /cVincent Lowe. aUpper Saddle River, NJ :bPrentice Hall PTP,cc1999. axx, 633 p. :bill. ;c23 cm. 0aPerl (Computer program language)00696nam 22002538a 4500001001300000003000600013005001700019008004100036010001700077020002800094040001300122042000800135050002600143082001700169100002600186245004400212260005100256263000900307300001100316500002000327650003700347650001700384650004100401fol05882032 IMchF20000707091904.0000630s2000 cau 001 0 eng a 00058174 a0764547291 (alk. paper) aDLCcDLC apcc00aQA76.73.P22bF64 200000a005.13/32212 aFoster-Johnson, Eric.10aCross-platform Perl /cEric F. Johnson. aFoster City, CA :bIDG Books Worldwide,c2000. a0009 ap. cm. aIncludes index. 0aPerl (Computer program language) 0aWeb servers. 0aCross-platform software development.
|