dbf 1.3.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
1
  module DBF
2
- VERSION = '1.3.0'
2
+ VERSION = '1.5.0'
3
3
  end
@@ -1,37 +1,35 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "../spec_helper"))
1
+ require "spec_helper"
2
2
 
3
3
  describe DBF::Column do
4
4
 
5
5
  context "when initialized" do
6
- before do
7
- @column = DBF::Column.new "ColumnName", "N", 1, 0
8
- end
6
+ let(:column) { DBF::Column.new "ColumnName", "N", 1, 0 }
9
7
 
10
8
  it "sets the #name accessor" do
11
- @column.name.should == "ColumnName"
9
+ column.name.should == "ColumnName"
12
10
  end
13
11
 
14
12
  it "sets the #type accessor" do
15
- @column.type.should == "N"
13
+ column.type.should == "N"
16
14
  end
17
15
 
18
16
  it "sets the #length accessor" do
19
- @column.length.should == 1
17
+ column.length.should == 1
20
18
  end
21
19
 
22
20
  it "sets the #decimal accessor" do
23
- @column.decimal.should == 0
21
+ column.decimal.should == 0
24
22
  end
25
23
 
26
- context 'with length of 0' do
24
+ describe 'with length of 0' do
27
25
  specify { lambda { DBF::Column.new "ColumnName", "N", 0, 0 }.should raise_error(DBF::ColumnLengthError) }
28
26
  end
29
27
 
30
- context 'with length less than 0' do
28
+ describe 'with length less than 0' do
31
29
  specify { lambda { DBF::Column.new "ColumnName", "N", -1, 0 }.should raise_error(DBF::ColumnLengthError) }
32
30
  end
33
31
 
34
- context 'with empty column name' do
32
+ describe 'with empty column name' do
35
33
  specify { lambda { DBF::Column.new "\xFF\xFC", "N", 1, 0 }.should raise_error(DBF::ColumnNameError) }
36
34
  end
37
35
  end
@@ -75,60 +73,57 @@ describe DBF::Column do
75
73
  end
76
74
 
77
75
  context 'with type L (logical/boolean)' do
76
+ let(:column) { DBF::Column.new "ColumnName", "L", 1, 0 }
77
+
78
78
  it "casts 'y' to true" do
79
- value = "y"
80
- column = DBF::Column.new "ColumnName", "L", 1, 0
81
- column.type_cast(value).should == true
79
+ column.type_cast('y').should == true
82
80
  end
83
81
 
84
- it "casts 'n' to false" do
85
- value = "n"
86
- column = DBF::Column.new "ColumnName", "L", 1, 0
87
- column.type_cast(value).should == false
82
+ it "casts 't' to true" do
83
+ column.type_cast('t').should == true
84
+ end
85
+
86
+ it "casts value other than 't' or 'y' to false" do
87
+ column.type_cast('n').should == false
88
88
  end
89
89
  end
90
90
 
91
91
  context 'with type T (datetime)' do
92
+ let(:column) { DBF::Column.new "ColumnName", "T", 16, 0 }
93
+
92
94
  context 'with valid datetime' do
93
95
  it "casts to DateTime" do
94
- value = "Nl%\000\300Z\252\003"
95
- column = DBF::Column.new "ColumnName", "T", 16, 0
96
- column.type_cast(value).should == "2002-10-10T17:04:56+00:00"
96
+ column.type_cast("Nl%\000\300Z\252\003").should == "2002-10-10T17:04:56+00:00"
97
97
  end
98
98
  end
99
99
 
100
100
  context 'with invalid datetime' do
101
101
  it "casts to nil" do
102
- value = "Nl%\000\000A\000\999"
103
- column = DBF::Column.new "ColumnName", "T", 16, 0
104
- column.type_cast(value).should be_nil
102
+ column.type_cast("Nl%\000\000A\000\999").should be_nil
105
103
  end
106
104
  end
107
105
  end
108
106
 
109
107
  context 'with type D (date)' do
108
+ let(:column) { DBF::Column.new "ColumnName", "D", 8, 0 }
109
+
110
110
  context 'with valid date' do
