dbf 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt CHANGED
@@ -1,3 +1,9 @@
1
+ == 1.0.6
2
+
3
+ * DBF::Table now includes the Enumerable module
4
+ * Return nil for memo values if the memo file is missing
5
+ * Finder conditions now support the original and downcased/underscored column names
6
+
1
7
  == 1.0.5
2
8
 
3
9
  * Strip non-ascii characters from column names
data/Manifest.txt CHANGED
@@ -2,9 +2,8 @@ History.txt
2
2
  Manifest.txt
3
3
  README.txt
4
4
  Rakefile
5
- benchmarks/performance.rb
6
- benchmarks/seek_benchmark.rb
7
5
  bin/dbf
6
+ dbf.gemspec
8
7
  lib/dbf.rb
9
8
  lib/dbf/column.rb
10
9
  lib/dbf/globals.rb
data/README.txt CHANGED
@@ -70,14 +70,6 @@ An example of migrating a DBF book table to ActiveRecord using a migration:
70
70
  end
71
71
  end
72
72
 
73
- == Large databases
74
-
75
- DBF::Table defaults to loading all records into memory. This may not be what
76
- you want, especially if the database is large. To disable this behavior, set
77
- the in_memory option to false during initialization.
78
-
79
- table = DBF::Table.new("old_data.dbf", :in_memory => false)
80
-
81
73
  == Command-line utility
82
74
 
83
75
  A small command-line utility called dbf is installed along with the gem.
@@ -97,7 +89,7 @@ A small command-line utility called dbf is installed along with the gem.
97
89
 
98
90
  (The MIT Licence)
99
91
 
100
- Copyright (c) 2006-2007 Keith Morrison <keithm@infused.org>
92
+ Copyright (c) 2006-2008 Keith Morrison <keithm@infused.org>
101
93
 
102
94
  Permission is hereby granted, free of charge, to any person
103
95
  obtaining a copy of this software and associated documentation
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'hoe'
2
2
  require 'spec/rake/spectask'
3
3
 
4
4
  PKG_NAME = "dbf"
5
- PKG_VERSION = "1.0.5"
5
+ PKG_VERSION = "1.0.6"
6
6
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
7
7
 
8
8
  Hoe.new PKG_NAME, PKG_VERSION do |p|
@@ -12,12 +12,12 @@ Hoe.new PKG_NAME, PKG_VERSION do |p|
12
12
  p.summary = "A small fast library for reading dBase, xBase, Clipper and FoxPro database files."
13
13
  p.description = p.paragraphs_of("README.txt", 1..3).join("\n\n")
14
14
  p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
15
- p.url = "http://dbf.rubyforge.org"
15
+ p.url = "http://github.com/infused/dm-dbf/tree/master"
16
16
  p.need_tar = true
17
17
  p.need_zip = true
18
18
  end
19
19
 
20
- task :default => [:spec]
20
+ task :default => :spec
21
21
 
22
22
  desc "Run specs"
23
23
  Spec::Rake::SpecTask.new :spec do |t|
@@ -28,4 +28,9 @@ desc "Run spec docs"
28
28
  Spec::Rake::SpecTask.new :specdoc do |t|
29
29
  t.spec_opts = ["-f specdoc"]
30
30
  t.spec_files = FileList['spec/**/*spec.rb']
31
+ end
32
+
33
+ desc "Generate gemspec"
34
+ task :gemspec do |t|
35
+ `rake debug_gem > dbf.gemspec`
31
36
  end
