marc 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,9 @@
1
+ module MARC
2
+
3
+ # basic exception class for exceptions that
4
+ # can occur during MARC processing.
5
+
6
+ class Exception < RuntimeError
7
+ end
8
+
9
+ 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,8 @@
1
+ require 'marc/record'
2
+ require 'marc/field'
3
+ require 'marc/control'
4
+ require 'marc/subfield'
5
+ require 'marc/reader'
6
+ require 'marc/writer'
7
+ require 'marc/exception'
8
+ require 'marc/marc21'
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
@@ -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: []