dbf 5.1.1 → 5.3.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +19 -9
- data/bin/dbf +2 -54
- data/dbf.gemspec +6 -9
- data/lib/dbf/cli.rb +95 -0
- data/lib/dbf/column.rb +17 -15
- data/lib/dbf/column_builder.rb +31 -0
- data/lib/dbf/column_type.rb +66 -16
- data/lib/dbf/database/foxpro.rb +19 -32
- data/lib/dbf/encoder.rb +116 -0
- data/lib/dbf/encodings.rb +8 -0
- data/lib/dbf/file_handler.rb +36 -0
- data/lib/dbf/find.rb +54 -0
- data/lib/dbf/header.rb +5 -8
- data/lib/dbf/memo/base.rb +2 -0
- data/lib/dbf/memo/dbase3.rb +2 -2
- data/lib/dbf/memo/dbase4.rb +2 -2
- data/lib/dbf/memo/foxpro.rb +14 -7
- data/lib/dbf/record.rb +60 -34
- data/lib/dbf/record_context.rb +5 -0
- data/lib/dbf/record_iterator.rb +35 -0
- data/lib/dbf/schema.rb +21 -21
- data/lib/dbf/table.rb +50 -181
- data/lib/dbf/version.rb +1 -1
- data/lib/dbf/version_config.rb +79 -0
- data/lib/dbf.rb +8 -0
- metadata +17 -64
- data/spec/dbf/column_spec.rb +0 -287
- data/spec/dbf/database/foxpro_spec.rb +0 -53
- data/spec/dbf/encoding_spec.rb +0 -49
- data/spec/dbf/file_formats_spec.rb +0 -221
- data/spec/dbf/record_spec.rb +0 -116
- data/spec/dbf/table_spec.rb +0 -377
- data/spec/fixtures/cp1251.dbf +0 -0
- data/spec/fixtures/cp1251_summary.txt +0 -12
- data/spec/fixtures/dbase_02.dbf +0 -0
- data/spec/fixtures/dbase_02_summary.txt +0 -23
- data/spec/fixtures/dbase_03.dbf +0 -0
- data/spec/fixtures/dbase_03_cyrillic.dbf +0 -0
- data/spec/fixtures/dbase_03_cyrillic_summary.txt +0 -11
- data/spec/fixtures/dbase_03_summary.txt +0 -40
- data/spec/fixtures/dbase_30.dbf +0 -0
- data/spec/fixtures/dbase_30.fpt +0 -0
- data/spec/fixtures/dbase_30_summary.txt +0 -154
- data/spec/fixtures/dbase_31.dbf +0 -0
- data/spec/fixtures/dbase_31_summary.txt +0 -20
- data/spec/fixtures/dbase_32.dbf +0 -0
- data/spec/fixtures/dbase_32_summary.txt +0 -11
- data/spec/fixtures/dbase_83.dbf +0 -0
- data/spec/fixtures/dbase_83.dbt +0 -0
- data/spec/fixtures/dbase_83_missing_memo.dbf +0 -0
- data/spec/fixtures/dbase_83_missing_memo_record_0.yml +0 -16
- data/spec/fixtures/dbase_83_record_0.yml +0 -16
- data/spec/fixtures/dbase_83_record_9.yml +0 -23
- data/spec/fixtures/dbase_83_schema_ar.txt +0 -19
- data/spec/fixtures/dbase_83_schema_sq.txt +0 -21
- data/spec/fixtures/dbase_83_schema_sq_lim.txt +0 -21
- data/spec/fixtures/dbase_83_summary.txt +0 -24
- data/spec/fixtures/dbase_8b.dbf +0 -0
- data/spec/fixtures/dbase_8b.dbt +0 -0
- data/spec/fixtures/dbase_8b_summary.txt +0 -15
- data/spec/fixtures/dbase_8c.dbf +0 -0
- data/spec/fixtures/dbase_f5.dbf +0 -0
- data/spec/fixtures/dbase_f5.fpt +0 -0
- data/spec/fixtures/dbase_f5_summary.txt +0 -68
- data/spec/fixtures/foxprodb/FOXPRO-DB-TEST.DBC +0 -0
- data/spec/fixtures/foxprodb/FOXPRO-DB-TEST.DCT +0 -0
- data/spec/fixtures/foxprodb/FOXPRO-DB-TEST.DCX +0 -0
- data/spec/fixtures/foxprodb/calls.CDX +0 -0
- data/spec/fixtures/foxprodb/calls.FPT +0 -0
- data/spec/fixtures/foxprodb/calls.dbf +0 -0
- data/spec/fixtures/foxprodb/contacts.CDX +0 -0
- data/spec/fixtures/foxprodb/contacts.FPT +0 -0
- data/spec/fixtures/foxprodb/contacts.dbf +0 -0
- data/spec/fixtures/foxprodb/setup.CDX +0 -0
- data/spec/fixtures/foxprodb/setup.dbf +0 -0
- data/spec/fixtures/foxprodb/types.CDX +0 -0
- data/spec/fixtures/foxprodb/types.dbf +0 -0
- data/spec/fixtures/polygon.dbf +0 -0
- data/spec/spec_helper.rb +0 -35
data/spec/dbf/column_spec.rb
DELETED
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
# encoding: ascii-8bit
|
|
3
|
-
|
|
4
|
-
require 'spec_helper'
|
|
5
|
-
|
|
6
|
-
RSpec.describe DBF::Column do
|
|
7
|
-
let(:table) { DBF::Table.new fixture('dbase_30.dbf') }
|
|
8
|
-
|
|
9
|
-
context 'when initialized' do
|
|
10
|
-
let(:column) { DBF::Column.new table, 'ColumnName', 'N', 1, 0 }
|
|
11
|
-
|
|
12
|
-
it 'sets :name accessor' do
|
|
13
|
-
expect(column.name).to eq 'ColumnName'
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it 'sets :type accessor' do
|
|
17
|
-
expect(column.type).to eq 'N'
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it 'sets the #length accessor' do
|
|
21
|
-
expect(column.length).to eq 1
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
it 'sets the #decimal accessor' do
|
|
25
|
-
expect(column.decimal).to eq 0
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
it 'accepts length of 0' do
|
|
29
|
-
column = DBF::Column.new table, 'ColumnName', 'N', 0, 0
|
|
30
|
-
expect(column.length).to eq 0
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
describe 'with length less than 0' do
|
|
34
|
-
it 'raises DBF::Column::LengthError' do
|
|
35
|
-
expect { DBF::Column.new table, 'ColumnName', 'N', -1, 0 }.to raise_error(DBF::Column::LengthError)
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
describe 'with empty column name' do
|
|
40
|
-
it 'raises DBF::Column::NameError' do
|
|
41
|
-
expect { DBF::Column.new table, '', 'N', 1, 0 }.to raise_error(DBF::Column::NameError)
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
describe '#type_cast' do
|
|
47
|
-
context 'with type N (number)' do
|
|
48
|
-
context 'when value is empty' do
|
|
49
|
-
it 'returns nil' do
|
|
50
|
-
value = ''
|
|
51
|
-
column = DBF::Column.new table, 'ColumnName', 'N', 5, 2
|
|
52
|
-
expect(column.type_cast(value)).to be_nil
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
context 'with 0 length' do
|
|
57
|
-
it 'returns nil' do
|
|
58
|
-
column = DBF::Column.new table, 'ColumnName', 'N', 0, 0
|
|
59
|
-
expect(column.type_cast('')).to be_nil
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
context 'with 0 decimals' do
|
|
64
|
-
it 'casts value to Integer' do
|
|
65
|
-
value = '135'
|
|
66
|
-
column = DBF::Column.new table, 'ColumnName', 'N', 3, 0
|
|
67
|
-
expect(column.type_cast(value)).to eq 135
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it 'supports negative Integer' do
|
|
71
|
-
value = '-135'
|
|
72
|
-
column = DBF::Column.new table, 'ColumnName', 'N', 3, 0
|
|
73
|
-
expect(column.type_cast(value)).to eq(-135)
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
context 'with more than 0 decimals' do
|
|
78
|
-
it 'casts value to Float' do
|
|
79
|
-
value = '13.5'
|
|
80
|
-
column = DBF::Column.new table, 'ColumnName', 'N', 2, 1
|
|
81
|
-
expect(column.type_cast(value)).to eq 13.5
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
it 'casts negative value to Float' do
|
|
85
|
-
value = '-13.5'
|
|
86
|
-
column = DBF::Column.new table, 'ColumnName', 'N', 2, 1
|
|
87
|
-
expect(column.type_cast(value)).to eq(-13.5)
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
context 'with type F (float)' do
|
|
93
|
-
context 'with 0 length' do
|
|
94
|
-
it 'returns nil' do
|
|
95
|
-
column = DBF::Column.new table, 'ColumnName', 'F', 0, 0
|
|
96
|
-
expect(column.type_cast('')).to be_nil
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
it 'casts value to Float' do
|
|
101
|
-
value = '135'
|
|
102
|
-
column = DBF::Column.new table, 'ColumnName', 'F', 3, 0
|
|
103
|
-
expect(column.type_cast(value)).to eq 135.0
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
it 'casts negative value to Float' do
|
|
107
|
-
value = '-135'
|
|
108
|
-
column = DBF::Column.new table, 'ColumnName', 'F', 3, 0
|
|
109
|
-
expect(column.type_cast(value)).to eq(-135.0)
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
context 'with type B (binary)' do
|
|
114
|
-
context 'with Foxpro dbf' do
|
|
115
|
-
it 'casts to float' do
|
|
116
|
-
column = DBF::Column.new table, 'ColumnName', 'B', 1, 2
|
|
117
|
-
expect(column.type_cast("\xEC\x51\xB8\x1E\x85\x6B\x31\x40")).to be_a(Float)
|
|
118
|
-
expect(column.type_cast("\xEC\x51\xB8\x1E\x85\x6B\x31\x40")).to eq 17.42
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
it 'stores original precision' do
|
|
122
|
-
column = DBF::Column.new table, 'ColumnName', 'B', 1, 0
|
|
123
|
-
expect(column.type_cast("\xEC\x51\xB8\x1E\x85\x6B\x31\x40")).to be_a(Float)
|
|
124
|
-
expect(column.type_cast("\xEC\x51\xB8\x1E\x85\x6B\x31\x40")).to eq 17.42
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
it 'supports negative binary' do
|
|
128
|
-
column = DBF::Column.new table, 'ColumnName', 'B', 1, 2
|
|
129
|
-
expect(column.type_cast("\x00\x00\x00\x00\x00\xC0\x65\xC0")).to be_a(Float)
|
|
130
|
-
expect(column.type_cast("\x00\x00\x00\x00\x00\xC0\x65\xC0")).to eq(-174.0)
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
context 'with type I (integer)' do
|
|
136
|
-
context 'with 0 length' do
|
|
137
|
-
it 'returns nil' do
|
|
138
|
-
column = DBF::Column.new table, 'ColumnName', 'I', 0, 0
|
|
139
|
-
expect(column.type_cast('')).to be_nil
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
it 'casts value to Integer' do
|
|
144
|
-
value = "\203\171\001\000"
|
|
145
|
-
column = DBF::Column.new table, 'ColumnName', 'I', 3, 0
|
|
146
|
-
expect(column.type_cast(value)).to eq 96_643
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
it 'supports negative Integer' do
|
|
150
|
-
value = "\x24\xE1\xFF\xFF"
|
|
151
|
-
column = DBF::Column.new table, 'ColumnName', 'I', 3, 0
|
|
152
|
-
expect(column.type_cast(value)).to eq(-7900)
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
context 'with type L (logical/boolean)' do
|
|
157
|
-
let(:column) { DBF::Column.new table, 'ColumnName', 'L', 1, 0 }
|
|
158
|
-
|
|
159
|
-
it "casts 'y' to true" do
|
|
160
|
-
expect(column.type_cast('y')).to be true
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
it "casts 't' to true" do
|
|
164
|
-
expect(column.type_cast('t')).to be true
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
it "casts value other than 't' or 'y' to false" do
|
|
168
|
-
expect(column.type_cast('n')).to be false
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
context 'with 0 length' do
|
|
172
|
-
it 'returns nil' do
|
|
173
|
-
column = DBF::Column.new table, 'ColumnName', 'L', 0, 0
|
|
174
|
-
expect(column.type_cast('')).to be_nil
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
context 'with type T (datetime)' do
|
|
180
|
-
let(:column) { DBF::Column.new table, 'ColumnName', 'T', 16, 0 }
|
|
181
|
-
|
|
182
|
-
context 'with valid datetime' do
|
|
183
|
-
it 'casts to DateTime' do
|
|
184
|
-
expect(column.type_cast("Nl%\000\300Z\252\003")).to eq Time.parse('2002-10-10T17:04:56+00:00')
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
context 'with invalid datetime' do
|
|
189
|
-
it 'casts to nil' do
|
|
190
|
-
expect(column.type_cast("Nl%\000\000A\000\999")).to be_nil
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
context 'with 0 length' do
|
|
195
|
-
it 'returns nil' do
|
|
196
|
-
column = DBF::Column.new table, 'ColumnName', 'T', 0, 0
|
|
197
|
-
expect(column.type_cast('')).to be_nil
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
context 'with type D (date)' do
|
|
203
|
-
let(:column) { DBF::Column.new table, 'ColumnName', 'D', 8, 0 }
|
|
204
|
-
|
|
205
|
-
context 'with valid date' do
|
|
206
|
-
it 'casts to Date' do
|
|
207
|
-
expect(column.type_cast('20050712')).to eq Date.new(2005, 7, 12)
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
context 'with invalid date' do
|
|
212
|
-
it 'casts to nil' do
|
|
213
|
-
expect(column.type_cast('000000000')).to be_nil
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
context 'with 0 length' do
|
|
218
|
-
it 'returns nil' do
|
|
219
|
-
column = DBF::Column.new table, 'ColumnName', 'D', 0, 0
|
|
220
|
-
expect(column.type_cast('')).to be_nil
|
|
221
|
-
end
|
|
222
|
-
end
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
context 'with type M (memo)' do
|
|
226
|
-
it 'casts to string' do
|
|
227
|
-
column = DBF::Column.new table, 'ColumnName', 'M', 3, 0
|
|
228
|
-
expect(column.type_cast('abc')).to eq 'abc'
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
it 'casts nil to nil' do
|
|
232
|
-
column = DBF::Column.new table, 'ColumnName', 'M', 3, 0
|
|
233
|
-
expect(column.type_cast(nil)).to be_nil
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
context 'with 0 length' do
|
|
237
|
-
it 'returns nil' do
|
|
238
|
-
column = DBF::Column.new table, 'ColumnName', 'M', 0, 0
|
|
239
|
-
expect(column.type_cast('')).to be_nil
|
|
240
|
-
end
|
|
241
|
-
end
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
context 'with type G (memo)' do
|
|
245
|
-
it 'returns binary data' do
|
|
246
|
-
column = DBF::Column.new table, 'ColumnName', 'G', 3, 0
|
|
247
|
-
expect(column.type_cast("\000\013\120")).to eq "\000\013\120"
|
|
248
|
-
expect(column.type_cast("\000\013\120").encoding).to eq Encoding::ASCII_8BIT
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
it 'casts nil to nil' do
|
|
252
|
-
column = DBF::Column.new table, 'ColumnName', 'G', 3, 0
|
|
253
|
-
expect(column.type_cast(nil)).to be_nil
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
context 'with 0 length' do
|
|
257
|
-
it 'returns nil' do
|
|
258
|
-
column = DBF::Column.new table, 'ColumnName', 'G', 0, 0
|
|
259
|
-
expect(column.type_cast('')).to be_nil
|
|
260
|
-
end
|
|
261
|
-
end
|
|
262
|
-
end
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
context 'with type Y (currency)' do
|
|
266
|
-
let(:column) { DBF::Column.new table, 'ColumnName', 'Y', 8, 4 }
|
|
267
|
-
|
|
268
|
-
it 'casts to float' do
|
|
269
|
-
expect(column.type_cast(" \xBF\x02\x00\x00\x00\x00\x00")).to eq 18.0
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
it 'supports negative currency' do
|
|
273
|
-
expect(column.type_cast("\xFC\xF0\xF0\xFE\xFF\xFF\xFF\xFF")).to eq(-1776.41)
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
it 'supports 64bit negative currency' do
|
|
277
|
-
expect(column.type_cast("pN'9\xFF\xFF\xFF\xFF")).to eq(-333_609.0)
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
context 'with 0 length' do
|
|
281
|
-
it 'returns nil' do
|
|
282
|
-
column = DBF::Column.new table, 'ColumnName', 'Y', 0, 0
|
|
283
|
-
expect(column.type_cast('')).to be_nil
|
|
284
|
-
end
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
end
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
RSpec.describe DBF::Database::Foxpro do
|
|
6
|
-
let(:dbf_path) { fixture('foxprodb/FOXPRO-DB-TEST.DBC') }
|
|
7
|
-
let(:db) { DBF::Database::Foxpro.new(dbf_path) }
|
|
8
|
-
|
|
9
|
-
describe '#initialize' do
|
|
10
|
-
describe 'when given a path to an existing dbc file' do
|
|
11
|
-
it 'does not raise an error' do
|
|
12
|
-
expect { DBF::Database::Foxpro.new dbf_path }.to_not raise_error
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
describe 'when given a path to a non-existent dbf file' do
|
|
17
|
-
it 'raises a DBF::FileNotFound error' do
|
|
18
|
-
expect { DBF::Database::Foxpro.new 'x' }.to raise_error(DBF::FileNotFoundError, 'file not found: x')
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
describe 'it loads the example db correctly' do
|
|
23
|
-
it 'shows a correct list of tables' do
|
|
24
|
-
expect(db.table_names.sort).to eq(%w[contacts calls setup types].sort)
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
describe '#table' do
|
|
30
|
-
describe 'when accessing related tables' do
|
|
31
|
-
let(:db) { DBF::Database::Foxpro.new(dbf_path) }
|
|
32
|
-
|
|
33
|
-
it 'loads an existing related table' do
|
|
34
|
-
expect(db.contacts.record_count).to eq 5
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it 'supports a long table field name' do
|
|
38
|
-
expect(db.contacts.record(1).spouses_interests).to eq 'Tennis, golf'
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
it 'loads an existing related table with wrong filename casing' do
|
|
42
|
-
expect(db.calls.record_count).to eq 16
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
describe '#table_path' do
|
|
48
|
-
it 'returns an absolute path' do
|
|
49
|
-
expect(db.table_path('contacts')).to eq File.expand_path('spec/fixtures/foxprodb/contacts.dbf')
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
end
|
data/spec/dbf/encoding_spec.rb
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
RSpec.describe 'DBF::Table' do
|
|
6
|
-
context 'with default encoding' do
|
|
7
|
-
let(:dbf_path) { fixture('dbase_03_cyrillic.dbf') }
|
|
8
|
-
let(:table) { DBF::Table.new dbf_path }
|
|
9
|
-
|
|
10
|
-
it 'defaults to UTF-8 encoding' do
|
|
11
|
-
expect(table.encoding).to eq Encoding::UTF_8
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
it 'uses the table encoding for column encoding' do
|
|
15
|
-
column = table.columns.first
|
|
16
|
-
expect(column.encoding).to eq table.encoding
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it 'encodes column names' do
|
|
20
|
-
expect(table.column_names).to eq %w[ШАР ПЛОЩА]
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
it 'encodes record values' do
|
|
24
|
-
expect(table.record(0).attributes['ШАР']).to eq 'Номер'
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
context 'with embedded encoding' do
|
|
29
|
-
let(:dbf_path) { fixture('cp1251.dbf') }
|
|
30
|
-
let(:table) { DBF::Table.new dbf_path }
|
|
31
|
-
|
|
32
|
-
it 'defaults to UTF-8 encoding' do
|
|
33
|
-
expect(table.encoding).to eq 'cp1251'
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
it 'uses the table encoding for column encoding' do
|
|
37
|
-
column = table.columns.first
|
|
38
|
-
expect(column.encoding).to eq table.encoding
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
it 'encodes column names' do
|
|
42
|
-
expect(table.column_names).to eq %w[RN NAME]
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
it 'encodes record values' do
|
|
46
|
-
expect(table.record(0).attributes['NAME']).to eq 'амбулаторно-поликлиническое'
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
RSpec.shared_examples_for 'DBF' do
|
|
6
|
-
let(:header_record_length) { table.instance_eval { header.record_length } }
|
|
7
|
-
let(:sum_of_column_lengths) { table.columns.inject(1) { |sum, column| sum + column.length } }
|
|
8
|
-
|
|
9
|
-
specify 'sum of column lengths should equal record length specified in header plus one' do
|
|
10
|
-
expect(header_record_length).to eq sum_of_column_lengths
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
specify 'records should be instances of DBF::Record' do
|
|
14
|
-
expect(table).to all be_a(DBF::Record)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
specify 'record count should be the same as reported in the header' do
|
|
18
|
-
expect(table.entries.size).to eq table.record_count
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
specify 'column names should not be blank' do
|
|
22
|
-
table.columns.each do |column|
|
|
23
|
-
expect(column.name).to_not be_empty
|
|
24
|
-
end
|
|
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.each do |column|
|
|
30
|
-
expect(valid_column_types).to include(column.type)
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
specify 'column lengths should be instances of Integer' do
|
|
35
|
-
table.columns.each do |column|
|
|
36
|
-
expect(column.length).to be_a(Integer)
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
specify 'column lengths should be larger than 0' do
|
|
41
|
-
table.columns.each do |column|
|
|
42
|
-
expect(column.length).to be > 0
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
specify 'column decimals should be instances of Integer' do
|
|
47
|
-
table.columns.each do |column|
|
|
48
|
-
expect(column.decimal).to be_a(Integer)
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
RSpec.describe DBF, 'of type 02 (FoxBase)' do
|
|
54
|
-
let(:table) { DBF::Table.new fixture('dbase_02.dbf') }
|
|
55
|
-
|
|
56
|
-
it_behaves_like 'DBF'
|
|
57
|
-
|
|
58
|
-
it 'reports the correct version number' do
|
|
59
|
-
expect(table.version).to eq '02'
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
it 'reports the correct version description' do
|
|
63
|
-
expect(table.version_description).to eq 'FoxBase'
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
it 'determines the number of records' do
|
|
67
|
-
expect(table.record_count).to eq 9
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
RSpec.describe DBF, 'of type 03 (dBase III without memo file)' do
|
|
72
|
-
let(:table) { DBF::Table.new fixture('dbase_03.dbf') }
|
|
73
|
-
|
|
74
|
-
it_behaves_like 'DBF'
|
|
75
|
-
|
|
76
|
-
it 'reports the correct version number' do
|
|
77
|
-
expect(table.version).to eq '03'
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
it 'reports the correct version description' do
|
|
81
|
-
expect(table.version_description).to eq 'dBase III without memo file'
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
it 'determines the number of records' do
|
|
85
|
-
expect(table.record_count).to eq 14
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
RSpec.describe DBF, 'of type 30 (Visual FoxPro)' do
|
|
90
|
-
let(:table) { DBF::Table.new fixture('dbase_30.dbf') }
|
|
91
|
-
|
|
92
|
-
it_behaves_like 'DBF'
|
|
93
|
-
|
|
94
|
-
it 'reports the correct version number' do
|
|
95
|
-
expect(table.version).to eq '30'
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
it 'reports the correct version description' do
|
|
99
|
-
expect(table.version_description).to eq 'Visual FoxPro'
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
it 'determines the number of records' do
|
|
103
|
-
expect(table.record_count).to eq 34
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
it 'reads memo data' do
|
|
107
|
-
expect(table.record(3).classes).to match(/\AAgriculture.*Farming\r\n\Z/m)
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
RSpec.describe DBF, 'of type 31 (Visual FoxPro with AutoIncrement field)' do
|
|
112
|
-
let(:table) { DBF::Table.new fixture('dbase_31.dbf') }
|
|
113
|
-
|
|
114
|
-
it_behaves_like 'DBF'
|
|
115
|
-
|
|
116
|
-
it 'has a dBase version of 31' do
|
|
117
|
-
expect(table.version).to eq '31'
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
it 'reports the correct version description' do
|
|
121
|
-
expect(table.version_description).to eq 'Visual FoxPro with AutoIncrement field'
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
it 'determines the number of records' do
|
|
125
|
-
expect(table.record_count).to eq 77
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
RSpec.describe DBF, 'of type 32 (Visual FoxPro with field type Varchar or Varbinary)' do
|
|
130
|
-
let(:table) { DBF::Table.new fixture('dbase_32.dbf') }
|
|
131
|
-
|
|
132
|
-
it_behaves_like 'DBF'
|
|
133
|
-
|
|
134
|
-
it 'has a dBase version of 32' do
|
|
135
|
-
expect(table.version).to eq '32'
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
it 'reports the correct version description' do
|
|
139
|
-
expect(table.version_description).to eq 'Visual FoxPro with field type Varchar or Varbinary'
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
it 'determines the number of records' do
|
|
143
|
-
expect(table.record_count).to eq 1
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
RSpec.describe DBF, 'of type 83 (dBase III with memo file)' do
|
|
148
|
-
let(:table) { DBF::Table.new fixture('dbase_83.dbf') }
|
|
149
|
-
|
|
150
|
-
it_behaves_like 'DBF'
|
|
151
|
-
|
|
152
|
-
it 'reports the correct version number' do
|
|
153
|
-
expect(table.version).to eq '83'
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
it 'reports the correct version description' do
|
|
157
|
-
expect(table.version_description).to eq 'dBase III with memo file'
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
it 'determines the number of records' do
|
|
161
|
-
expect(table.record_count).to eq 67
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
RSpec.describe DBF, 'of type 8b (dBase IV with memo file)' do
|
|
166
|
-
let(:table) { DBF::Table.new fixture('dbase_8b.dbf') }
|
|
167
|
-
|
|
168
|
-
it_behaves_like 'DBF'
|
|
169
|
-
|
|
170
|
-
it 'reports the correct version number' do
|
|
171
|
-
expect(table.version).to eq '8b'
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
it 'reports the correct version description' do
|
|
175
|
-
expect(table.version_description).to eq 'dBase IV with memo file'
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
it 'determines the number of records' do
|
|
179
|
-
expect(table.record_count).to eq 10
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
RSpec.describe DBF, 'of type 8c (unknown)' do
|
|
184
|
-
let(:table) { DBF::Table.new fixture('dbase_8c.dbf') }
|
|
185
|
-
|
|
186
|
-
it_behaves_like 'DBF'
|
|
187
|
-
|
|
188
|
-
it 'reports the correct version number' do
|
|
189
|
-
expect(table.version).to eq '8c'
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
it 'reports the correct version description' do
|
|
193
|
-
expect(table.version_description).to eq 'dBase 7'
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
it 'determines the number of records' do
|
|
197
|
-
expect(table.record_count).to eq 10
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
RSpec.describe DBF, 'of type f5 (FoxPro with memo file)' do
|
|
202
|
-
let(:table) { DBF::Table.new fixture('dbase_f5.dbf') }
|
|
203
|
-
|
|
204
|
-
it_behaves_like 'DBF'
|
|
205
|
-
|
|
206
|
-
it 'reports the correct version number' do
|
|
207
|
-
expect(table.version).to eq 'f5'
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
it 'reports the correct version description' do
|
|
211
|
-
expect(table.version_description).to eq 'FoxPro with memo file'
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
it 'determines the number of records' do
|
|
215
|
-
expect(table.record_count).to eq 975
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
it 'reads memo data' do
|
|
219
|
-
expect(table.record(3).datn.to_s).to eq '1870-06-30'
|
|
220
|
-
end
|
|
221
|
-
end
|