111
111
  it "casts to Date" do
112
- value = "20050712"
113
- column = DBF::Column.new "ColumnName", "D", 8, 0
114
- column.type_cast(value).should == Date.new(2005,7,12)
112
+ column.type_cast("20050712").should == Date.new(2005,7,12)
115
113
  end
116
114
  end
117
115
 
118
116
  context 'with invalid date' do
119
117
  it "casts to nil" do
120
- value = "0"
121
- column = DBF::Column.new "ColumnName", "D", 8, 0
122
- column.type_cast(value).should be_nil
118
+ column.type_cast("0").should be_nil
123
119
  end
124
120
  end
125
121
  end
126
122
 
127
123
  context 'with type M (memo)' do
128
124
  it "casts to string" do
129
- value = 'abc'
130
125
  column = DBF::Column.new "ColumnName", "M", 3, 0
131
- column.type_cast(value).should be_a String
126
+ column.type_cast('abc').should be_a String
132
127
  end
133
128
  end
134
129
  end
@@ -172,31 +167,27 @@ describe DBF::Column do
172
167
  end
173
168
  end
174
169
 
175
- context "#strip_non_ascii_chars" do
176
- before do
177
- @column = DBF::Column.new "ColumnName", "N", 1, 0
178
- end
179
-
180
- it "strips characters below decimal 32 and above decimal 127" do
181
- @column.strip_non_ascii_chars("--\x1F-\x68\x65\x6C\x6C\x6F world-\x80--").should == "---hello world---"
170
+ context "#name" do
171
+ it "contains only ASCII characters" do
172
+ column = DBF::Column.new "--\x1F-\x68\x65\x6C\x6C\x6F world-\x80--", "N", 1, 0
173
+ column.name.should == "---hello world---"
182
174
  end
183
175
 
184
- it "truncates characters with decimal 0" do
185
- @column.strip_non_ascii_chars("--\x1F-\x68\x65\x6C\x6C\x6F \x00 world-\x80--").should == "---hello "
176
+ it "is truncated at the null character" do
177
+ column = DBF::Column.new "--\x1F-\x68\x65\x6C\x6C\x6F \x00 world-\x80--", "N", 1, 0
178
+ column.name.should == "---hello "
186
179
  end
187
180
  end
188
181
 
189
182
  context '#decode_date' do
190
- before do
191
- @column = DBF::Column.new "ColumnName", "N", 1, 0
192
- end
183
+ let(:column) { DBF::Column.new "ColumnName", "N", 1, 0 }
193
184
 
194
185
  it 'is nil if value is blank' do
195
- @column.decode_date('').should be_nil
186
+ column.send(:decode_date, '').should be_nil
196
187
  end
197
188
 
198
189
  it 'interperets spaces as zeros' do
199
- @column.decode_date('2010 715').should == Date.parse('20100715')
190
+ column.send(:decode_date, '2010 715').should == Date.parse('20100715')
200
191
  end
201
192
  end
202
193
 
