dbf 1.2.2 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,13 @@
1
+ == 1.2.4
2
+
3
+ * Add csv output option to dbf command-line utility
4
+ * Read Visual FoxPro memos
5
+
6
+ == 1.2.3
7
+
8
+ * Small performance gain when unpacking values from the dbf file
9
+ * Correctly handle FoxPro's integer data type
10
+
1
11
  == 1.2.2
2
12
 
3
13
  * Handle invalid date fields
data/VERSION.yml CHANGED
@@ -2,4 +2,4 @@
2
2
  :major: 1
3
3
  :minor: 2
4
4
  :build:
5
- :patch: 2
5
+ :patch: 4
data/bin/dbf CHANGED
@@ -5,12 +5,14 @@ require 'dbf'
5
5
 
6
6
  $a ||= false
7
7
  $s ||= false
8
+ $c ||= false
8
9
 
9
10
  if defined? $h then
10
- puts "usage: #{File.basename(__FILE__)} [-h|-s|-a] filename"
11
+ puts "usage: #{File.basename(__FILE__)} [-h|-s|-a|-c] filename"
11
12
  puts " -h = print this message"
12
13
  puts " -s = print summary information"
13
14
  puts " -a = create an ActiveRecord::Schema"
15
+ puts " -c = create a csv file"
14
16
  else
15
17
 
16
18
  filename = ARGV.shift
@@ -37,4 +39,10 @@ else
37
39
  puts "%-16s %-10s %-10s %-10s" % [f.name, f.type, f.length, f.decimal]
38
40
  end
39
41
  end
40
- end
42
+
43
+ if $c
44
+ table = DBF::Table.new filename
45
+ table.to_csv
46
+ end
47
+
48
+ end
data/dbf.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{dbf}
8
- s.version = "1.2.2"
8
+ s.version = "1.2.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Keith Morrison"]
12
- s.date = %q{2010-04-01}
12
+ s.date = %q{2010-04-06}
13
13
  s.default_executable = %q{dbf}
14
14
  s.description = %q{A small fast library for reading dBase, xBase, Clipper and FoxPro database files.}
15
15
  s.email = %q{keithm@infused.org}
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
34
34
  "spec/fixtures/dbase_03.dbf",
35
35
  "spec/fixtures/dbase_30.dbf",
36
36
  "spec/fixtures/dbase_30.fpt",
37
+ "spec/fixtures/dbase_31.dbf",
37
38
  "spec/fixtures/dbase_83.dbf",
38
39
  "spec/fixtures/dbase_83.dbt",
39
40
  "spec/fixtures/dbase_83_schema.txt",
@@ -44,6 +45,7 @@ Gem::Specification.new do |s|
44
45
  "spec/functional/dbf_shared.rb",
45
46
  "spec/functional/format_03_spec.rb",
46
47
  "spec/functional/format_30_spec.rb",
48
+ "spec/functional/format_31_spec.rb",
47
49
  "spec/functional/format_83_spec.rb",
48
50
  "spec/functional/format_8b_spec.rb",
49
51
  "spec/functional/format_f5_spec.rb",
@@ -61,6 +63,7 @@ Gem::Specification.new do |s|
61
63
  "spec/functional/dbf_shared.rb",
62
64
  "spec/functional/format_03_spec.rb",
63
65
  "spec/functional/format_30_spec.rb",
66
+ "spec/functional/format_31_spec.rb",
64
67
  "spec/functional/format_83_spec.rb",
65
68
  "spec/functional/format_8b_spec.rb",
66
69
  "spec/functional/format_f5_spec.rb",
data/lib/dbf/column.rb CHANGED
@@ -29,7 +29,7 @@ module DBF
29
29
  when 'N' # number
30
30
  unpack_number(value)
31
31
  when 'I' # integer
32
- unpack_integer(value)
32
+ unpack_unsigned_long(value)
33
33
  when 'F' # float
34
34
  unpack_float(value)
35
35
  when 'D' # date
@@ -87,6 +87,14 @@ module DBF
87
87
  value.to_i
88
88
  end
89
89
 
90
+ # Decode an unsigned long
91
+ #
92
+ # @param [String] value
93
+ # @return [Fixnum]
94
+ def unpack_unsigned_long(value)
95
+ value.unpack('V')[0]
96
+ end
97
+
90
98
  # Decode a boolean value
91
99
  #
92
100
  # @param [String] value
data/lib/dbf/record.rb CHANGED
@@ -50,18 +50,30 @@ module DBF
50
50
  def initialize_values
51
51
  @attributes = columns.inject({}) do |hash, column|
52
52
  if column.type == 'M'
53
- starting_block = unpack_data(column.length).to_i
54
- hash[column.name] = read_memo(starting_block)
55
- hash[column.name.underscore] = read_memo(starting_block)
53
+ memo = read_memo(get_starting_block(column))
54
+ hash[column.name] = memo
55
+ hash[column.name.underscore] = memo
56
56
  else
57
57
  value = unpack_data(column.length)
