lib/dbf/table.rb in dbf-2.0.5 vs lib/dbf/table.rb in dbf-2.0.6

- old
+ new

@@ -32,12 +32,11 @@ "31" => "Visual FoxPro with AutoIncrement field", "f5" => "FoxPro with memo file", "fb" => "FoxPro without memo file" } - attr_reader :version # Internal dBase version number - attr_reader :record_count # Total number of records + attr_reader :header attr_accessor :encoding # Source encoding (for ex. :cp1251) # Opens a DBF::Table # Examples: # # working with a file stored on the filesystem @@ -59,12 +58,13 @@ # @param [String, StringIO] data Path to the dbf file or a StringIO object # @param [optional String, StringIO] memo Path to the memo file or a StringIO object # @param [optional String, Encoding] encoding Name of the encoding or an Encoding object def initialize(data, memo = nil, encoding = nil) @data = open_data(data) - @version, @record_count, @header_length, @record_length, @encoding_key, @encoding = get_header_info - @encoding = encoding if encoding + @data.rewind + @header = Header.new(@data.read(DBF_HEADER_SIZE), supports_encoding? || supports_iconv?) + @encoding = encoding || header.encoding @memo = open_memo(data, memo) end # @return [TrueClass, FalseClass] def has_memo_file? @@ -96,28 +96,42 @@ # Calls block once for each record in the table. The record may be nil # if the record has been marked as deleted. # # @yield [nil, DBF::Record] def each - @record_count.times {|i| yield record(i)} + header.record_count.times {|i| yield record(i)} end # Retrieve a record by index number. # The record will be nil if it has been deleted, but not yet pruned from # the database. # # @param [Fixnum] index # @return [DBF::Record, NilClass] def record(index) - seek(index * @record_length) + seek(index * header.record_length) if !deleted_record? - DBF::Record.new(@data.read(@record_length), columns, version, @memo) + DBF::Record.new(@data.read(header.record_length), columns, version, @memo) end end alias_method :row, :record + # Internal dBase version number + # + # @return [String] + def version + @version ||= header.version + end + + # Total number of records + # + # @return [Fixnum] + def record_count + @record_count ||= header.record_count + end + # Human readable version description # # @return [String] def version_description VERSIONS[version] @@ -208,11 +222,11 @@ columns = [] while !["\0", "\r"].include?(first_byte = @data.read(1)) column_data = first_byte + @data.read(31) name, type, length, decimal = column_data.unpack('a10 x a x4 C2') if length > 0 - columns << column_class.new(name.strip, type, length, decimal, version, @encoding) + columns << column_class.new(name.strip, type, length, decimal, version, encoding) end end columns end end @@ -227,11 +241,11 @@ rescue false end def foxpro? - FOXPRO_VERSIONS.keys.include? @version + FOXPRO_VERSIONS.keys.include? version end private def column_class #nodoc @@ -240,20 +254,20 @@ def memo_class #nodoc @memo_class ||= if foxpro? Memo::Foxpro else - if @version == "83" + if version == "83" Memo::Dbase3 else Memo::Dbase4 end end end def column_count #nodoc - @column_count ||= ((@header_length - DBF_HEADER_SIZE + 1) / DBF_HEADER_SIZE).to_i + @column_count ||= ((header.header_length - DBF_HEADER_SIZE + 1) / DBF_HEADER_SIZE).to_i end def open_data(data) #nodoc data.is_a?(StringIO) ? data : File.open(data, 'rb') end @@ -292,22 +306,11 @@ def deleted_record? #nodoc @data.read(1).unpack('a') == ['*'] end - def get_header_info #nodoc - @data.rewind - version, record_count, header_length, record_length, encoding_key = read_header - encoding = ENCODINGS[encoding_key] if supports_encoding? || supports_iconv? - [version, record_count, header_length, record_length, encoding_key, encoding] - end - - def read_header #nodoc - @data.read(DBF_HEADER_SIZE).unpack("H2 x3 V v2 x17H2") - end - def seek(offset) #nodoc - @data.seek @header_length + offset + @data.seek header.header_length + offset end def csv_class #nodoc @csv_class ||= CSV.const_defined?(:Reader) ? FCSV : CSV end