marc4j4r 0.1.6 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|