dbf 4.3.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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