dbf 5.1.1 → 5.2.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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +4 -2
  4. data/dbf.gemspec +6 -9
  5. data/lib/dbf/column.rb +17 -15
  6. data/lib/dbf/column_builder.rb +31 -0
  7. data/lib/dbf/column_type.rb +58 -14
  8. data/lib/dbf/database/foxpro.rb +19 -32
  9. data/lib/dbf/file_handler.rb +36 -0
  10. data/lib/dbf/find.rb +54 -0
  11. data/lib/dbf/header.rb +5 -8
  12. data/lib/dbf/memo/base.rb +2 -0
  13. data/lib/dbf/memo/dbase3.rb +2 -2
  14. data/lib/dbf/memo/dbase4.rb +2 -2
  15. data/lib/dbf/memo/foxpro.rb +14 -7
  16. data/lib/dbf/record.rb +60 -34
  17. data/lib/dbf/record_context.rb +5 -0
  18. data/lib/dbf/record_iterator.rb +35 -0
  19. data/lib/dbf/schema.rb +21 -21
  20. data/lib/dbf/table.rb +42 -178
  21. data/lib/dbf/version.rb +1 -1
  22. data/lib/dbf/version_config.rb +79 -0
  23. data/lib/dbf.rb +6 -0
  24. metadata +15 -64
  25. data/spec/dbf/column_spec.rb +0 -287
  26. data/spec/dbf/database/foxpro_spec.rb +0 -53
  27. data/spec/dbf/encoding_spec.rb +0 -49
  28. data/spec/dbf/file_formats_spec.rb +0 -221
  29. data/spec/dbf/record_spec.rb +0 -116
  30. data/spec/dbf/table_spec.rb +0 -377
  31. data/spec/fixtures/cp1251.dbf +0 -0
  32. data/spec/fixtures/cp1251_summary.txt +0 -12
  33. data/spec/fixtures/dbase_02.dbf +0 -0
  34. data/spec/fixtures/dbase_02_summary.txt +0 -23
  35. data/spec/fixtures/dbase_03.dbf +0 -0
  36. data/spec/fixtures/dbase_03_cyrillic.dbf +0 -0
  37. data/spec/fixtures/dbase_03_cyrillic_summary.txt +0 -11
  38. data/spec/fixtures/dbase_03_summary.txt +0 -40
  39. data/spec/fixtures/dbase_30.dbf +0 -0
  40. data/spec/fixtures/dbase_30.fpt +0 -0
  41. data/spec/fixtures/dbase_30_summary.txt +0 -154
  42. data/spec/fixtures/dbase_31.dbf +0 -0
  43. data/spec/fixtures/dbase_31_summary.txt +0 -20
  44. data/spec/fixtures/dbase_32.dbf +0 -0
  45. data/spec/fixtures/dbase_32_summary.txt +0 -11
  46. data/spec/fixtures/dbase_83.dbf +0 -0
  47. data/spec/fixtures/dbase_83.dbt +0 -0
  48. data/spec/fixtures/dbase_83_missing_memo.dbf +0 -0
  49. data/spec/fixtures/dbase_83_missing_memo_record_0.yml +0 -16
  50. data/spec/fixtures/dbase_83_record_0.yml +0 -16
  51. data/spec/fixtures/dbase_83_record_9.yml +0 -23
  52. data/spec/fixtures/dbase_83_schema_ar.txt +0 -19
  53. data/spec/fixtures/dbase_83_schema_sq.txt +0 -21
  54. data/spec/fixtures/dbase_83_schema_sq_lim.txt +0 -21
  55. data/spec/fixtures/dbase_83_summary.txt +0 -24
  56. data/spec/fixtures/dbase_8b.dbf +0 -0
  57. data/spec/fixtures/dbase_8b.dbt +0 -0
  58. data/spec/fixtures/dbase_8b_summary.txt +0 -15
  59. data/spec/fixtures/dbase_8c.dbf +0 -0
  60. data/spec/fixtures/dbase_f5.dbf +0 -0
  61. data/spec/fixtures/dbase_f5.fpt +0 -0
  62. data/spec/fixtures/dbase_f5_summary.txt +0 -68
  63. data/spec/fixtures/foxprodb/FOXPRO-DB-TEST.DBC +0 -0
  64. data/spec/fixtures/foxprodb/FOXPRO-DB-TEST.DCT +0 -0
  65. data/spec/fixtures/foxprodb/FOXPRO-DB-TEST.DCX +0 -0
  66. data/spec/fixtures/foxprodb/calls.CDX +0 -0
  67. data/spec/fixtures/foxprodb/calls.FPT +0 -0
  68. data/spec/fixtures/foxprodb/calls.dbf +0 -0
  69. data/spec/fixtures/foxprodb/contacts.CDX +0 -0
  70. data/spec/fixtures/foxprodb/contacts.FPT +0 -0
  71. data/spec/fixtures/foxprodb/contacts.dbf +0 -0
  72. data/spec/fixtures/foxprodb/setup.CDX +0 -0
  73. data/spec/fixtures/foxprodb/setup.dbf +0 -0
  74. data/spec/fixtures/foxprodb/types.CDX +0 -0
  75. data/spec/fixtures/foxprodb/types.dbf +0 -0
  76. data/spec/fixtures/polygon.dbf +0 -0
  77. data/spec/spec_helper.rb +0 -35
