dbf 3.1.3 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +8 -3
- data/LICENSE +1 -1
- data/README.md +5 -4
- data/bin/dbf +2 -2
- data/dbf.gemspec +1 -1
- data/lib/dbf.rb +1 -0
- data/lib/dbf/column.rb +3 -8
- data/lib/dbf/column_type.rb +9 -9
- data/lib/dbf/database/foxpro.rb +1 -3
- data/lib/dbf/memo/base.rb +1 -0
- data/lib/dbf/memo/dbase4.rb +1 -1
- data/lib/dbf/memo/foxpro.rb +2 -3
- data/lib/dbf/record.rb +1 -1
- data/lib/dbf/table.rb +14 -20
- data/lib/dbf/version.rb +1 -1
- data/spec/dbf/column_spec.rb +9 -9
- data/spec/dbf/file_formats_spec.rb +25 -25
- data/spec/dbf/record_spec.rb +5 -5
- data/spec/dbf/table_spec.rb +14 -14
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c958b14933bbb6d5a9f1e4489b61603d68e43d5fc39331267aac586c324a9afb
|
4
|
+
data.tar.gz: 43714e5ff6c6c67f5e0d77fd0c6f7485466545ace2e3d911937076bb74ff4a23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1b0f3d7edf0b5ec26d748c1c1f67be7877c4f150cb9adb14d0eb2994c3515ba466d803e3bc94c3111608c574908b54d1fd69077591e676ca75ea24cb81db6be
|
7
|
+
data.tar.gz: 28358a00908e6f8bdaec6e74731b9961380a87c67e43dab21971bd686b7aef6fa6ba554faedee3168082a62125fd4dda24d23b257b5f1fa536b3313a8e2ef7a8
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
dbf (
|
4
|
+
dbf (4.0.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -27,6 +27,7 @@ GEM
|
|
27
27
|
guard (~> 2.1)
|
28
28
|
guard-compat (~> 1.1)
|
29
29
|
rspec (>= 2.99.0, < 4.0)
|
30
|
+
irb (1.0.0)
|
30
31
|
jaro_winkler (1.5.1)
|
31
32
|
listen (3.1.5)
|
32
33
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
@@ -56,7 +57,7 @@ GEM
|
|
56
57
|
rspec-mocks (~> 3.8.0)
|
57
58
|
rspec-core (3.8.0)
|
58
59
|
rspec-support (~> 3.8.0)
|
59
|
-
rspec-expectations (3.8.
|
60
|
+
rspec-expectations (3.8.2)
|
60
61
|
diff-lcs (>= 1.2.0, < 2.0)
|
61
62
|
rspec-support (~> 3.8.0)
|
62
63
|
rspec-mocks (3.8.0)
|
@@ -71,6 +72,8 @@ GEM
|
|
71
72
|
rainbow (>= 2.2.2, < 4.0)
|
72
73
|
ruby-progressbar (~> 1.7)
|
73
74
|
unicode-display_width (~> 1.0, >= 1.0.1)
|
75
|
+
rubocop-rspec (1.30.0)
|
76
|
+
rubocop (>= 0.58.0)
|
74
77
|
ruby-progressbar (1.10.0)
|
75
78
|
ruby_dep (1.5.0)
|
76
79
|
shellany (0.0.1)
|
@@ -86,9 +89,11 @@ DEPENDENCIES
|
|
86
89
|
dbf!
|
87
90
|
guard
|
88
91
|
guard-rspec
|
92
|
+
irb
|
89
93
|
rake
|
90
94
|
rspec
|
91
95
|
rubocop
|
96
|
+
rubocop-rspec
|
92
97
|
|
93
98
|
BUNDLED WITH
|
94
|
-
|
99
|
+
2.0.0
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -16,14 +16,15 @@ database files
|
|
16
16
|
subject line
|
17
17
|
* Change log: <https://github.com/infused/dbf/blob/master/CHANGELOG.md>
|
18
18
|
|
19
|
-
NOTE:
|
19
|
+
NOTE: Beginninf with version 4 we have dropped support for Ruby 2.0, 2.1, 2.2, and 2.3. If you need support for these older Rubies, please use 3.0.x (https://github.com/infused.org/dbf/tree/3_stable)
|
20
|
+
|
21
|
+
NOTE: Beginning with version 3 we have dropped support for Ruby 1.8 and 1.9. If you need support for older Rubies, please use 2.0.x (https://github.com/infused/dbf/tree/2_stable)
|
20
22
|
|
21
23
|
## Compatibility
|
22
24
|
|
23
25
|
DBF is tested to work with the following versions of Ruby:
|
24
26
|
|
25
|
-
*
|
26
|
-
* JRuby 1.7.x
|
27
|
+
* Ruby 2.3.x, 2.4.x, 2.5.x, 2.6.x
|
27
28
|
|
28
29
|
## Installation
|
29
30
|
|
@@ -272,7 +273,7 @@ for a full list of supported column types.
|
|
272
273
|
|
273
274
|
## License
|
274
275
|
|
275
|
-
Copyright (c) 2006-
|
276
|
+
Copyright (c) 2006-2019 Keith Morrison <<keithm@infused.org>>
|
276
277
|
|
277
278
|
Permission is hereby granted, free of charge, to any person
|
278
279
|
obtaining a copy of this software and associated documentation
|
data/bin/dbf
CHANGED
@@ -9,7 +9,7 @@ params = ARGV.getopts('h', 's', 'a', 'c', 'r', 'v')
|
|
9
9
|
if params['v']
|
10
10
|
puts "dbf version: #{DBF::VERSION}"
|
11
11
|
|
12
|
-
elsif params['h']
|
12
|
+
elsif params['h']
|
13
13
|
puts "usage: #{File.basename(__FILE__)} [-h|-s|-a|-c|-r] filename"
|
14
14
|
puts ' -h = print this message'
|
15
15
|
puts ' -v = print the DBF gem version'
|
@@ -46,7 +46,7 @@ else
|
|
46
46
|
puts 'Name Type Length Decimal'
|
47
47
|
puts '-' * 78
|
48
48
|
table.columns.each do |f|
|
49
|
-
puts '%-16s %-10s %-10s %-10s'
|
49
|
+
puts format('%-16s %-10s %-10s %-10s', f.name, f.type, f.length, f.decimal)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
data/dbf.gemspec
CHANGED
data/lib/dbf.rb
CHANGED
data/lib/dbf/column.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module DBF
|
2
2
|
class Column
|
3
|
+
extend Forwardable
|
4
|
+
|
3
5
|
class LengthError < StandardError
|
4
6
|
end
|
5
7
|
|
@@ -7,6 +9,7 @@ module DBF
|
|
7
9
|
end
|
8
10
|
|
9
11
|
attr_reader :table, :name, :type, :length, :decimal
|
12
|
+
def_delegator :type_cast_class, :type_cast
|
10
13
|
|
11
14
|
TYPE_CAST_CLASS = {
|
12
15
|
N: ColumnType::Number,
|
@@ -56,14 +59,6 @@ module DBF
|
|
56
59
|
{name: name, type: type, length: length, decimal: decimal}
|
57
60
|
end
|
58
61
|
|
59
|
-
# Cast value to native type
|
60
|
-
#
|
61
|
-
# @param [String] value
|
62
|
-
# @return [Integer, Float, Date, DateTime, Boolean, String]
|
63
|
-
def type_cast(value)
|
64
|
-
type_cast_class.type_cast(value)
|
65
|
-
end
|
66
|
-
|
67
62
|
# Underscored name
|
68
63
|
#
|
69
64
|
# This is the column name converted to underscore format.
|
data/lib/dbf/column_type.rb
CHANGED
@@ -15,7 +15,7 @@ module DBF
|
|
15
15
|
end
|
16
16
|
|
17
17
|
class Nil < Base
|
18
|
-
def type_cast(
|
18
|
+
def type_cast(_value)
|
19
19
|
nil
|
20
20
|
end
|
21
21
|
end
|
@@ -23,19 +23,20 @@ module DBF
|
|
23
23
|
class Number < Base
|
24
24
|
def type_cast(value)
|
25
25
|
return nil if value.strip.empty?
|
26
|
+
|
26
27
|
@decimal.zero? ? value.to_i : value.to_f
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
30
31
|
class Currency < Base
|
31
32
|
def type_cast(value)
|
32
|
-
(value.
|
33
|
+
(value.unpack1('q<') / 10_000.0).to_f
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
36
37
|
class SignedLong < Base
|
37
38
|
def type_cast(value)
|
38
|
-
value.
|
39
|
+
value.unpack1('l<')
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
@@ -47,20 +48,20 @@ module DBF
|
|
47
48
|
|
48
49
|
class Double < Base
|
49
50
|
def type_cast(value)
|
50
|
-
value.
|
51
|
+
value.unpack1('E')
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
54
55
|
class Boolean < Base
|
55
56
|
def type_cast(value)
|
56
|
-
value.strip
|
57
|
+
value.strip.match? /^(y|t)$/i
|
57
58
|
end
|
58
59
|
end
|
59
60
|
|
60
61
|
class Date < Base
|
61
62
|
def type_cast(value)
|
62
|
-
value
|
63
|
-
rescue
|
63
|
+
value.match?(/\d{8}/) && ::Date.strptime(value, '%Y%m%d')
|
64
|
+
rescue StandardError
|
64
65
|
nil
|
65
66
|
end
|
66
67
|
end
|
@@ -70,7 +71,7 @@ module DBF
|
|
70
71
|
days, msecs = value.unpack('l2')
|
71
72
|
secs = (msecs / 1000).to_i
|
72
73
|
::DateTime.jd(days, (secs / 3600).to_i, (secs / 60).to_i % 60, secs % 60)
|
73
|
-
rescue
|
74
|
+
rescue StandardError
|
74
75
|
nil
|
75
76
|
end
|
76
77
|
end
|
@@ -97,6 +98,5 @@ module DBF
|
|
97
98
|
@encoding ? value.force_encoding(@encoding).encode(*ENCODING_ARGS) : value
|
98
99
|
end
|
99
100
|
end
|
100
|
-
|
101
101
|
end
|
102
102
|
end
|
data/lib/dbf/database/foxpro.rb
CHANGED
@@ -45,9 +45,7 @@ module DBF
|
|
45
45
|
glob = File.join(@dirname, "#{name}.dbf")
|
46
46
|
path = Dir.glob(glob, File::FNM_CASEFOLD).first
|
47
47
|
|
48
|
-
unless path && File.exist?(path)
|
49
|
-
raise DBF::FileNotFoundError, "related table not found: #{name}"
|
50
|
-
end
|
48
|
+
raise DBF::FileNotFoundError, "related table not found: #{name}" unless path && File.exist?(path)
|
51
49
|
|
52
50
|
path
|
53
51
|
end
|
data/lib/dbf/memo/base.rb
CHANGED
data/lib/dbf/memo/dbase4.rb
CHANGED
data/lib/dbf/memo/foxpro.rb
CHANGED
@@ -15,8 +15,7 @@ module DBF
|
|
15
15
|
memo_string = memo_string[0, memo_size]
|
16
16
|
end
|
17
17
|
memo_string
|
18
|
-
|
19
|
-
rescue
|
18
|
+
rescue StandardError
|
20
19
|
nil
|
21
20
|
end
|
22
21
|
|
@@ -25,7 +24,7 @@ module DBF
|
|
25
24
|
def block_size # :nodoc:
|
26
25
|
@block_size ||= begin
|
27
26
|
@data.rewind
|
28
|
-
@data.read(FPT_HEADER_SIZE).
|
27
|
+
@data.read(FPT_HEADER_SIZE).unpack1('x6n') || 0
|
29
28
|
end
|
30
29
|
end
|
31
30
|
end
|
data/lib/dbf/record.rb
CHANGED
data/lib/dbf/table.rb
CHANGED
@@ -5,6 +5,7 @@ module DBF
|
|
5
5
|
# DBF::Table is the primary interface to a single DBF file and provides
|
6
6
|
# methods for enumerating and searching the records.
|
7
7
|
class Table
|
8
|
+
extend Forwardable
|
8
9
|
include Enumerable
|
9
10
|
include ::DBF::Schema
|
10
11
|
|
@@ -40,6 +41,11 @@ module DBF
|
|
40
41
|
attr_accessor :encoding
|
41
42
|
attr_writer :name
|
42
43
|
|
44
|
+
def_delegator :header, :header_length
|
45
|
+
def_delegator :header, :record_count
|
46
|
+
def_delegator :header, :record_length
|
47
|
+
def_delegator :header, :version
|
48
|
+
|
43
49
|
# Opens a DBF::Table
|
44
50
|
# Examples:
|
45
51
|
# # working with a file stored on the filesystem
|
@@ -104,7 +110,7 @@ module DBF
|
|
104
110
|
#
|
105
111
|
# @yield [nil, DBF::Record]
|
106
112
|
def each
|
107
|
-
|
113
|
+
record_count.times { |i| yield record(i) }
|
108
114
|
end
|
109
115
|
|
110
116
|
# @return [String]
|
@@ -169,18 +175,12 @@ module DBF
|
|
169
175
|
def record(index)
|
170
176
|
seek_to_record(index)
|
171
177
|
return nil if deleted_record?
|
172
|
-
|
178
|
+
|
179
|
+
DBF::Record.new(@data.read(record_length), columns, version, @memo)
|
173
180
|
end
|
174
181
|
|
175
182
|
alias row record
|
176
183
|
|
177
|
-
# Total number of records
|
178
|
-
#
|
179
|
-
# @return [Integer]
|
180
|
-
def record_count
|
181
|
-
@record_count ||= header.record_count
|
182
|
-
end
|
183
|
-
|
184
184
|
# Dumps all records to a CSV file. If no filename is given then CSV is
|
185
185
|
# output to STDOUT.
|
186
186
|
#
|
@@ -192,13 +192,6 @@ module DBF
|
|
192
192
|
each { |record| csv << record.to_a }
|
193
193
|
end
|
194
194
|
|
195
|
-
# Internal dBase version number
|
196
|
-
#
|
197
|
-
# @return [String]
|
198
|
-
def version
|
199
|
-
@version ||= header.version
|
200
|
-
end
|
201
|
-
|
202
195
|
# Human readable version description
|
203
196
|
#
|
204
197
|
# @return [String]
|
@@ -222,7 +215,7 @@ module DBF
|
|
222
215
|
|
223
216
|
def deleted_record? # :nodoc:
|
224
217
|
flag = @data.read(1)
|
225
|
-
flag ? flag.
|
218
|
+
flag ? flag.unpack1('a') == '*' : true
|
226
219
|
end
|
227
220
|
|
228
221
|
def end_of_record? # :nodoc:
|
@@ -232,6 +225,7 @@ module DBF
|
|
232
225
|
def find_all(options) # :nodoc:
|
233
226
|
select do |record|
|
234
227
|
next unless record && record.match?(options)
|
228
|
+
|
235
229
|
yield record if block_given?
|
236
230
|
record
|
237
231
|
end
|
@@ -242,7 +236,7 @@ module DBF
|
|
242
236
|
end
|
243
237
|
|
244
238
|
def foxpro? # :nodoc:
|
245
|
-
FOXPRO_VERSIONS.
|
239
|
+
FOXPRO_VERSIONS.key?(version)
|
246
240
|
end
|
247
241
|
|
248
242
|
def header # :nodoc:
|
@@ -290,11 +284,11 @@ module DBF
|
|
290
284
|
end
|
291
285
|
|
292
286
|
def seek(offset) # :nodoc:
|
293
|
-
@data.seek(
|
287
|
+
@data.seek(header_length + offset)
|
294
288
|
end
|
295
289
|
|
296
290
|
def seek_to_record(index) # :nodoc:
|
297
|
-
seek(index *
|
291
|
+
seek(index * record_length)
|
298
292
|
end
|
299
293
|
end
|
300
294
|
end
|
data/lib/dbf/version.rb
CHANGED
data/spec/dbf/column_spec.rb
CHANGED
@@ -69,7 +69,7 @@ RSpec.describe DBF::Column do
|
|
69
69
|
it 'supports negative Integer' do
|
70
70
|
value = '-135'
|
71
71
|
column = DBF::Column.new table, 'ColumnName', 'N', 3, 0
|
72
|
-
expect(column.type_cast(value)).to eq
|
72
|
+
expect(column.type_cast(value)).to eq -135
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
@@ -83,7 +83,7 @@ RSpec.describe DBF::Column do
|
|
83
83
|
it 'casts negative value to Float' do
|
84
84
|
value = '-13.5'
|
85
85
|
column = DBF::Column.new table, 'ColumnName', 'N', 2, 1
|
86
|
-
expect(column.type_cast(value)).to eq
|
86
|
+
expect(column.type_cast(value)).to eq -13.5
|
87
87
|
end
|
88
88
|
end
|
89
89
|
end
|
@@ -105,7 +105,7 @@ RSpec.describe DBF::Column do
|
|
105
105
|
it 'casts negative value to Float' do
|
106
106
|
value = '-135'
|
107
107
|
column = DBF::Column.new table, 'ColumnName', 'F', 3, 0
|
108
|
-
expect(column.type_cast(value)).to eq
|
108
|
+
expect(column.type_cast(value)).to eq -135.0
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
@@ -126,7 +126,7 @@ RSpec.describe DBF::Column do
|
|
126
126
|
it 'supports negative binary' do
|
127
127
|
column = DBF::Column.new table, 'ColumnName', 'B', 1, 2
|
128
128
|
expect(column.type_cast("\x00\x00\x00\x00\x00\xC0\x65\xC0")).to be_a(Float)
|
129
|
-
expect(column.type_cast("\x00\x00\x00\x00\x00\xC0\x65\xC0")).to eq
|
129
|
+
expect(column.type_cast("\x00\x00\x00\x00\x00\xC0\x65\xC0")).to eq -174.0
|
130
130
|
end
|
131
131
|
end
|
132
132
|
end
|
@@ -142,13 +142,13 @@ RSpec.describe DBF::Column do
|
|
142
142
|
it 'casts value to Integer' do
|
143
143
|
value = "\203\171\001\000"
|
144
144
|
column = DBF::Column.new table, 'ColumnName', 'I', 3, 0
|
145
|
-
expect(column.type_cast(value)).to eq
|
145
|
+
expect(column.type_cast(value)).to eq 96_643
|
146
146
|
end
|
147
147
|
|
148
148
|
it 'supports negative Integer' do
|
149
149
|
value = "\x24\xE1\xFF\xFF"
|
150
150
|
column = DBF::Column.new table, 'ColumnName', 'I', 3, 0
|
151
|
-
expect(column.type_cast(value)).to eq
|
151
|
+
expect(column.type_cast(value)).to eq -7900
|
152
152
|
end
|
153
153
|
end
|
154
154
|
|
@@ -203,7 +203,7 @@ RSpec.describe DBF::Column do
|
|
203
203
|
|
204
204
|
context 'with valid date' do
|
205
205
|
it 'casts to Date' do
|
206
|
-
expect(column.type_cast('20050712')).to eq Date.new(2005,7,12)
|
206
|
+
expect(column.type_cast('20050712')).to eq Date.new(2005, 7, 12)
|
207
207
|
end
|
208
208
|
end
|
209
209
|
|
@@ -269,11 +269,11 @@ RSpec.describe DBF::Column do
|
|
269
269
|
end
|
270
270
|
|
271
271
|
it 'supports negative currency' do
|
272
|
-
expect(column.type_cast("\xFC\xF0\xF0\xFE\xFF\xFF\xFF\xFF")).to eq
|
272
|
+
expect(column.type_cast("\xFC\xF0\xF0\xFE\xFF\xFF\xFF\xFF")).to eq -1776.41
|
273
273
|
end
|
274
274
|
|
275
275
|
it 'supports 64bit negative currency' do
|
276
|
-
expect(column.type_cast("pN'9\xFF\xFF\xFF\xFF")).to eq
|
276
|
+
expect(column.type_cast("pN'9\xFF\xFF\xFF\xFF")).to eq -333_609.0
|
277
277
|
end
|
278
278
|
|
279
279
|
context 'and 0 length' do
|
@@ -20,7 +20,7 @@ RSpec.shared_examples_for 'DBF' do
|
|
20
20
|
|
21
21
|
specify 'column names should not be blank' do
|
22
22
|
table.columns.each do |column|
|
23
|
-
expect(column.name).
|
23
|
+
expect(column.name).to_not be_empty
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -53,17 +53,17 @@ end
|
|
53
53
|
RSpec.describe DBF, 'of type 03 (dBase III without memo file)' do
|
54
54
|
let(:table) { DBF::Table.new fixture('dbase_03.dbf') }
|
55
55
|
|
56
|
-
|
56
|
+
it_behaves_like 'DBF'
|
57
57
|
|
58
|
-
it '
|
58
|
+
it 'reports the correct version number' do
|
59
59
|
expect(table.version).to eq '03'
|
60
60
|
end
|
61
61
|
|
62
|
-
it '
|
62
|
+
it 'reports the correct version description' do
|
63
63
|
expect(table.version_description).to eq 'dBase III without memo file'
|
64
64
|
end
|
65
65
|
|
66
|
-
it '
|
66
|
+
it 'determines the number of records' do
|
67
67
|
expect(table.record_count).to eq 14
|
68
68
|
end
|
69
69
|
end
|
@@ -71,17 +71,17 @@ end
|
|
71
71
|
RSpec.describe DBF, 'of type 30 (Visual FoxPro)' do
|
72
72
|
let(:table) { DBF::Table.new fixture('dbase_30.dbf') }
|
73
73
|
|
74
|
-
|
74
|
+
it_behaves_like 'DBF'
|
75
75
|
|
76
|
-
it '
|
76
|
+
it 'reports the correct version number' do
|
77
77
|
expect(table.version).to eq '30'
|
78
78
|
end
|
79
79
|
|
80
|
-
it '
|
80
|
+
it 'reports the correct version description' do
|
81
81
|
expect(table.version_description).to eq 'Visual FoxPro'
|
82
82
|
end
|
83
83
|
|
84
|
-
it '
|
84
|
+
it 'determines the number of records' do
|
85
85
|
expect(table.record_count).to eq 34
|
86
86
|
end
|
87
87
|
|
@@ -93,17 +93,17 @@ end
|
|
93
93
|
RSpec.describe DBF, 'of type 31 (Visual FoxPro with AutoIncrement field)' do
|
94
94
|
let(:table) { DBF::Table.new fixture('dbase_31.dbf') }
|
95
95
|
|
96
|
-
|
96
|
+
it_behaves_like 'DBF'
|
97
97
|
|
98
|
-
it '
|
98
|
+
it 'has a dBase version of 31' do
|
99
99
|
expect(table.version).to eq '31'
|
100
100
|
end
|
101
101
|
|
102
|
-
it '
|
102
|
+
it 'reports the correct version description' do
|
103
103
|
expect(table.version_description).to eq 'Visual FoxPro with AutoIncrement field'
|
104
104
|
end
|
105
105
|
|
106
|
-
it '
|
106
|
+
it 'determines the number of records' do
|
107
107
|
expect(table.record_count).to eq 77
|
108
108
|
end
|
109
109
|
end
|
@@ -111,17 +111,17 @@ end
|
|
111
111
|
RSpec.describe DBF, 'of type 83 (dBase III with memo file)' do
|
112
112
|
let(:table) { DBF::Table.new fixture('dbase_83.dbf') }
|
113
113
|
|
114
|
-
|
114
|
+
it_behaves_like 'DBF'
|
115
115
|
|
116
|
-
it '
|
116
|
+
it 'reports the correct version number' do
|
117
117
|
expect(table.version).to eq '83'
|
118
118
|
end
|
119
119
|
|
120
|
-
it '
|
120
|
+
it 'reports the correct version description' do
|
121
121
|
expect(table.version_description).to eq 'dBase III with memo file'
|
122
122
|
end
|
123
123
|
|
124
|
-
it '
|
124
|
+
it 'determines the number of records' do
|
125
125
|
expect(table.record_count).to eq 67
|
126
126
|
end
|
127
127
|
end
|
@@ -129,17 +129,17 @@ end
|
|
129
129
|
RSpec.describe DBF, 'of type 8b (dBase IV with memo file)' do
|
130
130
|
let(:table) { DBF::Table.new fixture('dbase_8b.dbf') }
|
131
131
|
|
132
|
-
|
132
|
+
it_behaves_like 'DBF'
|
133
133
|
|
134
|
-
it '
|
134
|
+
it 'reports the correct version number' do
|
135
135
|
expect(table.version).to eq '8b'
|
136
136
|
end
|
137
137
|
|
138
|
-
it '
|
138
|
+
it 'reports the correct version description' do
|
139
139
|
expect(table.version_description).to eq 'dBase IV with memo file'
|
140
140
|
end
|
141
141
|
|
142
|
-
it '
|
142
|
+
it 'determines the number of records' do
|
143
143
|
expect(table.record_count).to eq 10
|
144
144
|
end
|
145
145
|
end
|
@@ -147,17 +147,17 @@ end
|
|
147
147
|
RSpec.describe DBF, 'of type f5 (FoxPro with memo file)' do
|
148
148
|
let(:table) { DBF::Table.new fixture('dbase_f5.dbf') }
|
149
149
|
|
150
|
-
|
150
|
+
it_behaves_like 'DBF'
|
151
151
|
|
152
|
-
it '
|
152
|
+
it 'reports the correct version number' do
|
153
153
|
expect(table.version).to eq 'f5'
|
154
154
|
end
|
155
155
|
|
156
|
-
it '
|
156
|
+
it 'reports the correct version description' do
|
157
157
|
expect(table.version_description).to eq 'FoxPro with memo file'
|
158
158
|
end
|
159
159
|
|
160
|
-
it '
|
160
|
+
it 'determines the number of records' do
|
161
161
|
expect(table.record_count).to eq 975
|
162
162
|
end
|
163
163
|
|
data/spec/dbf/record_spec.rb
CHANGED
@@ -6,7 +6,7 @@ RSpec.describe DBF::Record do
|
|
6
6
|
let(:record_0) { YAML.load_file(fixture('dbase_83_record_0.yml')) }
|
7
7
|
let(:record_9) { YAML.load_file(fixture('dbase_83_record_9.yml')) }
|
8
8
|
|
9
|
-
it '
|
9
|
+
it 'returns an ordered array of attribute values' do
|
10
10
|
record = table.record(0)
|
11
11
|
expect(record.to_a).to eq record_0
|
12
12
|
|
@@ -80,11 +80,11 @@ RSpec.describe DBF::Record do
|
|
80
80
|
let(:table) { DBF::Table.new fixture('cp1251.dbf') }
|
81
81
|
let(:record) { table.find(0) }
|
82
82
|
|
83
|
-
it '
|
83
|
+
it 'automaticallies encodes to default system encoding' do
|
84
84
|
expect(record.name.encoding).to eq Encoding.default_external
|
85
85
|
|
86
86
|
# russian a
|
87
|
-
expect(record.name.encode('UTF-8').
|
87
|
+
expect(record.name.encode('UTF-8').unpack1('H4')).to eq 'd0b0'
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
@@ -92,11 +92,11 @@ RSpec.describe DBF::Record do
|
|
92
92
|
let(:table) { DBF::Table.new fixture('cp1251.dbf'), nil, 'cp866' }
|
93
93
|
let(:record) { table.find(0) }
|
94
94
|
|
95
|
-
it '
|
95
|
+
it 'transcodes from manually specified encoding to default system encoding' do
|
96
96
|
expect(record.name.encoding).to eq Encoding.default_external
|
97
97
|
|
98
98
|
# russian а encoded in cp1251 and read as if it was encoded in cp866
|
99
|
-
expect(record.name.encode('UTF-8').
|
99
|
+
expect(record.name.encode('UTF-8').unpack1('H4')).to eq 'd180'
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end
|
data/spec/dbf/table_spec.rb
CHANGED
@@ -83,12 +83,12 @@ RSpec.describe DBF::Table do
|
|
83
83
|
end
|
84
84
|
|
85
85
|
describe '#sequel_schema' do
|
86
|
-
it '
|
86
|
+
it 'returns a valid Sequel migration by default' do
|
87
87
|
control_schema = File.read(fixture('dbase_83_schema_sq.txt'))
|
88
88
|
expect(table.sequel_schema).to eq control_schema
|
89
89
|
end
|
90
90
|
|
91
|
-
it '
|
91
|
+
it 'returns a limited Sequel migration when passed true' do
|
92
92
|
control_schema = File.read(fixture('dbase_83_schema_sq_lim.txt'))
|
93
93
|
expect(table.sequel_schema).to eq control_schema
|
94
94
|
end
|
@@ -132,7 +132,7 @@ RSpec.describe DBF::Table do
|
|
132
132
|
begin
|
133
133
|
$stdout = StringIO.new
|
134
134
|
table.to_csv
|
135
|
-
expect($stdout.string).
|
135
|
+
expect($stdout.string).to_not be_empty
|
136
136
|
ensure
|
137
137
|
$stdout = STDOUT
|
138
138
|
end
|
@@ -143,7 +143,7 @@ RSpec.describe DBF::Table do
|
|
143
143
|
before { table.to_csv('test.csv') }
|
144
144
|
|
145
145
|
it 'creates a custom csv file' do
|
146
|
-
expect(File.
|
146
|
+
expect(File).to be_exist('test.csv')
|
147
147
|
end
|
148
148
|
end
|
149
149
|
end
|
@@ -156,7 +156,7 @@ RSpec.describe DBF::Table do
|
|
156
156
|
end
|
157
157
|
|
158
158
|
describe '#current_record' do
|
159
|
-
it '
|
159
|
+
it 'returns nil for deleted records' do
|
160
160
|
allow(table).to receive(:deleted_record?).and_return(true)
|
161
161
|
expect(table.record(0)).to be_nil
|
162
162
|
end
|
@@ -201,24 +201,24 @@ RSpec.describe DBF::Table do
|
|
201
201
|
expect(table.find(:all, 'WEIGHT' => 0.0)).to eq table.select { |r| r['weight'] == 0.0 }
|
202
202
|
end
|
203
203
|
|
204
|
-
it '
|
204
|
+
it 'ANDS multiple search terms' do
|
205
205
|
expect(table.find(:all, 'ID' => 30, :IMAGE => 'graphics/00000001/TBC01.jpg')).to be_empty
|
206
206
|
end
|
207
207
|
|
208
|
-
it '
|
209
|
-
expect(table.find(:all, 'WEIGHT' => 0.0)).
|
208
|
+
it 'matches original column names' do
|
209
|
+
expect(table.find(:all, 'WEIGHT' => 0.0)).to_not be_empty
|
210
210
|
end
|
211
211
|
|
212
212
|
it 'matches symbolized column names' do
|
213
|
-
expect(table.find(:all, :
|
213
|
+
expect(table.find(:all, WEIGHT: 0.0)).to_not be_empty
|
214
214
|
end
|
215
215
|
|
216
216
|
it 'matches downcased column names' do
|
217
|
-
expect(table.find(:all, 'weight' => 0.0)).
|
217
|
+
expect(table.find(:all, 'weight' => 0.0)).to_not be_empty
|
218
218
|
end
|
219
219
|
|
220
220
|
it 'matches symbolized downcased column names' do
|
221
|
-
expect(table.find(:all, :
|
221
|
+
expect(table.find(:all, weight: 0.0)).to_not be_empty
|
222
222
|
end
|
223
223
|
end
|
224
224
|
|
@@ -276,13 +276,13 @@ RSpec.describe DBF::Table do
|
|
276
276
|
let(:table) { DBF::Table.new fixture('dbase_03.dbf') }
|
277
277
|
|
278
278
|
it 'is false' do
|
279
|
-
expect(table
|
279
|
+
expect(table).to_not have_memo_file
|
280
280
|
end
|
281
281
|
end
|
282
282
|
|
283
283
|
describe 'with a memo file' do
|
284
284
|
it 'is true' do
|
285
|
-
expect(table
|
285
|
+
expect(table).to have_memo_file
|
286
286
|
end
|
287
287
|
end
|
288
288
|
end
|
@@ -293,7 +293,7 @@ RSpec.describe DBF::Table do
|
|
293
293
|
it 'is an array of Columns' do
|
294
294
|
expect(columns).to be_an(Array)
|
295
295
|
expect(columns).to_not be_empty
|
296
|
-
expect(columns.
|
296
|
+
expect(columns).to be_all { |c| c.class == DBF::Column }
|
297
297
|
end
|
298
298
|
end
|
299
299
|
|
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:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keith Morrison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A small fast library for reading dBase, xBase, Clipper and FoxPro database
|
14
14
|
files.
|
@@ -111,8 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
111
|
- !ruby/object:Gem::Version
|
112
112
|
version: 1.3.0
|
113
113
|
requirements: []
|
114
|
-
|
115
|
-
rubygems_version: 2.7.6
|
114
|
+
rubygems_version: 3.0.2
|
116
115
|
signing_key:
|
117
116
|
specification_version: 4
|
118
117
|
summary: Read xBase files
|