lib/dbf/reader.rb in dbf-0.2.0 vs lib/dbf/reader.rb in dbf-0.3.0
- old
+ new
@@ -8,10 +8,13 @@
DATE_REGEXP = /([\d]{4})([\d]{2})([\d]{2})/
VERSION_DESCRIPTIONS = {"02" => "FoxBase", "03" => "dBase III without memo file", "04" => "dBase IV without memo file",
"05" => "dBase V without memo file", "30" => "Visual FoxPro", "31" => "Visual FoxPro with AutoIncrement field",
"7b" => "dBase IV with memo file", "83" => "dBase III with memo file", "8b" => "dBase IV with memo file",
"8e" => "dBase IV with SQL table", "f5" => "FoxPro with memo file", "fb" => "FoxPro without memo file"}
+
+ class DBFError < StandardError; end
+ class UnpackError < DBFError; end
class Reader
attr_reader :field_count
attr_reader :fields
@@ -83,16 +86,16 @@
else
record[field.name] = unpack_float(field) rescue nil
end
when 'D' # date
raw = unpack_string(field).to_s.strip
- record[field.name] = raw.empty ? nil : Date.new(*raw.match(DATE_REGEXP).to_a.slice(1,3).map {|n| n.to_i}) rescue nil
+ record[field.name] = raw.empty? ? nil : Date.new(*raw.match(DATE_REGEXP).to_a.slice(1,3).map {|n| n.to_i}) rescue nil
when 'M' # memo
starting_block = unpack_integer(field)
record[field.name] = starting_block == 0 ? nil : memo(starting_block) rescue nil
when 'L' # logical
- record[field.name] = unpack_string(field) =~ /(y|t)/i ? true : false rescue false
+ record[field.name] = unpack_string(field) =~ /^(y|t)$/i ? true : false rescue false
else
record[field.name] = unpack_string(field)
end
end
record
@@ -119,12 +122,16 @@
def seek_to_record(index)
seek(@record_length * index)
end
+ def unpack_field(field)
+ @data_file.read(field.length).unpack("a#{field.length}")
+ end
+
def unpack_string(field)
- @data_file.read(field.length).unpack("a#{field.length}").to_s
+ unpack_field(field).to_s
end
def unpack_integer(field)
unpack_string(field).to_i
end
@@ -133,13 +140,16 @@
unpack_string(field).to_f
end
end
+ class FieldError < StandardError; end
+
class Field
attr_accessor :name, :type, :length, :decimal
def initialize(name, type, length, decimal)
+ raise FieldError, "field length must be greater than 0" unless length > 0
self.name, self.type, self.length, self.decimal = name, type, length, decimal
end
def name=(name)
@name = name.gsub(/\0/, '')