dbf 2.0.7 → 2.0.8
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/CHANGELOG.md +3 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +250 -13
- data/Gemfile.travis +9 -0
- data/Gemfile.travis18 +8 -0
- data/Guardfile +8 -0
- data/{MIT-LICENSE → LICENSE} +1 -1
- data/README.md +74 -49
- data/Rakefile +0 -7
- data/dbf.gemspec +1 -12
- data/lib/dbf.rb +1 -0
- data/lib/dbf/column/base.rb +48 -25
- data/lib/dbf/column/foxpro.rb +4 -4
- data/lib/dbf/header.rb +5 -1
- data/lib/dbf/memo/base.rb +2 -2
- data/lib/dbf/record.rb +17 -8
- data/lib/dbf/schema.rb +34 -0
- data/lib/dbf/table.rb +55 -55
- data/lib/dbf/version.rb +2 -2
- data/spec/dbf/column_spec.rb +39 -29
- data/spec/dbf/file_formats_spec.rb +28 -14
- data/spec/dbf/record_spec.rb +35 -34
- data/spec/dbf/table_spec.rb +46 -47
- data/spec/spec_helper.rb +10 -0
- metadata +17 -37
- checksums.yaml +0 -7
data/lib/dbf/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module DBF
|
2
|
-
VERSION = '2.0.
|
3
|
-
end
|
2
|
+
VERSION = '2.0.8'
|
3
|
+
end
|
data/spec/dbf/column_spec.rb
CHANGED
@@ -3,9 +3,10 @@
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
5
|
describe DBF::Column::Dbase do
|
6
|
+
let(:table) { DBF::Table.new fixture_path('dbase_30.dbf')}
|
6
7
|
|
7
8
|
context "when initialized" do
|
8
|
-
let(:column) { DBF::Column::Dbase.new "ColumnName", "N", 1, 0
|
9
|
+
let(:column) { DBF::Column::Dbase.new table, "ColumnName", "N", 1, 0 }
|
9
10
|
|
10
11
|
it "sets :name accessor" do
|
11
12
|
expect(column.name).to eq "ColumnName"
|
@@ -25,19 +26,19 @@ describe DBF::Column::Dbase do
|
|
25
26
|
|
26
27
|
describe 'with length of 0' do
|
27
28
|
it 'raises DBF::Column::LengthError' do
|
28
|
-
expect { DBF::Column::Dbase.new "ColumnName", "N", 0, 0
|
29
|
+
expect { DBF::Column::Dbase.new table, "ColumnName", "N", 0, 0 }.to raise_error(DBF::Column::LengthError)
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
32
33
|
describe 'with length less than 0' do
|
33
34
|
it 'raises DBF::Column::LengthError' do
|
34
|
-
expect { DBF::Column::Dbase.new "ColumnName", "N", -1, 0
|
35
|
+
expect { DBF::Column::Dbase.new table, "ColumnName", "N", -1, 0 }.to raise_error(DBF::Column::LengthError)
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
39
|
describe 'with empty column name' do
|
39
40
|
it 'raises DBF::Column::NameError' do
|
40
|
-
expect { DBF::Column::Dbase.new "\xFF\xFC", "N", 1, 0
|
41
|
+
expect { DBF::Column::Dbase.new table, "\xFF\xFC", "N", 1, 0 }.to raise_error(DBF::Column::NameError)
|
41
42
|
end
|
42
43
|
end
|
43
44
|
end
|
@@ -47,7 +48,7 @@ describe DBF::Column::Dbase do
|
|
47
48
|
context 'and 0 decimals' do
|
48
49
|
it 'casts value to Fixnum' do
|
49
50
|
value = '135'
|
50
|
-
column = DBF::Column::Dbase.new "ColumnName", "N", 3, 0
|
51
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "N", 3, 0
|
51
52
|
expect(column.type_cast(value)).to be_a(Fixnum)
|
52
53
|
expect(column.type_cast(value)).to eq 135
|
53
54
|
end
|
@@ -56,7 +57,7 @@ describe DBF::Column::Dbase do
|
|
56
57
|
context 'and more than 0 decimals' do
|
57
58
|
it 'casts value to Float' do
|
58
59
|
value = '13.5'
|
59
|
-
column = DBF::Column::Dbase.new "ColumnName", "N", 2, 1
|
60
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "N", 2, 1
|
60
61
|
expect(column.type_cast(value)).to be_a(Float)
|
61
62
|
expect(column.type_cast(value)).to eq 13.5
|
62
63
|
end
|
@@ -66,7 +67,7 @@ describe DBF::Column::Dbase do
|
|
66
67
|
context 'with type F (float)' do
|
67
68
|
it 'casts value to Float' do
|
68
69
|
value = '135'
|
69
|
-
column = DBF::Column::Dbase.new "ColumnName", "F", 3, 0
|
70
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "F", 3, 0
|
70
71
|
expect(column.type_cast(value)).to be_a(Float)
|
71
72
|
expect(column.type_cast(value)).to eq 135.0
|
72
73
|
end
|
@@ -75,32 +76,34 @@ describe DBF::Column::Dbase do
|
|
75
76
|
context 'with type I (integer)' do
|
76
77
|
it "casts value to Fixnum" do
|
77
78
|
value = "\203\171\001\000"
|
78
|
-
column = DBF::Column::Dbase.new "ColumnName", "I", 3, 0
|
79
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "I", 3, 0
|
80
|
+
expect(column.type_cast(value)).to be_a(Fixnum)
|
79
81
|
expect(column.type_cast(value)).to eq 96643
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
83
85
|
context 'with type L (logical/boolean)' do
|
84
|
-
let(:column) { DBF::Column::Dbase.new "ColumnName", "L", 1, 0
|
86
|
+
let(:column) { DBF::Column::Dbase.new table, "ColumnName", "L", 1, 0 }
|
85
87
|
|
86
88
|
it "casts 'y' to true" do
|
87
|
-
expect(column.type_cast('y')).to
|
89
|
+
expect(column.type_cast('y')).to be true
|
88
90
|
end
|
89
91
|
|
90
92
|
it "casts 't' to true" do
|
91
|
-
expect(column.type_cast('t')).to
|
93
|
+
expect(column.type_cast('t')).to be true
|
92
94
|
end
|
93
95
|
|
94
96
|
it "casts value other than 't' or 'y' to false" do
|
95
|
-
expect(column.type_cast('n')).to
|
97
|
+
expect(column.type_cast('n')).to be false
|
96
98
|
end
|
97
99
|
end
|
98
100
|
|
99
101
|
context 'with type T (datetime)' do
|
100
|
-
let(:column) { DBF::Column::Dbase.new "ColumnName", "T", 16, 0
|
102
|
+
let(:column) { DBF::Column::Dbase.new table, "ColumnName", "T", 16, 0 }
|
101
103
|
|
102
104
|
context 'with valid datetime' do
|
103
105
|
it "casts to DateTime" do
|
106
|
+
expect(column.type_cast("Nl%\000\300Z\252\003")).to be_a(DateTime)
|
104
107
|
expect(column.type_cast("Nl%\000\300Z\252\003")).to eq DateTime.parse("2002-10-10T17:04:56+00:00")
|
105
108
|
end
|
106
109
|
end
|
@@ -112,6 +115,7 @@ describe DBF::Column::Dbase do
|
|
112
115
|
require 'mathn'
|
113
116
|
column.type_cast("Nl%\000\300Z\252\003")
|
114
117
|
end
|
118
|
+
expect(with_mathn.call).to be_a(DateTime)
|
115
119
|
expect(with_mathn.call).to eq DateTime.parse("2002-10-10T17:04:56+00:00")
|
116
120
|
end
|
117
121
|
end
|
@@ -119,22 +123,25 @@ describe DBF::Column::Dbase do
|
|
119
123
|
|
120
124
|
context 'with invalid datetime' do
|
121
125
|
it "casts to nil" do
|
126
|
+
expect(column.type_cast("Nl%\000\000A\000\999")).to be_a(NilClass)
|
122
127
|
expect(column.type_cast("Nl%\000\000A\000\999")).to be_nil
|
123
128
|
end
|
124
129
|
end
|
125
130
|
end
|
126
131
|
|
127
132
|
context 'with type D (date)' do
|
128
|
-
let(:column) { DBF::Column::Dbase.new "ColumnName", "D", 8, 0
|
133
|
+
let(:column) { DBF::Column::Dbase.new table, "ColumnName", "D", 8, 0 }
|
129
134
|
|
130
135
|
context 'with valid date' do
|
131
136
|
it "casts to Date" do
|
137
|
+
expect(column.type_cast("20050712")).to be_a(Date)
|
132
138
|
expect(column.type_cast("20050712")).to eq Date.new(2005,7,12)
|
133
139
|
end
|
134
140
|
end
|
135
141
|
|
136
142
|
context 'with invalid date' do
|
137
143
|
it "casts to nil" do
|
144
|
+
expect(column.type_cast("0")).to be_a(NilClass)
|
138
145
|
expect(column.type_cast("0")).to be_nil
|
139
146
|
end
|
140
147
|
end
|
@@ -142,21 +149,24 @@ describe DBF::Column::Dbase do
|
|
142
149
|
|
143
150
|
context 'with type M (memo)' do
|
144
151
|
it "casts to string" do
|
145
|
-
column = DBF::Column::Dbase.new "ColumnName", "M", 3, 0
|
152
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "M", 3, 0
|
146
153
|
expect(column.type_cast('abc')).to be_a(String)
|
154
|
+
expect(column.type_cast('abc')).to eq 'abc'
|
147
155
|
end
|
148
156
|
|
149
157
|
it 'casts nil to nil' do
|
150
|
-
column = DBF::Column::Dbase.new "ColumnName", "M", 3, 0
|
158
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "M", 3, 0
|
159
|
+
expect(column.type_cast(nil)).to be_a(NilClass)
|
151
160
|
expect(column.type_cast(nil)).to be_nil
|
152
161
|
end
|
153
162
|
end
|
154
163
|
end
|
155
164
|
|
156
165
|
context 'with type Y (currency)' do
|
157
|
-
let(:column) { DBF::Column::Dbase.new "ColumnName", "Y", 8, 4
|
166
|
+
let(:column) { DBF::Column::Dbase.new table, "ColumnName", "Y", 8, 4 }
|
158
167
|
|
159
168
|
it 'casts to float' do
|
169
|
+
expect(column.type_cast(" \xBF\x02\x00\x00\x00\x00\x00")).to be_a(Float)
|
160
170
|
expect(column.type_cast(" \xBF\x02\x00\x00\x00\x00\x00")).to eq 18.0
|
161
171
|
end
|
162
172
|
end
|
@@ -164,7 +174,7 @@ describe DBF::Column::Dbase do
|
|
164
174
|
context "#schema_definition" do
|
165
175
|
context 'with type N (number)' do
|
166
176
|
it "outputs an integer column" do
|
167
|
-
column = DBF::Column::Dbase.new "ColumnName", "N", 1, 0
|
177
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "N", 1, 0
|
168
178
|
expect(column.schema_definition).to eq "\"column_name\", :integer\n"
|
169
179
|
end
|
170
180
|
end
|
@@ -173,14 +183,14 @@ describe DBF::Column::Dbase do
|
|
173
183
|
context "with Foxpro dbf" do
|
174
184
|
context "when decimal is greater than 0" do
|
175
185
|
it "outputs an float column" do
|
176
|
-
column = DBF::Column::Dbase.new "ColumnName", "B", 1, 2
|
186
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "B", 1, 2
|
177
187
|
expect(column.schema_definition).to eq "\"column_name\", :float\n"
|
178
188
|
end
|
179
189
|
end
|
180
190
|
|
181
191
|
context "when decimal is 0" do
|
182
192
|
it "outputs an integer column" do
|
183
|
-
column = DBF::Column::Dbase.new "ColumnName", "B", 1, 0
|
193
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "B", 1, 0
|
184
194
|
expect(column.schema_definition).to eq "\"column_name\", :integer\n"
|
185
195
|
end
|
186
196
|
end
|
@@ -188,50 +198,50 @@ describe DBF::Column::Dbase do
|
|
188
198
|
end
|
189
199
|
|
190
200
|
it "defines a float colmn if type is (N)umber with more than 0 decimals" do
|
191
|
-
column = DBF::Column::Dbase.new "ColumnName", "N", 1, 2
|
201
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "N", 1, 2
|
192
202
|
expect(column.schema_definition).to eq "\"column_name\", :float\n"
|
193
203
|
end
|
194
204
|
|
195
205
|
it "defines a date column if type is (D)ate" do
|
196
|
-
column = DBF::Column::Dbase.new "ColumnName", "D", 8, 0
|
206
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "D", 8, 0
|
197
207
|
expect(column.schema_definition).to eq "\"column_name\", :date\n"
|
198
208
|
end
|
199
209
|
|
200
210
|
it "defines a datetime column if type is (D)ate" do
|
201
|
-
column = DBF::Column::Dbase.new "ColumnName", "T", 16, 0
|
211
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "T", 16, 0
|
202
212
|
expect(column.schema_definition).to eq "\"column_name\", :datetime\n"
|
203
213
|
end
|
204
214
|
|
205
215
|
it "defines a boolean column if type is (L)ogical" do
|
206
|
-
column = DBF::Column::Dbase.new "ColumnName", "L", 1, 0
|
216
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "L", 1, 0
|
207
217
|
expect(column.schema_definition).to eq "\"column_name\", :boolean\n"
|
208
218
|
end
|
209
219
|
|
210
220
|
it "defines a text column if type is (M)emo" do
|
211
|
-
column = DBF::Column::Dbase.new "ColumnName", "M", 1, 0
|
221
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "M", 1, 0
|
212
222
|
expect(column.schema_definition).to eq "\"column_name\", :text\n"
|
213
223
|
end
|
214
224
|
|
215
225
|
it "defines a string column with length for any other data types" do
|
216
|
-
column = DBF::Column::Dbase.new "ColumnName", "X", 20, 0
|
226
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "X", 20, 0
|
217
227
|
expect(column.schema_definition).to eq "\"column_name\", :string, :limit => 20\n"
|
218
228
|
end
|
219
229
|
end
|
220
230
|
|
221
231
|
context "#name" do
|
222
232
|
it "contains only ASCII characters" do
|
223
|
-
column = DBF::Column::Dbase.new "--\x1F-\x68\x65\x6C\x6C\x6F world-\x80--", "N", 1, 0
|
233
|
+
column = DBF::Column::Dbase.new table, "--\x1F-\x68\x65\x6C\x6C\x6F world-\x80--", "N", 1, 0
|
224
234
|
expect(column.name).to eq "---hello world---"
|
225
235
|
end
|
226
236
|
|
227
237
|
it "is truncated at the null character" do
|
228
|
-
column = DBF::Column::Dbase.new "--\x1F-\x68\x65\x6C\x6C\x6F \x00 world-\x80--", "N", 1, 0
|
238
|
+
column = DBF::Column::Dbase.new table, "--\x1F-\x68\x65\x6C\x6C\x6F \x00 world-\x80--", "N", 1, 0
|
229
239
|
expect(column.name).to eq "---hello "
|
230
240
|
end
|
231
241
|
end
|
232
242
|
|
233
243
|
context '#decode_date' do
|
234
|
-
let(:column) { DBF::Column::Dbase.new "ColumnName", "N", 1, 0
|
244
|
+
let(:column) { DBF::Column::Dbase.new table, "ColumnName", "N", 1, 0 }
|
235
245
|
|
236
246
|
it 'is nil if value is blank' do
|
237
247
|
expect(column.send(:decode_date, '')).to be_nil
|
@@ -9,7 +9,9 @@ shared_examples_for 'DBF' do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
specify "records should be instances of DBF::Record" do
|
12
|
-
|
12
|
+
table.each do |record|
|
13
|
+
expect(record).to be_kind_of(DBF::Record)
|
14
|
+
end
|
13
15
|
end
|
14
16
|
|
15
17
|
specify "record count should be the same as reported in the header" do
|
@@ -17,35 +19,47 @@ shared_examples_for 'DBF' do
|
|
17
19
|
end
|
18
20
|
|
19
21
|
specify "column names should not be blank" do
|
20
|
-
|
22
|
+
table.columns.each do |column|
|
23
|
+
expect(column.name).not_to be_empty
|
24
|
+
end
|
21
25
|
end
|
22
26
|
|
23
27
|
specify "column types should be valid" do
|
24
28
|
valid_column_types = %w(C N L D M F B G P Y T I V X @ O + 0)
|
25
|
-
|
29
|
+
table.columns.each do |column|
|
30
|
+
expect(valid_column_types).to include(column.type)
|
31
|
+
end
|
26
32
|
end
|
27
33
|
|
28
34
|
specify "column lengths should be instances of Fixnum" do
|
29
|
-
|
35
|
+
table.columns.each do |column|
|
36
|
+
expect(column.length).to be_kind_of(Fixnum)
|
37
|
+
end
|
30
38
|
end
|
31
39
|
|
32
40
|
specify "column lengths should be larger than 0" do
|
33
|
-
|
41
|
+
table.columns.each do |column|
|
42
|
+
expect(column.length).to be > 0
|
43
|
+
end
|
34
44
|
end
|
35
45
|
|
36
46
|
specify "column decimals should be instances of Fixnum" do
|
37
|
-
|
47
|
+
table.columns.each do |column|
|
48
|
+
expect(column.decimal).to be_kind_of(Fixnum)
|
49
|
+
end
|
38
50
|
end
|
39
51
|
end
|
40
52
|
|
41
53
|
shared_examples_for 'Foxpro DBF' do
|
42
54
|
specify "columns should be instances of DBF::FoxproColumn" do
|
43
|
-
|
55
|
+
table.columns.each do |column|
|
56
|
+
expect(column).to be_kind_of(DBF::Column::Foxpro)
|
57
|
+
end
|
44
58
|
end
|
45
59
|
end
|
46
60
|
|
47
61
|
describe DBF, "of type 03 (dBase III without memo file)" do
|
48
|
-
let(:table) { DBF::Table.new
|
62
|
+
let(:table) { DBF::Table.new fixture_path('dbase_03.dbf') }
|
49
63
|
|
50
64
|
it_should_behave_like "DBF"
|
51
65
|
|
@@ -63,7 +77,7 @@ describe DBF, "of type 03 (dBase III without memo file)" do
|
|
63
77
|
end
|
64
78
|
|
65
79
|
describe DBF, "of type 30 (Visual FoxPro)" do
|
66
|
-
let(:table) { DBF::Table.new
|
80
|
+
let(:table) { DBF::Table.new fixture_path('dbase_30.dbf') }
|
67
81
|
|
68
82
|
it_should_behave_like "DBF"
|
69
83
|
|
@@ -85,7 +99,7 @@ describe DBF, "of type 30 (Visual FoxPro)" do
|
|
85
99
|
end
|
86
100
|
|
87
101
|
describe DBF, "of type 31 (Visual FoxPro with AutoIncrement field)" do
|
88
|
-
let(:table) { DBF::Table.new
|
102
|
+
let(:table) { DBF::Table.new fixture_path('dbase_31.dbf') }
|
89
103
|
|
90
104
|
it_should_behave_like "DBF"
|
91
105
|
|
@@ -103,7 +117,7 @@ describe DBF, "of type 31 (Visual FoxPro with AutoIncrement field)" do
|
|
103
117
|
end
|
104
118
|
|
105
119
|
describe DBF, "of type 83 (dBase III with memo file)" do
|
106
|
-
let(:table) { DBF::Table.new
|
120
|
+
let(:table) { DBF::Table.new fixture_path('dbase_83.dbf') }
|
107
121
|
|
108
122
|
it_should_behave_like "DBF"
|
109
123
|
|
@@ -121,7 +135,7 @@ describe DBF, "of type 83 (dBase III with memo file)" do
|
|
121
135
|
end
|
122
136
|
|
123
137
|
describe DBF, "of type 8b (dBase IV with memo file)" do
|
124
|
-
let(:table) { DBF::Table.new
|
138
|
+
let(:table) { DBF::Table.new fixture_path('dbase_8b.dbf') }
|
125
139
|
|
126
140
|
it_should_behave_like "DBF"
|
127
141
|
|
@@ -139,7 +153,7 @@ describe DBF, "of type 8b (dBase IV with memo file)" do
|
|
139
153
|
end
|
140
154
|
|
141
155
|
describe DBF, "of type f5 (FoxPro with memo file)" do
|
142
|
-
let(:table) { DBF::Table.new
|
156
|
+
let(:table) { DBF::Table.new fixture_path('dbase_f5.dbf') }
|
143
157
|
|
144
158
|
it_should_behave_like "DBF"
|
145
159
|
it_should_behave_like "Foxpro DBF"
|
@@ -157,6 +171,6 @@ describe DBF, "of type f5 (FoxPro with memo file)" do
|
|
157
171
|
end
|
158
172
|
|
159
173
|
it "reads memo data" do
|
160
|
-
expect(table.record(3).
|
174
|
+
expect(table.record(3).datn.to_s).to eq '1870-06-30'
|
161
175
|
end
|
162
176
|
end
|
data/spec/dbf/record_spec.rb
CHANGED
@@ -3,7 +3,8 @@ require "spec_helper"
|
|
3
3
|
describe DBF::Record do
|
4
4
|
|
5
5
|
describe '#to_a' do
|
6
|
-
let(:table) { DBF::Table.new
|
6
|
+
let(:table) { DBF::Table.new fixture_path('dbase_83.dbf') }
|
7
|
+
|
7
8
|
it 'should return an ordered array of attribute values' do
|
8
9
|
record = table.record(0)
|
9
10
|
expect(record.to_a).to eq [87, 2, 0, 0, 87, "1", "Assorted Petits Fours", "graphics/00000001/t_1.jpg", "graphics/00000001/1.jpg", 0.0, 0.0, "Our Original assortment...a little taste of heaven for everyone. Let us\r\nselect a special assortment of our chocolate and pastel favorites for you.\r\nEach petit four is its own special hand decorated creation. Multi-layers of\r\nmoist cake with combinations of specialty fillings create memorable cake\r\nconfections. Varietes include; Luscious Lemon, Strawberry Hearts, White\r\nChocolate, Mocha Bean, Roasted Almond, Triple Chocolate, Chocolate Hazelnut,\r\nGrand Orange, Plum Squares, Milk chocolate squares, and Raspberry Blanc.", 5.51, true, true]
|
@@ -13,7 +14,7 @@ describe DBF::Record do
|
|
13
14
|
end
|
14
15
|
|
15
16
|
describe 'with missing memo file' do
|
16
|
-
let(:table) { DBF::Table.new
|
17
|
+
let(:table) { DBF::Table.new fixture_path('dbase_83_missing_memo.dbf') }
|
17
18
|
|
18
19
|
it 'returns nil values for memo fields' do
|
19
20
|
record = table.record(0)
|
@@ -23,75 +24,75 @@ describe DBF::Record do
|
|
23
24
|
end
|
24
25
|
|
25
26
|
describe '#==' do
|
26
|
-
let
|
27
|
-
|
28
|
-
table.record(9)
|
29
|
-
end
|
27
|
+
let(:table) { DBF::Table.new fixture_path('dbase_8b.dbf') }
|
28
|
+
let(:record) { table.record(9) }
|
30
29
|
|
31
30
|
describe 'when other does not have attributes' do
|
32
|
-
it '
|
33
|
-
expect((record == double('other'))).to
|
31
|
+
it 'returns false' do
|
32
|
+
expect((record == double('other'))).to be_falsey
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
37
36
|
describe 'if other attributes match' do
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
37
|
+
let(:attributes) { {:x => 1, :y => 2} }
|
38
|
+
let(:other) { double('object', :attributes => attributes) }
|
39
|
+
|
40
|
+
before do
|
41
|
+
allow(record).to receive(:attributes).and_return(attributes)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns true' do
|
45
|
+
expect(record == other).to be_truthy
|
43
46
|
end
|
44
47
|
end
|
45
48
|
|
46
49
|
end
|
47
50
|
|
48
51
|
describe 'column accessors' do
|
49
|
-
let(:table) { DBF::Table.new
|
52
|
+
let(:table) { DBF::Table.new fixture_path('dbase_8b.dbf') }
|
50
53
|
let(:record) { table.find(0) }
|
51
54
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
55
|
+
%w(character numerical date logical float memo).each do |column_name|
|
56
|
+
|
57
|
+
it "defines accessor method for '#{column_name}' column" do
|
58
|
+
expect(record).to respond_to(column_name.to_sym)
|
59
|
+
end
|
58
60
|
|
59
|
-
it 'should not define accessor methods on the base class' do
|
60
|
-
second_table = DBF::Table.new "#{DB_PATH}/dbase_03.dbf"
|
61
|
-
second_record = second_table.find(0)
|
62
|
-
expect(record.character).to eq 'One'
|
63
|
-
expect { second_record.character }.to raise_error(NoMethodError)
|
64
61
|
end
|
65
62
|
end
|
66
63
|
|
67
64
|
describe 'column data for table' do
|
68
65
|
describe 'using specified in dbf encoding' do
|
69
|
-
let(:table) { DBF::Table.new
|
70
|
-
|
66
|
+
let(:table) { DBF::Table.new fixture_path('cp1251.dbf') }
|
71
67
|
let(:record) { table.find(0) }
|
68
|
+
|
72
69
|
it 'should automatically encodes to default system encoding' do
|
73
|
-
if table.
|
70
|
+
if table.supports_string_encoding?
|
74
71
|
expect(record.name.encoding).to eq Encoding.default_external
|
75
|
-
|
72
|
+
|
73
|
+
# russian a
|
74
|
+
expect(record.name.encode("UTF-8").unpack("H4")).to eq ["d0b0"]
|
76
75
|
end
|
77
76
|
end
|
78
77
|
end
|
79
78
|
|
80
79
|
describe 'overriding specified in dbf encoding' do
|
81
|
-
let(:table) { DBF::Table.new
|
82
|
-
|
80
|
+
let(:table) { DBF::Table.new fixture_path('cp1251.dbf'), nil, 'cp866'}
|
83
81
|
let(:record) { table.find(0) }
|
82
|
+
|
84
83
|
it 'should transcode from manually specified encoding to default system encoding' do
|
85
|
-
if table.
|
84
|
+
if table.supports_string_encoding?
|
86
85
|
expect(record.name.encoding).to eq Encoding.default_external
|
87
|
-
|
86
|
+
|
87
|
+
# russian а encoded in cp1251 and read as if it was encoded in cp866
|
88
|
+
expect(record.name.encode("UTF-8").unpack("H4")).to eq ["d180"]
|
88
89
|
end
|
89
90
|
end
|
90
91
|
end
|
91
92
|
end
|
92
93
|
|
93
94
|
describe '#attributes' do
|
94
|
-
let(:table) { DBF::Table.new
|
95
|
+
let(:table) { DBF::Table.new fixture_path('dbase_8b.dbf') }
|
95
96
|
let(:record) { table.find(0) }
|
96
97
|
|
97
98
|
it 'is a hash of attribute name/value pairs' do
|