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)