@@ -0,0 +1,178 @@
1
+ require "spec_helper"
2
+
3
+ shared_examples_for 'DBF' do
4
+ specify "sum of column lengths should equal record length specified in header plus one" do
5
+ header_record_length = @table.instance_eval {@record_length}
6
+ sum_of_column_lengths = 1 + @table.columns.sum {|column| column.length}
7
+
8
+ header_record_length.should == sum_of_column_lengths
9
+ end
10
+
11
+ specify "records should be instances of DBF::Record" do
12
+ @table.all? {|record| record.should be_an_instance_of(DBF::Record)}
13
+ end
14
+
15
+ specify "record count should be the same as reported in the header" do
16
+ @table.count.should == @table.record_count
17
+ end
18
+
19
+ specify "columns should be instances of DBF::Column" do
20
+ @table.columns.all? {|column| column.should be_an_instance_of(DBF::Column)}
21
+ end
22
+
23
+ specify "column names should not be blank" do
24
+ @table.columns.all? {|column| column.name.should_not be_empty}
25
+ end
26
+
27
+ specify "column types should be valid" do
28
+ valid_column_types = %w(C N L D M F B G P Y T I V X @ O + 0)
29
+ @table.columns.all? {|column| valid_column_types.should include(column.type)}
30
+ end
31
+
32
+ specify "column lengths should be instances of Fixnum" do
33
+ @table.columns.all? {|column| column.length.should be_an_instance_of(Fixnum)}
34
+ end
35
+
36
+ specify "column lengths should be larger than 0" do
37
+ @table.columns.all? {|column| column.length.should > 0}
38
+ end
39
+
40
+ specify "column decimals should be instances of Fixnum" do
41
+ @table.columns.all? {|column| column.decimal.should be_an_instance_of(Fixnum)}
42
+ end
43
+
44
+ specify "column read accessors should return the attribute after typecast" do
45
+ @table.columns do |column|
46
+ record = @table.records.first
47
+ record.send(column.name).should == record[column.name]
48
+ end
49
+ end
50
+
51
+ specify "column attributes should be accessible in underscored form" do
52
+ @table.columns do |column|
53
+ record = @table.records.first
54
+ record.send(column_name).should == record.send(column_name.underscore)
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ describe DBF, "of type 03 (dBase III without memo file)" do
61
+ before do
62
+ @table = DBF::Table.new "#{DB_PATH}/dbase_03.dbf"
63
+ end
64
+
65
+ it_should_behave_like "DBF"
66
+
67
+ it "should report the correct version number" do
68
+ @table.version.should == "03"
69
+ end
70
+
71
+ it "should report the correct version description" do
72
+ @table.version_description.should == "dBase III without memo file"
73
+ end
74
+
75
+ it "should determine the number of records" do
76
+ @table.record_count.should == 14
77
+ end
78
+ end
79
+
80
+ describe DBF, "of type 30 (Visual FoxPro)" do
81
+ before do
82
+ @table = DBF::Table.new "#{DB_PATH}/dbase_30.dbf"
83
+ end
84
+
85
+ it_should_behave_like "DBF"
86
+
87
+ it "should report the correct version number" do
88
+ @table.version.should == "30"
89
+ end
90
+
91
+ it "should report the correct version description" do
92
+ @table.version_description.should == "Visual FoxPro"
93
+ end
94
+
95
+ it "should determine the number of records" do
96
+ @table.record_count.should == 34
97
+ end
98
+ end
99
+
100
+ describe DBF, "of type 31 (Visual FoxPro with AutoIncrement field)" do
101
+ before do
102
+ @table = DBF::Table.new "#{DB_PATH}/dbase_31.dbf"
103
+ end
104
+
105
+ it_should_behave_like "DBF"
106
+
107
+ it "should have a dBase version of 31" do
108
+ @table.version.should == "31"
109
+ end
110
+
111
+ it "should report the correct version description" do
112
+ @table.version_description.should == "Visual FoxPro with AutoIncrement field"
113
+ end
114
+
115
+ it "should determine the number of records" do
116
+ @table.record_count.should == 77
117
+ end
118
+ end
119
+
120
+ describe DBF, "of type 83 (dBase III with memo file)" do
121
+ before do
122
+ @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
123
+ end
124
+
125
+ it_should_behave_like "DBF"
126
+
127
+ it "should report the correct version number" do
128
+ @table.version.should == "83"
129
+ end
130
+
131
+ it "should report the correct version description" do
132
+ @table.version_description.should == "dBase III with memo file"
133
+ end
134
+
135
+ it "should determine the number of records" do
136
+ @table.record_count.should == 67
137
+ end
138
+ end
139
+
140
+ describe DBF, "of type 8b (dBase IV with memo file)" do
141
+ before do
142
+ @table = DBF::Table.new "#{DB_PATH}/dbase_8b.dbf"
143
+ end
144
+
145
+ it_should_behave_like "DBF"
146
+
147
+ it "should report the correct version number" do
148
+ @table.version.should == "8b"
149
+ end
150
+
151
+ it "should report the correct version description" do
152
+ @table.version_description.should == "dBase IV with memo file"
153
+ end
154
+
155
+ it "should determine the number of records" do
156
+ @table.record_count.should == 10
157
+ end
158
+ end
159
+
160
+ describe DBF, "of type f5 (FoxPro with memo file)" do
161
+ before do
162
+ @table = DBF::Table.new "#{DB_PATH}/dbase_f5.dbf"
163
+ end
164
+
165
+ it_should_behave_like "DBF"
166
+
167
+ it "should report the correct version number" do
168
+ @table.version.should == "f5"
169
+ end
170
+
171
+ it "should report the correct version description" do
172
+ @table.version_description.should == "FoxPro with memo file"
173
+ end
174
+
175
+ it "should determine the number of records" do
176
+ @table.record_count.should == 975
177
+ end
178
+ end
@@ -0,0 +1,45 @@
1
+ require "spec_helper"
2
+
3
+ describe DBF::Record do
4
+
5
+ describe '#to_a' do
6
+ it 'should return an ordered array of attribute values' do
7
+ table = DBF::Table.new "#{DB_PATH}/dbase_8b.dbf"
8
+
9
+ record = table.record(0)
10
+ record.to_a.should == ["One", 1.0, Date.new(1970, 1, 1), true, 1.23456789012346, "First memo\r\n\037 \037 \037 \037 "]
11
+
12
+ record = table.record(9)
13
+ record.to_a.should == ["Ten records stored in this database", 10.0, nil, false, 0.1, nil]
14
+ end
15
+ end
16
+
17
+ describe '#==' do
18
+ before do
19
+ table = DBF::Table.new "#{DB_PATH}/dbase_8b.dbf"
20
+ @record = table.record(9)
21
+ end
22
+
23
+ it 'should be false if other does not have attributes' do
24
+ (@record == mock('other')).should be_false
25
+ end
26
+
27
+ it 'should be true if other attributes match' do
28
+ attributes = {:x => 1, :y => 2}
29
+ @record.stub!(:attributes).and_return(attributes)
30
+ other = mock('object', :attributes => attributes)
31
+ (@record == other).should be_true
32
+ end
33
+ end
34
+
35
+ describe 'column accessors' do
36
+ let(:table) { DBF::Table.new "#{DB_PATH}/dbase_8b.dbf"}
37
+
38
+ it 'should define accessor methods for each column' do
39
+ record = table.find(0)
40
+ record.should respond_to(:character)
41
+ record.character.should == 'One'
42
+ end
43
+ end
44
+
45
+ end
@@ -1,67 +1,18 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "../spec_helper"))
1
+ require "spec_helper"
2
2
 
