marc4j4r 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/marc4j4r.rb ADDED
@@ -0,0 +1,345 @@
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
+ module MARC4J4R
15
+
16
+ # Add some sugar to the MarcReader interface
17
+ #
18
+ # Adjust the interface so that a #new call to any implementations that
19
+ # implement it can take a java.io.InputStream, ruby IO obejct, or String
20
+ # (that will be interpreted as a filename) without complaining.
21
+ #
22
+ # The mechanism -- running module_eval on a string-representation of the
23
+ # new method in each of the hard-coded implementations of MarcReader
24
+ # (MarcStreamReader,MarcPermissiveStreamReader,MarcXmlReader) -- is ugly
25
+ # and deeply unsettling.
26
+ #
27
+ # @author Bill Dueber
28
+ #
29
+ # A string used to override the initializer for each stream reader
30
+ # Need to do it this ugly way because of the way java and ruby interact;
31
+ # can't just add it to the MarcReader interface the way I wanted to.
32
+
33
+ NEWINIT = <<-ENDBINDER
34
+ alias_method :oldinit, :initialize
35
+ def initialize(fromwhere)
36
+ stream = nil
37
+ if fromwhere.is_a? Java::JavaIO::InputStream
38
+ stream = fromwhere
39
+ elsif fromwhere.is_a? IO
40
+ stream = fromwhere.to_inputstream
41
+ else
42
+ stream = java.io.FileInputStream.new(fromwhere.to_java_string)
43
+ end
44
+ if self.class == Java::org.marc4j.MarcPermissiveStreamReader
45
+ self.oldinit(stream, true, true)
46
+ else
47
+ self.oldinit(stream)
48
+ end
49
+ end
50
+ ENDBINDER
51
+
52
+ Java::org.marc4j.MarcStreamReader.module_eval(NEWINIT)
53
+ Java::org.marc4j.MarcPermissiveStreamReader.module_eval(NEWINIT)
54
+ Java::org.marc4j.MarcXmlReader.module_eval(NEWINIT)
55
+
56
+
57
+ # Get a marc reader of the appropriate type
58
+ # @param [String, IO, java.io.InputStream] input The IO stream (or filename) from which you want to read
59
+ # @param [:strictmarc, :permissivemarc, :marcxml] The type of MARC reader you want.
60
+ # @return [MarcReader] A MarcReader object with the syntactic sugar added in this file (e.g, each)
61
+ #
62
+ # @example Get a strict binary MARC reader for the file 'test.mrc'
63
+ # reader = MARC4J4R.reader('test.mrc')
64
+ #
65
+ # @example Get a permissive binary MARC reader
66
+ # reader = MARC4J4R.reader('test.mrc', :permissivemarc)
67
+ #
68
+ # @example Get a reader for an xml file
69
+ # reader = MARC4J4R.reader('test.xml', :marcxml)
70
+ #
71
+ # @example Get a reader based on an existing IO object
72
+ # require 'open-uri'
73
+ # infile = open('http://my.machine.com/test.mrc')
74
+ # reader = MARC4J4R.reader(infile)
75
+
76
+ def reader(input, type = :strictmarc)
77
+ case type
78
+ when :strictmarc
79
+ return Java::org.marc4j.MarcStreamReader.new(input)
80
+ when :permissivemarc
81
+ return Java::org.marc4j.MarcPermissiveStreamReader.new(input)
82
+ when :marcxml
83
+ return Java::org.marc4j.MarcXmlReader.new(input)
84
+ else
85
+ raise ArgumentError, "Reader type must be :strictmarc, :permissivemarc, or :marcxml"
86
+ end
87
+ end
88
+ module_function :reader
89
+
90
+ end
91
+
92
+
93
+ # Re-open the MarcReader interface, define #each and include Enumerable
94
+ #
95
+ # We also automatically call #hashify on the records that stream through
96
+ # #each in order to speed up RecordImpl#[] when (a) doing many operations on a single
97
+ # record, and (b) we're not worried about interleaved tags (e.g., a 520 followed by a 510 followed
98
+ # by another 520)
99
+
100
+ module Java::OrgMarc4j::MarcReader
101
+ include Enumerable
102
+
103
+ # Return the next record, after calling #hashify on it
104
+ def each
105
+ while self.hasNext
106
+ r = self.next
107
+ r.hashify
108
+ yield r
109
+ end
110
+ end
111
+ end
112
+
113
+
114
+
115
+ include_class Java::org.marc4j.marc.impl::RecordImpl
116
+ include_class Java::org.marc4j.marc.impl::ControlFieldImpl
117
+ include_class Java::org.marc4j.marc.impl::DataFieldImpl
118
+ include_class Java::org.marc4j.marc.impl::SubfieldImpl
119
+
120
+ # Open up RecordImpl to add some sugar, including Enumberable as well
121
+ # @author Bill Dueber
122
+
123
+ class RecordImpl
124
+ include Enumerable
125
+
126
+ # Create a local hash by tag number; makes some stuff faster
127
+ # Called automatically if you use reader.each
128
+
129
+ def hashify
130
+ return if @hashedtags # don't do it more than once
131
+ @hashedtags = {}
132
+ self.getVariableFields.each do |f|
133
+ @hashedtags[f.tag] ||= []
134
+ @hashedtags[f.tag].push f
135
+ end
136
+ end
137
+
138
+ # Create a nice string of the record
139
+ def to_s
140
+ arr = ['LEADER ' + self.leader]
141
+ self.each do |f|
142
+ arr.push f.to_s
143
+ end
144
+ return arr.join("\n")
145
+ end
146
+
147
+ # Get the leader as a string (marc4j would otherwise return Leader object)
148
+ def leader
149
+ self.get_leader.toString
150
+ end
151
+
152
+ # Cycle through the fields in the order the appear in the record
153
+ def each
154
+ self.getVariableFields.each do |f|
155
+ yield f
156
+ end
157
+ end
158
+
159
+ # Get the first field associated with a tag
160
+ # @param [String] tag The tag
161
+ # @return [Field] The first matching field, or nil if none. Note that
162
+ # to mirror ruby-marc, this returns a single field
163
+
164
+ def [] tag
165
+ if defined? @hashedtags
166
+ return @hashedtags[tag][0]
167
+ else
168
+ return self.getVariableField(tag)
169
+ end
170
+ end
171
+
172
+
173
+ # Get a (possibly empty) list of fields with the given tag(s)
174
+ #
175
+ # @param [String, Array<String>] tags A string (or Array of strings) with the tags you're interested in
176
+ # @param [Boolean] originalorder Whether or not results should be presented in the original order within the
177
+ # record or with a two-column sort of (a) Order of the tag in the list of tags sent, (b) order within that tag
178
+ # in the record
179
+ # @return [Array<Field>] Either an empty list or a list of one or more matched fields will be returned.
180
+ #
181
+ # originalorder == false will use an internal hash and be faster in many cases (see #hashify)
182
+ #
183
+ # @example originalorder == false
184
+ # # Given a record that looks like
185
+ # # 010 $a 68027371
186
+ # # 035 $a (RLIN)MIUG0001728-B
187
+ # # 035 $a (CaOTULAS)159818044
188
+ # # 035 $a (OCoLC)ocm00001728
189
+ #
190
+ # r.find_by_tag(['035', '010']).each {|f| puts f.to_s}
191
+ # # 035 $a (RLIN)MIUG0001728-B
192
+ # # 035 $a (CaOTULAS)159818044
193
+ # # 035 $a (OCoLC)ocm00001728
194
+ # # 010 $a 68027371
195
+ #
196
+ # # The results are ordered first by tag as passed in, then by original order within the tag
197
+ #
198
+ # @example originalorder == true
199
+ # r.find_by_tag(['035', '010'], true).each {|f| puts f.to_s}
200
+ # # 010 $a 68027371
201
+ # # 035 $a (RLIN)MIUG0001728-B
202
+ # # 035 $a (CaOTULAS)159818044
203
+ # # 035 $a (OCoLC)ocm00001728
204
+
205
+
206
+ def find_by_tag(tags, originalorder = false)
207
+ if !tags.is_a? Array
208
+ tags = [tags]
209
+ end
210
+ if (originalorder == false and @hashedtags == nil)
211
+ self.hashify
212
+ end
213
+ if originalorder
214
+ return self.find_all {|f| tags.include? f.tag}
215
+ else
216
+ # puts "Tags is #{tags}: got #{@hashedtags.values_at(*tags)}"
217
+ return @hashedtags.values_at(*tags).flatten.compact
218
+ end
219
+ end
220
+
221
+
222
+ # Return the record as valid MARC-XML
223
+ # @return String A MARC-XML representation of the record, including the XML header
224
+ def to_xml
225
+ return @xml if @xml
226
+ @xml = java.io.StringWriter.new
227
+ res = javax.xml.transform.stream.StreamResult.new(@xml)
228
+ writer = org.marc4j.MarcXmlWriter.new(res)
229
+ writer.write(self)
230
+ return @xml.toString
231
+ end
232
+
233
+ end
234
+
235
+ class ControlFieldImpl
236
+ def value
237
+ return self.data
238
+ end
239
+
240
+ # Pretty-print
241
+ # @param [String] joiner What string to use to join the subfields
242
+ # @param [String] The pretty string
243
+ def to_s
244
+ return self.tag + " " + self.value
245
+ end
246
+
247
+ end
248
+
249
+ class DataFieldImpl
250
+ include Enumerable
251
+
252
+ # Pretty-print
253
+ # @param [String] joiner What string to use to join the subfields
254
+ # @param [String] The pretty string
255
+ def to_s (joiner = ' ')
256
+ arr = [self.tag + ' ' + self.indicator1 + self.indicator2]
257
+ self.each do |s|
258
+ arr.push s.to_s
259
+ end
260
+ return arr.join(joiner)
261
+ end
262
+
263
+ # Get the value of the first subfield of this field with the given code
264
+ # @param [String] code 1-character string of the subfield code
265
+ # @return [String] The value of the first matched subfield
266
+ def [] code
267
+ raise ArgumentError, "Code must be a one-character string, not #{code}" unless code.is_a? String and code.size == 1
268
+ # note that code[0] is just converting the one-character string into an integer
269
+ # char value that the underlying java can deal with
270
+ self.getSubfield(code[0]).getData
271
+ end
272
+
273
+
274
+ # Get all values from the subfields for the given code or array of codes
275
+ # @param [String, Array<String>] code (Array of?) 1-character string(s) of the subfield code
276
+ # @param [Boolean] myorder Use the order of subfields that I gave instead of the order they're in the record
277
+ # @return [Array<String>] A possibly-empty array of Strings made up of the values in the subfields whose
278
+ # code is included in the given codes. If myorder == true, use the order in which they are passed in; if a code is repeated
279
+ # (ocassionally legal) subfield values will appear first ordered by the passed array, then by order within
280
+ # the document.
281
+ #
282
+ # If myorder is false, just return the values for matching subfields in the order they appear in the field.
283
+ #
284
+ # @example Quick examples:
285
+ # # 260 $a New York, $b Van Nostrand Reinhold Co. $c 1969
286
+ # rec['260'].sub_values('a') #=> ["New York,"]
287
+ # rec['260'].sub_values(['a', 'c']) #=> ["New York,", "1969"]
288
+ # rec['260'].sub_values(['c', 'a']) #=> ["New York,", "1969"]
289
+ # rec['260'].sub_values(['c', 'a'], true) #=> ["1969", "New York"]
290
+
291
+ def sub_values(code, myorder = false)
292
+ unless [Set, Array].include? code.class
293
+ code = [code]
294
+ # puts "Arrayified for code #{code} / #{code.class}"
295
+ end
296
+ if myorder
297
+ subs = []
298
+ code.each do |c|
299
+ subs << self.find_all {|s| c == s.code}
300
+ end
301
+ return subs.flatten.map {|s| s.data}
302
+ else
303
+ return self.find_all{|s| code.include? s.code}.map {|s| s.data}
304
+ end
305
+ end
306
+
307
+ # Get first indicator as a one-character string
308
+ def indicator1
309
+ return self.getIndicator1.chr
310
+ end
311
+
312
+ # Get second indicator as a one-character string
313
+ def indicator2
314
+ return self.getIndicator2.chr
315
+ end
316
+
317
+ # Iterate over the subfields
318
+ def each
319
+ self.getSubfields.each do |s|
320
+ yield s
321
+ end
322
+ end
323
+
324
+ # Get the concatentated values of the subfields in order the appear in the field
325
+ # @param [String] joiner The string used to join the subfield values
326
+ def value joiner=' '
327
+ data = self.getSubfields.map {|s| s.data}
328
+ return data.join(joiner)
329
+ end
330
+ end
331
+
332
+ class SubfieldImpl
333
+
334
+ def value
335
+ return self.data
336
+ end
337
+
338
+ def code
339
+ return self.getCode.chr
340
+ end
341
+
342
+ def to_s
343
+ return '$' + self.code + " " + self.data
344
+ end
345
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'marc4j4r'
8
+
9
+ class Test::Unit::TestCase
10
+ end
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/one.xml ADDED
@@ -0,0 +1,55 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.loc.gov/MARC21/slim" xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd">
3
+ <record>
4
+ <leader> njm a22 uu 4500</leader>
5
+ <controlfield tag="001">afc99990058366</controlfield>
6
+ <controlfield tag="003">DLC</controlfield>
7
+ <controlfield tag="005">20071104155141.9</controlfield>
8
+ <controlfield tag="007">sd ummunniauub</controlfield>
9
+ <controlfield tag="008">071103s1939 xxufmnne||||||||| u eng||</controlfield>
10
+ <datafield tag="010" ind1=" " ind2=" ">
11
+ <subfield code="a">afc99990058366</subfield>
12
+ </datafield>
13
+ <datafield tag="040" ind1=" " ind2=" ">
14
+ <subfield code="a">DLC</subfield>
15
+ <subfield code="c">DLC</subfield>
16
+ </datafield>
17
+ <datafield tag="245" ind1="0" ind2="4">
18
+ <subfield code="a">The Texas ranger</subfield>
19
+ <subfield code="h">[sound recording] /</subfield>
20
+ <subfield code="c">Sung by Beale D. Taylor.</subfield>
21
+ </datafield>
22
+ <datafield tag="260" ind1=" " ind2=" ">
23
+ <subfield code="a">Medina, Texas,</subfield>
24
+ <subfield code="c">1939.</subfield>
25
+ </datafield>
26
+ <datafield tag="300" ind1=" " ind2=" ">
27
+ <subfield code="a">1 sound disc :</subfield>
28
+ <subfield code="b">analog, 33 1/3 rpm, mono. ;</subfield>
29
+ <subfield code="c">12 in.</subfield>
30
+ </datafield>
31
+ <datafield tag="651" ind1=" " ind2="0">
32
+ <subfield code="a">Medina</subfield>
33
+ <subfield code="z">Texas</subfield>
34
+ <subfield code="z">United States of America.</subfield>
35
+ </datafield>
36
+ <datafield tag="700" ind1="1" ind2=" ">
37
+ <subfield code="a">Lomax, John Avery, 1867-1948</subfield>
38
+ <subfield code="e">Recording engineer.</subfield>
39
+ </datafield>
40
+ <datafield tag="700" ind1="1" ind2=" ">
41
+ <subfield code="a">Lomax, Ruby T. (Ruby Terrill)</subfield>
42
+ <subfield code="e">Recording engineer.</subfield>
43
+ </datafield>
44
+ <datafield tag="700" ind1="1" ind2=" ">
45
+ <subfield code="a">Taylor, Beale D.</subfield>
46
+ <subfield code="e">Singer.</subfield>
47
+ </datafield>
48
+ <datafield tag="852" ind1=" " ind2=" ">
49
+ <subfield code="a">American Folklife Center, Library of Congress</subfield>
50
+ </datafield>
51
+ <datafield tag="852" ind1=" " ind2=" ">
52
+ <subfield code="a">DLC</subfield>
53
+ </datafield>
54
+ </record>
55
+ </collection>
@@ -0,0 +1,76 @@
1
+ require 'helper'
2
+
3
+ # one.xml
4
+ # LEADER 00000njm a2200000uu 4500
5
+ # 001 afc99990058366
6
+ # 003 DLC
7
+ # 005 20071104155141.9
8
+ # 007 sd ummunniauub
9
+ # 008 071103s1939 xxufmnne||||||||| u eng||
10
+ # 010 $a afc99990058366
11
+ # 040 $a DLC $c DLC
12
+ # 245 04 $a The Texas ranger $h [sound recording] / $c Sung by Beale D. Taylor.
13
+ # 260 $a Medina, Texas, $c 1939.
14
+ # 300 $a 1 sound disc : $b analog, 33 1/3 rpm, mono. ; $c 12 in.
15
+ # 651 0 $a Medina $z Texas $z United States of America.
16
+ # 700 1 $a Lomax, John Avery, 1867-1948 $e Recording engineer.
17
+ # 700 1 $a Lomax, Ruby T. (Ruby Terrill) $e Recording engineer.
18
+ # 700 1 $a Taylor, Beale D. $e Singer.
19
+ # 852 $a American Folklife Center, Library of Congress
20
+ # 852 $a DLC
21
+
22
+ class TestMarc4j4r < Test::Unit::TestCase
23
+
24
+ def setup
25
+ reader = MARC4J4R.reader(File.dirname(__FILE__) + '/one.xml', :marcxml)
26
+ @r = reader.next
27
+ end
28
+
29
+ should "get the leader as a string" do
30
+ assert_equal '00000njm a2200000uu 4500', @r.leader
31
+ end
32
+
33
+ should "get all fields with the given tag" do
34
+ assert_equal 3, @r.find_by_tag('700').size
35
+ end
36
+
37
+ should "get all fields with any of the given tags" do
38
+ assert_equal 6, @r.find_by_tag(['010','700', '852']).size
39
+ end
40
+
41
+ should "get an empty array trying to find a non-existent tag" do
42
+ assert_equal [], @r.find_by_tag('002')
43
+ end
44
+
45
+ should "not return anything for a non-existent tag" do
46
+ assert_equal 1, @r.find_by_tag(['010', '002']).size
47
+ end
48
+
49
+ should "get the value of a control tag" do
50
+ assert_equal 'DLC', @r['003'].value
51
+ end
52
+
53
+ should "get a subfield value via field[]" do
54
+ assert_equal 'Sung by Beale D. Taylor.', @r['245']['c']
55
+ end
56
+
57
+ should "joing all values of a field with a space" do
58
+ assert_equal "DLC DLC", @r['040'].value
59
+ end
60
+
61
+ should "Get the first field with a given tag via []" do
62
+ assert_equal '700 1 $a Lomax, John Avery, 1867-1948 $e Recording engineer.', @r['700'].to_s
63
+ end
64
+
65
+ should "get the subfield values in order of the original record" do
66
+ assert_equal ['Medina, Texas,', '1939.'], @r['260'].sub_values(['a', 'c'])
67
+ assert_equal ['Medina, Texas,', '1939.'], @r['260'].sub_values(['c', 'a'])
68
+ end
69
+
70
+ should "get the subfield values in order of the codes I pass" do
71
+ assert_equal [ '1939.', 'Medina, Texas,'], @r['260'].sub_values(['c', 'a'], true)
72
+ end
73
+
74
+
75
+
76
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: marc4j4r
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - BillDueber
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-14 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: thoughtbot-shoulda
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: yard
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description: Syntactic sugar and some extra methods to deal with classes in the marc4j java package
36
+ email: bill@dueber.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.markdown
44
+ files:
45
+ - .document
46
+ - .gitignore
47
+ - LICENSE
48
+ - README.markdown
49
+ - Rakefile
50
+ - VERSION
51
+ - doc/ControlFieldImpl.html
52
+ - doc/DataFieldImpl.html
53
+ - doc/Java/OrgMarc4j/MarcReader.html
54
+ - doc/MARC4J4R.html
55
+ - doc/MARC4J4R/Reader.html
56
+ - doc/RecordImpl.html
57
+ - doc/SubfieldImpl.html
58
+ - doc/_index.html
59
+ - doc/class_list.html
60
+ - doc/css/common.css
61
+ - doc/css/full_list.css
62
+ - doc/css/style.css
63
+ - doc/file.README.html
64
+ - doc/file_list.html
65
+ - doc/frames.html
66
+ - doc/index.html
67
+ - doc/js/app.js
68
+ - doc/js/full_list.js
69
+ - doc/js/jquery.js
70
+ - doc/method_list.html
71
+ - doc/top-level-namespace.html
72
+ - jars/marc4j.jar
73
+ - lib/marc4j4r.rb
74
+ - test/helper.rb
75
+ - test/one.dat
76
+ - test/one.xml
77
+ - test/test_marc4j4r.rb
78
+ has_rdoc: true
79
+ homepage: http://github.com/billdueber/marc4j4r
80
+ licenses: []
81
+
82
+ post_install_message:
83
+ rdoc_options:
84
+ - --charset=UTF-8
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: "0"
92
+ version:
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: "0"
98
+ version:
99
+ requirements: []
100
+
101
+ rubyforge_project:
102
+ rubygems_version: 1.3.5
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Use marc4j java library in JRuby in a more ruby-ish way
106
+ test_files:
107
+ - test/helper.rb
108
+ - test/test_marc4j4r.rb