dbf 5.0.1 → 5.1.1
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 +8 -0
- data/README.md +1 -1
- data/dbf.gemspec +3 -3
- data/lib/dbf/column.rb +3 -1
- data/lib/dbf/column_type.rb +4 -2
- data/lib/dbf/database/foxpro.rb +3 -3
- data/lib/dbf/encodings.rb +2 -0
- data/lib/dbf/header.rb +2 -0
- data/lib/dbf/memo/base.rb +2 -0
- data/lib/dbf/memo/dbase3.rb +3 -1
- data/lib/dbf/memo/dbase4.rb +2 -0
- data/lib/dbf/memo/foxpro.rb +2 -0
- data/lib/dbf/record.rb +3 -1
- data/lib/dbf/schema.rb +4 -2
- data/lib/dbf/table.rb +4 -3
- data/lib/dbf/version.rb +3 -1
- data/lib/dbf.rb +2 -0
- data/spec/dbf/column_spec.rb +1 -0
- data/spec/dbf/database/foxpro_spec.rb +2 -0
- data/spec/dbf/encoding_spec.rb +44 -42
- data/spec/dbf/file_formats_spec.rb +5 -3
- data/spec/dbf/record_spec.rb +8 -10
- data/spec/dbf/table_spec.rb +3 -1
- data/spec/spec_helper.rb +2 -0
- metadata +6 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d565a51490240e9f5ed724970a568f12641b595b66e426a3a4a1a6ba0c84003
|
4
|
+
data.tar.gz: 12fc66ce2b83c55157532d252b52eb6a343174898a7965a636beb7877aa29c17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2de237f84ddc71f271a782b537f03d10a8586e939ad08f66b34c9f6bcc38a1b34aa4a2899d3248a1ff2f574bfb9920c19d2f134cae01ac66f0e228acd9a1c13
|
7
|
+
data.tar.gz: 5b5b3ee469e5afe32bc54ea4f494b543c675a2b4c61b6e6cf56af68ab2ab989a35644b7795a29e1cd9e4dfe8e4129c1abf85696a4ff7df8fb0444f89c7f80193
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -14,7 +14,7 @@ DBF is a small, fast Ruby library for reading dBase, xBase, Clipper, and FoxPro
|
|
14
14
|
* Report bugs: <https://github.com/infused/dbf/issues>
|
15
15
|
* Questions: Email <mailto:keithm@infused.org> and put DBF somewhere in the
|
16
16
|
subject line
|
17
|
-
* Change log: <https://github.com/infused/dbf/blob/
|
17
|
+
* Change log: <https://github.com/infused/dbf/blob/main/CHANGELOG.md>
|
18
18
|
|
19
19
|
NOTE: Beginning with version 4.3 we have dropped support for Ruby 3.0 and earlier.
|
20
20
|
|
data/dbf.gemspec
CHANGED
@@ -17,8 +17,8 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.extra_rdoc_files = ['README.md', 'CHANGELOG.md', 'LICENSE']
|
18
18
|
s.files = Dir['README.md', 'CHANGELOG.md', 'LICENSE', '{bin,lib,spec}/**/*', 'dbf.gemspec']
|
19
19
|
s.require_paths = ['lib']
|
20
|
-
s.required_rubygems_version = Gem::Requirement.new('>=
|
21
|
-
s.required_ruby_version = Gem::Requirement.new('>= 3.
|
20
|
+
s.required_rubygems_version = Gem::Requirement.new('>= 3.2.3')
|
21
|
+
s.required_ruby_version = Gem::Requirement.new('>= 3.1.0')
|
22
22
|
s.metadata['rubygems_mfa_required'] = 'true'
|
23
|
-
s.
|
23
|
+
s.add_dependency 'csv'
|
24
24
|
end
|
data/lib/dbf/column.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DBF
|
2
4
|
class Column
|
3
5
|
extend Forwardable
|
@@ -24,7 +26,7 @@ module DBF
|
|
24
26
|
M: ColumnType::Memo,
|
25
27
|
B: ColumnType::Double,
|
26
28
|
G: ColumnType::General,
|
27
|
-
|
29
|
+
:+ => ColumnType::SignedLong2
|
28
30
|
}
|
29
31
|
# rubocop:enable Style/MutableConstant
|
30
32
|
TYPE_CAST_CLASS.default = ColumnType::String
|
data/lib/dbf/column_type.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DBF
|
2
4
|
module ColumnType
|
3
5
|
class Base
|
@@ -95,7 +97,7 @@ module DBF
|
|
95
97
|
# @param value [String]
|
96
98
|
def type_cast(value)
|
97
99
|
if encoding && !value.nil?
|
98
|
-
value.force_encoding(@encoding).encode(Encoding.default_external, undef: :replace, invalid: :replace)
|
100
|
+
value.dup.force_encoding(@encoding).encode(Encoding.default_external, undef: :replace, invalid: :replace)
|
99
101
|
else
|
100
102
|
value
|
101
103
|
end
|
@@ -105,7 +107,7 @@ module DBF
|
|
105
107
|
class General < Base
|
106
108
|
# @param value [String]
|
107
109
|
def type_cast(value)
|
108
|
-
value
|
110
|
+
value&.dup&.force_encoding(Encoding::ASCII_8BIT)
|
109
111
|
end
|
110
112
|
end
|
111
113
|
|
data/lib/dbf/database/foxpro.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DBF
|
2
4
|
# DBF::Database::Foxpro is the primary interface to a Visual Foxpro database
|
3
5
|
# container (.dbc file). When using this database container, long fieldnames
|
@@ -85,9 +87,7 @@ module DBF
|
|
85
87
|
end
|
86
88
|
end
|
87
89
|
|
88
|
-
|
89
|
-
data.values.map { |v| [v[:name], v[:fields]] }
|
90
|
-
]
|
90
|
+
data.values.to_h { |v| [v[:name], v[:fields]] }
|
91
91
|
end
|
92
92
|
|
93
93
|
def process_table(record, data)
|
data/lib/dbf/encodings.rb
CHANGED
data/lib/dbf/header.rb
CHANGED
data/lib/dbf/memo/base.rb
CHANGED
data/lib/dbf/memo/dbase3.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DBF
|
2
4
|
module Memo
|
3
5
|
class Dbase3 < Base
|
4
6
|
def build_memo(start_block) # :nodoc:
|
5
7
|
@data.seek offset(start_block)
|
6
|
-
memo_string = ''
|
8
|
+
memo_string = +''
|
7
9
|
loop do
|
8
10
|
block = @data.read(BLOCK_SIZE).gsub(/(\000|\032)/, '')
|
9
11
|
memo_string << block
|
data/lib/dbf/memo/dbase4.rb
CHANGED
data/lib/dbf/memo/foxpro.rb
CHANGED
data/lib/dbf/record.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DBF
|
2
4
|
# An instance of DBF::Record represents a row in the DBF file
|
3
5
|
class Record
|
@@ -38,7 +40,7 @@ module DBF
|
|
38
40
|
#
|
39
41
|
# @return [Hash]
|
40
42
|
def attributes
|
41
|
-
@attributes ||=
|
43
|
+
@attributes ||= column_names.zip(to_a).to_h
|
42
44
|
end
|
43
45
|
|
44
46
|
# Do all search parameters match?
|
data/lib/dbf/schema.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DBF
|
2
4
|
# The Schema module is mixin for the Table class
|
3
5
|
module Schema
|
@@ -47,7 +49,7 @@ module DBF
|
|
47
49
|
end
|
48
50
|
|
49
51
|
def activerecord_schema(*) # :nodoc:
|
50
|
-
s = "ActiveRecord::Schema.define do\n"
|
52
|
+
s = +"ActiveRecord::Schema.define do\n"
|
51
53
|
s << " create_table \"#{name}\" do |t|\n"
|
52
54
|
columns.each do |column|
|
53
55
|
s << " t.column #{activerecord_schema_definition(column)}"
|
@@ -57,7 +59,7 @@ module DBF
|
|
57
59
|
end
|
58
60
|
|
59
61
|
def sequel_schema(table_only: false) # :nodoc:
|
60
|
-
s = ''
|
62
|
+
s = +''
|
61
63
|
s << "Sequel.migration do\n" unless table_only
|
62
64
|
s << " change do\n " unless table_only
|
63
65
|
s << " create_table(:#{name}) do\n"
|
data/lib/dbf/table.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DBF
|
2
4
|
class FileNotFoundError < StandardError
|
3
5
|
end
|
@@ -295,10 +297,9 @@ module DBF
|
|
295
297
|
def memo_class # :nodoc:
|
296
298
|
@memo_class ||= if foxpro?
|
297
299
|
Memo::Foxpro
|
298
|
-
|
299
|
-
|
300
|
+
else
|
301
|
+
version == '83' ? Memo::Dbase3 : Memo::Dbase4
|
300
302
|
end
|
301
|
-
|
302
303
|
end
|
303
304
|
|
304
305
|
def memo_search_path(io) # :nodoc:
|
data/lib/dbf/version.rb
CHANGED
data/lib/dbf.rb
CHANGED
data/spec/dbf/column_spec.rb
CHANGED
data/spec/dbf/encoding_spec.rb
CHANGED
@@ -1,47 +1,49 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
RSpec.describe '
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
column
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
column
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
46
48
|
end
|
47
49
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
RSpec.shared_examples_for 'DBF' do
|
@@ -9,7 +11,7 @@ RSpec.shared_examples_for 'DBF' do
|
|
9
11
|
end
|
10
12
|
|
11
13
|
specify 'records should be instances of DBF::Record' do
|
12
|
-
expect(table).to all
|
14
|
+
expect(table).to all be_a(DBF::Record)
|
13
15
|
end
|
14
16
|
|
15
17
|
specify 'record count should be the same as reported in the header' do
|
@@ -31,7 +33,7 @@ RSpec.shared_examples_for 'DBF' do
|
|
31
33
|
|
32
34
|
specify 'column lengths should be instances of Integer' do
|
33
35
|
table.columns.each do |column|
|
34
|
-
expect(column.length).to
|
36
|
+
expect(column.length).to be_a(Integer)
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
@@ -43,7 +45,7 @@ RSpec.shared_examples_for 'DBF' do
|
|
43
45
|
|
44
46
|
specify 'column decimals should be instances of Integer' do
|
45
47
|
table.columns.each do |column|
|
46
|
-
expect(column.decimal).to
|
48
|
+
expect(column.decimal).to be_a(Integer)
|
47
49
|
end
|
48
50
|
end
|
49
51
|
end
|
data/spec/dbf/record_spec.rb
CHANGED
@@ -1,27 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
RSpec.describe DBF::Record do
|
4
6
|
describe '#to_a' do
|
5
7
|
let(:table) { DBF::Table.new fixture('dbase_83.dbf') }
|
6
|
-
let(:record0) { YAML.load_file(fixture('dbase_83_record_0.yml')) }
|
7
|
-
let(:record9) { YAML.load_file(fixture('dbase_83_record_9.yml')) }
|
8
8
|
|
9
9
|
it 'returns an ordered array of attribute values' do
|
10
10
|
record = table.record(0)
|
11
|
-
expect(record.to_a).to eq
|
11
|
+
expect(record.to_a).to eq YAML.load_file(fixture('dbase_83_record_0.yml'))
|
12
12
|
|
13
13
|
record = table.record(9)
|
14
|
-
expect(record.to_a).to eq
|
14
|
+
expect(record.to_a).to eq YAML.load_file(fixture('dbase_83_record_9.yml'))
|
15
15
|
end
|
16
16
|
|
17
17
|
describe 'with missing memo file' do
|
18
18
|
describe 'when opening a path' do
|
19
19
|
let(:table) { DBF::Table.new fixture('dbase_83_missing_memo.dbf') }
|
20
|
-
let(:record0) { YAML.load_file(fixture('dbase_83_missing_memo_record_0.yml')) }
|
21
20
|
|
22
21
|
it 'returns nil values for memo fields' do
|
23
22
|
record = table.record(0)
|
24
|
-
expect(record.to_a).to eq
|
23
|
+
expect(record.to_a).to eq YAML.load_file(fixture('dbase_83_missing_memo_record_0.yml'))
|
25
24
|
end
|
26
25
|
end
|
27
26
|
end
|
@@ -29,11 +28,10 @@ RSpec.describe DBF::Record do
|
|
29
28
|
describe 'when opening StringIO' do
|
30
29
|
let(:data) { StringIO.new(File.read(fixture('dbase_83_missing_memo.dbf'))) }
|
31
30
|
let(:table) { DBF::Table.new(data) }
|
32
|
-
let(:record0) { YAML.load_file(fixture('dbase_83_missing_memo_record_0.yml')) }
|
33
31
|
|
34
32
|
it 'returns nil values for memo fields' do
|
35
33
|
record = table.record(0)
|
36
|
-
expect(record.to_a).to eq
|
34
|
+
expect(record.to_a).to eq YAML.load_file(fixture('dbase_83_missing_memo_record_0.yml'))
|
37
35
|
end
|
38
36
|
end
|
39
37
|
end
|
@@ -44,13 +42,13 @@ RSpec.describe DBF::Record do
|
|
44
42
|
|
45
43
|
describe 'when other does not have attributes' do
|
46
44
|
it 'returns false' do
|
47
|
-
expect(
|
45
|
+
expect(record == instance_double(DBF::Record)).to be_falsey
|
48
46
|
end
|
49
47
|
end
|
50
48
|
|
51
49
|
describe 'if other attributes match' do
|
52
50
|
let(:attributes) { {x: 1, y: 2} }
|
53
|
-
let(:other) { instance_double(
|
51
|
+
let(:other) { instance_double(DBF::Record, attributes: attributes) }
|
54
52
|
|
55
53
|
before do
|
56
54
|
allow(record).to receive(:attributes).and_return(attributes)
|
data/spec/dbf/table_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
RSpec.describe DBF::Table do
|
@@ -142,7 +144,7 @@ RSpec.describe DBF::Table do
|
|
142
144
|
before { table.to_csv('test.csv') }
|
143
145
|
|
144
146
|
it 'creates a custom csv file' do
|
145
|
-
expect(File).to
|
147
|
+
expect(File).to exist('test.csv')
|
146
148
|
end
|
147
149
|
end
|
148
150
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dbf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keith Morrison
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: csv
|
@@ -31,9 +30,9 @@ executables:
|
|
31
30
|
- dbf
|
32
31
|
extensions: []
|
33
32
|
extra_rdoc_files:
|
34
|
-
- README.md
|
35
33
|
- CHANGELOG.md
|
36
34
|
- LICENSE
|
35
|
+
- README.md
|
37
36
|
files:
|
38
37
|
- CHANGELOG.md
|
39
38
|
- LICENSE
|
@@ -112,7 +111,6 @@ licenses:
|
|
112
111
|
- MIT
|
113
112
|
metadata:
|
114
113
|
rubygems_mfa_required: 'true'
|
115
|
-
post_install_message:
|
116
114
|
rdoc_options:
|
117
115
|
- "--charset=UTF-8"
|
118
116
|
require_paths:
|
@@ -121,15 +119,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
121
119
|
requirements:
|
122
120
|
- - ">="
|
123
121
|
- !ruby/object:Gem::Version
|
124
|
-
version: 3.
|
122
|
+
version: 3.1.0
|
125
123
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
124
|
requirements:
|
127
125
|
- - ">="
|
128
126
|
- !ruby/object:Gem::Version
|
129
|
-
version:
|
127
|
+
version: 3.2.3
|
130
128
|
requirements: []
|
131
|
-
rubygems_version: 3.
|
132
|
-
signing_key:
|
129
|
+
rubygems_version: 3.6.7
|
133
130
|
specification_version: 4
|
134
131
|
summary: Read xBase files
|
135
132
|
test_files: []
|