3
- describe DBF::Table do
4
- context "when initialized" do
5
- before 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 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 determine the number of columns in each record" do
27
- @table.columns.size.should == 15
28
- end
29
-
30
- it "should determine the number of records in the database" do
31
- @table.record_count.should == 67
32
- end
33
-
34
- it "should determine the database version" do
35
- @table.version.should == "83"
36
- end
37
- end
38
-
3
+ describe DBF::Table do
39
4
  context "when closed" do
40
5
  before do
41
6
  @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
7
+ @table.close
42
8
  end
43
9
 
44
10
  it "should close the data file" do
45
- @table.close
46
- lambda { @table.record(1) }.should raise_error(IOError)
47
- end
48
- end
49
-
50
- describe "#column" do
51
- it "should accept a string or symbol as input" do
52
- table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
53
- table.column(:IMAGE).should be_kind_of(DBF::Column)
54
- table.column("IMAGE").should be_kind_of(DBF::Column)
11
+ @table.instance_eval { @data }.should be_closed
55
12
  end
56
13
 
57
- it "should return a DBF::Field object when the column_name exists" do
58
- table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
59
- table.column(:IMAGE).should be_kind_of(DBF::Column)
60
- end
61
-
62
- it "should return nil when the column_name does not exist" do
63
- table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
64
- table.column(:NOTANIMAGE).should be_nil
14
+ it "should close the memo file" do
15
+ @table.instance_eval { @memo }.instance_eval { @data }.should be_closed
65
16
  end
