marc 0.0.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/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: []
|