Class: MARC::Record
Overview
A class that represents an individual MARC record. Every record is made up of a collection of MARC::DataField objects.
MARC::Record mixes in Enumerable to enable access to constituent DataFields. For example, to return a list of all subject DataFields:
record.find_all {|field| field.tag =~ /^6../}
The accessor ‘fields’ is also an Array of MARC::DataField objects which the client can modify if neccesary.
record.fields.delete(field)
Other accessor attribute: ‘leader’ for record leader as String
High-performance lookup by tag
A frequent use case is looking up fields in a MARC record by tag, such as ‘all the 500 fields’. Certain methods can use a hash keyed by tag name for higher performance lookup by tag. The hash is lazily created on first access – there is some cost of creating the hash, testing shows you get a performance advantage to using the hash-based methods if you are doing at least a dozen lookups.
record.fields("500") # returns an array
record.each_by_tag("500") {|field| ... }
record.fields(['100', '700']) # can also use an array in both methods
record.each_by_tag( 600..699 ) # or a range
Freezing for thread-safety and high performance
MARC::Record is not generally safe for sharing between threads. Even if you think you are just acccessing it read-only, you may accidentally trigger a reindex of the by-tag cache (see above).
However, after you are done constructing a Record, you can mark the ‘fields` array as immutable. This makes a Record safe for sharing between threads for read-only use, and also helps you avoid accidentally triggering a reindex, as accidental reindexes can harm by-tag lookup performance.
record.fields.freeze
Instance Attribute Summary collapse
-
#leader ⇒ Object
the record leader.
Class Method Summary collapse
- .new_from_hash(h) ⇒ Object
-
.new_from_marc(raw, params = {}) ⇒ Object
Factory method for creating a MARC::Record from MARC21 in transmission format.
-
.new_from_marchash(mh) ⇒ Object
Factory method for creating a new MARC::Record from a marchash object.
Instance Method Summary collapse
-
#<<(field) ⇒ Object
alias to append.
-
#==(other) ⇒ Object
For testing if two records can be considered equal.
-
#=~(regex) ⇒ Object
Handy for using a record in a regex: if record =~ /Gravity’s Rainbow/ then print “Slothrop” end.
-
#[](tag) ⇒ Object
You can lookup fields using this shorthand: title = record.
-
#append(field) ⇒ Object
add a field to the record record.append(MARC::DataField.new( ‘100’, ‘2’, ‘0’, [‘a’, ‘Fred’])).
-
#each ⇒ Object
each() is here to support iterating and searching since MARC::Record mixes in Enumerable.
-
#each_by_tag(filter) ⇒ Object
A more convenient way to iterate over each field with a given tag.
-
#fields(filter = nil) ⇒ Object
Provides a backwards compatible means to access the FieldMap.
-
#initialize ⇒ Record
constructor
A new instance of Record.
-
#tags ⇒ Object
Returns an array of all of the tags that appear in the record (not necessarily in the order they appear).
-
#to_dublin_core ⇒ Object
Handy method for returning a hash mapping this records values to the Dublin Core.
-
#to_hash ⇒ Object
Returns a (roundtrippable) hash representation for MARC-in-JSON.
-
#to_marc ⇒ Object
Returns a record in MARC21 transmission format (ANSI Z39.2).
-
#to_marchash ⇒ Object
Return a marc-hash version of the record.
-
#to_s ⇒ Object
Returns a string version of the record, suitable for printing.
-
#to_xml ⇒ Object
Handy method for returning the MARCXML serialization for a MARC::Record object.
Constructor Details
#initialize ⇒ Record
Returns a new instance of Record.
118 119 120 121 122 123 124 125 126 |
# File 'lib/marc/record.rb', line 118 def initialize @fields = FieldMap.new # leader is 24 bytes @leader = ' ' * 24 # leader defaults: # http://www.loc.gov/marc/bibliographic/ecbdldrd.html @leader[10..11] = '22' @leader[20..23] = '4500' end |
Instance Attribute Details
#leader ⇒ Object
the record leader
116 117 118 |
# File 'lib/marc/record.rb', line 116 def leader @leader end |
Class Method Details
.new_from_hash(h) ⇒ Object
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
# File 'lib/marc/record.rb', line 289 def self.new_from_hash(h) r = self.new r.leader = h['leader'] if h['fields'] h['fields'].each do |position| position.each_pair do |tag, field| if field.is_a?(Hash) f = MARC::DataField.new(tag, field['ind1'], field['ind2']) field['subfields'].each do |pos| pos.each_pair do |code, value| f.append MARC::Subfield.new(code, value) end end r << f else r << MARC::ControlField.new(tag, field) end end end end return r end |
.new_from_marc(raw, params = {}) ⇒ Object
Factory method for creating a MARC::Record from MARC21 in transmission format.
record = MARC::Record.new_from_marc(marc21)
in cases where you might be working with somewhat flawed MARC data you may want to use the :forgiving parameter which will bypass using field byte offsets and simply look for the end of field byte to figure out the end of fields.
record = MARC::Record.new_from_marc(marc21, :forgiving => true)
216 217 218 |
# File 'lib/marc/record.rb', line 216 def self.new_from_marc(raw, params={}) return MARC::Reader.decode(raw, params) end |
.new_from_marchash(mh) ⇒ Object
Factory method for creating a new MARC::Record from a marchash object
record = MARC::Record->new_from_marchash(mh)
267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/marc/record.rb', line 267 def self.new_from_marchash(mh) r = self.new() r.leader = mh['leader'] mh['fields'].each do |f| if (f.length == 2) r << MARC::ControlField.new(f[0], f[1]) elsif r << MARC::DataField.new(f[0], f[1], f[2], *f[3]) end end return r end |
Instance Method Details
#<<(field) ⇒ Object
alias to append
138 139 140 |
# File 'lib/marc/record.rb', line 138 def <<(field) append(field) end |
#==(other) ⇒ Object
For testing if two records can be considered equal.
325 326 327 |
# File 'lib/marc/record.rb', line 325 def ==(other) return self.to_s == other.to_s end |
#=~(regex) ⇒ Object
Handy for using a record in a regex:
if record =~ /Gravity's Rainbow/ then print "Slothrop" end
333 334 335 |
# File 'lib/marc/record.rb', line 333 def =~(regex) return self.to_s =~ regex end |
#[](tag) ⇒ Object
You can lookup fields using this shorthand:
title = record['245']
169 170 171 |
# File 'lib/marc/record.rb', line 169 def [](tag) return self.find { |f| f.tag == tag } end |
#append(field) ⇒ Object
131 132 133 134 |
# File 'lib/marc/record.rb', line 131 def append(field) @fields.push(field) @fields.clean = false end |
#each ⇒ Object
each() is here to support iterating and searching since MARC::Record mixes in Enumerable
iterating through the fields in a record:
record.each { |f| print f }
getting the 245
title = record.find {|f| f.tag == '245'}
getting all subjects
subjects = record.find_all {|f| ('600'..'699') === f.tag}
154 155 156 157 158 |
# File 'lib/marc/record.rb', line 154 def each for field in @fields yield field end end |
#each_by_tag(filter) ⇒ Object
A more convenient way to iterate over each field with a given tag. The filter argument can be a string, array or range.
162 163 164 |
# File 'lib/marc/record.rb', line 162 def each_by_tag(filter) @fields.each_by_tag(filter) { |tag| yield tag } end |
#fields(filter = nil) ⇒ Object
Provides a backwards compatible means to access the FieldMap. No argument returns the FieldMap array in entirety. Providing a string, array or range of tags will return an array of fields in the order they appear in the record.
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/marc/record.rb', line 177 def fields(filter=nil) unless filter # Since we're returning the FieldMap object, which the caller # may mutate, we precautionarily mark dirty -- unless it's frozen # immutable. @fields.clean = false unless @fields.frozen? return @fields end @fields.reindex unless @fields.clean flds = [] if filter.is_a?(String) && @fields.[filter] @fields.[filter].each do |idx| flds << @fields[idx] end elsif filter.is_a?(Array) || filter.is_a?(Range) @fields.each_by_tag(filter) do |tag| flds << tag end end flds end |
#tags ⇒ Object
Returns an array of all of the tags that appear in the record (not necessarily in the order they appear).
200 201 202 |
# File 'lib/marc/record.rb', line 200 def return @fields.tag_list end |
#to_dublin_core ⇒ Object
Handy method for returning a hash mapping this records values to the Dublin Core.
dc = record.to_dublin_core()
print dc['title']
246 247 248 |
# File 'lib/marc/record.rb', line 246 def to_dublin_core return MARC::DublinCore.map(self) end |
#to_hash ⇒ Object
Returns a (roundtrippable) hash representation for MARC-in-JSON
281 282 283 284 285 286 287 |
# File 'lib/marc/record.rb', line 281 def to_hash record_hash = {'leader' => @leader, 'fields' => []} @fields.each do |field| record_hash['fields'] << field.to_hash end record_hash end |
#to_marc ⇒ Object
Returns a record in MARC21 transmission format (ANSI Z39.2). Really this is just a wrapper around MARC::MARC21::encode
marc = record.to_marc()
226 227 228 |
# File 'lib/marc/record.rb', line 226 def to_marc return MARC::Writer.encode(self) end |
#to_marchash ⇒ Object
Return a marc-hash version of the record
251 252 253 254 255 256 257 258 |
# File 'lib/marc/record.rb', line 251 def to_marchash return { 'type' => 'marc-hash', 'version' => [MARCHASH_MAJOR_VERSION, MARCHASH_MINOR_VERSION], 'leader' => self.leader, 'fields' => self.map { |f| f.to_marchash } } end |
#to_s ⇒ Object
Returns a string version of the record, suitable for printing
314 315 316 317 318 319 320 |
# File 'lib/marc/record.rb', line 314 def to_s str = "LEADER #{leader}\n" self.each do |field| str += field.to_s() + "\n" end return str end |
#to_xml ⇒ Object
Handy method for returning the MARCXML serialization for a MARC::Record object. You’ll get back a REXML::Document object. Really this is just a wrapper around MARC::XMLWriter::encode
xml_doc = record.to_xml()
236 237 238 |
# File 'lib/marc/record.rb', line 236 def to_xml return MARC::XMLWriter.encode(self, :include_namespace => true) end |