dbf 4.3.1 → 5.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d40b6c4a0c614eda7638ef810b682b3ee767153b95cc4075d90c1f12937e57c
4
- data.tar.gz: 6b74646387585dc0d497181d2253324cf92717b217b6642f5a1e307a7413e557
3
+ metadata.gz: a59c64cae2987160691a8cc8e99ed63e68cd7e50b5dbc1941a186454d5c37903
4
+ data.tar.gz: 618e8a2512bab2d9cedf26e94e1bca45159db880d11243695669c3bbc43452ac
5
5
  SHA512:
6
- metadata.gz: 98414f9a53a66b60f69b419740cb2f28eff4bdd81de67e5b09b9ae274c1f5a2e40c8730546f4719c09078b590837b1da607685833034f96a86ab2bea62637629
7
- data.tar.gz: 28a3a92617d4d889777d718cd88f43cec0217c6fd64135375699f81047186ddad0d1a345f32e2822d8f29a192fec579bef255efd316c5fb10594740042cd63a3
6
+ metadata.gz: cdd9d908bbc01b061d300ce780c83577f0bbaff1dcaba5375a69e71d43714d599a62879c0f6f56537a7d059764fc32102ca97eb67c4cafe6c38a68563ec88f74
7
+ data.tar.gz: 663fc952afb30bf77a5287edac7118ce5ab649cf3819f4a40994dd2f533765be9c42ec5e825a3443b47f5eba79393216fdc1448a6ebfd95fd8e1016d2fc69283
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.0.0
4
+
5
+ - Refactor the Column class to support non-ASCII header names
6
+ - Output encoding is now set to UTF-8 if there is no embedded encoding and one is not
7
+ specified during DBF::Table initialization.
8
+
9
+ ## 4.3.2
10
+
11
+ - Fixes to maintain support for Ruby 3.0.x until it's EOL
12
+
3
13
  ## 4.3.1
4
14
 
5
15
  - Fix bug (since 4.2.0) that caused column names not to be truncated after null character
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
@@ -61,7 +62,7 @@ module DBF
61
62
  #
62
63
  # @return [Hash]
63
64
  def to_hash
64
- {name:, type:, length:, decimal:}
65
+ {name: name, type: type, length: length, decimal: decimal}
65
66
  end
66
67
 
67
68
  # Underscored 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.gsub(/[^\x20-\x7E]/, '')
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(@decimal, @encoding)
87
+ klass.new(self)
106
88
  end
107
89
  end
108
90
 
@@ -5,9 +5,9 @@ module DBF
5
5
 
6
6
  # @param decimal [Integer]
7
7
  # @param encoding [String, Encoding]
8
- def initialize(decimal, encoding)
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
 
@@ -105,7 +105,7 @@ module DBF
105
105
  end
106
106
 
107
107
  def table_field_hash(name)
108
- {name:, fields: []}
108
+ {name: name, fields: []}
109
109
  end
110
110
  end
111
111
 
data/lib/dbf/schema.rb CHANGED
@@ -37,7 +37,7 @@ module DBF
37
37
  # @return [String]
38
38
  def schema(format = :activerecord, table_only: false)
39
39
  schema_method_name = schema_name(format)
40
- send(schema_method_name, table_only:)
40
+ send(schema_method_name, table_only: table_only)
41
41
  rescue NameError
42
42
  raise ArgumentError, ":#{format} is not a valid schema. Valid schemas are: #{FORMATS.join(', ')}."
43
43
  end
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:
data/lib/dbf/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module DBF
2
- VERSION = '4.3.1'.freeze
2
+ VERSION = '5.0.0'.freeze
3
3
  end
@@ -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, "\xFF\xFC", 'N', 1, 0 }.to raise_error(DBF::Column::NameError)
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
@@ -50,7 +50,7 @@ RSpec.describe DBF::Record do
50
50
 
51
51
  describe 'if other attributes match' do
52
52
  let(:attributes) { {x: 1, y: 2} }
53
- let(:other) { instance_double('DBF::Record', attributes:) }
53
+ let(:other) { instance_double('DBF::Record', attributes: attributes) }
54
54
 
55
55
  before do
56
56
  allow(record).to receive(:attributes).and_return(attributes)
@@ -1,6 +1,7 @@
1
1
 
2
2
  Database: cp1251.dbf
3
3
  Type: (30) Visual FoxPro
4
+ Encoding: cp1251
4
5
  Memo File: false
5
6
  Records: 4
6
7
 
Binary file
@@ -0,0 +1,11 @@
1
+
2
+ Database: dbase_03_cyrillic.dbf
3
+ Type: (03) dBase III without memo file
4
+ Memo File: false
5
+ Records: 2
6
+
7
+ Fields:
8
+ Name Type Length Decimal
9
+ ------------------------------------------------------------------------------
10
+ ШАР C 25 0
11
+ ПЛОЩА N 15 2
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.3.1
4
+ version: 5.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: 2024-01-22 00:00:00.000000000 Z
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.5.3
131
+ rubygems_version: 3.5.8
129
132
  signing_key:
130
133
  specification_version: 4
131
134
  summary: Read xBase files