@@ -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
@@ -1,116 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe DBF::Record do
6
- describe '#to_a' do
7
- let(:table) { DBF::Table.new fixture('dbase_83.dbf') }
8
-
9
- it 'returns an ordered array of attribute values' do
10
- record = table.record(0)
11
- expect(record.to_a).to eq YAML.load_file(fixture('dbase_83_record_0.yml'))
12
-
13
- record = table.record(9)
14
- expect(record.to_a).to eq YAML.load_file(fixture('dbase_83_record_9.yml'))
15
- end
16
-
17
- describe 'with missing memo file' do
18
- describe 'when opening a path' do
19
- let(:table) { DBF::Table.new fixture('dbase_83_missing_memo.dbf') }
20
-
21
- it 'returns nil values for memo fields' do
22
- record = table.record(0)
23
- expect(record.to_a).to eq YAML.load_file(fixture('dbase_83_missing_memo_record_0.yml'))
24
- end
25
- end
26
- end
27
-
28
- describe 'when opening StringIO' do
29
- let(:data) { StringIO.new(File.read(fixture('dbase_83_missing_memo.dbf'))) }
30
- let(:table) { DBF::Table.new(data) }
31
-
32
- it 'returns nil values for memo fields' do
33
- record = table.record(0)
34
- expect(record.to_a).to eq YAML.load_file(fixture('dbase_83_missing_memo_record_0.yml'))
35
- end
36
- end
37
- end
38
-
39
- describe '#==' do
40
- let(:table) { DBF::Table.new fixture('dbase_8b.dbf') }
41
- let(:record) { table.record(9) }
42
-
43
- describe 'when other does not have attributes' do
44
- it 'returns false' do
45
- expect(record == instance_double(DBF::Record)).to be_falsey
46
- end
47
- end
48
-
49
- describe 'if other attributes match' do
50
- let(:attributes) { {x: 1, y: 2} }
51
- let(:other) { instance_double(DBF::Record, attributes: attributes) }
52
-
53
- before do
54
- allow(record).to receive(:attributes).and_return(attributes)
55
- end
56
-
57
- it 'returns true' do
58
- expect(record == other).to be_truthy
59
- end
60
- end
61
-
62
- end
63
-
64
- describe 'column accessors' do
65
- let(:table) { DBF::Table.new fixture('dbase_8b.dbf') }
66
- let(:record) { table.find(0) }
67
-
68
- %w[character numerical date logical float memo].each do |column_name|
69
- it "defines accessor method for '#{column_name}' column" do
70
- expect(record).to respond_to(column_name.to_sym)
71
- end
72
-
73
- end
74
- end
75
-
76
- describe 'column data for table' do
77
- describe 'using specified in dbf encoding' do
78
- let(:table) { DBF::Table.new fixture('cp1251.dbf') }
79
- let(:record) { table.find(0) }
80
-
81
- it 'encodes to default system encoding' do
82
- expect(record.name.encoding).to eq Encoding.default_external
83
-
84
- # russian a
85
- expect(record.name.encode('UTF-8').unpack1('H4')).to eq 'd0b0'
86
- end
87
- end
88
-
89
- describe 'overriding specified in dbf encoding' do
90
- let(:table) { DBF::Table.new fixture('cp1251.dbf'), nil, 'cp866' }
91
- let(:record) { table.find(0) }
92
-
93
- it 'transcodes from manually specified encoding to default system encoding' do
94
- expect(record.name.encoding).to eq Encoding.default_external
95
-
96
- # russian а encoded in cp1251 and read as if it was encoded in cp866
97
- expect(record.name.encode('UTF-8').unpack1('H4')).to eq 'd180'
98
- end
99
- end
100
- end
101
-
102
- describe '#attributes' do
103
- let(:table) { DBF::Table.new fixture('dbase_8b.dbf') }
104
- let(:record) { table.find(0) }
105
-
106
- it 'is a hash of attribute name/value pairs' do
107
- expect(record.attributes).to be_a(Hash)
108
- expect(record.attributes['CHARACTER']).to eq 'One'
109
- end
110
-
111
- it 'has only original field names as keys' do
112
- original_field_names = %w[CHARACTER DATE FLOAT LOGICAL MEMO NUMERICAL]
113
- expect(record.attributes.keys.sort).to eq original_field_names
114
- end
115
- end
116
- end