lib/dbf/table.rb in dbf-2.0.10 vs lib/dbf/table.rb in dbf-2.0.11
- old
+ new
@@ -9,37 +9,37 @@
include Schema
DBF_HEADER_SIZE = 32
VERSIONS = {
- "02" => "FoxBase",
- "03" => "dBase III without memo file",
- "04" => "dBase IV without memo file",
- "05" => "dBase V without memo file",
- "07" => "Visual Objects 1.x",
- "30" => "Visual FoxPro",
- "31" => "Visual FoxPro with AutoIncrement field",
- "43" => "dBASE IV SQL table files, no memo",
- "63" => "dBASE IV SQL system files, no memo",
- "7b" => "dBase IV with memo file",
- "83" => "dBase III with memo file",
- "87" => "Visual Objects 1.x with memo file",
- "8b" => "dBase IV with memo file",
- "8e" => "dBase IV with SQL table",
- "cb" => "dBASE IV SQL table files, with memo",
- "f5" => "FoxPro with memo file",
- "fb" => "FoxPro without memo file"
+ '02' => 'FoxBase',
+ '03' => 'dBase III without memo file',
+ '04' => 'dBase IV without memo file',
+ '05' => 'dBase V without memo file',
+ '07' => 'Visual Objects 1.x',
+ '30' => 'Visual FoxPro',
+ '31' => 'Visual FoxPro with AutoIncrement field',
+ '43' => 'dBASE IV SQL table files, no memo',
+ '63' => 'dBASE IV SQL system files, no memo',
+ '7b' => 'dBase IV with memo file',
+ '83' => 'dBase III with memo file',
+ '87' => 'Visual Objects 1.x with memo file',
+ '8b' => 'dBase IV with memo file',
+ '8e' => 'dBase IV with SQL table',
+ 'cb' => 'dBASE IV SQL table files, with memo',
+ 'f5' => 'FoxPro with memo file',
+ 'fb' => 'FoxPro without memo file'
}
FOXPRO_VERSIONS = {
- "30" => "Visual FoxPro",
- "31" => "Visual FoxPro with AutoIncrement field",
- "f5" => "FoxPro with memo file",
- "fb" => "FoxPro without memo file"
+ '30' => 'Visual FoxPro',
+ '31' => 'Visual FoxPro with AutoIncrement field',
+ 'f5' => 'FoxPro with memo file',
+ 'fb' => 'FoxPro without memo file'
}
- attr_reader :header
+ attr_reader :header
attr_accessor :encoding # Source encoding (for ex. :cp1251)
# Opens a DBF::Table
# Examples:
# # working with a file stored on the filesystem
@@ -60,20 +60,18 @@
#
# @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)
- begin
- @data = open_data(data)
- @data.rewind
- @header = Header.new(@data.read(DBF_HEADER_SIZE), supports_encoding?)
- @encoding = encoding || header.encoding
- @memo = open_memo(data, memo)
- yield self if block_given?
- rescue Errno::ENOENT => error
- raise DBF::FileNotFoundError.new("file not found: #{data}")
- end
+ @data = open_data(data)
+ @data.rewind
+ @header = Header.new(@data.read(DBF_HEADER_SIZE), supports_encoding?)
+ @encoding = encoding || header.encoding
+ @memo = open_memo(data, memo)
+ yield self if block_given?
+ rescue Errno::ENOENT
+ raise DBF::FileNotFoundError, "file not found: #{data}"
end
# @return [TrueClass, FalseClass]
def has_memo_file?
!!@memo
@@ -104,24 +102,23 @@
# 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
- header.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_to_record(index)
- if !deleted_record?
- DBF::Record.new(@data.read(header.record_length), columns, version, @memo)
- end
+ return nil if deleted_record?
+ DBF::Record.new(@data.read(header.record_length), columns, version, @memo)
end
alias_method :row, :record
# Internal dBase version number
@@ -169,25 +166,26 @@
#
# # Find first record
# table.find :first, :first_name => "Keith"
#
# The <b>command</b> may be a record index, :all, or :first.
- # <b>options</b> is optional and, if specified, should be a hash where the keys correspond
- # to column names in the database. The values will be matched exactly with the value
- # in the database. If you specify more than one key, all values must match in order
- # for the record to be returned. The equivalent SQL would be "WHERE key1 = 'value1'
+ # <b>options</b> is optional and, if specified, should be a hash where the
+ # keys correspond to column names in the database. The values will be
+ # matched exactly with the value in the database. If you specify more
+ # than one key, all values must match in order for the record to be
+ # returned. The equivalent SQL would be "WHERE key1 = 'value1'
# AND key2 = 'value2'".
#
# @param [Fixnum, Symbol] command
# @param [optional, Hash] options Hash of search parameters
# @yield [optional, DBF::Record, NilClass]
def find(command, options = {}, &block)
case command
when Fixnum
record(command)
when Array
- command.map {|i| record(i)}
+ command.map { |i| record(i) }
when :all
find_all(options, &block)
when :first
find_first(options)
end
@@ -202,11 +200,11 @@
# Column names
#
# @return [String]
def column_names
- columns.map { |column| column.name }
+ columns.map(&:name)
end
# Is string encoding supported?
# String encoding is always supported in Ruby 1.9+.
# Ruby 1.8.x requires that Ruby be compiled with iconv support.
@@ -217,104 +215,91 @@
# Does String support encoding? Should be true in Ruby 1.9+
def supports_string_encoding?
''.respond_to?(:encoding)
end
- def supports_iconv? #nodoc
+ def supports_iconv? # nodoc
require 'iconv'
true
rescue
false
end
private
- def build_columns #nodoc
+ def build_columns # nodoc
columns = []
@data.seek(DBF_HEADER_SIZE)
- while !["\0", "\r"].include?(first_byte = @data.read(1))
+ until ["\0", "\r"].include?(first_byte = @data.read(1))
column_data = first_byte + @data.read(DBF_HEADER_SIZE - 1)
name, type, length, decimal = column_data.unpack('a10 x a x4 C2')
columns << column_class.new(self, name, type, length, decimal)
end
columns
end
-
- def foxpro? #nodoc
+ def foxpro? # nodoc
FOXPRO_VERSIONS.keys.include? version
end
- def column_class #nodoc
+ def column_class # nodoc
@column_class ||= foxpro? ? Column::Foxpro : Column::Dbase
end
- def memo_class #nodoc
+ def memo_class # nodoc
@memo_class ||= if foxpro?
Memo::Foxpro
else
- if version == "83"
- Memo::Dbase3
- else
- Memo::Dbase4
- end
+ version == '83' ? Memo::Dbase3 : Memo::Dbase4
end
end
- def column_count #nodoc
- @column_count ||= ((header.header_length - DBF_HEADER_SIZE + 1) / DBF_HEADER_SIZE).to_i
- end
-
- def open_data(data) #nodoc
+ def open_data(data) # nodoc
data.is_a?(StringIO) ? data : File.open(data, 'rb')
end
- def open_memo(data, memo = nil) #nodoc
- if memo.is_a? StringIO
- memo_class.new(memo, version)
- elsif memo
- memo_class.open(memo, version)
+ def open_memo(data, memo = nil) # nodoc
+ if memo
+ meth = memo.is_a?(StringIO) ? :new : :open
+ memo_class.send(meth, memo, version)
elsif !data.is_a? StringIO
- files = Dir.glob(memo_search_path(data))
+ files = Dir.glob(memo_search_path data)
files.any? ? memo_class.open(files.first, version) : nil
- else
- nil
end
end
- def memo_search_path(io) #nodoc
+ def memo_search_path(io) # nodoc
dirname = File.dirname(io)
basename = File.basename(io, '.*')
"#{dirname}/#{basename}*.{fpt,FPT,dbt,DBT}"
end
- def find_all(options) #nodoc
+ def find_all(options) # nodoc
map do |record|
if record && record.match?(options)
yield record if block_given?
record
end
end.compact
end
- def find_first(options) #nodoc
- detect {|record| record && record.match?(options)}
+ def find_first(options) # nodoc
+ detect { |record| record && record.match?(options) }
end
- def deleted_record? #nodoc
+ def deleted_record? # nodoc
@data.read(1).unpack('a') == ['*']
end
- def seek(offset) #nodoc
+ def seek(offset) # nodoc
@data.seek header.header_length + offset
end
- def seek_to_record(index) #nodoc
+ def seek_to_record(index) # nodoc
seek(index * header.record_length)
end
- def csv_class #nodoc
+ def csv_class # nodoc
@csv_class ||= CSV.const_defined?(:Reader) ? FCSV : CSV
end
end
-
end