data/dbf.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ (in /Users/keithm/projects/dbf)
2
+ Gem::Specification.new do |s|
3
+ s.name = %q{dbf}
4
+ s.version = "1.0.6"
5
+
6
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
7
+ s.authors = ["Keith Morrison"]
8
+ s.date = %q{2008-06-30}
9
+ s.default_executable = %q{dbf}
10
+ s.description = %q{DBF is a small fast library for reading dBase, xBase, Clipper and FoxPro database files. It is written completely in Ruby and has no external dependencies. Copyright (c) 2006-2007 Keith Morrison <keithm@infused.org, www.infused.org> * Official project page: http://rubyforge.org/projects/dbf * API Documentation: http://dbf.rubyforge.org/docs * To report bugs: http://www.rubyforge.org/tracker/?group_id=2009 * Questions: Email keithm@infused.org and put DBF somewhere in the subject line}
11
+ s.email = %q{keithm@infused.org}
12
+ s.executables = ["dbf"]
13
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt", "spec/fixtures/dbase_83_schema.txt"]
14
+ s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "bin/dbf", "dbf.gemspec", "lib/dbf.rb", "lib/dbf/column.rb", "lib/dbf/globals.rb", "lib/dbf/record.rb", "lib/dbf/table.rb", "spec/fixtures/dbase_03.dbf", "spec/fixtures/dbase_30.dbf", "spec/fixtures/dbase_30.fpt", "spec/fixtures/dbase_83.dbf", "spec/fixtures/dbase_83.dbt", "spec/fixtures/dbase_83_schema.txt", "spec/fixtures/dbase_8b.dbf", "spec/fixtures/dbase_8b.dbt", "spec/fixtures/dbase_f5.dbf", "spec/fixtures/dbase_f5.fpt", "spec/functional/dbf_shared.rb", "spec/functional/format_03_spec.rb", "spec/functional/format_30_spec.rb", "spec/functional/format_83_spec.rb", "spec/functional/format_8b_spec.rb", "spec/functional/format_f5_spec.rb", "spec/spec_helper.rb", "spec/unit/column_spec.rb", "spec/unit/record_spec.rb", "spec/unit/table_spec.rb"]
15
+ s.has_rdoc = true
16
+ s.homepage = %q{http://github.com/infused/dm-dbf/tree/master}
17
+ s.rdoc_options = ["--main", "README.txt"]
18
+ s.require_paths = ["lib"]
19
+ s.rubyforge_project = %q{dbf}
20
+ s.rubygems_version = %q{1.2.0}
21
+ s.summary = %q{A small fast library for reading dBase, xBase, Clipper and FoxPro database files.}
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if current_version >= 3 then
28
+ s.add_runtime_dependency(%q<hoe>, [">= 1.6.0"])
29
+ else
30
+ s.add_dependency(%q<hoe>, [">= 1.6.0"])
31
+ end
32
+ else
33
+ s.add_dependency(%q<hoe>, [">= 1.6.0"])
34
+ end
35
+ end
data/lib/dbf/column.rb CHANGED
@@ -2,6 +2,8 @@ module DBF
2
2
  class ColumnLengthError < DBFError; end
3
3
 
4
4
  class Column
5
+ include Helpers
6
+
5
7
  attr_reader :name, :type, :length, :decimal
6
8
 
7
9
  def initialize(name, type, length, decimal)
@@ -10,8 +12,7 @@ module DBF
10
12
  end
11
13
 
12
14
  def schema_definition
13
- "\"#{underscore(name)}\", " +
14
- case type
15
+ data_type = case type
15
16
  when "N" # number
16
17
  if decimal > 0
17
18
  ":float"
@@ -26,19 +27,12 @@ module DBF
26
27
  ":text"
27
28
  else
28
29
  ":string, :limit => #{length}"
29
- end +
30
- "\n"
30
+ end
31
+
32
+ "\"#{underscore(name)}\", #{data_type}\n"
31
33
  end
32
34
 
33
35
  private
34
-
35
- def underscore(camel_cased_word)
36
- camel_cased_word.to_s.gsub(/::/, '/').
37
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
38
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
39
- tr("-", "_").
40
- downcase
41
- end
42
36
 
43
37
  def strip_non_ascii_chars(s)
44
38
  clean = ''
data/lib/dbf/globals.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module DBF
2
2
  DBF_HEADER_SIZE = 32
3
3
  FPT_HEADER_SIZE = 512
4
- FPT_BLOCK_HEADER_SIZE = 8
4
+ BLOCK_HEADER_SIZE = 8
5
5
  DATE_REGEXP = /([\d]{4})([\d]{2})([\d]{2})/
6
6
  VERSION_DESCRIPTIONS = {
7
7
  "02" => "FoxBase",
@@ -20,9 +20,17 @@ module DBF
20
20
 
21
21
  MS_PER_SECOND = 1000
22
22
  MS_PER_MINUTE = MS_PER_SECOND * 60
23
- MS_PER_HOUR = MS_PER_MINUTE * 60
23
+ MS_PER_HOUR = MS_PER_MINUTE * 60
24
24
 
25
25
  class DBFError < StandardError; end
26
- class InvalidColumnName < DBFError; end
27
- class InvalidColumnLength < DBFError; end
26
+
27
+ module Helpers
28
+ def underscore(camel_cased_word)
29
+ camel_cased_word.to_s.gsub(/::/, '/').
30
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
31
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
32
+ tr("-", "_").
33
+ downcase
34
+ end
35
+ end
28
36
  end
data/lib/dbf/record.rb CHANGED
@@ -1,33 +1,34 @@
1
1
  module DBF
2
2
  class Record
3
- attr_reader :attributes
3
+ include Helpers
4
4
 
5
- @@accessors_defined = false
5
+ attr_reader :attributes
6
6
 
7
7
  def initialize(table)
8
8
  @table, @data, @memo = table, table.data, table.memo
9
- @attributes = {}
10
9
  initialize_values(table.columns)
11
10
  define_accessors
12
- self
11
+ end
12
+
13
+ def ==(other)
14
+ other.respond_to?(:attributes) && other.attributes == attributes
13
15
  end
14
16
 
15
17
  private
16
18
 
17
19
  def define_accessors
18
- return if @@accessors_defined
19
20
  @table.columns.each do |column|
20
21
  underscored_column_name = underscore(column.name)
21
- if @table.options[:accessors] && !respond_to?(underscored_column_name)
22
+ unless respond_to?(underscored_column_name)
22
23
  self.class.send :define_method, underscored_column_name do
23
24
  @attributes[column.name]
24
25
  end
25
- @@accessors_defined = true
26
26
  end
27
27
  end
28
28
  end
29
29
 
30
30
  def initialize_values(columns)
31
+ @attributes = {}
31
32
  columns.each do |column|
32
33
  @attributes[column.name] = case column.type
33
34
  when 'N' # number
@@ -54,11 +55,13 @@ module DBF
54
55
  else
55
56
  unpack_string(column).strip
56
57
  end
58
+ @attributes[underscore(column.name)] = @attributes[column.name]
59
+ @attributes
57
60
  end
58
61
  end
59
62
 
60
63
  def unpack_column(column)
61
- @data.read(column.length).unpack("a#{column.length}")
64
+ @data.read(column.length).to_s.unpack("a#{column.length}")
62
65
  end
63
66
 
64
67
  def unpack_string(column)
@@ -78,42 +81,53 @@ module DBF
78
81
  end
79
82
 
80
83
  def read_memo(start_block)
81
- return nil if start_block <= 0 || @table.memo_block_size.nil?
82
- @memo.seek(start_block * @table.memo_block_size)
83
- if @table.memo_file_format == :fpt
84
- memo_type, memo_size, memo_string = @memo.read(@table.memo_block_size).unpack("NNa56")
84
+ return nil if !@table.has_memo_file? || start_block < 1
85
+
86
+ @table.memo_file_format == :fpt ? build_fpt_memo(start_block) : build_dbt_memo(start_block)
87
+ end
88
+
89
+ def build_fpt_memo(start_block)
90
+ @memo.seek(start_block * memo_block_size)
85
91
 
86
- # skip the memo if it isn't text
87
- return nil unless memo_type == 1
88
-
89
- memo_block_content_size = @table.memo_block_size - FPT_BLOCK_HEADER_SIZE
90
- if memo_size > memo_block_content_size
91
- memo_string << @memo.read(memo_size - @table.memo_block_size + FPT_BLOCK_HEADER_SIZE)
92
- elsif memo_size > 0 and memo_size < memo_block_content_size
93
- memo_string = memo_string[0, memo_size]
94
- end
92
+ memo_type, memo_size, memo_string = @memo.read(memo_block_size).unpack("NNa56")
93
+ return nil unless memo_type == 1 and memo_size > 0
94
+
95
+ if memo_size > memo_block_content_size
96
+ memo_string << @memo.read(memo_content_size(memo_size))
95
97
  else
96
- case @table.version
97
- when "83" # dbase iii
98
- memo_string = ""
99
- loop do
100
- memo_string << block = @memo.read(512)
101
- break if block.strip.size < 512
102
- end
103
- when "8b" # dbase iv
104
- memo_type, memo_size = @memo.read(8).unpack("LL")
105
- memo_string = @memo.read(memo_size)
98
+ memo_string = memo_string[0, memo_size]
99
+ end
100
+ memo_string
101
+ end
102
+
103
+ def build_dbt_memo(start_block)
104
+ @memo.seek(start_block * memo_block_size)
105
+
106
+ case @table.version
107
+ when "83" # dbase iii
108
+ memo_string = ""
109
+ loop do
110
+ memo_string << block = @memo.read(memo_block_size)
111
+ break if block.rstrip.size < memo_block_size
106
112
  end
113
+ when "8b" # dbase iv
114
+ memo_type, memo_size = @memo.read(BLOCK_HEADER_SIZE).unpack("LL")
115
+ memo_string = @memo.read(memo_size)
107
116
  end
108
117
  memo_string
109
118
  end
110
119
 
111
- def underscore(camel_cased_word)
112
- camel_cased_word.to_s.gsub(/::/, '/').
113
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
114
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
115
- tr("-", "_").
116
- downcase
120
+ def memo_block_size
121
+ @memo_block_size ||= @table.memo_block_size
117
122
  end
123
+
124
+ def memo_block_content_size
125
+ memo_block_size - BLOCK_HEADER_SIZE
126
+ end
127
+
128
+ def memo_content_size(memo_size)
129
+ (memo_size - memo_block_size) + BLOCK_HEADER_SIZE
130
+ end
131
+
118
132
  end
119
133
  end
data/lib/dbf/table.rb CHANGED
@@ -1,40 +1,25 @@
1
1
  module DBF
2
2
 
3
3
  class Table
4
- # The total number of columns (columns)
5
- attr_reader :column_count
6
-
7
- # An array of DBF::Column records
8
- attr_reader :columns
9
-
10
- # Internal dBase version number
11
- attr_reader :version
12
-
13
- # Last updated datetime
14
- attr_reader :last_updated
15
-
16
- # Either :fpt or :dpt
17
- attr_reader :memo_file_format
18
-
19
- # The block size for memo records
20
- attr_reader :memo_block_size
21
-
22
- # The options that were used when initializing DBF::Table. This is a Hash.
23
- attr_reader :options
24
-
25
- attr_reader :data
26
- attr_reader :memo
27
-
28
- # Initialize a new DBF::Reader.
4
+ include Enumerable
5
+
6
+ attr_reader :column_count # The total number of columns (columns)
7
+ attr_reader :columns # An array of DBF::Column
8
+ attr_reader :version # Internal dBase version number
9
+ attr_reader :last_updated # Last updated datetime
10
+ attr_reader :memo_file_format # :fpt or :dpt
11
+ attr_reader :memo_block_size # The block size for memo records
12
+ attr_reader :options # The options hash that was used to initialize the table
13
+ attr_reader :data # DBF file handle
14
+ attr_reader :memo # Memo file handle
15
+
16
+ # Initializes a new DBF::Reader
29
17
  # Example:
30
18
  # reader = DBF::Reader.new 'data.dbf'
31
19
  def initialize(filename, options = {})
32
- @options = {:in_memory => true, :accessors => true}.merge(options)
33
-
34
- @in_memory = @options[:in_memory]
35
- @accessors = @options[:accessors]
36
20
  @data = File.open(filename, 'rb')
37
21
  @memo = open_memo(filename)
22
+ @options = options
38
23
  reload!
39
24
  end
40
25
 
@@ -57,8 +42,8 @@ module DBF
57
42
  @db_index.size
58
43
  end
59
44
 
60
- # Returns an instance of DBF::Column for <b>column_name</b>. <b>column_name</b>
61
- # can be a symbol or a string.
45
+ # Returns an instance of DBF::Column for <b>column_name</b>. The <b>column_name</b>
46
+ # can be a specified as either a symbol or string.
62
47
  def column(column_name)
63
48
  @columns.detect {|f| f.name == column_name.to_s}
64
49
  end
@@ -66,22 +51,28 @@ module DBF
66
51
  # An array of all the records contained in the database file. Each record is an instance
67
52
  # of DBF::Record (or nil if the record is marked for deletion).
68
53
  def records
69
- if options[:in_memory]
70
- @records ||= get_all_records_from_file
71
- else
72
- get_all_records_from_file
54
+ self.to_a
55
+ end
56
+
57
+ alias_method :rows, :records
58
+
59
+ def each
60
+ 0.upto(@record_count - 1) do |n|
61
+ seek_to_record(n)
62
+ unless deleted_record?
63
+ yield DBF::Record.new(self)
64
+ end
73
65
  end
74
66
  end
75
67
 
76
- alias_method :rows, :records
68
+ # def get_record_from_file(index)
69
+ # seek_to_record(@db_index[index])
70
+ # Record.new(self)
71
+ # end
77
72
 
78
73
  # Returns a DBF::Record (or nil if the record has been marked for deletion) for the record at <tt>index</tt>.
79
74
  def record(index)
80
- if options[:in_memory]
81
- records[index]
82
- else
83
- get_record_from_file(index)
84
- end
75
+ records[index]
85
76
  end
86
77
 
87
78
  # Find records using a simple ActiveRecord-like syntax.
@@ -158,21 +149,38 @@ module DBF
158
149
  end
159
150
  end
160
151
 
152
+ # Returns the record at <tt>index</tt> by seeking to the record in the
153
+ # physical database file. See the documentation for the records method for
154
+ # information on how these two methods differ.
155
+ def get_record_from_file(index)
156
+ seek_to_record(@db_index[index])
157
+ Record.new(self)
158
+ end
159
+
161
160
  private
162
161
 
163
162
  def open_memo(file)
164
- %w(fpt FPT dbt DBT).each do |extension|
165
- filename = file.sub(/#{File.extname(file)[1..-1]}$/, extension)
163
+ %w(fpt FPT dbt DBT).each do |extname|
164
+ filename = replace_extname(file, extname)
166
165
  if File.exists?(filename)
167
- @memo_file_format = extension.downcase.to_sym
166
+ @memo_file_format = extname.downcase.to_sym
168
167
  return File.open(filename, 'rb')
169
168
  end
170
169
  end
171
170
  nil
172
171
  end
172
+
173
+ def replace_extname(filename, extension)
174
+ filename.sub(/#{File.extname(filename)[1..-1]}$/, extension)
175
+ end
173
176
 
174
177
  def deleted_record?
175
- @data.read(1).unpack('a') == ['*']
178
+ if @data.read(1).unpack('a') == ['*']
179
+ @data.rewind
180
+ true
181
+ else
182
+ false
183
+ end
176
184
  end
177
185
 
178
186
  def get_header_info
@@ -189,7 +197,7 @@ module DBF
189
197
  @columns << Column.new(name.strip, type, length, decimal)
190
198
  end
191
199
  end
192
- # Reset the column count
200
+ # Reset the column count in case any were skipped
193
201
  @column_count = @columns.size
194
202
 
195
203
  @columns
@@ -199,6 +207,7 @@ module DBF
199
207
  @memo.rewind
200
208
  if @memo_file_format == :fpt
201
209
  @memo_next_available_block, @memo_block_size = @memo.read(FPT_HEADER_SIZE).unpack('N x2 n')
210
+ @memo_block_size = 0 if @memo_block_size.nil?
202
211
  else
203
212
  @memo_block_size = 512
204
213
  @memo_next_available_block = File.size(@memo.path) / @memo_block_size
@@ -213,23 +222,6 @@ module DBF
213
222
  seek(index * @record_length)
214
223
  end
215
224
 
216
- # Returns the record at <tt>index</tt> by seeking to the record in the
217
- # physical database file. See the documentation for the records method for
218
- # information on how these two methods differ.
219
- def get_record_from_file(index)
220
- seek_to_record(@db_index[index])
221
- deleted_record? ? nil : Record.new(self)
222
- end
223
-
224
- def get_all_records_from_file
225
- all_records = []
226
- 0.upto(@record_count - 1) do |n|
227
- seek_to_record(n)
228
- all_records << DBF::Record.new(self) unless deleted_record?
229
- end
230
- all_records
231
- end
232
-
233
225
  def build_db_index
234
226
  @db_index = []
235
227
  @deleted_records = []
File without changes
File without changes
File without changes
@@ -36,11 +36,9 @@ describe DBF, :shared => true do
36
36
  end
37
37
 
38
38
  specify "column read accessors should return the attribute after typecast" do
39
- if @table.options[:accessors]
40
- @table.columns do |column|
41
- record = table.records.first
42
- record.send(column.name).should == record[column.name]
43
- end
39
+ @table.columns do |column|
40
+ record = table.records.first
41
+ record.send(column.name).should == record[column.name]
44
42
  end
45
43
  end
46
44
 
data/spec/spec_helper.rb CHANGED
@@ -6,5 +6,5 @@ require "dbf"
6
6
  DB_PATH = File.dirname(__FILE__) + '/fixtures' unless defined?(DB_PATH)
7
7
 
8
8
  Spec::Runner.configure do |config|
9
- config.mock_with :mocha
9
+
10
10
  end
@@ -1,34 +1,71 @@
1
1
  require File.dirname(__FILE__) + "/../spec_helper"
2
2
 
3
- describe DBF::Column, "when initialized" do
3
+ describe DBF::Column do
4
4
 
5
- before(:each) do
6
- @column = DBF::Column.new "ColumnName", "N", 1, 0
7
- end
5
+ context "when initialized" do
6
+ before do
7
+ @column = DBF::Column.new "ColumnName", "N", 1, 0
8
+ end
9
+
10
+ it "should set the #name accessor" do
11
+ @column.name.should == "ColumnName"
12
+ end
8
13
 
9
- it "should set the #name accessor" do
10
- @column.name.should == "ColumnName"
11
- end
14
+ it "should set the #type accessor" do
15
+ @column.type.should == "N"
16
+ end
12
17
 
13
- it "should set the #type accessor" do
14
- @column.type.should == "N"
15
- end
18
+ it "should set the #length accessor" do
19
+ @column.length.should == 1
20
+ end
16
21
 
17
- it "should set the #length accessor" do
18
- @column.length.should == 1
19
- end
22
+ it "should set the #decimal accessor" do
23
+ @column.decimal.should == 0
24
+ end
20
25
 
21
- it "should set the #decimal accessor" do
22
- @column.decimal.should == 0
26
+ it "should raise an error if length is greater than 0" do
27
+ lambda { column = DBF::Column.new "ColumnName", "N", -1, 0 }.should raise_error(DBF::ColumnLengthError)
28
+ end
29
+
23
30
  end
24
31
 
25
- it "should raise an error if length is greater than 0" do
26
- lambda { column = DBF::Column.new "ColumnName", "N", -1, 0 }.should raise_error(DBF::ColumnLengthError)
32
+ context "#schema_definition" do
33
+ it "should define an integer column if type is (N)umber with 9 decimals" do
34
+ column = DBF::Column.new "ColumnName", "N", 1, 0
35
+ column.schema_definition.should == "\"column_name\", :integer\n"
36
+ end
37
+
38
+ it "should define a float colmn if type is (N)umber with more than 0 decimals" do
39
+ column = DBF::Column.new "ColumnName", "N", 1, 2
40
+ column.schema_definition.should == "\"column_name\", :float\n"
41
+ end
42
+
43
+ it "should define a datetime column if type is (D)ate" do
44
+ column = DBF::Column.new "ColumnName", "D", 8, 0
45
+ column.schema_definition.should == "\"column_name\", :datetime\n"
46
+ end
47
+
48
+ it "should define a boolean column if type is (L)ogical" do
49
+ column = DBF::Column.new "ColumnName", "L", 1, 0
50
+ column.schema_definition.should == "\"column_name\", :boolean\n"
51
+ end
52
+
53
+ it "should define a text column if type is (M)emo" do
54
+ column = DBF::Column.new "ColumnName", "M", 1, 0
55
+ column.schema_definition.should == "\"column_name\", :text\n"
56
+ end
57
+
58
+ it "should define a string column with length for any other data types" do
59
+ column = DBF::Column.new "ColumnName", "X", 20, 0
60
+ column.schema_definition.should == "\"column_name\", :string, :limit => 20\n"
61
+ end
27
62
  end
28
63
 
29
- it "should strip non-ascii characters from the name" do
30
- column = DBF::Column.new "Col\200umn\0Name\037", "N", 1, 0
31
- column.name.should == "ColumnName"
64
+ context "#strip_non_ascii_chars" do
65
+ it "should strip characters below decimal 32 and above decimal 128" do
66
+ column = DBF::Column.new "ColumnName", "N", 1, 0
67
+ column.send(:strip_non_ascii_chars, "--\x1F-\x68\x65\x6C\x6C\x6F world-\x80--").should == "---hello world---"
68
+ end
32
69
  end
33
70
 
34
71
  end
@@ -1,56 +1,100 @@
1
1
  require File.dirname(__FILE__) + "/../spec_helper"
2
2
 
3
- describe DBF::Record, "when initialized" do
4
-
5
- def standalone_record(binary_data)
6
- table = mock
7
- table.stubs(:data)
8
- table.data.stubs(:read).returns(binary_data)
9
- table.stubs(:memo).returns(nil)
10
- table.stubs(:columns).returns([])
11
- DBF::Record.new(table)
12
- end
13
-
14
- it "should typecast number columns with decimals == 0 to Integer" do
15
- table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
16
- table.column("ID").type.should == "N"
17
- table.column("ID").decimal.should == 0
18
- table.records.all? {|record| record.attributes['ID'].should be_kind_of(Integer)}
3
+ describe DBF::Record do
4
+
5
+ def example_record(data = '')
6
+ DBF::Record.new(mock_table(data))
19
7
  end
20
8
 
21
- it "should typecast number columns with decimals > 0 to Float" do
22
- table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
23
- table.column("ID").type.should == "N"
24
- table.column("COST").decimal.should == 2
25
- table.records.all? {|record| record.attributes['COST'].should be_kind_of(Float)}
9
+ def mock_table(data = '')
10
+ table = mock('table')
11
+ table.stub!(:memo_block_size).and_return(8)
12
+ table.stub!(:memo).and_return(nil)
13
+ table.stub!(:columns).and_return([])
14
+ table.stub!(:data)
15
+ table.stub!(:has_memo_file?).and_return(true)
16
+ table.data.stub!(:read).and_return(data)
17
+ table
26
18
  end
27
19
 
28
- it "should typecast memo columns to String" do
29
- table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
30
- table.column("DESC").type.should == "M"
31
- table.records.all? {|record| record.attributes['DESC'].should be_kind_of(String)}
20
+ context "when initialized" do
21
+ it "should typecast number columns with decimals == 0 to Integer" do
22
+ table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
23
+ table.column("ID").type.should == "N"
24
+ table.column("ID").decimal.should == 0
25
+ table.records.all? {|record| record.attributes['ID'].should be_kind_of(Integer)}
26
+ end
27
+
28
+ it "should typecast number columns with decimals > 0 to Float" do
29
+ table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
30
+ table.column("ID").type.should == "N"
31
+ table.column("COST").decimal.should == 2
32
+ table.records.all? {|record| record.attributes['COST'].should be_kind_of(Float)}
33
+ end
34
+
35
+ it "should typecast memo columns to String" do
36
+ table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
37
+ table.column("DESC").type.should == "M"
38
+ table.records.all? {|record| record.attributes['DESC'].should be_kind_of(String)}
39
+ end
40
+
41
+ it "should typecast logical columns to True or False" do
42
+ table = DBF::Table.new "#{DB_PATH}/dbase_30.dbf"
43
+ table.column("WEBINCLUDE").type.should == "L"
44
+ table.records.all? {|record| record.attributes["WEBINCLUDE"].should satisfy {|v| v == true || v == false}}
45
+ end
46
+
47
+ it "should typecast datetime columns to DateTime" do
48
+ record = example_record("Nl%\000\300Z\252\003")
49
+ column = mock('column', :length => 8)
50
+
51
+ record.instance_eval {unpack_datetime(column)}.to_s.should == "2002-10-10T17:04:56+00:00"
52
+ end
53
+
54
+ it "should typecast integers to Fixnum" do
55
+ record = example_record("\017\020\000\000")
56
+ column = mock('column', :length => 4)
57
+
58
+ record.instance_eval {unpack_integer(column)}.should == 4111
59
+ end
32
60
  end
33
61
 
34
- it "should typecast logical columns to True or False" do
35
- table = DBF::Table.new "#{DB_PATH}/dbase_30.dbf"
36
- table.column("WEBINCLUDE").type.should == "L"
37
- table.records.all? {|record| record.attributes["WEBINCLUDE"].should satisfy {|v| v == true || v == false}}
62
+ describe '#memo_block_content_size' do
63
+ it "should equal the difference between the table's memo_block_size and 8" do
64
+ table = mock_table
65
+ table.should_receive(:memo_block_size).and_return(128)
66
+ record = DBF::Record.new(table)
67
+
68
+ record.send(:memo_block_content_size).should == 120
69
+ end
38
70
  end
39
71
 
40
- it "should typecast datetime columns to DateTime" do
41
- binary_data = "Nl%\000\300Z\252\003"
42
- record = standalone_record(binary_data)
43
- column = stub(:length => 8)
44
-
45
- record.instance_eval {unpack_datetime(column)}.to_s.should == "2002-10-10T17:04:56+00:00"
72
+ describe '#memo_content_size' do
73
+ it "should equal 8 plus the difference between memo_size and the table's memo_block_size" do
74
+ record = example_record
75
+ record.should_receive(:memo_block_size).and_return(8)
76
+
77
+ record.send(:memo_content_size, 1024).should == 1024
78
+ end
46
79
  end
47
80
 
48
- it "should typecast integers to Fixnum" do
49
- binary_data = "\017\020\000\000"
50
- record = standalone_record(binary_data)
51
- column = stub(:length => 4)
81
+ describe '#read_memo' do
82
+ it 'should return nil if start_block is less than 1' do
83
+ table = mock_table
84
+ record = DBF::Record.new(table)
85
+
86
+ record.send(:read_memo, 0).should be_nil
87
+ record.send(:read_memo, -1).should be_nil
88
+ end
89
+
90
+ it 'should return nil if memo file is missing' do
91
+ table = mock_table
92
+ table.should_receive(:has_memo_file?).and_return(false)
93
+ record = DBF::Record.new(table)
52
94
 
53
- record.instance_eval {unpack_integer(column)}.should == 4111
95
+ record.send(:read_memo, 5).should be_nil
96
+ end
97
+
54
98
  end
55
99
 
56
100
  end
@@ -1,167 +1,161 @@
1
1
  require File.dirname(__FILE__) + "/../spec_helper"
2
2
 
3
- describe DBF::Table, "when initialized" do
4
-
5
- before(:all) do
6
- @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
7
- end
8
-
9
- it "should load the data file" do
10
- @table.data.should be_kind_of(File)
11
- end
12
-
13
- it "should locate load the memo file" do
14
- @table.has_memo_file?.should be_true
15
- @table.instance_eval("@memo").should be_kind_of(File)
16
- end
17
-
18
- it "should determine the memo file format" do
19
- @table.memo_file_format.should == :dbt
20
- end
21
-
22
- it "should determine the correct memo block size" do
23
- @table.memo_block_size.should == 512
24
- end
25
-
26
- it "should default to loading all records into memory" do
27
- @table.options[:in_memory].should be_true
28
- end
29
-
30
- it "should determine the number of columns in each record" do
31
- @table.columns.size.should == 15
32
- end
33
-
34
- it "should determine the number of records in the database" do
35
- @table.record_count.should == 67
36
- end
37
-
38
- it "should determine the database version" do
39
- @table.version.should == "83"
40
- end
41
-
42
- it "should set the in_memory option" do
43
- table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf", :in_memory => false
44
- table.options[:in_memory].should be_false
45
- end
3
+ describe DBF::Table do
46
4
 
47
- end
5
+ context "when initialized" do
6
+ before do
7
+ @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
8
+ end
48
9
 
49
- describe DBF::Table, "when the in_memory flag is true" do
50
-
51
- before(:each) do
52
- @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
53
- end
54
-
55
- it "should build the records array from disk only on the first request" do
56
- @table.expects(:get_all_records_from_file).at_most_once.returns([])
57
- 3.times { @table.records }
58
- end
59
-
60
- it "should read from the records array when using the record() method" do
61
- @table.expects(:get_all_records_from_file).at_most_once.returns([])
62
- @table.expects(:get_record_from_file).never
63
- @table.expects(:records).times(2).returns([])
64
- @table.record(1)
65
- @table.record(10)
66
- end
67
-
68
- end
10
+ it "should load the data file" do
11
+ @table.data.should be_kind_of(File)
12
+ end
69
13
 
70
- describe DBF::Table, "when the in_memory flag is false" do
71
-
72
- it "should read the records from disk on every request" do
73
- table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf", :in_memory => false
74
- table.expects(:get_all_records_from_file).times(3).returns([])
75
- 3.times { table.records }
76
- end
77
- end
14
+ it "should locate load the memo file" do
15
+ @table.has_memo_file?.should be_true
16
+ @table.instance_eval("@memo").should be_kind_of(File)
17
+ end
78
18
 
79
- describe DBF::Table, "schema" do
80
-
81
- it "should match test schema " do
82
- table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
83
- control_schema = File.read(File.dirname(__FILE__) + '/../fixtures/dbase_83_schema.txt')
84
-
85
- table.schema.should == control_schema
86
- end
87
-
88
- end
19
+ it "should determine the memo file format" do
20
+ @table.memo_file_format.should == :dbt
21
+ end
89
22
 
90
- describe DBF::Table, "find(index)" do
91
-
92
- before(:all) do
93
- @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
94
- end
95
-
96
- it "should return the correct record" do
97
- @table.find(5).should == @table.record(5)
98
- end
99
-
100
- end
23
+ it "should determine the correct memo block size" do
24
+ @table.memo_block_size.should == 512
25
+ end
101
26
 
102
- describe DBF::Table, "find(:all)" do
103
-
104
- before(:all) do
105
- @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
106
- end
107
-
108
- it "should return all records if options are empty" do
109
- @table.find(:all).should == @table.records
110
- end
111
-
112
- it "should return matching records when used with options" do
113
- @table.find(:all, "WEIGHT" => 0.0).should == @table.records.select {|r| r.attributes["WEIGHT"] == 0.0}
114
- end
115
-
116
- it "with multiple options should search for all search terms as if using AND" do
117
- @table.find(:all, "ID" => 30, "IMAGE" => "graphics/00000001/TBC01.jpg").should == []
118
- end
119
- end
27
+ it "should determine the number of columns in each record" do
28
+ @table.columns.size.should == 15
29
+ end
30
+
31
+ it "should determine the number of records in the database" do
32
+ @table.record_count.should == 67
33
+ end
34
+
35
+ it "should determine the database version" do
36
+ @table.version.should == "83"
37
+ end
120
38
 
121
- describe DBF::Table, "find(:first)" do
122
-
123
- before(:all) do
124
- @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
125
39
  end
126
40
 
127
- it "should return the first record if options are empty" do
128
- @table.find(:first).should == @table.records.first
41
+ describe "#find" do
42
+ describe "with index" do
43
+ it "should return the correct record" do
44
+ table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
45
+ table.find(5).should == table.record(5)
46
+ end
47
+ end
48
+
49
+ describe "with :all" do
50
+ before do
51
+ @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
52
+ end
53
+
54
+ it "should return all records if options are empty" do
55
+ @table.find(:all).should == @table.records
56
+ end
57
+
58
+ it "should return matching records when used with options" do
59
+ @table.find(:all, "WEIGHT" => 0.0).should == @table.select {|r| r.attributes["WEIGHT"] == 0.0}
60
+ end
61
+
62
+ it "with multiple options should search for all search terms as if using AND" do
63
+ @table.find(:all, "ID" => 30, "IMAGE" => "graphics/00000001/TBC01.jpg").should == []
64
+ end
65
+
66
+ it "should match original column names" do
67
+ @table.find(:all, "WEIGHT" => 0.0).should_not be_empty
68
+ end
69
+
70
+ it "should match symbolized column names" do
71
+ @table.find(:all, :WEIGHT => 0.0).should_not be_empty
72
+ end
73
+
74
+ it "should match downcased column names" do
75
+ @table.find(:all, "weight" => 0.0).should_not be_empty
76
+ end
77
+
78
+ it "should match symbolized downcased column names" do
79
+ @table.find(:all, :weight => 0.0).should_not be_empty
80
+ end
81
+ end
82
+
83
+ describe "with :first" do
84
+ before do
85
+ @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
86
+ end
87
+
88
+ it "should return the first record if options are empty" do
89
+ @table.find(:first).should == @table.records.first
90
+ end
91
+
92
+ it "should return the first matching record when used with options" do
93
+ @table.find(:first, "CODE" => "C").should == @table.record(5)
94
+ end
95
+
96
+ it "with multiple options should search for all search terms as if using AND" do
97
+ @table.find(:first, "ID" => 30, "IMAGE" => "graphics/00000001/TBC01.jpg").should be_nil
98
+ end
99
+ end
129
100
  end
130
101
 
131
- it "should return the first matching record when used with options" do
132
- @table.find(:first, "CODE" => "C").should == @table.record(5)
102
+ describe "#reload" do
103
+ # TODO
133
104
  end
134
105
 
135
- it "with multiple options should search for all search terms as if using AND" do
136
- @table.find(:first, "ID" => 30, "IMAGE" => "graphics/00000001/TBC01.jpg").should be_nil
137
- end
138
- end
139
-
140
- describe DBF::Table do
106
+ describe "#column" do
107
+ it "should accept a string or symbol as input" do
108
+ table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
109
+ table.column(:IMAGE).should be_kind_of(DBF::Column)
110
+ table.column("IMAGE").should be_kind_of(DBF::Column)
111
+ end
112
+
113
+ it "should return a DBF::Field object when the column_name exists" do
114
+ table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
115
+ table.column(:IMAGE).should be_kind_of(DBF::Column)
116
+ end
141
117
 
142
- before(:each) do
143
- @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
118
+ it "should return nil when the column_name does not exist" do
119
+ table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
120
+ table.column(:NOTANIMAGE).should be_nil
121
+ end
144
122
  end
145
123
 
146
- it "should reload all data when sent #reload!" do
147
- @table.records
148
- @table.instance_eval("@records").should be_kind_of(Array)
149
- @table.reload!
150
- @table.instance_eval("@records").should be_nil
124
+ describe "#schema" do
125
+ it "should match the test schema fixture" do
126
+ table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
127
+ control_schema = File.read(File.dirname(__FILE__) + '/../fixtures/dbase_83_schema.txt')
128
+
129
+ table.schema.should == control_schema
130
+ end
151
131
  end
152
132
 
153
- it "should return a DBF::Field object when sent #column with a valid column_name given as a string or symbol" do
154
- @table.column("IMAGE").should be_kind_of(DBF::Column)
155
- @table.column(:IMAGE).should be_kind_of(DBF::Column)
133
+ describe "#version_description" do
134
+ it "should return a text description of the database type" do
135
+ table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
136
+ table.version_description.should == "dBase III with memo file"
137
+ end
156
138
  end
157
139
 
158
- it "should return nil when sent #column with an invalid column_name given as a string or symbol" do
159
- @table.column("NOTANIMAGE").should be_nil
160
- @table.column(:NOTANIMAGE).should be_nil
140
+ describe '#replace_extname' do
141
+ it 'should replace the extname' do
142
+ table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
143
+ table.send(:replace_extname, "dbase_83.dbf", 'fpt').should == 'dbase_83.fpt'
144
+ end
161
145
  end
162
146
 
163
- it "should return a text description of the database type when sent #version_description" do
164
- @table.version_description.should == "dBase III with memo file"
147
+ describe '#each' do
148
+ it 'should enumerate all records' do
149
+ table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
150
+ records = []
151
+ table.each do |record|
152
+ records << record
153
+ end
154
+
155
+ records.map! { |r| r.attributes }
156
+ records.should == table.records.map {|r| r.attributes}
157
+ end
158
+
165
159
  end
166
160
 
167
161
  end
metadata CHANGED
@@ -1,41 +1,45 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.4
3
- specification_version: 1
4
2
  name: dbf
5
3
  version: !ruby/object:Gem::Version
6
- version: 1.0.5
7
- date: 2007-11-27 00:00:00 -08:00
8
- summary: A small fast library for reading dBase, xBase, Clipper and FoxPro database files.
9
- require_paths:
10
- - lib
11
- email: keithm@infused.org
12
- homepage: http://dbf.rubyforge.org
13
- rubyforge_project: dbf
14
- description: "DBF is a small fast library for reading dBase, xBase, Clipper and FoxPro database files. It is written completely in Ruby and has no external dependencies. Copyright (c) 2006-2007 Keith Morrison <keithm@infused.org, www.infused.org> * Official project page: http://rubyforge.org/projects/dbf * API Documentation: http://dbf.rubyforge.org/docs * To report bugs: http://www.rubyforge.org/tracker/?group_id=2009 * Questions: Email keithm@infused.org and put DBF somewhere in the subject line"
15
- autorequire:
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ version: 1.0.6
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
6
  authors:
30
7
  - Keith Morrison
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-08-08 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.7.0
24
+ version:
25
+ description: "DBF is a small fast library for reading dBase, xBase, Clipper and FoxPro database files. It is written completely in Ruby and has no external dependencies. Copyright (c) 2006-2007 Keith Morrison <keithm@infused.org, www.infused.org> * Official project page: http://rubyforge.org/projects/dbf * API Documentation: http://dbf.rubyforge.org/docs * To report bugs: http://www.rubyforge.org/tracker/?group_id=2009 * Questions: Email keithm@infused.org and put DBF somewhere in the subject line"
26
+ email: keithm@infused.org
27
+ executables:
28
+ - dbf
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - History.txt
33
+ - Manifest.txt
34
+ - README.txt
35
+ - spec/fixtures/dbase_83_schema.txt
31
36
  files:
32
37
  - History.txt
33
38
  - Manifest.txt
34
39
  - README.txt
35
40
  - Rakefile
36
- - benchmarks/performance.rb
37
- - benchmarks/seek_benchmark.rb
38
41
  - bin/dbf
42
+ - dbf.gemspec
39
43
  - lib/dbf.rb
40
44
  - lib/dbf/column.rb
41
45
  - lib/dbf/globals.rb
@@ -61,29 +65,32 @@ files:
61
65
  - spec/unit/column_spec.rb
62
66
  - spec/unit/record_spec.rb
63
67
  - spec/unit/table_spec.rb
64
- test_files: []
65
-
68
+ has_rdoc: true
69
+ homepage: http://github.com/infused/dm-dbf/tree/master
70
+ post_install_message:
66
71
  rdoc_options:
67
72
  - --main
68
73
  - README.txt
69
- extra_rdoc_files:
70
- - History.txt
71
- - Manifest.txt
72
- - README.txt
73
- - spec/fixtures/dbase_83_schema.txt
74
- executables:
75
- - dbf
76
- extensions: []
77
-
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ version:
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: "0"
87
+ version:
78
88
  requirements: []
79
89
 
80
- dependencies:
81
- - !ruby/object:Gem::Dependency
82
- name: hoe
83
- version_requirement:
84
- version_requirements: !ruby/object:Gem::Version::Requirement
85
- requirements:
86
- - - ">="
87
- - !ruby/object:Gem::Version
88
- version: 1.3.0
89
- version:
90
+ rubyforge_project: dbf
91
+ rubygems_version: 1.2.0
92
+ signing_key:
93
+ specification_version: 2
94
+ summary: A small fast library for reading dBase, xBase, Clipper and FoxPro database files.
95
+ test_files: []
96
+
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- $:.unshift(File.dirname(__FILE__) + "/../lib/")
4
- require 'dbf'
5
- require 'profiler'
6
-
7
- dbf = DBF::Reader.new(File.join(File.dirname(__FILE__),'databases', 'foxpro.dbf'))
8
-
9
- Profiler__::start_profile
10
-
11
- dbf.records
12
-
13
- Profiler__::stop_profile
14
- Profiler__::print_profile($stdout)
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'benchmark'
3
- $:.unshift(File.dirname(__FILE__) + "/../lib/")
4
- require 'dbf'
5
-
6
- puts
7
- puts "Runs 5000 random row seeks first using the I/O based record(n) method and then using"
8
- puts "using the array of records."
9
- puts
10
-
11
- iterations = 5000
12
- Benchmark.bm(20) do |x|
13
- @dbf = DBF::Reader.new(File.join(File.dirname(__FILE__), '..', 'test', 'databases', 'foxpro.dbf'))
14
- max = @dbf.record_count + 1
15
-
16
- x.report("I/O based record(n)") { iterations.times { @dbf.record(rand(max)) } }
17
- x.report("array of records[n]") { iterations.times { @dbf.records[rand(max)] } }
18
- end