dbf 2.0.9 → 2.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/Gemfile +0 -2
- data/Gemfile.lock +40 -237
- data/Gemfile.travis +1 -1
- data/Guardfile +6 -3
- data/README.md +33 -1
- data/Rakefile +1 -1
- data/dbf.gemspec +2 -1
- data/lib/dbf.rb +1 -0
- data/lib/dbf/column/base.rb +5 -3
- data/lib/dbf/database/foxpro.rb +109 -0
- data/lib/dbf/table.rb +1 -0
- data/lib/dbf/version.rb +1 -1
- data/spec/dbf/column_spec.rb +59 -4
- data/spec/dbf/database_spec.rb +51 -0
- data/spec/dbf/record_spec.rb +8 -4
- data/spec/fixtures/dbase_83_missing_memo_record_0.yml +16 -0
- data/spec/fixtures/dbase_83_record_0.yml +16 -0
- data/spec/fixtures/dbase_83_record_9.yml +23 -0
- 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/spec_helper.rb +2 -0
- metadata +22 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c8808826478c973095384cbe5b0f86e94f96ed8
|
4
|
+
data.tar.gz: 0ccf185436e3753f2bc08cb7211d1dea19e4b438
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9cda0f53ddb72957e83d63504b0d0a58227b05f07623b057cacce2d5325203ebb3419ce8524a82d2ef59b5d5a2dd5a35edcc5f4f5e9cc1bee7e3186b2565a0ae
|
7
|
+
data.tar.gz: 965eaaf92b0274c7e88b88e5c31c02387f95dd9810b25a65b2e41c756e615850e1ad6778265e6aa343b4c189caa040e5610672419337a874693f9cdf3c296af5
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,272 +1,75 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
dbf (2.0.
|
5
|
-
fastercsv (~> 1.5
|
4
|
+
dbf (2.0.9)
|
5
|
+
fastercsv (~> 1.5)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
|
11
|
-
|
12
|
-
debugger-linecache (~> 1.2)
|
13
|
-
celluloid (0.15.2)
|
14
|
-
timers (~> 1.1.0)
|
10
|
+
celluloid (0.16.0)
|
11
|
+
timers (~> 4.0.0)
|
15
12
|
coderay (1.1.0)
|
16
|
-
columnize (0.9.0)
|
17
|
-
debugger-linecache (1.2.0)
|
18
13
|
diff-lcs (1.2.5)
|
19
14
|
fastercsv (1.5.5)
|
20
|
-
ffi (1.9.
|
21
|
-
ffi2-generators (0.1.1)
|
15
|
+
ffi (1.9.8)
|
22
16
|
formatador (0.2.5)
|
23
|
-
guard (2.
|
17
|
+
guard (2.12.5)
|
24
18
|
formatador (>= 0.2.4)
|
25
19
|
listen (~> 2.7)
|
26
20
|
lumberjack (~> 1.0)
|
21
|
+
nenv (~> 0.1)
|
22
|
+
notiffany (~> 0.0)
|
27
23
|
pry (>= 0.9.12)
|
24
|
+
shellany (~> 0.0)
|
28
25
|
thor (>= 0.18.1)
|
29
|
-
guard-
|
26
|
+
guard-compat (1.2.1)
|
27
|
+
guard-rspec (4.5.0)
|
30
28
|
guard (~> 2.1)
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
guard-compat (~> 1.1)
|
30
|
+
rspec (>= 2.99.0, < 4.0)
|
31
|
+
hitimes (1.2.2)
|
32
|
+
listen (2.10.0)
|
33
|
+
celluloid (~> 0.16.0)
|
34
34
|
rb-fsevent (>= 0.9.3)
|
35
35
|
rb-inotify (>= 0.9)
|
36
|
-
lumberjack (1.0.
|
36
|
+
lumberjack (1.0.9)
|
37
37
|
method_source (0.8.2)
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
nenv (0.2.0)
|
39
|
+
notiffany (0.0.6)
|
40
|
+
nenv (~> 0.1)
|
41
|
+
shellany (~> 0.0)
|
42
|
+
pry (0.10.1)
|
43
|
+
coderay (~> 1.1.0)
|
44
|
+
method_source (~> 0.8.1)
|
41
45
|
slop (~> 3.4)
|
42
46
|
rb-fsevent (0.9.4)
|
43
47
|
rb-inotify (0.9.5)
|
44
48
|
ffi (>= 0.5.0)
|
45
|
-
rspec (3.
|
46
|
-
rspec-core (~> 3.
|
47
|
-
rspec-expectations (~> 3.
|
48
|
-
rspec-mocks (~> 3.
|
49
|
-
rspec-core (3.
|
50
|
-
rspec-support (~> 3.
|
51
|
-
rspec-expectations (3.
|
49
|
+
rspec (3.2.0)
|
50
|
+
rspec-core (~> 3.2.0)
|
51
|
+
rspec-expectations (~> 3.2.0)
|
52
|
+
rspec-mocks (~> 3.2.0)
|
53
|
+
rspec-core (3.2.3)
|
54
|
+
rspec-support (~> 3.2.0)
|
55
|
+
rspec-expectations (3.2.1)
|
52
56
|
diff-lcs (>= 1.2.0, < 2.0)
|
53
|
-
rspec-support (~> 3.
|
54
|
-
rspec-mocks (3.
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
rubysl-benchmark (~> 2.0)
|
61
|
-
rubysl-bigdecimal (~> 2.0)
|
62
|
-
rubysl-cgi (~> 2.0)
|
63
|
-
rubysl-cgi-session (~> 2.0)
|
64
|
-
rubysl-cmath (~> 2.0)
|
65
|
-
rubysl-complex (~> 2.0)
|
66
|
-
rubysl-continuation (~> 2.0)
|
67
|
-
rubysl-coverage (~> 2.0)
|
68
|
-
rubysl-csv (~> 2.0)
|
69
|
-
rubysl-curses (~> 2.0)
|
70
|
-
rubysl-date (~> 2.0)
|
71
|
-
rubysl-delegate (~> 2.0)
|
72
|
-
rubysl-digest (~> 2.0)
|
73
|
-
rubysl-drb (~> 2.0)
|
74
|
-
rubysl-e2mmap (~> 2.0)
|
75
|
-
rubysl-english (~> 2.0)
|
76
|
-
rubysl-enumerator (~> 2.0)
|
77
|
-
rubysl-erb (~> 2.0)
|
78
|
-
rubysl-etc (~> 2.0)
|
79
|
-
rubysl-expect (~> 2.0)
|
80
|
-
rubysl-fcntl (~> 2.0)
|
81
|
-
rubysl-fiber (~> 2.0)
|
82
|
-
rubysl-fileutils (~> 2.0)
|
83
|
-
rubysl-find (~> 2.0)
|
84
|
-
rubysl-forwardable (~> 2.0)
|
85
|
-
rubysl-getoptlong (~> 2.0)
|
86
|
-
rubysl-gserver (~> 2.0)
|
87
|
-
rubysl-io-console (~> 2.0)
|
88
|
-
rubysl-io-nonblock (~> 2.0)
|
89
|
-
rubysl-io-wait (~> 2.0)
|
90
|
-
rubysl-ipaddr (~> 2.0)
|
91
|
-
rubysl-irb (~> 2.0)
|
92
|
-
rubysl-logger (~> 2.0)
|
93
|
-
rubysl-mathn (~> 2.0)
|
94
|
-
rubysl-matrix (~> 2.0)
|
95
|
-
rubysl-mkmf (~> 2.0)
|
96
|
-
rubysl-monitor (~> 2.0)
|
97
|
-
rubysl-mutex_m (~> 2.0)
|
98
|
-
rubysl-net-ftp (~> 2.0)
|
99
|
-
rubysl-net-http (~> 2.0)
|
100
|
-
rubysl-net-imap (~> 2.0)
|
101
|
-
rubysl-net-pop (~> 2.0)
|
102
|
-
rubysl-net-protocol (~> 2.0)
|
103
|
-
rubysl-net-smtp (~> 2.0)
|
104
|
-
rubysl-net-telnet (~> 2.0)
|
105
|
-
rubysl-nkf (~> 2.0)
|
106
|
-
rubysl-observer (~> 2.0)
|
107
|
-
rubysl-open-uri (~> 2.0)
|
108
|
-
rubysl-open3 (~> 2.0)
|
109
|
-
rubysl-openssl (~> 2.0)
|
110
|
-
rubysl-optparse (~> 2.0)
|
111
|
-
rubysl-ostruct (~> 2.0)
|
112
|
-
rubysl-pathname (~> 2.0)
|
113
|
-
rubysl-prettyprint (~> 2.0)
|
114
|
-
rubysl-prime (~> 2.0)
|
115
|
-
rubysl-profile (~> 2.0)
|
116
|
-
rubysl-profiler (~> 2.0)
|
117
|
-
rubysl-pstore (~> 2.0)
|
118
|
-
rubysl-pty (~> 2.0)
|
119
|
-
rubysl-rational (~> 2.0)
|
120
|
-
rubysl-readline (~> 2.0)
|
121
|
-
rubysl-resolv (~> 2.0)
|
122
|
-
rubysl-rexml (~> 2.0)
|
123
|
-
rubysl-rinda (~> 2.0)
|
124
|
-
rubysl-rss (~> 2.0)
|
125
|
-
rubysl-scanf (~> 2.0)
|
126
|
-
rubysl-securerandom (~> 2.0)
|
127
|
-
rubysl-set (~> 2.0)
|
128
|
-
rubysl-shellwords (~> 2.0)
|
129
|
-
rubysl-singleton (~> 2.0)
|
130
|
-
rubysl-socket (~> 2.0)
|
131
|
-
rubysl-stringio (~> 2.0)
|
132
|
-
rubysl-strscan (~> 2.0)
|
133
|
-
rubysl-sync (~> 2.0)
|
134
|
-
rubysl-syslog (~> 2.0)
|
135
|
-
rubysl-tempfile (~> 2.0)
|
136
|
-
rubysl-thread (~> 2.0)
|
137
|
-
rubysl-thwait (~> 2.0)
|
138
|
-
rubysl-time (~> 2.0)
|
139
|
-
rubysl-timeout (~> 2.0)
|
140
|
-
rubysl-tmpdir (~> 2.0)
|
141
|
-
rubysl-tsort (~> 2.0)
|
142
|
-
rubysl-un (~> 2.0)
|
143
|
-
rubysl-uri (~> 2.0)
|
144
|
-
rubysl-weakref (~> 2.0)
|
145
|
-
rubysl-webrick (~> 2.0)
|
146
|
-
rubysl-xmlrpc (~> 2.0)
|
147
|
-
rubysl-yaml (~> 2.0)
|
148
|
-
rubysl-zlib (~> 2.0)
|
149
|
-
rubysl-abbrev (2.0.4)
|
150
|
-
rubysl-base64 (2.0.0)
|
151
|
-
rubysl-benchmark (2.0.1)
|
152
|
-
rubysl-bigdecimal (2.0.2)
|
153
|
-
rubysl-cgi (2.0.1)
|
154
|
-
rubysl-cgi-session (2.0.1)
|
155
|
-
rubysl-cmath (2.0.0)
|
156
|
-
rubysl-complex (2.0.0)
|
157
|
-
rubysl-continuation (2.0.0)
|
158
|
-
rubysl-coverage (2.0.3)
|
159
|
-
rubysl-csv (2.0.2)
|
160
|
-
rubysl-english (~> 2.0)
|
161
|
-
rubysl-curses (2.0.1)
|
162
|
-
rubysl-date (2.0.6)
|
163
|
-
rubysl-delegate (2.0.1)
|
164
|
-
rubysl-digest (2.0.3)
|
165
|
-
rubysl-drb (2.0.1)
|
166
|
-
rubysl-e2mmap (2.0.0)
|
167
|
-
rubysl-english (2.0.0)
|
168
|
-
rubysl-enumerator (2.0.0)
|
169
|
-
rubysl-erb (2.0.1)
|
170
|
-
rubysl-etc (2.0.3)
|
171
|
-
ffi2-generators (~> 0.1)
|
172
|
-
rubysl-expect (2.0.0)
|
173
|
-
rubysl-fcntl (2.0.4)
|
174
|
-
ffi2-generators (~> 0.1)
|
175
|
-
rubysl-fiber (2.0.0)
|
176
|
-
rubysl-fileutils (2.0.3)
|
177
|
-
rubysl-find (2.0.1)
|
178
|
-
rubysl-forwardable (2.0.1)
|
179
|
-
rubysl-getoptlong (2.0.0)
|
180
|
-
rubysl-gserver (2.0.0)
|
181
|
-
rubysl-socket (~> 2.0)
|
182
|
-
rubysl-thread (~> 2.0)
|
183
|
-
rubysl-io-console (2.0.0)
|
184
|
-
rubysl-io-nonblock (2.0.0)
|
185
|
-
rubysl-io-wait (2.0.0)
|
186
|
-
rubysl-ipaddr (2.0.0)
|
187
|
-
rubysl-irb (2.0.4)
|
188
|
-
rubysl-e2mmap (~> 2.0)
|
189
|
-
rubysl-mathn (~> 2.0)
|
190
|
-
rubysl-readline (~> 2.0)
|
191
|
-
rubysl-thread (~> 2.0)
|
192
|
-
rubysl-logger (2.0.0)
|
193
|
-
rubysl-mathn (2.0.0)
|
194
|
-
rubysl-matrix (2.1.0)
|
195
|
-
rubysl-e2mmap (~> 2.0)
|
196
|
-
rubysl-mkmf (2.0.1)
|
197
|
-
rubysl-fileutils (~> 2.0)
|
198
|
-
rubysl-shellwords (~> 2.0)
|
199
|
-
rubysl-monitor (2.0.0)
|
200
|
-
rubysl-mutex_m (2.0.0)
|
201
|
-
rubysl-net-ftp (2.0.1)
|
202
|
-
rubysl-net-http (2.0.4)
|
203
|
-
rubysl-cgi (~> 2.0)
|
204
|
-
rubysl-erb (~> 2.0)
|
205
|
-
rubysl-singleton (~> 2.0)
|
206
|
-
rubysl-net-imap (2.0.1)
|
207
|
-
rubysl-net-pop (2.0.1)
|
208
|
-
rubysl-net-protocol (2.0.1)
|
209
|
-
rubysl-net-smtp (2.0.1)
|
210
|
-
rubysl-net-telnet (2.0.0)
|
211
|
-
rubysl-nkf (2.0.1)
|
212
|
-
rubysl-observer (2.0.0)
|
213
|
-
rubysl-open-uri (2.0.0)
|
214
|
-
rubysl-open3 (2.0.0)
|
215
|
-
rubysl-openssl (2.1.0)
|
216
|
-
rubysl-optparse (2.0.1)
|
217
|
-
rubysl-shellwords (~> 2.0)
|
218
|
-
rubysl-ostruct (2.0.4)
|
219
|
-
rubysl-pathname (2.0.0)
|
220
|
-
rubysl-prettyprint (2.0.3)
|
221
|
-
rubysl-prime (2.0.1)
|
222
|
-
rubysl-profile (2.0.0)
|
223
|
-
rubysl-profiler (2.0.1)
|
224
|
-
rubysl-pstore (2.0.0)
|
225
|
-
rubysl-pty (2.0.2)
|
226
|
-
rubysl-rational (2.0.1)
|
227
|
-
rubysl-readline (2.0.2)
|
228
|
-
rubysl-resolv (2.1.0)
|
229
|
-
rubysl-rexml (2.0.2)
|
230
|
-
rubysl-rinda (2.0.1)
|
231
|
-
rubysl-rss (2.0.0)
|
232
|
-
rubysl-scanf (2.0.0)
|
233
|
-
rubysl-securerandom (2.0.0)
|
234
|
-
rubysl-set (2.0.1)
|
235
|
-
rubysl-shellwords (2.0.0)
|
236
|
-
rubysl-singleton (2.0.0)
|
237
|
-
rubysl-socket (2.0.1)
|
238
|
-
rubysl-stringio (2.0.0)
|
239
|
-
rubysl-strscan (2.0.0)
|
240
|
-
rubysl-sync (2.0.0)
|
241
|
-
rubysl-syslog (2.0.1)
|
242
|
-
ffi2-generators (~> 0.1)
|
243
|
-
rubysl-tempfile (2.0.1)
|
244
|
-
rubysl-thread (2.0.2)
|
245
|
-
rubysl-thwait (2.0.0)
|
246
|
-
rubysl-time (2.0.3)
|
247
|
-
rubysl-timeout (2.0.0)
|
248
|
-
rubysl-tmpdir (2.0.1)
|
249
|
-
rubysl-tsort (2.0.1)
|
250
|
-
rubysl-un (2.0.0)
|
251
|
-
rubysl-fileutils (~> 2.0)
|
252
|
-
rubysl-optparse (~> 2.0)
|
253
|
-
rubysl-uri (2.0.0)
|
254
|
-
rubysl-weakref (2.0.0)
|
255
|
-
rubysl-webrick (2.0.0)
|
256
|
-
rubysl-xmlrpc (2.0.0)
|
257
|
-
rubysl-yaml (2.0.4)
|
258
|
-
rubysl-zlib (2.0.1)
|
259
|
-
slop (3.5.0)
|
57
|
+
rspec-support (~> 3.2.0)
|
58
|
+
rspec-mocks (3.2.1)
|
59
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
60
|
+
rspec-support (~> 3.2.0)
|
61
|
+
rspec-support (3.2.2)
|
62
|
+
shellany (0.0.1)
|
63
|
+
slop (3.6.0)
|
260
64
|
thor (0.19.1)
|
261
|
-
timers (
|
65
|
+
timers (4.0.1)
|
66
|
+
hitimes
|
262
67
|
|
263
68
|
PLATFORMS
|
264
69
|
ruby
|
265
70
|
|
266
71
|
DEPENDENCIES
|
267
|
-
byebug
|
268
72
|
dbf!
|
269
73
|
guard
|
270
74
|
guard-rspec
|
271
75
|
rspec
|
272
|
-
rubysl
|
data/Gemfile.travis
CHANGED
data/Guardfile
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
# A sample Guardfile
|
2
2
|
# More info at https://github.com/guard/guard#readme
|
3
3
|
|
4
|
-
guard :rspec do
|
4
|
+
guard :rspec, cmd: 'bundle exec rspec' do
|
5
5
|
watch(%r{^spec/.+_spec\.rb$})
|
6
|
-
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
7
|
-
watch(
|
6
|
+
# watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
7
|
+
watch(%r{^lib/(.+)\.rb$}) { 'spec' }
|
8
|
+
watch('spec/spec_helper.rb') { 'spec' }
|
9
|
+
watch(/spec\/fixtures\/(.+)/) { 'spec' }
|
10
|
+
watch('Guardfile') { 'spec' }
|
8
11
|
end
|
data/README.md
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
[![Code Quality](http://img.shields.io/codeclimate/github/infused/dbf.svg?style=flat)](https://codeclimate.com/github/infused/dbf)
|
5
5
|
[![Test Coverage](http://img.shields.io/codeclimate/coverage/github/infused/dbf.svg?style=flat)](https://codeclimate.com/github/infused/dbf)
|
6
6
|
[![Dependency Status](http://img.shields.io/gemnasium/infused/dbf.svg?style=flat)](https://gemnasium.com/infused/dbf)
|
7
|
+
[![Issues](https://img.shields.io/github/issues/infused/dbf.svg)](https://github.com/infused/dbf/issues)
|
8
|
+
[![Total Downloads](https://img.shields.io/gem/dt/dbf.svg)](https://rubygems.org/gems/dbf/)
|
7
9
|
|
8
10
|
DBF is a small fast library for reading dBase, xBase, Clipper and FoxPro
|
9
11
|
database files
|
@@ -18,7 +20,7 @@ database files
|
|
18
20
|
|
19
21
|
DBF is tested to work with the following versions of ruby:
|
20
22
|
|
21
|
-
* MRI Ruby 1.8.6, 1.8.7, 1.9.1, 1.9.2, 1.9.3, 2.0.x, 2.1.x
|
23
|
+
* MRI Ruby 1.8.6, 1.8.7, 1.9.1, 1.9.2, 1.9.3, 2.0.x, 2.1.x, 2.2.x
|
22
24
|
* JRuby 1.7.x (1.8 and 1.9 modes), JRuby head
|
23
25
|
* REE 1.8.7
|
24
26
|
* Rubinius 2.1+
|
@@ -98,6 +100,23 @@ widgets.find :first, :slot_number => 's42'
|
|
98
100
|
widgets.find(10)
|
99
101
|
```
|
100
102
|
|
103
|
+
## Enumeration
|
104
|
+
|
105
|
+
DBF::Table is a Ruby Enumerable. This means you can use any Enumerable method.
|
106
|
+
This means that you get a bunch of traversal, searching and sorting methods
|
107
|
+
for free. For example, let's get only records created before January 1st, 2015:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
widgets.select { |w| w.created_date < Date.new(2015, 1, 1) }
|
111
|
+
```
|
112
|
+
|
113
|
+
Or custom sorting:
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
widgets.sort_by { |w| w.created_date }
|
117
|
+
```
|
118
|
+
|
119
|
+
|
101
120
|
## Encodings (Code Pages)
|
102
121
|
|
103
122
|
dBase supports encoding non-english characters in different formats.
|
@@ -158,6 +177,19 @@ Dump all records to a CSV file:
|
|
158
177
|
|
159
178
|
dbf -c books.dbf > books.csv
|
160
179
|
|
180
|
+
## Reading a Visual Foxpro database (v8, v9)
|
181
|
+
|
182
|
+
A special Database::Foxpro class is available to read Visual Foxpro container files (.dbc-files). When using this class,
|
183
|
+
long fieldnames are supported and tables can be references without using names.
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
require 'dbf'
|
187
|
+
|
188
|
+
contacts = DBF::Database::Foxpro.new('contactdatabase.dbc').contacts
|
189
|
+
mycontact = contacts.record(1).spouses_interests
|
190
|
+
```
|
191
|
+
|
192
|
+
|
161
193
|
## dBase version compatibility
|
162
194
|
|
163
195
|
The basic dBase data types are generally supported well. Support for the
|
data/Rakefile
CHANGED
data/dbf.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
lib = File.expand_path('../lib/', __FILE__)
|
2
|
-
|
2
|
+
$LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
|
3
3
|
require 'dbf/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
@@ -12,6 +12,7 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.description = 'A small fast library for reading dBase, xBase, Clipper and FoxPro database files.'
|
13
13
|
s.license = 'MIT'
|
14
14
|
|
15
|
+
s.bindir = 'bin'
|
15
16
|
s.executables = ['dbf']
|
16
17
|
s.rdoc_options = ['--charset=UTF-8']
|
17
18
|
s.extra_rdoc_files = ['README.md', 'CHANGELOG.md', 'LICENSE']
|
data/lib/dbf.rb
CHANGED
data/lib/dbf/column/base.rb
CHANGED
@@ -24,12 +24,12 @@ module DBF
|
|
24
24
|
@version = table.version
|
25
25
|
@encoding = table.encoding
|
26
26
|
|
27
|
-
unless length
|
28
|
-
raise LengthError,
|
27
|
+
unless length >= 0
|
28
|
+
raise LengthError, 'field length must be 0 or greater'
|
29
29
|
end
|
30
30
|
|
31
31
|
if @name.empty?
|
32
|
-
raise NameError,
|
32
|
+
raise NameError, 'column name cannot be empty'
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -38,6 +38,8 @@ module DBF
|
|
38
38
|
# @param [String] value
|
39
39
|
# @return [Fixnum, Float, Date, DateTime, Boolean, String]
|
40
40
|
def type_cast(value)
|
41
|
+
return nil if length == 0
|
42
|
+
|
41
43
|
case type
|
42
44
|
when 'N' then unpack_number(value)
|
43
45
|
when 'I' then unpack_unsigned_long(value)
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module DBF
|
2
|
+
# DBF::Database::Foxpro is the primary interface to a Visual Foxpro database container (.dbc file).
|
3
|
+
# When using this database container, long fieldnames are supported, and you can reference tables
|
4
|
+
# directly instead of instantiating Table objects yourself.
|
5
|
+
# Table references are created based on the filename, but it this class tries to correct the
|
6
|
+
# table filenames because they could be wrong for case sensitive filesystems, e.g. when
|
7
|
+
# a foxpro database is uploaded to a linux server.
|
8
|
+
module Database
|
9
|
+
|
10
|
+
class Foxpro
|
11
|
+
# Opens a DBF::Database::Foxpro
|
12
|
+
# Examples:
|
13
|
+
# # working with a database stored on the filesystem
|
14
|
+
# db = DBF::Database::Foxpro.new 'path_to_db/database.dbc'
|
15
|
+
#
|
16
|
+
# # Calling a table
|
17
|
+
# contacts = db.contacts.record(0)
|
18
|
+
def initialize(path)
|
19
|
+
begin
|
20
|
+
@path = path
|
21
|
+
@dirname = File.dirname(@path)
|
22
|
+
@db = DBF::Table.new(@path)
|
23
|
+
@tables = extract_dbc_data
|
24
|
+
|
25
|
+
rescue Errno::ENOENT
|
26
|
+
raise DBF::FileNotFoundError.new("file not found: #{data}")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def table_names
|
31
|
+
@tables.keys
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns table with given name
|
35
|
+
# @return Table
|
36
|
+
def table(name)
|
37
|
+
Table.new(table_path name) do |table|
|
38
|
+
table.long_names = @tables[name]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Searches the database directory for the table's dbf file
|
43
|
+
# and returns the absolute path. Ensures case-insensitivity
|
44
|
+
# on any platform.
|
45
|
+
# @return String
|
46
|
+
def table_path(name)
|
47
|
+
example = File.join(@dirname, "#{name}.dbf")
|
48
|
+
glob = File.join(@dirname, '*')
|
49
|
+
path = Dir.glob(glob).find { |match| match.downcase == example.downcase }
|
50
|
+
|
51
|
+
unless path && File.exist?(path)
|
52
|
+
raise DBF::FileNotFoundError.new("related table not found: #{name}")
|
53
|
+
end
|
54
|
+
|
55
|
+
path
|
56
|
+
end
|
57
|
+
|
58
|
+
def method_missing(method, *args) # nodoc
|
59
|
+
if index = table_names.index(method.to_s)
|
60
|
+
table method.to_s
|
61
|
+
else
|
62
|
+
super
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# This method extracts the data from the database container. This is just an ordinary table
|
69
|
+
# with a treelike structure. Field definitions are in the same order as in the linked tables
|
70
|
+
# but only the long name is provided.
|
71
|
+
def extract_dbc_data # nodoc
|
72
|
+
data = {}
|
73
|
+
@db.each do |record|
|
74
|
+
next unless record
|
75
|
+
|
76
|
+
case record.objecttype
|
77
|
+
when 'Table'
|
78
|
+
# This is a related table
|
79
|
+
data[record.objectid] = {:name => record.objectname, :fields => []}
|
80
|
+
when 'Field'
|
81
|
+
# This is a related field. The parentid points to the table object.
|
82
|
+
# Create using the parentid if the parentid is still unknown.
|
83
|
+
data[record.parentid] ||= {:name => "UNKNOWN", :fields => []}
|
84
|
+
data[record.parentid][:fields] << record.objectname
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
Hash[data.values.map {|v| [v[:name], v[:fields]] }]
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
class Table < DBF::Table
|
94
|
+
attr_accessor :long_names
|
95
|
+
|
96
|
+
def build_columns # nodoc
|
97
|
+
columns = super
|
98
|
+
|
99
|
+
# modify the column definitions to use the long names as the
|
100
|
+
# columnname property is readonly, recreate the column definitions
|
101
|
+
columns.map do |column|
|
102
|
+
long_name = long_names[columns.index(column)]
|
103
|
+
column_class.new(self, long_name, column.type, column.length, column.decimal)
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/dbf/table.rb
CHANGED
@@ -68,6 +68,7 @@ module DBF
|
|
68
68
|
@header = Header.new(@data.read(DBF_HEADER_SIZE), supports_encoding?)
|
69
69
|
@encoding = encoding || header.encoding
|
70
70
|
@memo = open_memo(data, memo)
|
71
|
+
yield self if block_given?
|
71
72
|
rescue Errno::ENOENT => error
|
72
73
|
raise DBF::FileNotFoundError.new("file not found: #{data}")
|
73
74
|
end
|
data/lib/dbf/version.rb
CHANGED
data/spec/dbf/column_spec.rb
CHANGED
@@ -24,10 +24,9 @@ describe DBF::Column::Dbase do
|
|
24
24
|
expect(column.decimal).to eq 0
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
27
|
+
it 'accepts length of 0' do
|
28
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "N", 0, 0
|
29
|
+
expect(column.length).to eq 0
|
31
30
|
end
|
32
31
|
|
33
32
|
describe 'with length less than 0' do
|
@@ -45,6 +44,13 @@ describe DBF::Column::Dbase do
|
|
45
44
|
|
46
45
|
context '#type_cast' do
|
47
46
|
context 'with type N (number)' do
|
47
|
+
context 'and 0 length' do
|
48
|
+
it 'returns nil' do
|
49
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "N", 0, 0
|
50
|
+
expect(column.type_cast('')).to be_nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
48
54
|
context 'and 0 decimals' do
|
49
55
|
it 'casts value to Fixnum' do
|
50
56
|
value = '135'
|
@@ -65,6 +71,13 @@ describe DBF::Column::Dbase do
|
|
65
71
|
end
|
66
72
|
|
67
73
|
context 'with type F (float)' do
|
74
|
+
context 'and 0 length' do
|
75
|
+
it 'returns nil' do
|
76
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "F", 0, 0
|
77
|
+
expect(column.type_cast('')).to be_nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
68
81
|
it 'casts value to Float' do
|
69
82
|
value = '135'
|
70
83
|
column = DBF::Column::Dbase.new table, "ColumnName", "F", 3, 0
|
@@ -74,6 +87,13 @@ describe DBF::Column::Dbase do
|
|
74
87
|
end
|
75
88
|
|
76
89
|
context 'with type I (integer)' do
|
90
|
+
context 'and 0 length' do
|
91
|
+
it 'returns nil' do
|
92
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "I", 0, 0
|
93
|
+
expect(column.type_cast('')).to be_nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
77
97
|
it "casts value to Fixnum" do
|
78
98
|
value = "\203\171\001\000"
|
79
99
|
column = DBF::Column::Dbase.new table, "ColumnName", "I", 3, 0
|
@@ -96,6 +116,13 @@ describe DBF::Column::Dbase do
|
|
96
116
|
it "casts value other than 't' or 'y' to false" do
|
97
117
|
expect(column.type_cast('n')).to be false
|
98
118
|
end
|
119
|
+
|
120
|
+
context 'and 0 length' do
|
121
|
+
it 'returns nil' do
|
122
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "L", 0, 0
|
123
|
+
expect(column.type_cast('')).to be_nil
|
124
|
+
end
|
125
|
+
end
|
99
126
|
end
|
100
127
|
|
101
128
|
context 'with type T (datetime)' do
|
@@ -127,6 +154,13 @@ describe DBF::Column::Dbase do
|
|
127
154
|
expect(column.type_cast("Nl%\000\000A\000\999")).to be_nil
|
128
155
|
end
|
129
156
|
end
|
157
|
+
|
158
|
+
context 'and 0 length' do
|
159
|
+
it 'returns nil' do
|
160
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "T", 0, 0
|
161
|
+
expect(column.type_cast('')).to be_nil
|
162
|
+
end
|
163
|
+
end
|
130
164
|
end
|
131
165
|
|
132
166
|
context 'with type D (date)' do
|
@@ -145,6 +179,13 @@ describe DBF::Column::Dbase do
|
|
145
179
|
expect(column.type_cast("0")).to be_nil
|
146
180
|
end
|
147
181
|
end
|
182
|
+
|
183
|
+
context 'and 0 length' do
|
184
|
+
it 'returns nil' do
|
185
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "D", 0, 0
|
186
|
+
expect(column.type_cast('')).to be_nil
|
187
|
+
end
|
188
|
+
end
|
148
189
|
end
|
149
190
|
|
150
191
|
context 'with type M (memo)' do
|
@@ -159,6 +200,13 @@ describe DBF::Column::Dbase do
|
|
159
200
|
expect(column.type_cast(nil)).to be_a(NilClass)
|
160
201
|
expect(column.type_cast(nil)).to be_nil
|
161
202
|
end
|
203
|
+
|
204
|
+
context 'and 0 length' do
|
205
|
+
it 'returns nil' do
|
206
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "M", 0, 0
|
207
|
+
expect(column.type_cast('')).to be_nil
|
208
|
+
end
|
209
|
+
end
|
162
210
|
end
|
163
211
|
end
|
164
212
|
|
@@ -169,6 +217,13 @@ describe DBF::Column::Dbase do
|
|
169
217
|
expect(column.type_cast(" \xBF\x02\x00\x00\x00\x00\x00")).to be_a(Float)
|
170
218
|
expect(column.type_cast(" \xBF\x02\x00\x00\x00\x00\x00")).to eq 18.0
|
171
219
|
end
|
220
|
+
|
221
|
+
context 'and 0 length' do
|
222
|
+
it 'returns nil' do
|
223
|
+
column = DBF::Column::Dbase.new table, "ColumnName", "Y", 0, 0
|
224
|
+
expect(column.type_cast('')).to be_nil
|
225
|
+
end
|
226
|
+
end
|
172
227
|
end
|
173
228
|
|
174
229
|
context "#schema_definition" do
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DBF::Database::Foxpro do
|
4
|
+
let(:dbf_path) { fixture_path('foxprodb/FOXPRO-DB-TEST.DBC') }
|
5
|
+
let(:db) { DBF::Database::Foxpro.new(dbf_path) }
|
6
|
+
|
7
|
+
describe '#initialize' do
|
8
|
+
describe 'when given a path to an existing dbc file' do
|
9
|
+
it 'does not raise an error' do
|
10
|
+
expect { DBF::Database::Foxpro.new dbf_path }.to_not raise_error
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'when given a path to a non-existent dbf file' do
|
15
|
+
it 'raises a DBF::FileNotFound error' do
|
16
|
+
expect { DBF::Database::Foxpro.new 'x' }.to raise_error(DBF::FileNotFoundError, 'file not found: x')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'it loads the example db correctly' do
|
21
|
+
it 'shows a correct list of tables' do
|
22
|
+
expect(db.table_names.sort).to eq(%w(contacts calls setup types).sort)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#table' do
|
28
|
+
describe "when accessing related tables" do
|
29
|
+
let(:db) { DBF::Database::Foxpro.new(dbf_path) }
|
30
|
+
|
31
|
+
it 'loads an existing related table' do
|
32
|
+
expect(db.contacts.record_count).to eq 5
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'supports a long table field name' do
|
36
|
+
expect(db.contacts.record(1).spouses_interests).to eq 'Tennis, golf'
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'loads an existing related table with wrong filename casing' do
|
40
|
+
expect(db.calls.record_count).to eq 16
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#table_path' do
|
46
|
+
it 'returns an absolute path' do
|
47
|
+
expect(db.table_path('contacts')).to eq File.expand_path('spec/fixtures/foxprodb/contacts.dbf')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/spec/dbf/record_spec.rb
CHANGED
@@ -4,22 +4,25 @@ describe DBF::Record do
|
|
4
4
|
|
5
5
|
describe '#to_a' do
|
6
6
|
let(:table) { DBF::Table.new fixture_path('dbase_83.dbf') }
|
7
|
+
let(:record_0) { YAML.load_file(fixture_path('dbase_83_record_0.yml')) }
|
8
|
+
let(:record_9) { YAML.load_file(fixture_path('dbase_83_record_9.yml')) }
|
7
9
|
|
8
10
|
it 'should return an ordered array of attribute values' do
|
9
11
|
record = table.record(0)
|
10
|
-
expect(record.to_a).to eq
|
12
|
+
expect(record.to_a).to eq record_0
|
11
13
|
|
12
14
|
record = table.record(9)
|
13
|
-
expect(record.to_a).to eq
|
15
|
+
expect(record.to_a).to eq record_9
|
14
16
|
end
|
15
17
|
|
16
18
|
describe 'with missing memo file' do
|
17
19
|
describe 'when opening a path' do
|
18
20
|
let(:table) { DBF::Table.new fixture_path('dbase_83_missing_memo.dbf') }
|
21
|
+
let(:record_0) { YAML.load_file(fixture_path('dbase_83_missing_memo_record_0.yml')) }
|
19
22
|
|
20
23
|
it 'returns nil values for memo fields' do
|
21
24
|
record = table.record(0)
|
22
|
-
expect(record.to_a).to eq
|
25
|
+
expect(record.to_a).to eq record_0
|
23
26
|
end
|
24
27
|
end
|
25
28
|
end
|
@@ -27,10 +30,11 @@ describe DBF::Record do
|
|
27
30
|
describe 'when opening StringIO' do
|
28
31
|
let(:data) { StringIO.new(File.read(fixture_path('dbase_83_missing_memo.dbf'))) }
|
29
32
|
let(:table) { DBF::Table.new(data) }
|
33
|
+
let(:record_0) { YAML.load_file(fixture_path('dbase_83_missing_memo_record_0.yml')) }
|
30
34
|
|
31
35
|
it 'returns nil values for memo fields' do
|
32
36
|
record = table.record(0)
|
33
|
-
expect(record.to_a).to eq
|
37
|
+
expect(record.to_a).to eq record_0
|
34
38
|
end
|
35
39
|
end
|
36
40
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
---
|
2
|
+
- 87
|
3
|
+
- 2
|
4
|
+
- 0
|
5
|
+
- 0
|
6
|
+
- 87
|
7
|
+
- '1'
|
8
|
+
- Assorted Petits Fours
|
9
|
+
- graphics/00000001/t_1.jpg
|
10
|
+
- graphics/00000001/1.jpg
|
11
|
+
- 0.0
|
12
|
+
- 0.0
|
13
|
+
- "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."
|
14
|
+
- 5.51
|
15
|
+
- true
|
16
|
+
- true
|
@@ -0,0 +1,23 @@
|
|
1
|
+
---
|
2
|
+
- 34
|
3
|
+
- 1
|
4
|
+
- 0
|
5
|
+
- 0
|
6
|
+
- 34
|
7
|
+
- AB01
|
8
|
+
- Apricot Brandy Fruitcake
|
9
|
+
- graphics/00000001/t_AB01.jpg
|
10
|
+
- graphics/00000001/AB01.jpg
|
11
|
+
- 37.95
|
12
|
+
- 37.95
|
13
|
+
- "Once tasted you will understand why we won The\r\nBoston Herald's Fruitcake Taste-off.
|
14
|
+
Judges liked its generous size,\r\nluscious appearance, moist texture and fruit
|
15
|
+
to cake ratio ... commented one\r\njudge \"It's a lip Smacker!\" Our signature fruitcake
|
16
|
+
is baked with carefully\r\nselected ingredients that will be savored until the last
|
17
|
+
moist crumb is\r\ndevoured each golden slice is brimming with Australian glaced
|
18
|
+
apricots,\r\ntoasted pecans, candied orange peel, and currants, folded gently into
|
19
|
+
a\r\nbrandy butter batter and slowly baked to perfection and then generously\r\nimbibed
|
20
|
+
with \"Holiday Spirits\". Presented in a gift tin. (3lbs. 4oz)"
|
21
|
+
- 0.0
|
22
|
+
- false
|
23
|
+
- true
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dbf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keith Morrison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fastercsv
|
@@ -52,6 +52,7 @@ files:
|
|
52
52
|
- lib/dbf/column/base.rb
|
53
53
|
- lib/dbf/column/dbase.rb
|
54
54
|
- lib/dbf/column/foxpro.rb
|
55
|
+
- lib/dbf/database/foxpro.rb
|
55
56
|
- lib/dbf/encodings.rb
|
56
57
|
- lib/dbf/header.rb
|
57
58
|
- lib/dbf/memo/base.rb
|
@@ -63,6 +64,7 @@ files:
|
|
63
64
|
- lib/dbf/table.rb
|
64
65
|
- lib/dbf/version.rb
|
65
66
|
- spec/dbf/column_spec.rb
|
67
|
+
- spec/dbf/database_spec.rb
|
66
68
|
- spec/dbf/file_formats_spec.rb
|
67
69
|
- spec/dbf/record_spec.rb
|
68
70
|
- spec/dbf/table_spec.rb
|
@@ -74,11 +76,27 @@ files:
|
|
74
76
|
- spec/fixtures/dbase_83.dbf
|
75
77
|
- spec/fixtures/dbase_83.dbt
|
76
78
|
- spec/fixtures/dbase_83_missing_memo.dbf
|
79
|
+
- spec/fixtures/dbase_83_missing_memo_record_0.yml
|
80
|
+
- spec/fixtures/dbase_83_record_0.yml
|
81
|
+
- spec/fixtures/dbase_83_record_9.yml
|
77
82
|
- spec/fixtures/dbase_83_schema.txt
|
78
83
|
- spec/fixtures/dbase_8b.dbf
|
79
84
|
- spec/fixtures/dbase_8b.dbt
|
80
85
|
- spec/fixtures/dbase_f5.dbf
|
81
86
|
- spec/fixtures/dbase_f5.fpt
|
87
|
+
- spec/fixtures/foxprodb/FOXPRO-DB-TEST.DBC
|
88
|
+
- spec/fixtures/foxprodb/FOXPRO-DB-TEST.DCT
|
89
|
+
- spec/fixtures/foxprodb/FOXPRO-DB-TEST.DCX
|
90
|
+
- spec/fixtures/foxprodb/calls.CDX
|
91
|
+
- spec/fixtures/foxprodb/calls.FPT
|
92
|
+
- spec/fixtures/foxprodb/calls.dbf
|
93
|
+
- spec/fixtures/foxprodb/contacts.CDX
|
94
|
+
- spec/fixtures/foxprodb/contacts.FPT
|
95
|
+
- spec/fixtures/foxprodb/contacts.dbf
|
96
|
+
- spec/fixtures/foxprodb/setup.CDX
|
97
|
+
- spec/fixtures/foxprodb/setup.dbf
|
98
|
+
- spec/fixtures/foxprodb/types.CDX
|
99
|
+
- spec/fixtures/foxprodb/types.dbf
|
82
100
|
- spec/spec_helper.rb
|
83
101
|
homepage: http://github.com/infused/dbf
|
84
102
|
licenses:
|
@@ -101,12 +119,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
119
|
version: 1.3.0
|
102
120
|
requirements: []
|
103
121
|
rubyforge_project:
|
104
|
-
rubygems_version: 2.4.
|
122
|
+
rubygems_version: 2.4.6
|
105
123
|
signing_key:
|
106
124
|
specification_version: 4
|
107
125
|
summary: Read xBase files
|
108
126
|
test_files:
|
109
127
|
- spec/dbf/column_spec.rb
|
128
|
+
- spec/dbf/database_spec.rb
|
110
129
|
- spec/dbf/file_formats_spec.rb
|
111
130
|
- spec/dbf/record_spec.rb
|
112
131
|
- spec/dbf/table_spec.rb
|