lib/dbf/table.rb in dbf-1.0.5 vs lib/dbf/table.rb in dbf-1.0.6
- old
+ new
@@ -1,42 +1,27 @@
module DBF
class Table
- # The total number of columns (columns)
- attr_reader :column_count
+ include Enumerable
- # An array of DBF::Column records
- attr_reader :columns
+ attr_reader :column_count # The total number of columns (columns)
+ attr_reader :columns # An array of DBF::Column
+ attr_reader :version # Internal dBase version number
+ attr_reader :last_updated # Last updated datetime
+ attr_reader :memo_file_format # :fpt or :dpt
+ attr_reader :memo_block_size # The block size for memo records
+ attr_reader :options # The options hash that was used to initialize the table
+ attr_reader :data # DBF file handle
+ attr_reader :memo # Memo file handle
- # Internal dBase version number
- attr_reader :version
-
- # Last updated datetime
- attr_reader :last_updated
-
- # Either :fpt or :dpt
- attr_reader :memo_file_format
-
- # The block size for memo records
- attr_reader :memo_block_size
-
- # The options that were used when initializing DBF::Table. This is a Hash.
- attr_reader :options
-
- attr_reader :data
- attr_reader :memo
-
- # Initialize a new DBF::Reader.
+ # Initializes a new DBF::Reader
# Example:
# reader = DBF::Reader.new 'data.dbf'
def initialize(filename, options = {})
- @options = {:in_memory => true, :accessors => true}.merge(options)
-
- @in_memory = @options[:in_memory]
- @accessors = @options[:accessors]
@data = File.open(filename, 'rb')
@memo = open_memo(filename)
+ @options = options
reload!
end
# Reloads the database and memo files
def reload!
@@ -55,35 +40,41 @@
# The total number of active records.
def record_count
@db_index.size
end
- # Returns an instance of DBF::Column for <b>column_name</b>. <b>column_name</b>
- # can be a symbol or a string.
+ # Returns an instance of DBF::Column for <b>column_name</b>. The <b>column_name</b>
+ # can be a specified as either a symbol or string.
def column(column_name)
@columns.detect {|f| f.name == column_name.to_s}
end
# An array of all the records contained in the database file. Each record is an instance
# of DBF::Record (or nil if the record is marked for deletion).
def records
- if options[:in_memory]
- @records ||= get_all_records_from_file
- else
- get_all_records_from_file
+ self.to_a
+ end
+
+ alias_method :rows, :records
+
+ def each
+ 0.upto(@record_count - 1) do |n|
+ seek_to_record(n)
+ unless deleted_record?
+ yield DBF::Record.new(self)
+ end
end
end
- alias_method :rows, :records
+ # def get_record_from_file(index)
+ # seek_to_record(@db_index[index])
+ # Record.new(self)
+ # end
# Returns a DBF::Record (or nil if the record has been marked for deletion) for the record at <tt>index</tt>.
def record(index)
- if options[:in_memory]
- records[index]
- else
- get_record_from_file(index)
- end
+ records[index]
end
# Find records using a simple ActiveRecord-like syntax.
#
# Examples:
@@ -156,25 +147,42 @@
else
s
end
end
+ # Returns the record at <tt>index</tt> by seeking to the record in the
+ # physical database file. See the documentation for the records method for
+ # information on how these two methods differ.
+ def get_record_from_file(index)
+ seek_to_record(@db_index[index])
+ Record.new(self)
+ end
+
private
def open_memo(file)
- %w(fpt FPT dbt DBT).each do |extension|
- filename = file.sub(/#{File.extname(file)[1..-1]}$/, extension)
+ %w(fpt FPT dbt DBT).each do |extname|
+ filename = replace_extname(file, extname)
if File.exists?(filename)
- @memo_file_format = extension.downcase.to_sym
+ @memo_file_format = extname.downcase.to_sym
return File.open(filename, 'rb')
end
end
nil
end
+
+ def replace_extname(filename, extension)
+ filename.sub(/#{File.extname(filename)[1..-1]}$/, extension)
+ end
def deleted_record?
- @data.read(1).unpack('a') == ['*']
+ if @data.read(1).unpack('a') == ['*']
+ @data.rewind
+ true
+ else
+ false
+ end
end
def get_header_info
@data.rewind
@version, @record_count, @header_length, @record_length = @data.read(DBF_HEADER_SIZE).unpack('H2 x3 V v2')
@@ -187,20 +195,21 @@
name, type, length, decimal = @data.read(32).unpack('a10 x a x4 C2')
if length > 0
@columns << Column.new(name.strip, type, length, decimal)
end
end
- # Reset the column count
+ # Reset the column count in case any were skipped
@column_count = @columns.size
@columns
end
def get_memo_header_info
@memo.rewind
if @memo_file_format == :fpt
@memo_next_available_block, @memo_block_size = @memo.read(FPT_HEADER_SIZE).unpack('N x2 n')
+ @memo_block_size = 0 if @memo_block_size.nil?
else
@memo_block_size = 512
@memo_next_available_block = File.size(@memo.path) / @memo_block_size
end
end
@@ -211,26 +220,9 @@
def seek_to_record(index)
seek(index * @record_length)
end
- # Returns the record at <tt>index</tt> by seeking to the record in the
- # physical database file. See the documentation for the records method for
- # information on how these two methods differ.
- def get_record_from_file(index)
- seek_to_record(@db_index[index])
- deleted_record? ? nil : Record.new(self)
- end
-
- def get_all_records_from_file
- all_records = []
- 0.upto(@record_count - 1) do |n|
- seek_to_record(n)
- all_records << DBF::Record.new(self) unless deleted_record?
- end
- all_records
- end
-
def build_db_index
@db_index = []
@deleted_records = []
0.upto(@record_count - 1) do |n|
seek_to_record(n)
\ No newline at end of file