marc 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/marc/control.rb +36 -0
- data/lib/marc/exception.rb +9 -0
- data/lib/marc/field.rb +141 -0
- data/lib/marc/marc21.rb +132 -0
- data/lib/marc/reader.rb +51 -0
- data/lib/marc/record.rb +117 -0
- data/lib/marc/subfield.rb +25 -0
- data/lib/marc/writer.rb +36 -0
- data/lib/marc.rb +8 -0
- data/test/batch.dat +1 -0
- data/test/one.dat +1 -0
- data/test/tc_field.rb +81 -0
- data/test/tc_reader.rb +31 -0
- data/test/tc_record.rb +55 -0
- data/test/tc_subfield.rb +18 -0
- data/test/tc_writer.rb +23 -0
- data/test/ts_marc.rb +12 -0
- metadata +57 -0
data/lib/marc/control.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module MARC
|
2
|
+
|
3
|
+
# A class for representing fields with a tag less than 010.
|
4
|
+
# Ordinary MARC::Field objects are for fields with tags >= 010
|
5
|
+
# which have indicators and subfields.
|
6
|
+
|
7
|
+
class Control
|
8
|
+
|
9
|
+
# the tag value (007, 008, etc)
|
10
|
+
attr_accessor :tag
|
11
|
+
|
12
|
+
# the value of the control field
|
13
|
+
attr_accessor :value
|
14
|
+
|
15
|
+
# The constructor which must be passed a tag value and
|
16
|
+
# an optional value for the field.
|
17
|
+
|
18
|
+
def initialize(tag,value='')
|
19
|
+
@tag = tag
|
20
|
+
@value = value
|
21
|
+
if tag.to_i > 9
|
22
|
+
raise MARC::Exception.new(), "tag must be greater than 009"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
return "#{tag} #{value}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def =~(regex)
|
31
|
+
return self.to_s =~ regex
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/lib/marc/field.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'marc/subfield'
|
2
|
+
require 'marc/record'
|
3
|
+
|
4
|
+
module MARC
|
5
|
+
|
6
|
+
# MARC records are made up of fields, each of which has a tag,
|
7
|
+
# indicators and subfields. If the tag is between 000-009 it is
|
8
|
+
# known as a control field, and actually does not have any
|
9
|
+
# indicators.
|
10
|
+
|
11
|
+
class Field
|
12
|
+
include Enumerable
|
13
|
+
|
14
|
+
# The tag for the field
|
15
|
+
attr_accessor :tag
|
16
|
+
|
17
|
+
# The first indicator
|
18
|
+
attr_accessor :indicator1
|
19
|
+
|
20
|
+
# The second indicator
|
21
|
+
attr_accessor :indicator2
|
22
|
+
|
23
|
+
# A list of MARC::Subfield objects
|
24
|
+
attr_accessor :subfields
|
25
|
+
|
26
|
+
|
27
|
+
# Create a new field with tag, indicators and subfields.
|
28
|
+
# Subfields are passed in as comma separated list of
|
29
|
+
# MARC::Subfield objects,
|
30
|
+
#
|
31
|
+
# field = MARC::Field.new('245','0','0',
|
32
|
+
# MARC::Subfield.new('a', 'Consilience :'),
|
33
|
+
# MARC::Subfield.new('b', 'the unity of knowledge ',
|
34
|
+
# MARC::Subfield.new('c', 'by Edward O. Wilson.'))
|
35
|
+
#
|
36
|
+
# or using a shorthand:
|
37
|
+
#
|
38
|
+
# field = MARC::Field.new('245','0','0',
|
39
|
+
# ['a', 'Consilience :'],['b','the unity of knowledge ',
|
40
|
+
# ['c', 'by Edward O. Wilson.'] )
|
41
|
+
|
42
|
+
def initialize(tag, i1=nil, i2=nil, *subfields)
|
43
|
+
@tag = tag
|
44
|
+
@indicator1 = i1
|
45
|
+
@indicator2 = i2
|
46
|
+
@subfields = []
|
47
|
+
|
48
|
+
# must use MARC::ControlField for tags < 010
|
49
|
+
if @tag.to_i < 10
|
50
|
+
raise MARC::Exception.new(),
|
51
|
+
"MARC::Field objects can't have tags < 010"
|
52
|
+
end
|
53
|
+
|
54
|
+
# allows MARC::Subfield objects to be passed directly
|
55
|
+
# or a shorthand of ['a','Foo'], ['b','Bar']
|
56
|
+
subfields.each do |subfield|
|
57
|
+
case subfield
|
58
|
+
when MARC::Subfield
|
59
|
+
@subfields.push(subfield)
|
60
|
+
when Array
|
61
|
+
if subfield.length > 2
|
62
|
+
raise MARC::Exception.new(),
|
63
|
+
"arrays must only have 2 elements"
|
64
|
+
end
|
65
|
+
@subfields.push(
|
66
|
+
MARC::Subfield.new(subfield[0],subfield[1]))
|
67
|
+
else
|
68
|
+
raise MARC::Exception.new(),
|
69
|
+
"invalid subfield type #{subfield.class}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# Returns a string representation of the field such as:
|
76
|
+
# 245 00 $aConsilience :$bthe unity of knowledge $cby Edward O. Wilson.
|
77
|
+
|
78
|
+
def to_s
|
79
|
+
str = "#{tag} "
|
80
|
+
str += "#{indicator1}#{indicator2} "
|
81
|
+
@subfields.each { |subfield| str += subfield.to_s }
|
82
|
+
return str
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# Add a subfield (MARC::Subfield) to the field
|
87
|
+
# field.append(MARC::Subfield('a','Dave Thomas'))
|
88
|
+
|
89
|
+
def append(subfield)
|
90
|
+
@subfields.push(subfield)
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
# You can iterate through the subfields in a Field:
|
95
|
+
# field.each {|s| print s}
|
96
|
+
|
97
|
+
def each
|
98
|
+
for subfield in subfields
|
99
|
+
yield subfield
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
# You can lookup subfields with this shorthand. Note it
|
105
|
+
# will return a string and not a MARC::Subfield object.
|
106
|
+
# subfield = field['a']
|
107
|
+
|
108
|
+
def [](code)
|
109
|
+
subfield = self.find {|s| s.code == code}
|
110
|
+
return subfield.value if subfield
|
111
|
+
return
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
# Two fields are equal if their tag, indicators and
|
116
|
+
# subfields are all equal.
|
117
|
+
|
118
|
+
def ==(other)
|
119
|
+
if @tag != other.tag
|
120
|
+
return false
|
121
|
+
elsif @indicator1 != other.indicator1
|
122
|
+
return false
|
123
|
+
elsif @indicator2 != other.indicator2
|
124
|
+
return false
|
125
|
+
elsif @subfields != other.subfields
|
126
|
+
return false
|
127
|
+
end
|
128
|
+
return true
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
# To support regex matching with fields
|
133
|
+
#
|
134
|
+
# if field =~ /Huckleberry/ ...
|
135
|
+
|
136
|
+
def =~(regex)
|
137
|
+
return self.to_s =~ regex
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
data/lib/marc/marc21.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
module MARC
|
2
|
+
|
3
|
+
# Provides methods for serializing and deserializing MARC::Record
|
4
|
+
# objects as MARC21 in transmission format.
|
5
|
+
|
6
|
+
class MARC21
|
7
|
+
|
8
|
+
LEADER_LENGTH = 24
|
9
|
+
DIRECTORY_ENTRY_LENGTH = 12
|
10
|
+
SUBFIELD_INDICATOR = 0x1F.chr
|
11
|
+
END_OF_FIELD = 0x1E.chr
|
12
|
+
END_OF_RECORD = 0x1D.chr
|
13
|
+
|
14
|
+
|
15
|
+
# Returns the MARC21 serialization for a MARC::Record
|
16
|
+
|
17
|
+
def encode(record)
|
18
|
+
directory = ''
|
19
|
+
fields = ''
|
20
|
+
offset = 0
|
21
|
+
for field in record.fields
|
22
|
+
|
23
|
+
# encode the field
|
24
|
+
field_data = ''
|
25
|
+
if field.class == MARC::Field
|
26
|
+
field_data = field.indicator1 + field.indicator2
|
27
|
+
for s in field.subfields
|
28
|
+
field_data += SUBFIELD_INDICATOR + s.code + s.value
|
29
|
+
end
|
30
|
+
elsif field.class == MARC::Control
|
31
|
+
field_data = field.value
|
32
|
+
end
|
33
|
+
field_data += END_OF_FIELD
|
34
|
+
|
35
|
+
# calculate directory entry for the field
|
36
|
+
field_length = field_data.length()
|
37
|
+
directory += sprintf("%03s%04i%05i", field.tag, field_length,
|
38
|
+
offset)
|
39
|
+
|
40
|
+
# add field to data for other fields
|
41
|
+
fields += field_data
|
42
|
+
|
43
|
+
# update offset for next field
|
44
|
+
offset += field_length
|
45
|
+
end
|
46
|
+
|
47
|
+
# determine the base (leader + directory)
|
48
|
+
base = record.leader + directory + END_OF_FIELD
|
49
|
+
|
50
|
+
# determine complete record
|
51
|
+
marc = base + fields + END_OF_RECORD
|
52
|
+
|
53
|
+
# update leader with the byte offest to the end of the directory
|
54
|
+
marc[12..16] = sprintf("%05i", base.length())
|
55
|
+
|
56
|
+
# update the record length
|
57
|
+
marc[0..4] = sprintf("%05i", marc.length())
|
58
|
+
|
59
|
+
# store updated leader in the record that was passed in
|
60
|
+
record.leader = marc[0..LEADER_LENGTH]
|
61
|
+
|
62
|
+
# return encoded marc
|
63
|
+
return marc
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
# Deserializes MARC21 as a MARC::Record object
|
68
|
+
|
69
|
+
def decode(marc)
|
70
|
+
record = Record.new()
|
71
|
+
record.leader = marc[0..LEADER_LENGTH]
|
72
|
+
|
73
|
+
# where the field data starts
|
74
|
+
base_address = record.leader[12..16].to_i
|
75
|
+
|
76
|
+
# get the byte offsets from the record directory
|
77
|
+
directory = marc[LEADER_LENGTH..base_address-1]
|
78
|
+
|
79
|
+
# the number of fields in the record corresponds to
|
80
|
+
# how many directory entries there are
|
81
|
+
num_fields = directory.length / DIRECTORY_ENTRY_LENGTH
|
82
|
+
|
83
|
+
0.upto(num_fields-1) do |field_num|
|
84
|
+
|
85
|
+
# pull the directory entry for a field out
|
86
|
+
entry_start = field_num * DIRECTORY_ENTRY_LENGTH
|
87
|
+
entry_end = entry_start + DIRECTORY_ENTRY_LENGTH
|
88
|
+
entry = directory[entry_start..entry_end]
|
89
|
+
|
90
|
+
# extract the tag, length and offset for pulling the
|
91
|
+
# field out of the field portion
|
92
|
+
tag = entry[0..2]
|
93
|
+
length = entry[3..6].to_i
|
94
|
+
offset = entry[7..11].to_i
|
95
|
+
field_start = base_address + offset
|
96
|
+
field_end = field_start + length - 1
|
97
|
+
field_data = marc[field_start..field_end]
|
98
|
+
|
99
|
+
# remove end of field
|
100
|
+
field_data.delete!(END_OF_FIELD)
|
101
|
+
|
102
|
+
# add a control field or variable field
|
103
|
+
if tag < '010'
|
104
|
+
record.append(MARC::Control.new(tag,field_data))
|
105
|
+
else
|
106
|
+
field = MARC::Field.new(tag)
|
107
|
+
|
108
|
+
# get all subfields
|
109
|
+
subfields = field_data.split(SUBFIELD_INDICATOR)
|
110
|
+
|
111
|
+
# get indicators
|
112
|
+
indicators = subfields.shift()
|
113
|
+
field.indicator1 = indicators[0,1]
|
114
|
+
field.indicator2 = indicators[1,1]
|
115
|
+
|
116
|
+
# add each subfield to the field
|
117
|
+
subfields.each() do |data|
|
118
|
+
subfield = MARC::Subfield.new(data[0,1],data[1..-1])
|
119
|
+
field.append(subfield)
|
120
|
+
end
|
121
|
+
|
122
|
+
# add the field to the record
|
123
|
+
record.append(field)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
return record
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
data/lib/marc/reader.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module MARC
|
2
|
+
|
3
|
+
class Reader
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
# The constructor which you may pass either a path
|
7
|
+
#
|
8
|
+
# reader = MARC::Reader.new('marc.dat')
|
9
|
+
#
|
10
|
+
# or, if it's more convenient a File object:
|
11
|
+
#
|
12
|
+
# fh = File.new('marc.dat')
|
13
|
+
# reader = MARC::Reader.new(fh)
|
14
|
+
#
|
15
|
+
# or really any object that responds to read(n).
|
16
|
+
|
17
|
+
def initialize(file)
|
18
|
+
if file.class == String:
|
19
|
+
@handle = File.new(file)
|
20
|
+
elsif file.respond_to?("read", 5)
|
21
|
+
@handle = file
|
22
|
+
else
|
23
|
+
throw "must pass in path or file"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# to support iteration:
|
28
|
+
# for record in reader
|
29
|
+
# print record
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# and even searching:
|
33
|
+
# record.find { |f| f['245'] =~ /Huckleberry/ }
|
34
|
+
|
35
|
+
def each
|
36
|
+
# while there is data left in the file
|
37
|
+
while length = @handle.read(5)
|
38
|
+
|
39
|
+
# get the raw MARC21 for a record back from the file
|
40
|
+
# using the record length
|
41
|
+
raw = length + @handle.read(length.to_i-5)
|
42
|
+
|
43
|
+
# create a record from the data and return it
|
44
|
+
record = MARC::Record.new_from_marc(raw)
|
45
|
+
yield record
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/marc/record.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
module MARC
|
2
|
+
|
3
|
+
# A class that represents an individual MARC record. Every record
|
4
|
+
# is made up of a collection of MARC::Field objects.
|
5
|
+
|
6
|
+
class Record
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
# the record fields
|
10
|
+
attr_accessor :fields,
|
11
|
+
|
12
|
+
# the record leader
|
13
|
+
:leader
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@fields = []
|
17
|
+
# leader is 24 bytes
|
18
|
+
@leader = ' ' * 24
|
19
|
+
# leader defaults:
|
20
|
+
# http://www.loc.gov/marc/bibliographic/ecbdldrd.html
|
21
|
+
@leader[10..11] = '22'
|
22
|
+
@leader[20..23] = '4500';
|
23
|
+
end
|
24
|
+
|
25
|
+
# add a field to the record
|
26
|
+
# record.append(MARC::Field.new( '100', '2', '0', ['a', 'Fred']))
|
27
|
+
|
28
|
+
def append(field)
|
29
|
+
@fields.push(field)
|
30
|
+
end
|
31
|
+
|
32
|
+
# each() is here to support iterating and searching since MARC::Record
|
33
|
+
# mixes in Enumberable
|
34
|
+
#
|
35
|
+
# iterating through the fields in a record:
|
36
|
+
# record.each { |f| print f }
|
37
|
+
#
|
38
|
+
# getting the 245
|
39
|
+
# title = record.find {|f| f.tag == '245'}
|
40
|
+
#
|
41
|
+
# getting all subjects
|
42
|
+
# subjects = record.find_all {|f| ('600'..'699' === f.tag)}
|
43
|
+
|
44
|
+
def each
|
45
|
+
for field in @fields
|
46
|
+
yield field
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# You can lookup fields using this shorthand:
|
51
|
+
# title = record['245']
|
52
|
+
|
53
|
+
def [](tag)
|
54
|
+
return self.find {|f| f.tag == tag}
|
55
|
+
end
|
56
|
+
|
57
|
+
# Factory method for creating a MARC::Record from MARC21 in
|
58
|
+
# transmission format. Really this is just a wrapper around
|
59
|
+
# MARC::MARC21::decode
|
60
|
+
#
|
61
|
+
# record = MARC::Record.new_from_marc(marc21)
|
62
|
+
|
63
|
+
|
64
|
+
def Record::new_from_marc(raw)
|
65
|
+
return MARC::MARC21.new().decode(raw)
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# Handy method for returning a the MARC21 serialization for a
|
70
|
+
# MARC::Record object. Really this is just a wrapper around
|
71
|
+
# MARC::MARC21::encode
|
72
|
+
#
|
73
|
+
# marc = record.to_marc()
|
74
|
+
|
75
|
+
def to_marc
|
76
|
+
return MARC::MARC21.new().encode(self)
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
# Returns a string version of the record, suitable for printing
|
81
|
+
|
82
|
+
def to_s
|
83
|
+
str = "LEADER #{leader}\n"
|
84
|
+
for field in fields:
|
85
|
+
str += field.to_s() + "\n"
|
86
|
+
end
|
87
|
+
return str
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
# For testing if two records can be considered equal.
|
92
|
+
|
93
|
+
def ==(other)
|
94
|
+
if @leader != other.leader:
|
95
|
+
return false
|
96
|
+
elsif @fields.length != other.fields.length()
|
97
|
+
return false
|
98
|
+
else
|
99
|
+
for i in [0..@fields.length()]:
|
100
|
+
return false if @fields[i] != other.fields[i]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
return true
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
# Handy for using a record in a regex:
|
108
|
+
# if record =~ /Gravity's Rainbow/ then print "Slothrop" end
|
109
|
+
|
110
|
+
def =~(regex)
|
111
|
+
return self.to_s =~ regex
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module MARC
|
2
|
+
|
3
|
+
class Subfield
|
4
|
+
attr_accessor :code, :value
|
5
|
+
|
6
|
+
def initialize(code,value)
|
7
|
+
@code = code
|
8
|
+
@value = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def ==(other)
|
12
|
+
if @code != other.code
|
13
|
+
return false
|
14
|
+
elsif @value != other.value
|
15
|
+
return false
|
16
|
+
end
|
17
|
+
return true
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
return "$#{code}#{value}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/lib/marc/writer.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module MARC
|
2
|
+
|
3
|
+
# A class for writing MARC records as MARC21.
|
4
|
+
|
5
|
+
class Writer
|
6
|
+
|
7
|
+
# the constructor which you must pass a file path
|
8
|
+
# or an object that responds to a write message
|
9
|
+
|
10
|
+
def initialize(file)
|
11
|
+
if file.class == String
|
12
|
+
@fh = File.new(file,"w")
|
13
|
+
elsif file.respond_to?(file)
|
14
|
+
@fh = file
|
15
|
+
else
|
16
|
+
throw "must pass in file name or handle"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
# write a record to the file or handle
|
22
|
+
|
23
|
+
def write(record)
|
24
|
+
@fh.write(record.to_marc)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# close underlying filehandle
|
29
|
+
|
30
|
+
def close
|
31
|
+
@fh.close
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/lib/marc.rb
ADDED
data/test/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.
|
data/test/one.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.
|
data/test/tc_field.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'marc'
|
3
|
+
|
4
|
+
class TestField < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_tag
|
7
|
+
f1 = MARC::Field.new('100')
|
8
|
+
assert_equal('100', f1.tag)
|
9
|
+
f2 = MARC::Field.new(tag='100')
|
10
|
+
assert_equal('100', f2.tag)
|
11
|
+
assert_equal(f1, f2)
|
12
|
+
f3 = MARC::Field.new('245')
|
13
|
+
assert_not_equal(f1, f3)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_indicators
|
17
|
+
f1 = MARC::Field.new('100', '0', '1')
|
18
|
+
assert_equal('0', f1.indicator1)
|
19
|
+
assert_equal('1', f1.indicator2)
|
20
|
+
f2 = MARC::Field.new(tag='100',i1='0',i2='1')
|
21
|
+
assert_equal('0', f2.indicator1)
|
22
|
+
assert_equal('1', f2.indicator2)
|
23
|
+
assert_equal(f1, f2)
|
24
|
+
f3 = MARC::Field.new(tag='100', i1='1', i2='1')
|
25
|
+
assert_not_equal(f1, f3)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_subfields
|
29
|
+
f1 = MARC::Field.new('100', '0', '1',
|
30
|
+
MARC::Subfield.new('a', 'Foo'),
|
31
|
+
MARC::Subfield.new('b', 'Bar') )
|
32
|
+
assert_equal("100 01 $aFoo$bBar", f1.to_s)
|
33
|
+
f2 = MARC::Field.new('100', '0', '1',
|
34
|
+
MARC::Subfield.new('a', 'Foo'),
|
35
|
+
MARC::Subfield.new('b', 'Bar') )
|
36
|
+
assert_equal(f1,f2)
|
37
|
+
f3 = MARC::Field.new('100', '0', '1',
|
38
|
+
MARC::Subfield.new('a', 'Foo'),
|
39
|
+
MARC::Subfield.new('b', 'Bez') )
|
40
|
+
assert_not_equal(f1,f3)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_subfield_shorthand
|
44
|
+
f = MARC::Field.new('100', '0', '1', ['a', 'Foo'], ['b', 'Bar'])
|
45
|
+
assert_equal('100 01 $aFoo$bBar', f.to_s)
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def test_iterator
|
50
|
+
field = MARC::Field.new('100','0','1', ['a', 'Foo'],['b', 'Bar'],
|
51
|
+
['a', 'Bez'])
|
52
|
+
count = 0
|
53
|
+
field.each {|x| count += 1}
|
54
|
+
assert_equal(count,3)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_lookup_shorthand
|
58
|
+
f = MARC::Field.new('100', '0', '1', ['a', 'Foo'], ['b', 'Bar'])
|
59
|
+
assert_equal(f['b'], 'Bar')
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_control
|
63
|
+
control = MARC::Control.new('005','foobarbaz')
|
64
|
+
assert_equal(control.to_s,'005 foobarbaz')
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_field_as_control
|
68
|
+
assert_raise(MARC::Exception) do
|
69
|
+
# can't have a field with a tag < 010
|
70
|
+
field = MARC::Field.new('007')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_control_as_field
|
75
|
+
assert_raise(MARC::Exception) do
|
76
|
+
# can't have a control with a tag > 009
|
77
|
+
f = MARC::Control.new('245')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
data/test/tc_reader.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'marc'
|
3
|
+
|
4
|
+
class ReaderTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_batch
|
7
|
+
reader = MARC::Reader.new('test/batch.dat')
|
8
|
+
count = 0
|
9
|
+
reader.each { count += 1 }
|
10
|
+
assert_equal(count, 10)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_search
|
14
|
+
reader = MARC::Reader.new('test/batch.dat')
|
15
|
+
records = reader.find_all { |r| r =~ /Perl/ }
|
16
|
+
assert_equal(records.length,10)
|
17
|
+
|
18
|
+
reader = MARC::Reader.new('test/batch.dat')
|
19
|
+
records = reader.find_all { |r| r['245'] =~ /Perl/ }
|
20
|
+
assert_equal(records.length,10)
|
21
|
+
|
22
|
+
reader = MARC::Reader.new('test/batch.dat')
|
23
|
+
records = reader.find_all { |r| r['245']['a'] =~ /Perl/ }
|
24
|
+
assert_equal(records.length,10)
|
25
|
+
|
26
|
+
reader = MARC::Reader.new('test/batch.dat')
|
27
|
+
records = reader.find_all { |r| r =~ /Foo/ }
|
28
|
+
assert_equal(records.length,0)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/test/tc_record.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'marc'
|
3
|
+
|
4
|
+
class TestRecord < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_constructor
|
7
|
+
r = MARC::Record.new()
|
8
|
+
assert_equal(r.class, MARC::Record)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_append_field
|
12
|
+
r = get_record()
|
13
|
+
assert_equal(r.fields.length(), 2)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_iterator
|
17
|
+
r = get_record()
|
18
|
+
count = 0
|
19
|
+
r.each {|f| count += 1}
|
20
|
+
assert_equal(count,2)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_decode
|
24
|
+
raw = IO.read('test/one.dat')
|
25
|
+
r = MARC::Record::new_from_marc(raw)
|
26
|
+
assert_equal(r.class, MARC::Record)
|
27
|
+
assert_equal(r.leader,'00755cam 22002414a 45000')
|
28
|
+
assert_equal(r.fields.length(), 18)
|
29
|
+
assert_equal(r.find {|f| f.tag == '245'}.to_s,
|
30
|
+
'245 10 $aActivePerl with ASP and ADO /$cTobias Martinsson.')
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_encode
|
34
|
+
r1 = MARC::Record.new()
|
35
|
+
r1.append(MARC::Field.new('100','2','0', ['a','Thomas, Dave']))
|
36
|
+
r1.append(MARC::Field.new('245','0','0', ['a','Pragmatic Programmer']))
|
37
|
+
raw = r1.to_marc()
|
38
|
+
r2 = MARC::Record::new_from_marc(raw)
|
39
|
+
assert_equal(r1, r2)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_lookup_shorthand
|
43
|
+
r = get_record
|
44
|
+
assert_equal(r['100']['a'], 'Thomas, Dave')
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_record
|
48
|
+
r = MARC::Record.new()
|
49
|
+
r.append(MARC::Field.new('100', '2', '0', ['a', 'Thomas, Dave']))
|
50
|
+
r.append(MARC::Field.new('245', '0', '4', ['The Pragmatic Programmer']))
|
51
|
+
return r
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
end
|
data/test/tc_subfield.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'marc/subfield'
|
3
|
+
|
4
|
+
class SubfieldTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_ok
|
7
|
+
s = MARC::Subfield.new('a','foo')
|
8
|
+
assert_equal(s.code,'a')
|
9
|
+
assert_equal(s.value,'foo')
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_equals
|
13
|
+
s1 =MARC::Subfield.new('a','foo')
|
14
|
+
s2 =MARC::Subfield.new('a','foo')
|
15
|
+
assert_equal(s1,s2)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/test/tc_writer.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'marc'
|
3
|
+
|
4
|
+
class WriterTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_writer()
|
7
|
+
writer = MARC::Writer.new('test/writer.dat')
|
8
|
+
record = MARC::Record.new()
|
9
|
+
record.append(MARC::Field.new('245', '0', '1', ['a','foo']))
|
10
|
+
writer.write(record)
|
11
|
+
writer.close()
|
12
|
+
|
13
|
+
# read it back to make sure
|
14
|
+
reader = MARC::Reader.new('test/writer.dat')
|
15
|
+
records = reader.entries()
|
16
|
+
assert_equal(records.length(), 1)
|
17
|
+
assert_equal(records[0], record)
|
18
|
+
|
19
|
+
# cleanup
|
20
|
+
File.unlink('test/writer.dat')
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/test/ts_marc.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# local marc library gets tested
|
4
|
+
# not already installed one
|
5
|
+
$LOAD_PATH.unshift("lib")
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
require 'test/tc_subfield'
|
9
|
+
require 'test/tc_field'
|
10
|
+
require 'test/tc_record'
|
11
|
+
require 'test/tc_reader'
|
12
|
+
require 'test/tc_writer'
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: marc
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.2
|
7
|
+
date: 2005-10-17 00:00:00 -05:00
|
8
|
+
summary: A ruby library for working with Machine Readable Cataloging
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: ehs@pobox.com
|
12
|
+
homepage: http://www.textualize.com/marc
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: marc
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
29
|
+
authors:
|
30
|
+
- Ed Summers
|
31
|
+
files:
|
32
|
+
- lib/marc
|
33
|
+
- lib/marc.rb
|
34
|
+
- lib/marc/control.rb
|
35
|
+
- lib/marc/exception.rb
|
36
|
+
- lib/marc/field.rb
|
37
|
+
- lib/marc/marc21.rb
|
38
|
+
- lib/marc/reader.rb
|
39
|
+
- lib/marc/record.rb
|
40
|
+
- lib/marc/subfield.rb
|
41
|
+
- lib/marc/writer.rb
|
42
|
+
- test/batch.dat
|
43
|
+
- test/one.dat
|
44
|
+
- test/tc_field.rb
|
45
|
+
- test/tc_reader.rb
|
46
|
+
- test/tc_record.rb
|
47
|
+
- test/tc_subfield.rb
|
48
|
+
- test/tc_writer.rb
|
49
|
+
- test/ts_marc.rb
|
50
|
+
test_files:
|
51
|
+
- test/ts_marc.rb
|
52
|
+
rdoc_options: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
executables: []
|
55
|
+
extensions: []
|
56
|
+
requirements: []
|
57
|
+
dependencies: []
|