58
- hash[column.name] = column.type_cast(value)
59
- hash[column.name.underscore] = column.type_cast(value)
58
+ type_cast_value = column.type_cast(value)
59
+ hash[column.name] = type_cast_value
60
+ hash[column.name.underscore] = type_cast_value
60
61
  end
61
62
  hash
62
63
  end
63
64
  end
64
-
65
+
66
+ # Unpack starting block from database
67
+ #
68
+ # @param [Fixnum] length
69
+ def get_starting_block(column)
70
+ if %w(30 31).include?(@table.version)
71
+ @data.read(column.length).unpack('V')[0]
72
+ else
73
+ unpack_data(column.length).to_i
74
+ end
75
+ end
76
+
65
77
  # Unpack raw data from database
66
78
  #
67
79
  # @param [Fixnum] length
@@ -93,7 +105,7 @@ module DBF
93
105
  else
94
106
  memo_string = memo_string[0, memo_size]
95
107
  end
96
- memo_string
108
+ memo_string.strip
97
109
  end
98
110
 
99
111
  # Reconstucts a memo from an DBT memo file
data/lib/dbf/table.rb CHANGED
@@ -135,6 +135,7 @@ module DBF
135
135
  def to_csv(path = nil)
136
136
  path = File.basename(@data.path, '.dbf') + '.csv' if path.nil?
137
137
  FCSV.open(path, 'w', :force_quotes => true) do |csv|
138
+ csv << columns.map {|c| c.name}
138
139
  each do |record|
139
140
  csv << record.to_a
140
141
  end
@@ -188,7 +189,7 @@ module DBF
188
189
  def find_all(options, &block)
189
190
  results = []
190
191
  each do |record|
191
- if all_values_match?(record, options)
192
+ if record && all_values_match?(record, options)
192
193
  if block_given?
193
194
  yield(record)
194
195
  else
@@ -205,7 +206,7 @@ module DBF
205
206
  # @return [DBF::Record, nil]
206
207
  def find_first(options)
207
208
  each do |record|
208
- return record if all_values_match?(record, options)
209
+ return record if record && all_values_match?(record, options)
209
210
  end
210
211
  nil
211
212
  end
Binary file
@@ -21,7 +21,7 @@ describe DBF, :shared => true do
21
21
  end
22
22
 
23
23
  specify "column types should be valid" do
24
- valid_column_types = %w(C N L D M F B G P Y T I V X @ O +)
24
+ valid_column_types = %w(C N L D M F B G P Y T I V X @ O + 0)
25
25
  @table.columns.all? {|column| valid_column_types.should include(column.type)}
26
26
  end
27
27
 
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + "/../spec_helper"
2
2
  require File.dirname(__FILE__) + "/dbf_shared"
3
3
 
4
4
  describe DBF, "of type 03 (dBase III without memo file)" do
5
- before(:each) do
5
+ before do
6
6
  @table = DBF::Table.new "#{DB_PATH}/dbase_03.dbf"
7
7
  end
8
8
 
@@ -16,7 +16,7 @@ describe DBF, "of type 03 (dBase III without memo file)" do
16
16
  @table.should_not have_memo_file
17
17
  end
18
18
 
19
- it "should report the correct memo type" do
19
+ it "should have a nil memo_file_format" do
20
20
  @table.memo_file_format.should be_nil
21
21
  end
22
22
 
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + "/../spec_helper"
2
2
  require File.dirname(__FILE__) + "/dbf_shared"
3
3
 
4
4
  describe DBF, "of type 30 (Visual FoxPro)" do
5
- before(:each) do
5
+ before do
6
6
  @table = DBF::Table.new "#{DB_PATH}/dbase_30.dbf"
7
7
  end
8
8
 
@@ -0,0 +1,23 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require File.dirname(__FILE__) + "/dbf_shared"
3
+
4
+ describe DBF, "of type 31 (Visual FoxPro with AutoIncrement field)" do
5
+ before do
6
+ @table = DBF::Table.new "#{DB_PATH}/dbase_31.dbf"
7
+ end
8
+
9
+ it_should_behave_like "DBF"
10
+
11
+ it "should have a dBase version of 31" do
12
+ @table.version.should == "31"
13
+ end
14
+
15
+ it "should have a memo file" do
16
+ @table.should_not have_memo_file
17
+ end
18
+
19
+ it "should have a nil memo_file_format" do
20
+ @table.memo_file_format.should be_nil
21
+ end
22
+
23
+ end
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + "/../spec_helper"
2
2
  require File.dirname(__FILE__) + "/dbf_shared"
3
3
 
4
4
  describe DBF, "of type 83 (dBase III with memo file)" do
5
- before(:each) do
5
+ before do
6
6
  @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
7
7
  end
8
8
 
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + "/../spec_helper"
2
2
  require File.dirname(__FILE__) + "/dbf_shared"
3
3
 
4
4
  describe DBF, "of type 8b (dBase IV with memo file)" do
