dbf 4.3.2 → 5.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/bin/dbf +1 -0
- data/lib/dbf/column.rb +5 -23
- data/lib/dbf/column_type.rb +3 -3
- data/lib/dbf/table.rb +24 -2
- data/lib/dbf/version.rb +1 -1
- data/spec/dbf/column_spec.rb +1 -13
- data/spec/dbf/encoding_spec.rb +47 -0
- data/spec/dbf/table_spec.rb +6 -0
- data/spec/fixtures/cp1251_summary.txt +1 -0
- data/spec/fixtures/dbase_03_cyrillic.dbf +0 -0
- data/spec/fixtures/dbase_03_cyrillic_summary.txt +11 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4db2b075394f8f3cb60fc36e71a71eb9f8367e7b34b8863481fe6c2ab0a2aeac
|
4
|
+
data.tar.gz: f3e7ba5bd793d1732d2ae20b23b3a56285fa81228d06db9d38b055049591b76e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7c5847999bf422df92d90bbdea11bf0d6baa09ace5649cd65814b22cb5192a5ec085e8b25b9a2c56cb889f0f23d0fd0e3e20561c737ae05857afb63db69aea4
|
7
|
+
data.tar.gz: e1ed01f59b6f13e5bd3a91b327cdcd2060f85f2a608dfaf3e4dae1723f9a97b0ef2221465b0ae14aed1345e99b0c6c8edf9de00259f8a741914d889212ca5dc6
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 5.0.1
|
4
|
+
|
5
|
+
- Raise ArgumentError data is not a string or StringIO object
|
6
|
+
|
7
|
+
## 5.0.0
|
8
|
+
|
9
|
+
- Refactor the Column class to support non-ASCII header names
|
10
|
+
- Output encoding is now set to UTF-8 if there is no embedded encoding and one is not
|
11
|
+
specified during DBF::Table initialization.
|
12
|
+
|
3
13
|
## 4.3.2
|
4
14
|
|
5
15
|
- Fixes to maintain support for Ruby 3.0.x until it's EOL
|
data/bin/dbf
CHANGED
@@ -41,6 +41,7 @@ else
|
|
41
41
|
puts
|
42
42
|
puts "Database: #{filename}"
|
43
43
|
puts "Type: (#{table.version}) #{table.version_description}"
|
44
|
+
puts "Encoding: #{table.header_encoding}" if table.header_encoding
|
44
45
|
puts "Memo File: #{table.has_memo_file? ? 'true' : 'false'}"
|
45
46
|
puts "Records: #{table.record_count}"
|
46
47
|
|
data/lib/dbf/column.rb
CHANGED
@@ -8,7 +8,7 @@ module DBF
|
|
8
8
|
class NameError < StandardError
|
9
9
|
end
|
10
10
|
|
11
|
-
attr_reader :table, :name, :type, :length, :decimal
|
11
|
+
attr_reader :table, :name, :type, :length, :decimal, :encoding
|
12
12
|
|
13
13
|
def_delegator :type_cast_class, :type_cast
|
14
14
|
|
@@ -38,13 +38,14 @@ module DBF
|
|
38
38
|
# @param length [Integer]
|
39
39
|
# @param decimal [Integer]
|
40
40
|
def initialize(table, name, type, length, decimal)
|
41
|
+
@encoding = table.encoding
|
42
|
+
|
41
43
|
@table = table
|
42
44
|
@name = clean(name)
|
43
45
|
@type = type
|
44
46
|
@length = length
|
45
47
|
@decimal = decimal
|
46
48
|
@version = table.version
|
47
|
-
@encoding = table.encoding
|
48
49
|
|
49
50
|
validate_length
|
50
51
|
validate_name
|
@@ -72,37 +73,18 @@ module DBF
|
|
72
73
|
# @return [String]
|
73
74
|
def underscored_name
|
74
75
|
@underscored_name ||= name.gsub(/([a-z\d])([A-Z])/, '\1_\2').tr('-', '_').downcase
|
75
|
-
|
76
76
|
end
|
77
77
|
|
78
78
|
private
|
79
79
|
|
80
80
|
def clean(value) # :nodoc:
|
81
|
-
value.strip.partition("\x00").first
|
82
|
-
end
|
83
|
-
|
84
|
-
def encode(value, strip_output: false) # :nodoc:
|
85
|
-
return value unless value.respond_to?(:encoding)
|
86
|
-
|
87
|
-
output = @encoding ? encode_string(value) : value
|
88
|
-
strip_output ? output.strip : output
|
89
|
-
end
|
90
|
-
|
91
|
-
def encoding_args # :nodoc:
|
92
|
-
@encoding_args ||= [
|
93
|
-
Encoding.default_external,
|
94
|
-
{undef: :replace, invalid: :replace}
|
95
|
-
]
|
96
|
-
end
|
97
|
-
|
98
|
-
def encode_string(string) # :nodoc:
|
99
|
-
string.force_encoding(@encoding).encode(*encoding_args)
|
81
|
+
table.encode_string(value.strip.partition("\x00").first)
|
100
82
|
end
|
101
83
|
|
102
84
|
def type_cast_class # :nodoc:
|
103
85
|
@type_cast_class ||= begin
|
104
86
|
klass = @length == 0 ? ColumnType::Nil : TYPE_CAST_CLASS[type.to_sym]
|
105
|
-
klass.new(
|
87
|
+
klass.new(self)
|
106
88
|
end
|
107
89
|
end
|
108
90
|
|
data/lib/dbf/column_type.rb
CHANGED
@@ -5,9 +5,9 @@ module DBF
|
|
5
5
|
|
6
6
|
# @param decimal [Integer]
|
7
7
|
# @param encoding [String, Encoding]
|
8
|
-
def initialize(
|
9
|
-
@decimal = decimal
|
10
|
-
@encoding = encoding
|
8
|
+
def initialize(column)
|
9
|
+
@decimal = column.decimal
|
10
|
+
@encoding = column.encoding
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
data/lib/dbf/table.rb
CHANGED
@@ -76,7 +76,7 @@ module DBF
|
|
76
76
|
# @param encoding [optional String, Encoding] encoding Name of the encoding or an Encoding object
|
77
77
|
def initialize(data, memo = nil, encoding = nil)
|
78
78
|
@data = open_data(data)
|
79
|
-
@encoding = encoding || header.encoding
|
79
|
+
@encoding = encoding || header.encoding || Encoding.default_external
|
80
80
|
@memo = open_memo(data, memo)
|
81
81
|
yield self if block_given?
|
82
82
|
end
|
@@ -211,6 +211,21 @@ module DBF
|
|
211
211
|
VERSIONS[version]
|
212
212
|
end
|
213
213
|
|
214
|
+
# Encode string
|
215
|
+
#
|
216
|
+
# @param [String] string
|
217
|
+
# @return [String]
|
218
|
+
def encode_string(string) # :nodoc:
|
219
|
+
string.force_encoding(@encoding).encode(Encoding.default_external, undef: :replace, invalid: :replace)
|
220
|
+
end
|
221
|
+
|
222
|
+
# Encoding specified in the file header
|
223
|
+
#
|
224
|
+
# @return [Encoding]
|
225
|
+
def header_encoding
|
226
|
+
header.encoding
|
227
|
+
end
|
228
|
+
|
214
229
|
private
|
215
230
|
|
216
231
|
def build_columns # :nodoc:
|
@@ -293,7 +308,14 @@ module DBF
|
|
293
308
|
end
|
294
309
|
|
295
310
|
def open_data(data) # :nodoc:
|
296
|
-
|
311
|
+
case data
|
312
|
+
when StringIO
|
313
|
+
data
|
314
|
+
when String
|
315
|
+
File.open(data, 'rb')
|
316
|
+
else
|
317
|
+
raise ArgumentError, 'data must be a file path or StringIO object'
|
318
|
+
end
|
297
319
|
rescue Errno::ENOENT
|
298
320
|
raise DBF::FileNotFoundError, "file not found: #{data}"
|
299
321
|
end
|
data/lib/dbf/version.rb
CHANGED
data/spec/dbf/column_spec.rb
CHANGED
@@ -37,7 +37,7 @@ RSpec.describe DBF::Column do
|
|
37
37
|
|
38
38
|
describe 'with empty column name' do
|
39
39
|
it 'raises DBF::Column::NameError' do
|
40
|
-
expect { DBF::Column.new table,
|
40
|
+
expect { DBF::Column.new table, '', 'N', 1, 0 }.to raise_error(DBF::Column::NameError)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -283,16 +283,4 @@ RSpec.describe DBF::Column do
|
|
283
283
|
end
|
284
284
|
end
|
285
285
|
end
|
286
|
-
|
287
|
-
describe '#name' do
|
288
|
-
it 'contains only ASCII characters' do
|
289
|
-
column = DBF::Column.new table, "--\x1F-\x68\x65\x6C\x6C\x6F \x00world-\x80--", 'N', 1, 0
|
290
|
-
expect(column.name).to eq '---hello '
|
291
|
-
end
|
292
|
-
|
293
|
-
it 'is truncated at the null character' do
|
294
|
-
column = DBF::Column.new table, "--\x1F-\x68\x65\x6C\x6C\x6F \x00world-\x80\x80--", 'N', 1, 0
|
295
|
-
expect(column.name).to eq '---hello '
|
296
|
-
end
|
297
|
-
end
|
298
286
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe 'default encoding' do
|
6
|
+
let(:dbf_path) { fixture('dbase_03_cyrillic.dbf') }
|
7
|
+
let(:table) { DBF::Table.new dbf_path }
|
8
|
+
|
9
|
+
it 'defaults to UTF-8 encoding' do
|
10
|
+
expect(table.encoding).to eq Encoding::UTF_8
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'uses the table encoding for column encoding' do
|
14
|
+
column = table.columns.first
|
15
|
+
expect(column.encoding).to eq table.encoding
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'encodes column names' do
|
19
|
+
expect(table.column_names).to eq ['ШАР', 'ПЛОЩА']
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'encodes record values' do
|
23
|
+
expect(table.record(0).attributes['ШАР']).to eq 'Номер'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
RSpec.describe 'embedded encoding' do
|
28
|
+
let(:dbf_path) { fixture('cp1251.dbf') }
|
29
|
+
let(:table) { DBF::Table.new dbf_path }
|
30
|
+
|
31
|
+
it 'defaults to UTF-8 encoding' do
|
32
|
+
expect(table.encoding).to eq 'cp1251'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'uses the table encoding for column encoding' do
|
36
|
+
column = table.columns.first
|
37
|
+
expect(column.encoding).to eq table.encoding
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'encodes column names' do
|
41
|
+
expect(table.column_names).to eq ['RN', 'NAME']
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'encodes record values' do
|
45
|
+
expect(table.record(0).attributes['NAME']).to eq 'амбулаторно-поликлиническое'
|
46
|
+
end
|
47
|
+
end
|
data/spec/dbf/table_spec.rb
CHANGED
@@ -29,6 +29,12 @@ RSpec.describe DBF::Table do
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
describe 'when data is nil' do
|
33
|
+
it 'raises ArgumentError' do
|
34
|
+
expect { DBF::Table.new nil }.to raise_error(ArgumentError, 'data must be a file path or StringIO object')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
32
38
|
describe 'when given paths to existing dbf and memo files' do
|
33
39
|
it 'does not raise an error' do
|
34
40
|
expect { DBF::Table.new dbf_path, memo_path }.to_not raise_error
|
Binary file
|
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: 5.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keith Morrison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: csv
|
@@ -56,6 +56,7 @@ files:
|
|
56
56
|
- lib/dbf/version.rb
|
57
57
|
- spec/dbf/column_spec.rb
|
58
58
|
- spec/dbf/database/foxpro_spec.rb
|
59
|
+
- spec/dbf/encoding_spec.rb
|
59
60
|
- spec/dbf/file_formats_spec.rb
|
60
61
|
- spec/dbf/record_spec.rb
|
61
62
|
- spec/dbf/table_spec.rb
|
@@ -64,6 +65,8 @@ files:
|
|
64
65
|
- spec/fixtures/dbase_02.dbf
|
65
66
|
- spec/fixtures/dbase_02_summary.txt
|
66
67
|
- spec/fixtures/dbase_03.dbf
|
68
|
+
- spec/fixtures/dbase_03_cyrillic.dbf
|
69
|
+
- spec/fixtures/dbase_03_cyrillic_summary.txt
|
67
70
|
- spec/fixtures/dbase_03_summary.txt
|
68
71
|
- spec/fixtures/dbase_30.dbf
|
69
72
|
- spec/fixtures/dbase_30.fpt
|
@@ -125,7 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
128
|
- !ruby/object:Gem::Version
|
126
129
|
version: 1.3.0
|
127
130
|
requirements: []
|
128
|
-
rubygems_version: 3.
|
131
|
+
rubygems_version: 3.5.8
|
129
132
|
signing_key:
|
130
133
|
specification_version: 4
|
131
134
|
summary: Read xBase files
|