class RADT::Table
RADT::Table
is the primary interface to a single RADT
file and provides methods for enumerating and searching the records.
Attributes
Public Class Methods
Opens a RADT:Table Example: table = RADT::Table.new
'data.adt'
@param [String] path Path to the adt file
# File lib/radt/table.rb, line 18 def initialize(path) @data = File.open(path, 'rb') reload! end
Public Instance Methods
Closes the table
# File lib/radt/table.rb, line 24 def close @data.close end
Retrieve a Column
by name
@param [String, Symbol] column_name @return [RADT::Column]
# File lib/radt/table.rb, line 40 def column(column_name) @columns.detect {|f| f.name == column_name.to_s} end
Calls block once for each record in the table. The record may be nil if the record has been marked as deleted.
@yield [nil, RADT::Record]
# File lib/radt/table.rb, line 48 def each 0.upto(@record_count - 1) do |n| seek_to_record(n) yield RADT::Record.new(self) end end
Find records using a simple ActiveRecord-like syntax.
Examples: table = RADT::Table.new
'mydata.adt'
# Find record number 5 table.find(5)
# Find all records for Chase Gray table.find :all, :first_name => “Chase”, :last_name => “Gray”
# Find first record table.find :first, :first_name => “Chase”
The command may be a record index, :all, or :first. options 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, RADT::Record]
# File lib/radt/table.rb, line 147 def find(command, options = {}, &block) case command when Fixnum record(command) when Array command.map {|i| record(i)} when :all find_all(options, &block) when :first find_first(options) end end
Retrieve a record by index number
@param [Fixnum] index @return [RADT::Record]
# File lib/radt/table.rb, line 59 def record(index) seek_to_record(index) RADT::Record.new(self) end
Reloads the database
# File lib/radt/table.rb, line 29 def reload! @records = nil get_header_info get_column_descriptors end
Generate an ActiveRecord::Schema
xBase data types are converted to generic types as follows:
-
Number columns with no decimals are converted to :integer
-
Number columns with decimals are converted to :float
-
Date columns are converted to :datetime
-
Logical columns are converted to :boolean
-
Memo columns are converted to :text
-
Character columns are converted to :string and the :limit option is set
to the length of the character column
Example: create_table “mydata” do |t| t.column :name, :string, :limit => 30 t.column :last_update, :datetime t.column :is_active, :boolean t.column :age, :integer t.column :notes, :text end
@param [optional String] path @return [String]
# File lib/radt/table.rb, line 89 def schema(path = nil) s = "ActiveRecord::Schema.define do\n" s << " create_table \"#{File.basename(@data.path, ".*")}\" do |t|\n" columns.each do |column| s << " t.column #{column.schema_definition}" end s << " end\nend" if path File.open(path, 'w') {|f| f.puts(s)} end s end
# File lib/radt/table.rb, line 104 def to_a records = [] each {|record| records << record if record} records end
Dumps all records to a CSV file. If no filename is given then CSV is output to STDOUT.
@param [optional String] path Defaults to basename of adt file
# File lib/radt/table.rb, line 114 def to_csv(path = nil) path = File.basename(@data.path, '.adt') + '.csv' if path.nil? CSV.open(path, 'w', :force_quotes => true) do |csv| each do |record| csv << record.to_a end end end
Private Instance Methods
Do all search parameters match?
@param [RADT::Record] record @param [Hash] options @return [Boolean]
# File lib/radt/table.rb, line 197 def all_values_match?(record, options) options.all? {|key, value| record.attributes[key.to_s.underscore] == value} end
Find all matching
@param [Hash] options @yield [optional RADT::Record] @return [Array]
# File lib/radt/table.rb, line 167 def find_all(options, &block) results = [] each do |record| if all_values_match?(record, options) if block_given? yield(record) else results << record end end end results end
Find first matching
@param [Hash] options @return [RADT::Record, nil]
# File lib/radt/table.rb, line 185 def find_first(options) each do |record| return record if all_values_match?(record, options) end nil end
Retrieves column information from the database
# File lib/radt/table.rb, line 223 def get_column_descriptors #skip past header to get to column information @data.seek(HEADER_LENGTH) # column names are the first 128 bytes and column info takes up the last 72 bytes. # byte 130 contains a 16-bit column type # byte 136 contains a 16-bit length field @columns = [] @column_count.times do name, type, length = @data.read(200).unpack('A128 x S x4 S') if length > 0 @columns << Column.new(name.strip, type, length) end end # Reset the column count in case any were skipped @column_count = @columns.size @columns end
Determine record count, record_count
, and record length
# File lib/radt/table.rb, line 213 def get_header_info @data.rewind #column_count_offset = 33, record_count_offset = 24, record_length_offset = 36 @record_count, @data_offset, @record_length = data.read(HEADER_LENGTH).unpack("@24 I x4 I I") @column_count = (@data_offset-400)/200 end
Replace the file extension
@param [String] path @param [String] extension @return [String]
# File lib/radt/table.rb, line 207 def replace_extname(path, extension) path.sub(/#{File.extname(path)[1..-1]}$/, extension) end
Seek to a byte offset in the record data
@params [Fixnum] offset
# File lib/radt/table.rb, line 247 def seek(offset) @data.seek(@data_offset + offset) end
Seek to a record
@param [Fixnum] index
# File lib/radt/table.rb, line 254 def seek_to_record(index) seek(index * @record_length) end