5
- before(:each) do
5
+ before do
6
6
  @table = DBF::Table.new "#{DB_PATH}/dbase_8b.dbf"
7
7
  end
8
8
 
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + "/../spec_helper"
2
2
  require File.dirname(__FILE__) + "/dbf_shared"
3
3
 
4
4
  describe DBF, "of type f5 (FoxPro with memo file)" do
5
- before(:each) do
5
+ before do
6
6
  @table = DBF::Table.new "#{DB_PATH}/dbase_f5.dbf"
7
7
  end
8
8
 
@@ -10,15 +10,15 @@ describe DBF::Column do
10
10
  it "should set the #name accessor" do
11
11
  @column.name.should == "ColumnName"
12
12
  end
13
-
13
+
14
14
  it "should set the #type accessor" do
15
15
  @column.type.should == "N"
16
16
  end
17
-
17
+
18
18
  it "should set the #length accessor" do
19
19
  @column.length.should == 1
20
20
  end
21
-
21
+
22
22
  it "should set the #decimal accessor" do
23
23
  @column.decimal.should == 0
24
24
  end
@@ -39,9 +39,10 @@ describe DBF::Column do
39
39
  context "#type_cast" do
40
40
  context 'with type N (number)' do
41
41
  context 'with 0 decimals' do
42
- it "should cast value to Integer" do
42
+ it 'should cast value to Fixnum' do
43
43
  value = "135"
44
44
  column = DBF::Column.new "ColumnName", "N", 3, 0
45
+ column.type_cast(value).should be_a Fixnum
45
46
  column.type_cast(value).should == 135
46
47
  end
47
48
  end
@@ -50,6 +51,7 @@ describe DBF::Column do
50
51
  it "should cast value to Float" do
51
52
  value = "13.5"
52
53
  column = DBF::Column.new "ColumnName", "N", 2, 1
54
+ column.type_cast(value).should be_a Float
53
55
  column.type_cast(value).should == 13.5
54
56
  end
55
57
  end
@@ -59,15 +61,17 @@ describe DBF::Column do
59
61
  it "should cast value to Float" do
60
62
  value = "135"
61
63
  column = DBF::Column.new "ColumnName", "F", 3, 0
64
+ column.type_cast(value).should be_a Float
62
65
  column.type_cast(value).should == 135.0
63
66
  end
64
67
  end
65
68
 
66
69
  context 'with type I (integer)' do
67
- it "should cast value to Integer" do
68
- value = "135"
70
+ it "should cast value to Fixnum" do
71
+ value = "\203\171\001\000"
69
72
  column = DBF::Column.new "ColumnName", "I", 3, 0
70
- column.type_cast(value).should == 135
73
+ column.type_cast(value).should be_a Fixnum
74
+ column.type_cast(value).should == 96643
71
75
  end
72
76
  end
73
77
 
@@ -75,12 +79,14 @@ describe DBF::Column do
75
79
  it "should cast 'y' to true" do
76
80
  value = "y"
77
81
  column = DBF::Column.new "ColumnName", "L", 1, 0
82
+ column.type_cast(value).should be_a TrueClass
78
83
  column.type_cast(value).should == true
79
84
  end
80
85
 
81
86
  it "should cast 'n' to false" do
82
87
  value = "n"
83
88
  column = DBF::Column.new "ColumnName", "L", 1, 0
89
+ column.type_cast(value).should be_a FalseClass
84
90
  column.type_cast(value).should == false
85
91
  end
86
92
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 2
8
- - 2
9
- version: 1.2.2
8
+ - 4
9
+ version: 1.2.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - Keith Morrison
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-01 00:00:00 -07:00
17
+ date: 2010-04-06 00:00:00 -07:00
18
18
  default_executable: dbf
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -70,6 +70,7 @@ files:
70
70
  - spec/fixtures/dbase_03.dbf
71
71
  - spec/fixtures/dbase_30.dbf
72
72
  - spec/fixtures/dbase_30.fpt
73
+ - spec/fixtures/dbase_31.dbf
73
74
  - spec/fixtures/dbase_83.dbf
74
75
  - spec/fixtures/dbase_83.dbt
75
76
  - spec/fixtures/dbase_83_schema.txt
@@ -80,6 +81,7 @@ files:
80
81
  - spec/functional/dbf_shared.rb
81
82
  - spec/functional/format_03_spec.rb
82
83
  - spec/functional/format_30_spec.rb
84
+ - spec/functional/format_31_spec.rb
83
85
  - spec/functional/format_83_spec.rb
84
86
  - spec/functional/format_8b_spec.rb
85
87
  - spec/functional/format_f5_spec.rb
@@ -121,6 +123,7 @@ test_files:
121
123
  - spec/functional/dbf_shared.rb
122
124
  - spec/functional/format_03_spec.rb
123
125
  - spec/functional/format_30_spec.rb
126
+ - spec/functional/format_31_spec.rb
124
127
  - spec/functional/format_83_spec.rb
125
128
  - spec/functional/format_8b_spec.rb
126
129
  - spec/functional/format_f5_spec.rb