66
17
  end
67
18
 
@@ -74,33 +25,6 @@ describe DBF::Table do
74
25
  end
75
26
  end
76
27
 
77
- describe "#version_description" do
78
- it "should return a text description of the database type" do
79
- table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
80
- table.version_description.should == "dBase III with memo file"
81
- end
82
- end
83
-
84
- describe '#replace_extname' do
85
- it "should change the file extension" do
86
- table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
87
- table.send(:replace_extname, 'dbase_83.dbf', 'fpt').should == 'dbase_83.fpt'
88
- end
89
- end
90
-
91
- describe '#to_a' do
92
- before do
93
- @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
94
-
95
- @records = []
96
- @table.each {|record| @records << record}
97
- end
98
-
99
- it 'should return an array of records' do
100
- @table.to_a.should == @records
101
- end
102
- end
103
-
104
28
  describe '#to_csv' do
105
29
  before do
106
30
  @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
@@ -115,22 +39,21 @@ describe DBF::Table do
115
39
  @table.to_csv
116
40
  File.exists?('dbase_83.csv').should be_true
117
41
  end
118
-
119
- it 'should create custom csv file' do
120
- @table.to_csv('test.csv')
121
- File.exists?('test.csv').should be_true
42
+
43
+ describe 'when path param passed' do
44
+ it 'should create custom csv file' do
45
+ @table.to_csv('test.csv')
46
+ File.exists?('test.csv').should be_true
47
+ end
122
48
  end
123
49
  end
124
50
 
125
51
  describe "#record" do
126
52
  before do
127
53
  @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
128
-
129
- @records = []
130
- @table.each {|record| @records << record}
131
54
  end
132
55
 
133
- it "should nullify deleted records" do
56
+ it "return nil for deleted records" do
134
57
  @table.stub!(:deleted_record?).and_return(true)
135
58
  @table.record(5).should be_nil
136
59
  end
@@ -145,10 +68,6 @@ describe DBF::Table do
145
68
  @table.stub!(:deleted_record?).and_return(true)
146
69
  @table.record(0).should be_nil
147
70
  end
148
-
149
- it 'should return a DBF::Record' do
150
- @table.record(0).should be_kind_of(DBF::Record)
151
- end
152
71
  end
153
72
 
154
73
  describe "#find" do
@@ -175,9 +94,6 @@ describe DBF::Table do
175
94
  describe "with :all" do
176
95
  before do
177
96
  @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
178
-
179
- @records = []
180
- @table.each {|record| @records << record}
181
97
  end
182
98
 
183
99
  it "should accept a block" do
@@ -189,11 +105,11 @@ describe DBF::Table do
189
105
  end
190
106
 
191
107
  it "should return all records if options are empty" do
192
- @table.find(:all).should == @records
108
+ @table.find(:all).should == @table.to_a
193
109
  end
194
110
 
195
111
  it "should return matching records when used with options" do
196
- @table.find(:all, "WEIGHT" => 0.0).should == @records.select {|r| r.attributes["weight"] == 0.0}
112
+ @table.find(:all, "WEIGHT" => 0.0).should == @table.select {|r| r.attributes["weight"] == 0.0}
197
113
  end
198
114
 
199
115
  it "should AND multiple search terms" do
@@ -220,17 +136,14 @@ describe DBF::Table do
220
136
  describe "with :first" do
221
137
  before do
222
138
  @table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
223
-
224
- @records = []
225
- @table.each {|record| @records << record}
226
139
  end
227
140
 
228
141
  it "should return the first record if options are empty" do
229
- @table.find(:first).should == @records.first
142
+ @table.find(:first).should == @table.first
230
143
  end
231
144
 
232
145
  it "should return the first matching record when used with options" do
233
- @table.find(:first, "CODE" => "C").should == @records[5]
146
+ @table.find(:first, "CODE" => "C").should == @table.record(5)
234
147
  end
235
148
 
236
149
  it "should AND multiple search terms" do