dbf 1.2.9 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md ADDED
@@ -0,0 +1,126 @@
1
+ ## 1.2.9
2
+
3
+ - Retain trailing whitespace in memos
4
+
5
+ ## 1.2.8
6
+
7
+ - Handle missing zeros in date values [#11]
8
+
9
+ ## 1.2.7
10
+
11
+ - MIT License
12
+
13
+ ## 1.2.6
14
+
15
+ - Support for Ruby 1.9.2
16
+
17
+ ## 1.2.5
18
+
19
+ - Remove ruby warning switch
20
+ - Requires activesupport version 2.3.5
21
+
22
+ ## 1.2.4
23
+
24
+ - Add csv output option to dbf command-line utility
25
+ - Read Visual FoxPro memos
26
+
27
+ ## 1.2.3
28
+
29
+ - Small performance gain when unpacking values from the dbf file
30
+ - Correctly handle FoxPro's integer data type
31
+
32
+ ## 1.2.2
33
+
34
+ - Handle invalid date fields
35
+
36
+ ## 1.2.1
37
+
38
+ - Add support for F field type (Float)
39
+
40
+ ## 1.2.0
41
+
42
+ - Add Table#to_a
43
+
44
+ ## 1.1.1
45
+
46
+ - Return invalid DateTime columns as nil
47
+
48
+ ## 1.1.0
49
+
50
+ - Add support for large table that will not fit into memory
51
+
52
+ ## 1.0.13
53
+
54
+ - Allow passing an array of ids to find
55
+
56
+ ## 1.0.11
57
+
58
+ - Attributes are now accessible by original or underscored name
59
+
60
+ ## 1.0.9
61
+
62
+ - Fix incorrect integer column values (only affecting some dbf files)
63
+ - Add CSV export
64
+
65
+ ## 1.0.8
66
+
67
+ - Truncate column names on NULL
68
+ - Fix schema dump for date and datetime columns
69
+ - Replace internal helpers with ActiveSupport
70
+ - Always underscore attribute names
71
+
72
+ ## 1.0.7
73
+
74
+ - Remove support for original column names. All columns names are now downcased/underscored.
75
+
76
+ ## 1.0.6
77
+
78
+ - DBF::Table now includes the Enumerable module
79
+ - Return nil for memo values if the memo file is missing
80
+ - Finder conditions now support the original and downcased/underscored column names
81
+
82
+ ## 1.0.5
83
+
84
+ - Strip non-ascii characters from column names
85
+
86
+ ## 1.0.4
87
+
88
+ - Underscore column names when dumping schemas (FieldId becomes field_id)
89
+
90
+ ## 1.0.3
91
+
92
+ - Add support for Visual Foxpro Integer and Datetime columns
93
+
94
+ ## 1.0.2
95
+
96
+ - Compatibility fix for Visual Foxpro memo files (ignore negative memo index values)
97
+
98
+ ## 1.0.1
99
+
100
+ - Fixes error when using the command-line interface [#11984]
101
+
102
+ ## 1.0.0
103
+
104
+ - Renamed classes and refactored code in preparation for adding the
105
+ ability to save records and create/compact databases.
106
+ - The Reader class has been renamed to Table
107
+ - Attributes are no longer accessed directly from the record. Use record.attribute['column_name']
108
+ instead, or use the new attribute accessors detailed under Basic Usage.
109
+
110
+ ## 0.5.4
111
+
112
+ - Ignore deleted records in both memory modes
113
+
114
+ ## 0.5.3
115
+
116
+ - Added a standalone dbf utility (try dbf -h for help)
117
+
118
+ ## 0.5.0 / 2007-05-25
119
+
120
+ - New find method
121
+ - Full compatibility with the two flavors of memo file
122
+ - Two modes of operation:
123
+ - In memory (default): All records are loaded into memory on the first
124
+ request. Records are retrieved from memory for all subsequent requests.
125
+ - File I/O: All records are retrieved from disk on every request
126
+ - Improved documentation and more usage examples
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source :rubygems
2
+
3
+ gem 'activesupport', '3.0.0'
4
+ gem 'i18n', '0.4.1'
5
+ gem 'rspec', '1.3.0'
data/Gemfile.lock ADDED
@@ -0,0 +1,14 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.0.0)
5
+ i18n (0.4.1)
6
+ rspec (1.3.0)
7
+
8
+ PLATFORMS
9
+ ruby
10
+
11
+ DEPENDENCIES
12
+ activesupport (= 3.0.0)
13
+ i18n (= 0.4.1)
14
+ rspec (= 1.3.0)
@@ -11,7 +11,7 @@ database files
11
11
 
12
12
  ## Compatibility
13
13
 
14
- DBF is tested to work with Ruby 1.8.6, 1.8.7, 1.9.1 and 1.9.2-head (using ActiveSupport 2.3.5 and 3 beta 3).
14
+ DBF is tested to work with Ruby 1.8.6, 1.8.7, 1.9.1 and 1.9.2
15
15
 
16
16
  ## Installation
17
17
 
@@ -38,21 +38,21 @@ Load a single record using <tt>record</tt> or <tt>find</tt>
38
38
  table.find(6)
39
39
 
40
40
  Attributes can also be accessed through the attributes hash in original or
41
- underscored form or as an accessor method using the underscored name.
42
- (Note that record() will return nil if the requested record has been
43
- deleted and not yet pruned from the database)
41
+ underscored form or as an accessor method using the underscored name. (Note
42
+ that record() will return nil if the requested record has been deleted and not
43
+ yet pruned from the database)
44
44
 
45
45
  table.record(4).attributes["PhoneBook"]
46
46
  table.record(4).attributes["phone_book"]
47
47
  table.record(4).phone_book
48
48
 
49
- Search for records using a simple hash format. Multiple search criteria are
50
- ANDed. Use the block form of find if the resulting recordset could be large
51
- otherwise all records will be loaded into memory.
49
+ Search for records using a simple hash format. Multiple search criteria are
50
+ ANDed. Use the block form if the resulting recordset could be large, otherwise
51
+ all records will be loaded into memory.
52
52
 
53
53
  # find all records with first_name equal to Keith
54
54
  table.find(:all, :first_name => 'Keith') do |record|
55
- # the record will be nil if deleted and not yet pruned from the database
55
+ # the record will be nil if deleted, but not yet pruned from the database
56
56
  if record
57
57
  puts record.last_name
58
58
  end
@@ -100,26 +100,23 @@ A small command-line utility called dbf is installed along with the gem.
100
100
 
101
101
  The basic dBase data types are generally supported well. Support for the
102
102
  advanced data types in dbase V and FoxPro are still experimental or not
103
- supported. If you have any insight into how any of unsupported data
104
- types are implemented, please give me a shout. FoxBase/dBase II files are not
105
- supported at this time.
103
+ supported. If you have insight into how any of unsupported data types are
104
+ implemented, please give me a shout. FoxBase/dBase II files are not supported
105
+ at this time.
106
106
 
107
- See [docs/supported_types.markdown](http://github.com/infused/dbf/blob/master/docs/supported_types.markdown) for a full
108
- list of supported column types.
107
+ See
108
+ [docs/supported_types.markdown](http://github.com/infused/dbf/blob/master/docs/supported_types.markdown)
109
+ for a full list of supported column types.
109
110
 
110
111
  ## Limitations
111
112
 
112
113
  * DBF is read-only
113
- * index files are not utilized
114
- * No attempt is made to convert character sets based on the code page defined
115
- in the dBase file
114
+ * Index files are not utilized
115
+ * No character set conversions from the code page defined in the dBase file
116
116
 
117
117
  ## License
118
118
 
119
- (The MIT Licence)
120
-
121
- Copyright (c) 2006-2010 Keith Morrison <mailto:keithm@infused.org>,
122
- <http://www.infused.org>.
119
+ Copyright (c) 2006-2010 Keith Morrison <keithm@infused.org>
123
120
 
124
121
  Permission is hereby granted, free of charge, to any person
125
122
  obtaining a copy of this software and associated documentation
data/Rakefile CHANGED
@@ -1,40 +1,68 @@
1
- PROJECT_ROOT = File.expand_path(File.dirname(__FILE__))
2
- $: << File.join(PROJECT_ROOT, 'lib')
1
+ # encoding: utf-8
3
2
 
4
3
  require 'rubygems'
5
- require 'jeweler'
6
- require 'spec/rake/spectask'
7
-
8
- Jeweler::Tasks.new do |s|
9
- s.name = 'dbf'
10
- s.description = 'A small fast library for reading dBase, xBase, Clipper and FoxPro database files.'
11
- s.summary = 'Read xBase files'
12
- s.platform = Gem::Platform::RUBY
13
- s.authors = ['Keith Morrison']
14
- s.email = 'keithm@infused.org'
15
- s.add_dependency('activesupport', ['>= 2.3.5'])
16
- s.add_dependency('fastercsv', ['>= 1.4.0'])
17
- s.homepage = 'http://github.com/infused/dbf'
4
+ require 'rubygems/specification'
5
+
6
+ def gemspec
7
+ @gemspec ||= begin
8
+ file = File.expand_path('../dbf.gemspec', __FILE__)
9
+ eval(File.read(file), binding, file)
10
+ end
18
11
  end
19
12
 
20
- Jeweler::GemcutterTasks.new
13
+ begin
14
+ require 'rake/gempackagetask'
15
+ rescue LoadError
16
+ task(:gem) { $stderr.puts '`gem install rake` to package gems' }
17
+ else
18
+ Rake::GemPackageTask.new(gemspec) do |pkg|
19
+ pkg.gem_spec = gemspec
20
+ end
21
+ task :gem => :gemspec
22
+ end
21
23
 
22
- task :default => :spec
24
+ begin
25
+ require 'spec/rake/spectask'
26
+ rescue LoadError
27
+ raise 'Run `gem install rspec` to be able to run specs'
28
+ else
29
+ task :clear_tmp do
30
+ FileUtils.rm_rf(File.expand_path("../tmp", __FILE__))
31
+ end
23
32
 
24
- desc "Run specs"
25
- Spec::Rake::SpecTask.new :spec do |t|
26
- t.spec_files = FileList['spec/**/*spec.rb']
33
+ desc "Run specs"
34
+ Spec::Rake::SpecTask.new do |t|
35
+ t.spec_files = FileList['spec/**/*_spec.rb']
36
+ t.spec_opts = %w(-fs --color)
37
+ t.warning = true
38
+ end
39
+ task :spec
27
40
  end
28
41
 
29
- desc "Run rcov"
30
- Spec::Rake::SpecTask.new :rcov do |t|
31
- t.spec_files = FileList['spec/**/*spec.rb']
32
- t.rcov = true
33
- t.rcov_opts = ["--exclude ~\/.gem"]
42
+ require 'rake'
43
+ require 'rake/rdoctask'
44
+ Rake::RDocTask.new { |rdoc|
45
+ rdoc.rdoc_dir = 'doc'
46
+ rdoc.title = "DBF - A small fast library for reading dBase, xBase, Clipper and FoxPro database files."
47
+ rdoc.options << '--line-numbers'
48
+ rdoc.template = "#{ENV['template']}.rb" if ENV['template']
49
+ rdoc.rdoc_files.include('README.md', 'docs/supported_types.markdown', 'lib/**/*.rb')
50
+ }
51
+
52
+ desc "install the gem locally"
53
+ task :install => :package do
54
+ sh %{gem install pkg/#{gemspec.name}-#{gemspec.version}}
34
55
  end
35
56
 
36
- desc "Run spec docs"
37
- Spec::Rake::SpecTask.new :specdoc do |t|
38
- t.spec_opts = ["-f specdoc"]
39
- t.spec_files = FileList['spec/**/*spec.rb']
57
+ desc "validate the gemspec"
58
+ task :gemspec do
59
+ gemspec.validate
40
60
  end
61
+
62
+ task :package => :gemspec
63
+ task :default => :spec
64
+
65
+ desc "Open an irb session preloaded with this library"
66
+ task :console do
67
+ sh "irb -rubygems -I lib -r dbf.rb"
68
+ end
data/lib/dbf.rb CHANGED
@@ -1,7 +1,12 @@
1
1
  require 'date'
2
- gem 'activesupport', '>=2.3.5'
3
- require 'active_support'
4
- require 'active_support/core_ext'
2
+ gem 'activesupport', '=3.0.0'
3
+ require 'active_support/core_ext/object'
4
+ require 'active_support/core_ext/date/conversions'
5
+ require 'active_support/core_ext/time/conversions'
6
+ require 'active_support/core_ext/date_time/conversions'
7
+ require 'active_support/core_ext/string/conversions'
8
+ require 'active_support/core_ext/module/delegation'
9
+ require 'active_support/core_ext/string/inflections'
5
10
 
6
11
  if RUBY_VERSION > '1.9'
7
12
  require 'csv'
@@ -15,7 +20,7 @@ else
15
20
  require 'fastercsv'
16
21
  end
17
22
 
18
- require 'dbf/globals'
23
+ require 'dbf/attributes'
19
24
  require 'dbf/record'
20
25
  require 'dbf/column'
21
26
  require 'dbf/table'
@@ -0,0 +1,6 @@
1
+ class Attributes < Hash
2
+ def []=(key, value)
3
+ merge!(key => value)
4
+ merge!(key.underscore => value)
5
+ end
6
+ end
data/lib/dbf/column.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module DBF
2
- class ColumnLengthError < DBFError; end
3
- class ColumnNameError < DBFError; end
2
+ class ColumnLengthError < StandardError; end
3
+ class ColumnNameError < StandardError; end
4
4
 
5
5
  # DBF::Column stores all the information about a column including its name,
6
6
  # type, length and number of decimal places (if any)
@@ -143,6 +143,10 @@ module DBF
143
143
 
144
144
  s.gsub(/[^\x20-\x7E]/,"")
145
145
  end
146
+
147
+ def memo?
148
+ type == 'M'
149
+ end
146
150
  end
147
151
 
148
152
  end
data/lib/dbf/record.rb CHANGED
@@ -1,11 +1,13 @@
1
1
  module DBF
2
-
3
2
  # An instance of DBF::Record represents a row in the DBF file
4
3
  class Record
4
+ BLOCK_HEADER_SIZE = 8
5
+
6
+ attr_reader :table
5
7
  attr_reader :attributes
6
8
  attr_reader :memo_block_size
7
9
 
8
- delegate :columns, :to => :@table
10
+ delegate :columns, :to => :table
9
11
 
10
12
  # Initialize a new DBF::Record
11
13
  #
@@ -32,14 +34,21 @@ module DBF
32
34
  columns.map { |column| @attributes[column.name.underscore] }
33
35
  end
34
36
 
37
+ # Do all search parameters match?
38
+ #
39
+ # @param [Hash] options
40
+ # @return [Boolean]
41
+ def match?(options)
42
+ options.all? {|key, value| attributes[key.to_s.underscore] == value}
43
+ end
44
+
35
45
  private
36
46
 
37
47
  # Defined attribute accessor methods
38
48
  def define_accessors
39
49
  columns.each do |column|
40
- underscored_column_name = column.name.underscore
41
- unless respond_to?(underscored_column_name)
42
- self.class.send :define_method, underscored_column_name do
50
+ unless self.class.method_defined?(column.name.underscore)
51
+ self.class.send :define_method, column.name.underscore do
43
52
  @attributes[column.name.underscore]
44
53
  end
45
54
  end
@@ -48,16 +57,11 @@ module DBF
48
57
 
49
58
  # Initialize values for a row
50
59
  def initialize_values
51
- @attributes = columns.inject({}) do |hash, column|
52
- if column.type == 'M'
53
- memo = read_memo(get_starting_block(column))
54
- hash[column.name] = memo
55
- hash[column.name.underscore] = memo
60
+ @attributes = columns.inject(Attributes.new) do |hash, column|
61
+ if column.memo?
62
+ hash[column.name] = read_memo(get_starting_block(column))
56
63
  else
57
- value = unpack_data(column.length)
58
- type_cast_value = column.type_cast(value)
59
- hash[column.name] = type_cast_value
60
- hash[column.name.underscore] = type_cast_value
64
+ hash[column.name] = column.type_cast(unpack_data(column.length))
61
65
  end
62
66
  hash
63
67
  end
@@ -86,8 +90,7 @@ module DBF
86
90
  # @param [Fixnum] start_block
87
91
  def read_memo(start_block)
88
92
  return nil if !@table.has_memo_file? || start_block < 1
89
-
90
- @table.memo_file_format == :fpt ? build_fpt_memo(start_block) : build_dbt_memo(start_block)
93
+ send "build_#{@table.memo_file_format}_memo", start_block
91
94
  end
92
95
 
93
96
  # Reconstructs a memo from an FPT memo file
@@ -98,7 +101,7 @@ module DBF
98
101
  @memo.seek(start_block * memo_block_size)
99
102
 
100
103
  memo_type, memo_size, memo_string = @memo.read(memo_block_size).unpack("NNa*")
101
- return nil unless memo_type == 1 and memo_size > 0
104
+ return nil unless memo_type == 1 && memo_size > 0
102
105
 
103
106
  if memo_size > memo_block_content_size
104
107
  memo_string << @memo.read(memo_content_size(memo_size))
data/lib/dbf/table.rb CHANGED
@@ -3,6 +3,24 @@ module DBF
3
3
  # DBF::Table is the primary interface to a single DBF file and provides
4
4
  # methods for enumerating and searching the records.
5
5
  class Table
6
+ DBF_HEADER_SIZE = 32
7
+ FPT_HEADER_SIZE = 512
8
+
9
+ VERSION_DESCRIPTIONS = {
10
+ "02" => "FoxBase",
11
+ "03" => "dBase III without memo file",
12
+ "04" => "dBase IV without memo file",
13
+ "05" => "dBase V without memo file",
14
+ "30" => "Visual FoxPro",
15
+ "31" => "Visual FoxPro with AutoIncrement field",
16
+ "7b" => "dBase IV with memo file",
17
+ "83" => "dBase III with memo file",
18
+ "8b" => "dBase IV with memo file",
19
+ "8e" => "dBase IV with SQL table",
20
+ "f5" => "FoxPro with memo file",
21
+ "fb" => "FoxPro without memo file"
22
+ }
23
+
6
24
  attr_reader :column_count # The total number of columns
7
25
  attr_reader :columns # An array of DBF::Column
8
26
  attr_reader :version # Internal dBase version number
@@ -35,7 +53,7 @@ module DBF
35
53
  def reload!
36
54
  @records = nil
37
55
  get_header_info
38
- get_memo_header_info if @memo
56
+ get_memo_header_info
39
57
  get_column_descriptors
40
58
  end
41
59
 
@@ -59,10 +77,7 @@ module DBF
59
77
  #
60
78
  # @yield [nil, DBF::Record]
61
79
  def each
62
- 0.upto(@record_count - 1) do |n|
63
- seek_to_record(n)
64
- yield current_record
65
- end
80
+ 0.upto(@record_count - 1) {|index| yield record(index)}
66
81
  end
67
82
 
68
83
  # Retrieve a record by index number.
@@ -189,9 +204,9 @@ module DBF
189
204
  def find_all(options, &block)
190
205
  results = []
191
206
  each do |record|
192
- if record && all_values_match?(record, options)
207
+ if record.try(:match?, options)
193
208
  if block_given?
194
- yield(record)
209
+ yield record
195
210
  else
196
211
  results << record
197
212
  end
@@ -206,20 +221,11 @@ module DBF
206
221
  # @return [DBF::Record, nil]
207
222
  def find_first(options)
208
223
  each do |record|
209
- return record if record && all_values_match?(record, options)
224
+ return record if record.try(:match?, options)
210
225
  end
211
226
  nil
212
227
  end
213
228
 
214
- # Do all search parameters match?
215
- #
216
- # @param [DBF::Record] record
217
- # @param [Hash] options
218
- # @return [Boolean]
219
- def all_values_match?(record, options)
220
- options.all? {|key, value| record.attributes[key.to_s.underscore] == value}
221
- end
222
-
223
229
  # Open memo file
224
230
  #
225
231
  # @params [String] path
@@ -279,13 +285,15 @@ module DBF
279
285
 
280
286
  # Determines the memo block size and next available block
281
287
  def get_memo_header_info
282
- @memo.rewind
283
- if @memo_file_format == :fpt
284
- @memo_next_available_block, @memo_block_size = @memo.read(FPT_HEADER_SIZE).unpack('N x2 n')
285
- @memo_block_size = 0 if @memo_block_size.nil?
286
- else
287
- @memo_block_size = 512
288
- @memo_next_available_block = File.size(@memo.path) / @memo_block_size
288
+ if has_memo_file?
289
+ @memo.rewind
290
+ if @memo_file_format == :fpt
291
+ @memo_next_available_block, @memo_block_size = @memo.read(FPT_HEADER_SIZE).unpack('N x2 n')
292
+ @memo_block_size = 0 if @memo_block_size.nil?
293
+ else
294
+ @memo_block_size = 512
295
+ @memo_next_available_block = File.size(@memo.path) / @memo_block_size
296
+ end
289
297
  end
290
298
  end
291
299
 
@@ -0,0 +1,3 @@
1
+ module DBF
2
+ VERSION = '1.3.0'
3
+ end
@@ -7,19 +7,19 @@ describe DBF::Column do
7
7
  @column = DBF::Column.new "ColumnName", "N", 1, 0
8
8
  end
9
9
 
10
- it "should set the #name accessor" do
10
+ it "sets the #name accessor" do
11
11
  @column.name.should == "ColumnName"
12
12
  end
13
13
 
14
- it "should set the #type accessor" do
14
+ it "sets the #type accessor" do
15
15
  @column.type.should == "N"
16
16
  end
17
17
 
18
- it "should set the #length accessor" do
18
+ it "sets the #length accessor" do
19
19
  @column.length.should == 1
20
20
  end
21
21
 
22
- it "should set the #decimal accessor" do
22
+ it "sets the #decimal accessor" do
23
23
  @column.decimal.should == 0
24
24
  end
25
25
 
@@ -36,20 +36,20 @@ describe DBF::Column do
36
36
  end
37
37
  end
38
38
 
39
- context "#type_cast" do
39
+ context '#type_cast' do
40
40
  context 'with type N (number)' do
41
- context 'with 0 decimals' do
42
- it 'should cast value to Fixnum' do
43
- value = "135"
41
+ context 'and 0 decimals' do
42
+ it 'casts value to Fixnum' do
43
+ value = '135'
44
44
  column = DBF::Column.new "ColumnName", "N", 3, 0
45
45
  column.type_cast(value).should be_a Fixnum
46
46
  column.type_cast(value).should == 135
47
47
  end
48
48
  end
49
49
 
50
- context 'with more than 0 decimals' do
51
- it "should cast value to Float" do
52
- value = "13.5"
50
+ context 'and more than 0 decimals' do
51
+ it 'casts value to Float' do
52
+ value = '13.5'
53
53
  column = DBF::Column.new "ColumnName", "N", 2, 1
54
54
  column.type_cast(value).should be_a Float
55
55
  column.type_cast(value).should == 13.5
@@ -58,8 +58,8 @@ describe DBF::Column do
58
58
  end
59
59
 
60
60
  context 'with type F (float)' do
61
- it "should cast value to Float" do
62
- value = "135"
61
+ it 'casts value to Float' do
62
+ value = '135'
63
63
  column = DBF::Column.new "ColumnName", "F", 3, 0
64
64
  column.type_cast(value).should be_a Float
65
65
  column.type_cast(value).should == 135.0
@@ -67,33 +67,30 @@ describe DBF::Column do
67
67
  end
68
68
 
69
69
  context 'with type I (integer)' do
70
- it "should cast value to Fixnum" do
70
+ it "casts value to Fixnum" do
71
71
  value = "\203\171\001\000"
72
72
  column = DBF::Column.new "ColumnName", "I", 3, 0
73
- column.type_cast(value).should be_a Fixnum
74
73
  column.type_cast(value).should == 96643
75
74
  end
76
75
  end
77
76
 
78
77
  context 'with type L (logical/boolean)' do
79
- it "should cast 'y' to true" do
78
+ it "casts 'y' to true" do
80
79
  value = "y"
81
80
  column = DBF::Column.new "ColumnName", "L", 1, 0
82
- column.type_cast(value).should be_a TrueClass
83
81
  column.type_cast(value).should == true
84
82
  end
85
83
 
86
- it "should cast 'n' to false" do
84
+ it "casts 'n' to false" do
87
85
  value = "n"
88
86
  column = DBF::Column.new "ColumnName", "L", 1, 0
89
- column.type_cast(value).should be_a FalseClass
90
87
  column.type_cast(value).should == false
91
88
  end
92
89
  end
93
90
 
94
91
  context 'with type T (datetime)' do
95
92
  context 'with valid datetime' do
96
- it "should cast to DateTime" do
93
+ it "casts to DateTime" do
97
94
  value = "Nl%\000\300Z\252\003"
98
95
  column = DBF::Column.new "ColumnName", "T", 16, 0
99
96
  column.type_cast(value).should == "2002-10-10T17:04:56+00:00"
@@ -101,7 +98,7 @@ describe DBF::Column do
101
98
  end
102
99
 
103
100
  context 'with invalid datetime' do
104
- it "should cast to nil" do
101
+ it "casts to nil" do
105
102
  value = "Nl%\000\000A\000\999"
106
103
  column = DBF::Column.new "ColumnName", "T", 16, 0
107
104
  column.type_cast(value).should be_nil
@@ -111,7 +108,7 @@ describe DBF::Column do
111
108
 
112
109
  context 'with type D (date)' do
113
110
  context 'with valid date' do
114
- it "should cast to Date" do
111
+ it "casts to Date" do
115
112
  value = "20050712"
116
113
  column = DBF::Column.new "ColumnName", "D", 8, 0
117
114
  column.type_cast(value).should == Date.new(2005,7,12)
@@ -119,7 +116,7 @@ describe DBF::Column do
119
116
  end
120
117
 
121
118
  context 'with invalid date' do
122
- it "should cast to Date" do
119
+ it "casts to nil" do
123
120
  value = "0"
124
121
  column = DBF::Column.new "ColumnName", "D", 8, 0
125
122
  column.type_cast(value).should be_nil
@@ -128,7 +125,7 @@ describe DBF::Column do
128
125
  end
129
126
 
130
127
  context 'with type M (memo)' do
131
- it "should typecast memo columns to String" do
128
+ it "casts to string" do
132
129
  value = 'abc'
133
130
  column = DBF::Column.new "ColumnName", "M", 3, 0
134
131
  column.type_cast(value).should be_a String
@@ -138,38 +135,38 @@ describe DBF::Column do
138
135
 
139
136
  context "#schema_definition" do
140
137
  context 'with type N (number)' do
141
- it "should output an integer column" do
138
+ it "outputs an integer column" do
142
139
  column = DBF::Column.new "ColumnName", "N", 1, 0
143
140
  column.schema_definition.should == "\"column_name\", :integer\n"
144
141
  end
145
142
  end
146
143
 
147
- it "should define a float colmn if type is (N)umber with more than 0 decimals" do
144
+ it "defines a float colmn if type is (N)umber with more than 0 decimals" do
148
145
  column = DBF::Column.new "ColumnName", "N", 1, 2
149
146
  column.schema_definition.should == "\"column_name\", :float\n"
150
147
  end
151
148
 
152
- it "should define a date column if type is (D)ate" do
149
+ it "defines a date column if type is (D)ate" do
153
150
  column = DBF::Column.new "ColumnName", "D", 8, 0
154
151
  column.schema_definition.should == "\"column_name\", :date\n"
155
152
  end
156
153
 
157
- it "should define a datetime column if type is (D)ate" do
154
+ it "defines a datetime column if type is (D)ate" do
158
155
  column = DBF::Column.new "ColumnName", "T", 16, 0
159
156
  column.schema_definition.should == "\"column_name\", :datetime\n"
160
157
  end
161
158
 
162
- it "should define a boolean column if type is (L)ogical" do
159
+ it "defines a boolean column if type is (L)ogical" do
163
160
  column = DBF::Column.new "ColumnName", "L", 1, 0
164
161
  column.schema_definition.should == "\"column_name\", :boolean\n"
165
162
  end
166
163
 
167
- it "should define a text column if type is (M)emo" do
164
+ it "defines a text column if type is (M)emo" do
168
165
  column = DBF::Column.new "ColumnName", "M", 1, 0
169
166
  column.schema_definition.should == "\"column_name\", :text\n"
170
167
  end
171
168
 
172
- it "should define a string column with length for any other data types" do
169
+ it "defines a string column with length for any other data types" do
173
170
  column = DBF::Column.new "ColumnName", "X", 20, 0
174
171
  column.schema_definition.should == "\"column_name\", :string, :limit => 20\n"
175
172
  end
@@ -180,11 +177,11 @@ describe DBF::Column do
180
177
  @column = DBF::Column.new "ColumnName", "N", 1, 0
181
178
  end
182
179
 
183
- it "should strip characters below decimal 32 and above decimal 127" do
180
+ it "strips characters below decimal 32 and above decimal 127" do
184
181
  @column.strip_non_ascii_chars("--\x1F-\x68\x65\x6C\x6C\x6F world-\x80--").should == "---hello world---"
185
182
  end
186
183
 
187
- it "should truncate characters with decimal 0" do
184
+ it "truncates characters with decimal 0" do
188
185
  @column.strip_non_ascii_chars("--\x1F-\x68\x65\x6C\x6C\x6F \x00 world-\x80--").should == "---hello "
189
186
  end
190
187
  end
@@ -10,14 +10,14 @@ describe DBF::Record do
10
10
  def mock_table(data = '')
11
11
  @column1 = DBF::Column.new 'ColumnName', 'N', 1, 0
12
12
 
13
- returning mock('table') do |table|
14
- table.stub!(:memo_block_size).and_return(8)
15
- table.stub!(:memo).and_return(nil)
16
- table.stub!(:columns).and_return([@column1])
17
- table.stub!(:data).and_return(data)
18
- table.stub!(:has_memo_file?).and_return(true)
19
- table.data.stub!(:read).and_return(data)
20
- end
13
+ table = mock('table')
14
+ table.stub!(:memo_block_size).and_return(8)
15
+ table.stub!(:memo).and_return(nil)
16
+ table.stub!(:columns).and_return([@column1])
17
+ table.stub!(:data).and_return(data)
18
+ table.stub!(:has_memo_file?).and_return(true)
19
+ table.data.stub!(:read).and_return(data)
20
+ table
21
21
  end
22
22
 
23
23
  describe '#memo_block_content_size' do
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbf
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
5
4
  prerelease: false
6
5
  segments:
7
6
  - 1
8
- - 2
9
- - 9
10
- version: 1.2.9
7
+ - 3
8
+ - 0
9
+ version: 1.3.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - Keith Morrison
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-07-22 00:00:00 -07:00
17
+ date: 2010-10-08 00:00:00 -07:00
19
18
  default_executable: dbf
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
@@ -24,14 +23,13 @@ dependencies:
24
23
  requirement: &id001 !ruby/object:Gem::Requirement
25
24
  none: false
26
25
  requirements:
27
- - - ">="
26
+ - - "="
28
27
  - !ruby/object:Gem::Version
29
- hash: 9
30
28
  segments:
31
- - 2
32
29
  - 3
33
- - 5
34
- version: 2.3.5
30
+ - 0
31
+ - 0
32
+ version: 3.0.0
35
33
  type: :runtime
36
34
  version_requirements: *id001
37
35
  - !ruby/object:Gem::Dependency
@@ -40,16 +38,30 @@ dependencies:
40
38
  requirement: &id002 !ruby/object:Gem::Requirement
41
39
  none: false
42
40
  requirements:
43
- - - ">="
41
+ - - "="
44
42
  - !ruby/object:Gem::Version
45
- hash: 7
46
43
  segments:
47
44
  - 1
48
- - 4
49
- - 0
50
- version: 1.4.0
45
+ - 5
46
+ - 3
47
+ version: 1.5.3
51
48
  type: :runtime
52
49
  version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: rspec
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ segments:
59
+ - 1
60
+ - 3
61
+ - 0
62
+ version: 1.3.0
63
+ type: :development
64
+ version_requirements: *id003
53
65
  description: A small fast library for reading dBase, xBase, Clipper and FoxPro database files.
54
66
  email: keithm@infused.org
55
67
  executables:
@@ -57,23 +69,23 @@ executables:
57
69
  extensions: []
58
70
 
59
71
  extra_rdoc_files:
60
- - README.markdown
72
+ - README.md
73
+ - CHANGELOG.md
61
74
  files:
62
- - .autotest
63
- - .gitignore
64
- - History.txt
75
+ - CHANGELOG.md
76
+ - Gemfile
77
+ - Gemfile.lock
65
78
  - MIT-LICENSE
66
- - README.markdown
67
79
  - Rakefile
68
- - VERSION.yml
80
+ - README.md
69
81
  - bin/dbf
70
- - dbf.gemspec
71
82
  - docs/supported_types.markdown
72
- - lib/dbf.rb
83
+ - lib/dbf/attributes.rb
73
84
  - lib/dbf/column.rb
74
- - lib/dbf/globals.rb
75
85
  - lib/dbf/record.rb
76
86
  - lib/dbf/table.rb
87
+ - lib/dbf/version.rb
88
+ - lib/dbf.rb
77
89
  - spec/fixtures/dbase_03.dbf
78
90
  - spec/fixtures/dbase_30.dbf
79
91
  - spec/fixtures/dbase_30.fpt
@@ -110,7 +122,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
110
122
  requirements:
111
123
  - - ">="
112
124
  - !ruby/object:Gem::Version
113
- hash: 3
114
125
  segments:
115
126
  - 0
116
127
  version: "0"
@@ -119,10 +130,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
130
  requirements:
120
131
  - - ">="
121
132
  - !ruby/object:Gem::Version
122
- hash: 3
123
133
  segments:
134
+ - 1
135
+ - 3
124
136
  - 0
125
- version: "0"
137
+ version: 1.3.0
126
138
  requirements: []
127
139
 
128
140
  rubyforge_project:
@@ -131,14 +143,12 @@ signing_key:
131
143
  specification_version: 3
132
144
  summary: Read xBase files
133
145
  test_files:
134
- - spec/functional/dbf_shared.rb
135
146
  - spec/functional/format_03_spec.rb
136
147
  - spec/functional/format_30_spec.rb
137
148
  - spec/functional/format_31_spec.rb
138
149
  - spec/functional/format_83_spec.rb
139
150
  - spec/functional/format_8b_spec.rb
140
151
  - spec/functional/format_f5_spec.rb
141
- - spec/spec_helper.rb
142
152
  - spec/unit/column_spec.rb
143
153
  - spec/unit/record_spec.rb
144
154
  - spec/unit/table_spec.rb
data/.autotest DELETED
@@ -1,15 +0,0 @@
1
- Autotest.add_hook :initialize do |autotest|
2
- autotest.clear_mappings
3
-
4
- autotest.add_mapping(%r%^lib/dbf/(.*)\.rb$%) do |filename, m|
5
- autotest.files_matching %r!spec/(unit|functional)/#{m[1]}_spec.rb!
6
- end
7
-
8
- autotest.add_mapping(%r%^spec/(unit|functional)/.*\.rb$%) do |filename, m|
9
- filename
10
- end
11
-
12
- %w{.svn .hg .git .dbf .dbt .fpt .txt bin Rakefile .gemspec .autotest}.each do |exception|
13
- autotest.add_exception(exception)
14
- end
15
- end
data/.gitignore DELETED
@@ -1 +0,0 @@
1
- .DS_Store
data/History.txt DELETED
@@ -1,118 +0,0 @@
1
- == 1.2.7
2
-
3
- * MIT License
4
-
5
- == 1.2.6
6
-
7
- * Support for Ruby 1.9.2
8
-
9
- == 1.2.5
10
-
11
- * Remove ruby warning switch
12
- * Requires activesupport version 2.3.5
13
-
14
- == 1.2.4
15
-
16
- * Add csv output option to dbf command-line utility
17
- * Read Visual FoxPro memos
18
-
19
- == 1.2.3
20
-
21
- * Small performance gain when unpacking values from the dbf file
22
- * Correctly handle FoxPro's integer data type
23
-
24
- == 1.2.2
25
-
26
- * Handle invalid date fields
27
-
28
- == 1.2.1
29
-
30
- * Add support for F field type (Float)
31
-
32
- == 1.2.0
33
-
34
- * Add Table#to_a
35
-
36
- == 1.1.1
37
-
38
- * Return invalid DateTime columns as nil
39
-
40
- == 1.1.0
41
-
42
- * Add support for large table that will not fit into memory
43
-
44
- == 1.0.13
45
-
46
- * Allow passing an array of ids to find
47
-
48
- == 1.0.11
49
-
50
- * Attributes are now accessible by original or underscored name
51
-
52
- == 1.0.9
53
-
54
- * Fix incorrect integer column values (only affecting some dbf files)
55
- * Add CSV export
56
-
57
- == 1.0.8
58
-
59
- * Truncate column names on NULL
60
- * Fix schema dump for date and datetime columns
61
- * Replace internal helpers with ActiveSupport
62
- * Always underscore attribute names
63
-
64
- == 1.0.7
65
-
66
- * Remove support for original column names. All columns names are now downcased/underscored.
67
-
68
- == 1.0.6
69
-
70
- * DBF::Table now includes the Enumerable module
71
- * Return nil for memo values if the memo file is missing
72
- * Finder conditions now support the original and downcased/underscored column names
73
-
74
- == 1.0.5
75
-
76
- * Strip non-ascii characters from column names
77
-
78
- == 1.0.4
79
-
80
- * Underscore column names when dumping schemas (FieldId becomes field_id)
81
-
82
- == 1.0.3
83
-
84
- * Add support for Visual Foxpro Integer and Datetime columns
85
-
86
- == 1.0.2
87
-
88
- * Compatibility fix for Visual Foxpro memo files (ignore negative memo index values)
89
-
90
- == 1.0.1
91
-
92
- * Fixes error when using the command-line interface [#11984]
93
-
94
- == 1.0.0
95
-
96
- * Renamed classes and refactored code in preparation for adding the
97
- ability to save records and create/compact databases.
98
- * The Reader class has been renamed to Table
99
- * Attributes are no longer accessed directly from the record. Use record.attribute['column_name']
100
- instead, or use the new attribute accessors detailed under Basic Usage.
101
-
102
- == 0.5.4
103
-
104
- * Ignore deleted records in both memory modes
105
-
106
- == 0.5.3
107
-
108
- * Added a standalone dbf utility (try dbf -h for help)
109
-
110
- == 0.5.0 / 2007-05-25
111
-
112
- * New find method
113
- * Full compatibility with the two flavors of memo file
114
- * Two modes of operation:
115
- * In memory (default): All records are loaded into memory on the first
116
- request. Records are retrieved from memory for all subsequent requests.
117
- * File I/O: All records are retrieved from disk on every request
118
- * Improved documentation and more usage examples
data/VERSION.yml DELETED
@@ -1,5 +0,0 @@
1
- ---
2
- :patch: 9
3
- :build:
4
- :major: 1
5
- :minor: 2
data/dbf.gemspec DELETED
@@ -1,94 +0,0 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
5
-
6
- Gem::Specification.new do |s|
7
- s.name = %q{dbf}
8
- s.version = "1.2.9"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Keith Morrison"]
12
- s.date = %q{2010-07-22}
13
- s.default_executable = %q{dbf}
14
- s.description = %q{A small fast library for reading dBase, xBase, Clipper and FoxPro database files.}
15
- s.email = %q{keithm@infused.org}
16
- s.executables = ["dbf"]
17
- s.extra_rdoc_files = [
18
- "README.markdown"
19
- ]
20
- s.files = [
21
- ".autotest",
22
- ".gitignore",
23
- "History.txt",
24
- "MIT-LICENSE",
25
- "README.markdown",
26
- "Rakefile",
27
- "VERSION.yml",
28
- "bin/dbf",
29
- "dbf.gemspec",
30
- "docs/supported_types.markdown",
31
- "lib/dbf.rb",
32
- "lib/dbf/column.rb",
33
- "lib/dbf/globals.rb",
34
- "lib/dbf/record.rb",
35
- "lib/dbf/table.rb",
36
- "spec/fixtures/dbase_03.dbf",
37
- "spec/fixtures/dbase_30.dbf",
38
- "spec/fixtures/dbase_30.fpt",
39
- "spec/fixtures/dbase_31.dbf",
40
- "spec/fixtures/dbase_83.dbf",
41
- "spec/fixtures/dbase_83.dbt",
42
- "spec/fixtures/dbase_83_schema.txt",
43
- "spec/fixtures/dbase_8b.dbf",
44
- "spec/fixtures/dbase_8b.dbt",
45
- "spec/fixtures/dbase_f5.dbf",
46
- "spec/fixtures/dbase_f5.fpt",
47
- "spec/functional/dbf_shared.rb",
48
- "spec/functional/format_03_spec.rb",
49
- "spec/functional/format_30_spec.rb",
50
- "spec/functional/format_31_spec.rb",
51
- "spec/functional/format_83_spec.rb",
52
- "spec/functional/format_8b_spec.rb",
53
- "spec/functional/format_f5_spec.rb",
54
- "spec/spec_helper.rb",
55
- "spec/unit/column_spec.rb",
56
- "spec/unit/record_spec.rb",
57
- "spec/unit/table_spec.rb"
58
- ]
59
- s.homepage = %q{http://github.com/infused/dbf}
60
- s.rdoc_options = ["--charset=UTF-8"]
61
- s.require_paths = ["lib"]
62
- s.rubygems_version = %q{1.3.7}
63
- s.summary = %q{Read xBase files}
64
- s.test_files = [
65
- "spec/functional/dbf_shared.rb",
66
- "spec/functional/format_03_spec.rb",
67
- "spec/functional/format_30_spec.rb",
68
- "spec/functional/format_31_spec.rb",
69
- "spec/functional/format_83_spec.rb",
70
- "spec/functional/format_8b_spec.rb",
71
- "spec/functional/format_f5_spec.rb",
72
- "spec/spec_helper.rb",
73
- "spec/unit/column_spec.rb",
74
- "spec/unit/record_spec.rb",
75
- "spec/unit/table_spec.rb"
76
- ]
77
-
78
- if s.respond_to? :specification_version then
79
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
80
- s.specification_version = 3
81
-
82
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
83
- s.add_runtime_dependency(%q<activesupport>, [">= 2.3.5"])
84
- s.add_runtime_dependency(%q<fastercsv>, [">= 1.4.0"])
85
- else
86
- s.add_dependency(%q<activesupport>, [">= 2.3.5"])
87
- s.add_dependency(%q<fastercsv>, [">= 1.4.0"])
88
- end
89
- else
90
- s.add_dependency(%q<activesupport>, [">= 2.3.5"])
91
- s.add_dependency(%q<fastercsv>, [">= 1.4.0"])
92
- end
93
- end
94
-
data/lib/dbf/globals.rb DELETED
@@ -1,22 +0,0 @@
1
- module DBF
2
- DBF_HEADER_SIZE = 32
3
- FPT_HEADER_SIZE = 512
4
- BLOCK_HEADER_SIZE = 8
5
- VERSION_DESCRIPTIONS = {
6
- "02" => "FoxBase",
7
- "03" => "dBase III without memo file",
8
- "04" => "dBase IV without memo file",
9
- "05" => "dBase V without memo file",
10
- "30" => "Visual FoxPro",
11
- "31" => "Visual FoxPro with AutoIncrement field",
12
- "7b" => "dBase IV with memo file",
13
- "83" => "dBase III with memo file",
14
- "8b" => "dBase IV with memo file",
15
- "8e" => "dBase IV with SQL table",
16
- "f5" => "FoxPro with memo file",
17
- "fb" => "FoxPro without memo file"
18
- }
19
-
20
- class DBFError < StandardError
21
- end
22
- end