lib/marc/datafield.rb in marc-0.3.3 vs lib/marc/datafield.rb in marc-0.4.0
- old
+ new
@@ -1,10 +1,48 @@
require 'marc/subfield'
require 'marc/record'
require 'marc/controlfield'
module MARC
+
+ class SubfieldMap < Array
+ attr_reader :codes
+ def initialize
+ @codes = HashWithChecksumAttribute.new
+ end
+
+ def in_sync?
+ @codes.checksum == self.hash
+ end
+
+ def reindex
+ @codes.clear
+ self.each do |subfield|
+ @codes[subfield.code] ||= []
+ @codes[subfield.code] << self.index(subfield)
+ end
+ @codes.checksum = self.hash
+ end
+ def code_list
+ reindex unless in_sync?
+ @codes.keys
+ end
+
+ def each_by_code(codes)
+ reindex unless in_sync?
+ matched_codes = []
+ [*codes].each do |code|
+ next unless code && @codes[code]
+ @codes[code].each do |idx|
+ matched_codes << self[idx]
+ yield self[idx]
+ end
+ end
+ matched_codes
+ end
+
+ end
# MARC records contain data fields, each of which has a tag,
# indicators and subfields. Tags for data fields must are all
# three-character tags that are not control fields (generally,
# any numeric tag greater than 009).
@@ -32,11 +70,11 @@
# The second indicator
attr_accessor :indicator2
# A list of MARC::Subfield objects
- attr_accessor :subfields
+ #attr_accessor :subfields
# Create a new field with tag, indicators and subfields.
# Subfields are passed in as comma separated list of
# MARC::Subfield objects,
@@ -62,11 +100,11 @@
end
# can't allow nil to be passed in or else it'll
# screw us up later when we try to encode
@indicator1 = i1 == nil ? ' ' : i1
@indicator2 = i2 == nil ? ' ' : i2
- @subfields = []
+ @subfields = SubfieldMap.new
# must use MARC::ControlField for tags < 010 or
# those in MARC::ControlField#extra_control_fields
if MARC::ControlField.control_tag?(@tag)
@@ -108,38 +146,73 @@
# Turn into a marc-hash structure
def to_marchash
return [@tag, @indicator1, @indicator2, @subfields.map {|sf| [sf.code, sf.value]} ]
end
+ # Turn the variable field and subfields into a hash for MARC-in-JSON
+
+ def to_hash
+ field_hash = {@tag=>{'ind1'=>@indicator1,'ind2'=>@indicator2,'subfields'=>[]}}
+ self.each do |subfield|
+ field_hash[@tag]['subfields'] << {subfield.code=>subfield.value}
+ end
+ field_hash
+ end
# Add a subfield (MARC::Subfield) to the field
# field.append(MARC::Subfield.new('a','Dave Thomas'))
def append(subfield)
@subfields.push(subfield)
end
+
# You can iterate through the subfields in a Field:
# field.each {|s| print s}
def each
for subfield in subfields
yield subfield
end
end
+ def each_by_code(filter)
+ @subfields.each_by_code(filter)
+ end
# You can lookup subfields with this shorthand. Note it
# will return a string and not a MARC::Subfield object.
# subfield = field['a']
def [](code)
subfield = self.find {|s| s.code == code}
return subfield.value if subfield
return
end
+
+ def subfields(filter=nil)
+ return @subfields unless filter
+ @subfields.reindex unless subfields.in_sync?
+ subflds = []
+ if filter.is_a?(String) && @subfields.codes[filter]
+ @subfields.codes[filter].each do |idx|
+ subflds << @subfields[idx]
+ end
+ elsif filter.is_a?(Array) || filter.is_a?(Range)
+ filter.each do |code|
+ next unless @subfields.codes[code]
+ @subfields.codes[code].each do |idx|
+ subflds << @subfields[idx]
+ end
+ end
+ end
+ subflds
+ end
+ def codes
+ @subfields.code_list
+ end
# Two fields are equal if their tag, indicators and
# subfields are all equal.
def ==(other)