dbf 3.0.0 → 3.0.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 +4 -0
- data/Gemfile.lock +18 -26
- data/Gemfile.travis +1 -3
- data/README.md +11 -3
- data/Rakefile +1 -1
- data/docs/supported_types.markdown +5 -5
- data/lib/dbf.rb +2 -3
- data/lib/dbf/column.rb +161 -0
- data/lib/dbf/column_type.rb +85 -0
- data/lib/dbf/database/foxpro.rb +2 -2
- data/lib/dbf/header.rb +3 -4
- data/lib/dbf/record.rb +8 -9
- data/lib/dbf/table.rb +4 -27
- data/lib/dbf/version.rb +1 -1
- data/spec/dbf/column_spec.rb +68 -91
- data/spec/dbf/database_spec.rb +2 -2
- data/spec/dbf/file_formats_spec.rb +13 -22
- data/spec/dbf/record_spec.rb +21 -26
- data/spec/dbf/table_spec.rb +30 -20
- data/spec/spec_helper.rb +15 -11
- metadata +5 -6
- data/lib/dbf/column/base.rb +0 -199
- data/lib/dbf/column/dbase.rb +0 -7
- data/lib/dbf/column/foxpro.rb +0 -9
data/spec/dbf/database_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe DBF::Database::Foxpro do
|
4
|
-
let(:dbf_path) {
|
3
|
+
RSpec.describe DBF::Database::Foxpro do
|
4
|
+
let(:dbf_path) { fixture('foxprodb/FOXPRO-DB-TEST.DBC') }
|
5
5
|
let(:db) { DBF::Database::Foxpro.new(dbf_path) }
|
6
6
|
|
7
7
|
describe '#initialize' do
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
shared_examples_for 'DBF' do
|
3
|
+
RSpec.shared_examples_for 'DBF' do
|
4
4
|
specify "sum of column lengths should equal record length specified in header plus one" do
|
5
5
|
header_record_length = table.instance_eval {@header.record_length}
|
6
6
|
sum_of_column_lengths = table.columns.inject(1) {|sum, column| sum += column.length}
|
@@ -50,16 +50,8 @@ shared_examples_for 'DBF' do
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
table.columns.each do |column|
|
56
|
-
expect(column).to be_kind_of(DBF::Column::Foxpro)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
describe DBF, "of type 03 (dBase III without memo file)" do
|
62
|
-
let(:table) { DBF::Table.new fixture_path('dbase_03.dbf') }
|
53
|
+
RSpec.describe DBF, "of type 03 (dBase III without memo file)" do
|
54
|
+
let(:table) { DBF::Table.new fixture('dbase_03.dbf') }
|
63
55
|
|
64
56
|
it_should_behave_like "DBF"
|
65
57
|
|
@@ -76,8 +68,8 @@ describe DBF, "of type 03 (dBase III without memo file)" do
|
|
76
68
|
end
|
77
69
|
end
|
78
70
|
|
79
|
-
describe DBF, "of type 30 (Visual FoxPro)" do
|
80
|
-
let(:table) { DBF::Table.new
|
71
|
+
RSpec.describe DBF, "of type 30 (Visual FoxPro)" do
|
72
|
+
let(:table) { DBF::Table.new fixture('dbase_30.dbf') }
|
81
73
|
|
82
74
|
it_should_behave_like "DBF"
|
83
75
|
|
@@ -98,8 +90,8 @@ describe DBF, "of type 30 (Visual FoxPro)" do
|
|
98
90
|
end
|
99
91
|
end
|
100
92
|
|
101
|
-
describe DBF, "of type 31 (Visual FoxPro with AutoIncrement field)" do
|
102
|
-
let(:table) { DBF::Table.new
|
93
|
+
RSpec.describe DBF, "of type 31 (Visual FoxPro with AutoIncrement field)" do
|
94
|
+
let(:table) { DBF::Table.new fixture('dbase_31.dbf') }
|
103
95
|
|
104
96
|
it_should_behave_like "DBF"
|
105
97
|
|
@@ -116,8 +108,8 @@ describe DBF, "of type 31 (Visual FoxPro with AutoIncrement field)" do
|
|
116
108
|
end
|
117
109
|
end
|
118
110
|
|
119
|
-
describe DBF, "of type 83 (dBase III with memo file)" do
|
120
|
-
let(:table) { DBF::Table.new
|
111
|
+
RSpec.describe DBF, "of type 83 (dBase III with memo file)" do
|
112
|
+
let(:table) { DBF::Table.new fixture('dbase_83.dbf') }
|
121
113
|
|
122
114
|
it_should_behave_like "DBF"
|
123
115
|
|
@@ -134,8 +126,8 @@ describe DBF, "of type 83 (dBase III with memo file)" do
|
|
134
126
|
end
|
135
127
|
end
|
136
128
|
|
137
|
-
describe DBF, "of type 8b (dBase IV with memo file)" do
|
138
|
-
let(:table) { DBF::Table.new
|
129
|
+
RSpec.describe DBF, "of type 8b (dBase IV with memo file)" do
|
130
|
+
let(:table) { DBF::Table.new fixture('dbase_8b.dbf') }
|
139
131
|
|
140
132
|
it_should_behave_like "DBF"
|
141
133
|
|
@@ -152,11 +144,10 @@ describe DBF, "of type 8b (dBase IV with memo file)" do
|
|
152
144
|
end
|
153
145
|
end
|
154
146
|
|
155
|
-
describe DBF, "of type f5 (FoxPro with memo file)" do
|
156
|
-
let(:table) { DBF::Table.new
|
147
|
+
RSpec.describe DBF, "of type f5 (FoxPro with memo file)" do
|
148
|
+
let(:table) { DBF::Table.new fixture('dbase_f5.dbf') }
|
157
149
|
|
158
150
|
it_should_behave_like "DBF"
|
159
|
-
it_should_behave_like "Foxpro DBF"
|
160
151
|
|
161
152
|
it "should report the correct version number" do
|
162
153
|
expect(table.version).to eq "f5"
|
data/spec/dbf/record_spec.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe DBF::Record do
|
4
|
-
|
3
|
+
RSpec.describe DBF::Record do
|
5
4
|
describe '#to_a' do
|
6
|
-
let(:table) { DBF::Table.new
|
7
|
-
let(:record_0) { YAML.load_file(
|
8
|
-
let(:record_9) { YAML.load_file(
|
5
|
+
let(:table) { DBF::Table.new fixture('dbase_83.dbf') }
|
6
|
+
let(:record_0) { YAML.load_file(fixture('dbase_83_record_0.yml')) }
|
7
|
+
let(:record_9) { YAML.load_file(fixture('dbase_83_record_9.yml')) }
|
9
8
|
|
10
9
|
it 'should return an ordered array of attribute values' do
|
11
10
|
record = table.record(0)
|
@@ -17,8 +16,8 @@ describe DBF::Record do
|
|
17
16
|
|
18
17
|
describe 'with missing memo file' do
|
19
18
|
describe 'when opening a path' do
|
20
|
-
let(:table) { DBF::Table.new
|
21
|
-
let(:record_0) { YAML.load_file(
|
19
|
+
let(:table) { DBF::Table.new fixture('dbase_83_missing_memo.dbf') }
|
20
|
+
let(:record_0) { YAML.load_file(fixture('dbase_83_missing_memo_record_0.yml')) }
|
22
21
|
|
23
22
|
it 'returns nil values for memo fields' do
|
24
23
|
record = table.record(0)
|
@@ -28,9 +27,9 @@ describe DBF::Record do
|
|
28
27
|
end
|
29
28
|
|
30
29
|
describe 'when opening StringIO' do
|
31
|
-
let(:data) { StringIO.new(File.read(
|
30
|
+
let(:data) { StringIO.new(File.read(fixture('dbase_83_missing_memo.dbf'))) }
|
32
31
|
let(:table) { DBF::Table.new(data) }
|
33
|
-
let(:record_0) { YAML.load_file(
|
32
|
+
let(:record_0) { YAML.load_file(fixture('dbase_83_missing_memo_record_0.yml')) }
|
34
33
|
|
35
34
|
it 'returns nil values for memo fields' do
|
36
35
|
record = table.record(0)
|
@@ -40,7 +39,7 @@ describe DBF::Record do
|
|
40
39
|
end
|
41
40
|
|
42
41
|
describe '#==' do
|
43
|
-
let(:table) { DBF::Table.new
|
42
|
+
let(:table) { DBF::Table.new fixture('dbase_8b.dbf') }
|
44
43
|
let(:record) { table.record(9) }
|
45
44
|
|
46
45
|
describe 'when other does not have attributes' do
|
@@ -50,8 +49,8 @@ describe DBF::Record do
|
|
50
49
|
end
|
51
50
|
|
52
51
|
describe 'if other attributes match' do
|
53
|
-
let(:attributes) { {:
|
54
|
-
let(:other) { double('object', :
|
52
|
+
let(:attributes) { {x: 1, y: 2} }
|
53
|
+
let(:other) { double('object', attributes: attributes) }
|
55
54
|
|
56
55
|
before do
|
57
56
|
allow(record).to receive(:attributes).and_return(attributes)
|
@@ -65,7 +64,7 @@ describe DBF::Record do
|
|
65
64
|
end
|
66
65
|
|
67
66
|
describe 'column accessors' do
|
68
|
-
let(:table) { DBF::Table.new
|
67
|
+
let(:table) { DBF::Table.new fixture('dbase_8b.dbf') }
|
69
68
|
let(:record) { table.find(0) }
|
70
69
|
|
71
70
|
%w(character numerical date logical float memo).each do |column_name|
|
@@ -79,36 +78,32 @@ describe DBF::Record do
|
|
79
78
|
|
80
79
|
describe 'column data for table' do
|
81
80
|
describe 'using specified in dbf encoding' do
|
82
|
-
let(:table) { DBF::Table.new
|
81
|
+
let(:table) { DBF::Table.new fixture('cp1251.dbf') }
|
83
82
|
let(:record) { table.find(0) }
|
84
83
|
|
85
84
|
it 'should automatically encodes to default system encoding' do
|
86
|
-
|
87
|
-
expect(record.name.encoding).to eq Encoding.default_external
|
85
|
+
expect(record.name.encoding).to eq Encoding.default_external
|
88
86
|
|
89
|
-
|
90
|
-
|
91
|
-
end
|
87
|
+
# russian a
|
88
|
+
expect(record.name.encode("UTF-8").unpack("H4")).to eq ["d0b0"]
|
92
89
|
end
|
93
90
|
end
|
94
91
|
|
95
92
|
describe 'overriding specified in dbf encoding' do
|
96
|
-
let(:table) { DBF::Table.new
|
93
|
+
let(:table) { DBF::Table.new fixture('cp1251.dbf'), nil, 'cp866'}
|
97
94
|
let(:record) { table.find(0) }
|
98
95
|
|
99
96
|
it 'should transcode from manually specified encoding to default system encoding' do
|
100
|
-
|
101
|
-
expect(record.name.encoding).to eq Encoding.default_external
|
97
|
+
expect(record.name.encoding).to eq Encoding.default_external
|
102
98
|
|
103
|
-
|
104
|
-
|
105
|
-
end
|
99
|
+
# russian а encoded in cp1251 and read as if it was encoded in cp866
|
100
|
+
expect(record.name.encode("UTF-8").unpack("H4")).to eq ["d180"]
|
106
101
|
end
|
107
102
|
end
|
108
103
|
end
|
109
104
|
|
110
105
|
describe '#attributes' do
|
111
|
-
let(:table) { DBF::Table.new
|
106
|
+
let(:table) { DBF::Table.new fixture('dbase_8b.dbf') }
|
112
107
|
let(:record) { table.find(0) }
|
113
108
|
|
114
109
|
it 'is a hash of attribute name/value pairs' do
|
data/spec/dbf/table_spec.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe DBF::Table do
|
4
|
-
let(:dbf_path) {
|
5
|
-
let(:memo_path) {
|
3
|
+
RSpec.describe DBF::Table do
|
4
|
+
let(:dbf_path) { fixture('dbase_83.dbf') }
|
5
|
+
let(:memo_path) { fixture('dbase_83.dbt') }
|
6
6
|
let(:table) { DBF::Table.new dbf_path }
|
7
7
|
|
8
8
|
specify 'foxpro versions' do
|
@@ -10,6 +10,9 @@ describe DBF::Table do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
describe '#initialize' do
|
13
|
+
let(:data) { StringIO.new File.read(dbf_path) }
|
14
|
+
let(:memo) { StringIO.new File.read(memo_path) }
|
15
|
+
|
13
16
|
describe 'when given a path to an existing dbf file' do
|
14
17
|
it 'does not raise an error' do
|
15
18
|
expect { DBF::Table.new dbf_path }.to_not raise_error
|
@@ -29,27 +32,26 @@ describe DBF::Table do
|
|
29
32
|
end
|
30
33
|
|
31
34
|
it 'accepts an io-like data object' do
|
32
|
-
data = StringIO.new File.read(dbf_path)
|
33
35
|
expect { DBF::Table.new data }.to_not raise_error
|
34
36
|
end
|
35
37
|
|
36
38
|
it 'accepts an io-like data and memo object' do
|
37
|
-
data = StringIO.new File.read(dbf_path)
|
38
|
-
memo = StringIO.new File.read(memo_path)
|
39
39
|
expect { DBF::Table.new data, memo }.to_not raise_error
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
context '#close' do
|
44
|
+
before { table.close }
|
45
|
+
|
44
46
|
it 'closes the io' do
|
45
|
-
table.close
|
46
47
|
expect { table.record(1) }.to raise_error(IOError)
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
51
|
describe '#schema' do
|
52
|
+
let(:control_schema) { File.read(fixture('dbase_83_schema.txt')) }
|
53
|
+
|
51
54
|
it 'matches the test schema fixture' do
|
52
|
-
control_schema = File.read(fixture_path('dbase_83_schema.txt'))
|
53
55
|
expect(table.schema).to eq control_schema
|
54
56
|
end
|
55
57
|
end
|
@@ -99,8 +101,9 @@ describe DBF::Table do
|
|
99
101
|
end
|
100
102
|
|
101
103
|
describe 'when path param passed' do
|
104
|
+
before { table.to_csv('test.csv') }
|
105
|
+
|
102
106
|
it 'creates a custom csv file' do
|
103
|
-
table.to_csv('test.csv')
|
104
107
|
expect(File.exist?('test.csv')).to be_truthy
|
105
108
|
end
|
106
109
|
end
|
@@ -134,12 +137,14 @@ describe DBF::Table do
|
|
134
137
|
end
|
135
138
|
|
136
139
|
describe 'with :all' do
|
137
|
-
|
138
|
-
|
139
|
-
table.find(:all, :weight => 0.0) do |record|
|
140
|
+
let(:records) do
|
141
|
+
table.find(:all, weight: 0.0).inject([]) do |records, record|
|
140
142
|
records << record
|
141
143
|
end
|
142
|
-
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'accepts a block' do
|
147
|
+
expect(records).to eq table.find(:all, weight: 0.0)
|
143
148
|
end
|
144
149
|
|
145
150
|
it 'returns all records if options are empty' do
|
@@ -194,8 +199,9 @@ describe DBF::Table do
|
|
194
199
|
|
195
200
|
describe '#has_memo_file?' do
|
196
201
|
describe 'without a memo file' do
|
202
|
+
let(:table) { DBF::Table.new fixture('dbase_03.dbf') }
|
203
|
+
|
197
204
|
it 'is false' do
|
198
|
-
table = DBF::Table.new fixture_path('dbase_03.dbf')
|
199
205
|
expect(table.has_memo_file?).to be_falsey
|
200
206
|
end
|
201
207
|
end
|
@@ -208,18 +214,22 @@ describe DBF::Table do
|
|
208
214
|
end
|
209
215
|
|
210
216
|
describe '#columns' do
|
217
|
+
let(:columns) { table.columns }
|
218
|
+
|
211
219
|
it 'is an array of Columns' do
|
212
|
-
expect(
|
213
|
-
expect(
|
214
|
-
expect(
|
220
|
+
expect(columns).to be_an(Array)
|
221
|
+
expect(columns).to_not be_empty
|
222
|
+
expect(columns.all? {|c| c.class == DBF::Column}).to be_truthy
|
215
223
|
end
|
216
224
|
end
|
217
225
|
|
218
226
|
describe '#column_names' do
|
227
|
+
let(:column_names) do
|
228
|
+
%w(ID CATCOUNT AGRPCOUNT PGRPCOUNT ORDER CODE NAME THUMBNAIL IMAGE PRICE COST DESC WEIGHT TAXABLE ACTIVE)
|
229
|
+
end
|
230
|
+
|
219
231
|
it 'is an array of all column names' do
|
220
|
-
|
221
|
-
expect(table.column_names).to eq correct_column_names
|
232
|
+
expect(table.column_names).to eq column_names
|
222
233
|
end
|
223
234
|
end
|
224
|
-
|
225
235
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -9,20 +9,24 @@ require 'yaml'
|
|
9
9
|
require 'rspec'
|
10
10
|
require 'fileutils'
|
11
11
|
|
12
|
-
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.disable_monkey_patching!
|
14
|
+
config.warnings = true
|
15
|
+
config.order = :random
|
13
16
|
|
14
|
-
|
17
|
+
config.expect_with :rspec do |expectations|
|
18
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
19
|
+
end
|
15
20
|
|
16
|
-
|
17
|
-
|
18
|
-
begin
|
19
|
-
require 'mathn'
|
20
|
-
rescue UnsupportedLibraryError
|
21
|
-
false
|
22
|
-
end
|
21
|
+
config.mock_with :rspec do |mocks|
|
22
|
+
mocks.verify_partial_doubles = true
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def fixture_path
|
27
|
-
|
26
|
+
def fixture_path
|
27
|
+
@fixture_path ||= File.join(File.dirname(__FILE__), '/fixtures')
|
28
|
+
end
|
29
|
+
|
30
|
+
def fixture(filename)
|
31
|
+
File.join(fixture_path, filename)
|
28
32
|
end
|
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: 3.0.
|
4
|
+
version: 3.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: 2015-
|
11
|
+
date: 2015-11-20 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.
|
@@ -34,9 +34,8 @@ files:
|
|
34
34
|
- docs/supported_encodings.csv
|
35
35
|
- docs/supported_types.markdown
|
36
36
|
- lib/dbf.rb
|
37
|
-
- lib/dbf/column
|
38
|
-
- lib/dbf/
|
39
|
-
- lib/dbf/column/foxpro.rb
|
37
|
+
- lib/dbf/column.rb
|
38
|
+
- lib/dbf/column_type.rb
|
40
39
|
- lib/dbf/database/foxpro.rb
|
41
40
|
- lib/dbf/encodings.rb
|
42
41
|
- lib/dbf/header.rb
|
@@ -111,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
110
|
version: 1.3.0
|
112
111
|
requirements: []
|
113
112
|
rubyforge_project:
|
114
|
-
rubygems_version: 2.4.
|
113
|
+
rubygems_version: 2.4.5.1
|
115
114
|
signing_key:
|
116
115
|
specification_version: 4
|
117
116
|
summary: Read xBase files
|
data/lib/dbf/column/base.rb
DELETED
@@ -1,199 +0,0 @@
|
|
1
|
-
module DBF
|
2
|
-
module Column
|
3
|
-
# Raised if length is less than 1
|
4
|
-
class LengthError < StandardError; end
|
5
|
-
|
6
|
-
# Raised if name is empty
|
7
|
-
class NameError < StandardError; end
|
8
|
-
|
9
|
-
class Base
|
10
|
-
attr_reader :table, :name, :type, :length, :decimal
|
11
|
-
|
12
|
-
# Initialize a new DBF::Column
|
13
|
-
#
|
14
|
-
# @param [String] name
|
15
|
-
# @param [String] type
|
16
|
-
# @param [Fixnum] length
|
17
|
-
# @param [Fixnum] decimal
|
18
|
-
def initialize(table, name, type, length, decimal)
|
19
|
-
@table = table
|
20
|
-
@name = clean(name)
|
21
|
-
@type = type
|
22
|
-
@length = length
|
23
|
-
@decimal = decimal
|
24
|
-
@version = table.version
|
25
|
-
@encoding = table.encoding
|
26
|
-
|
27
|
-
validate_length
|
28
|
-
validate_name
|
29
|
-
end
|
30
|
-
|
31
|
-
# Cast value to native type
|
32
|
-
#
|
33
|
-
# @param [String] value
|
34
|
-
# @return [Fixnum, Float, Date, DateTime, Boolean, String]
|
35
|
-
def type_cast(value)
|
36
|
-
return nil if length == 0
|
37
|
-
|
38
|
-
meth = type_cast_methods[type]
|
39
|
-
meth ? send(meth, value) : encode_string(value, true)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Returns true if the column is a memo
|
43
|
-
#
|
44
|
-
# @return [Boolean]
|
45
|
-
def memo?
|
46
|
-
@memo ||= type == 'M'
|
47
|
-
end
|
48
|
-
|
49
|
-
# Schema definition
|
50
|
-
#
|
51
|
-
# @return [String]
|
52
|
-
def schema_definition
|
53
|
-
"\"#{underscored_name}\", #{schema_data_type}\n"
|
54
|
-
end
|
55
|
-
|
56
|
-
# Underscored name
|
57
|
-
#
|
58
|
-
# This is the column name converted to underscore format.
|
59
|
-
# For example, MyColumn will be returned as my_column.
|
60
|
-
#
|
61
|
-
# @return [String]
|
62
|
-
def underscored_name
|
63
|
-
@underscored_name ||= begin
|
64
|
-
un = name.dup
|
65
|
-
un.gsub!(/::/, '/')
|
66
|
-
un.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
67
|
-
un.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
68
|
-
un.tr!('-', '_')
|
69
|
-
un.downcase!
|
70
|
-
un
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def to_hash
|
75
|
-
{name: name, type: type, length: length, decimal: decimal}
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
def type_cast_methods # nodoc
|
81
|
-
{
|
82
|
-
'N' => :unpack_number,
|
83
|
-
'I' => :unpack_signed_long,
|
84
|
-
'F' => :unpack_float,
|
85
|
-
'Y' => :unpack_currency,
|
86
|
-
'D' => :decode_date,
|
87
|
-
'T' => :decode_datetime,
|
88
|
-
'L' => :boolean,
|
89
|
-
'M' => :decode_memo,
|
90
|
-
'B' => :unpack_double
|
91
|
-
}
|
92
|
-
end
|
93
|
-
|
94
|
-
def decode_date(value) # nodoc
|
95
|
-
v = value.tr(' ', '0')
|
96
|
-
v !~ /\S/ ? nil : Date.parse(v)
|
97
|
-
rescue
|
98
|
-
nil
|
99
|
-
end
|
100
|
-
|
101
|
-
def decode_datetime(value) # nodoc
|
102
|
-
days, msecs = value.unpack('l2')
|
103
|
-
secs = (msecs / 1000).to_i
|
104
|
-
DateTime.jd(days, (secs / 3600).to_i, (secs / 60).to_i % 60, secs % 60)
|
105
|
-
rescue
|
106
|
-
nil
|
107
|
-
end
|
108
|
-
|
109
|
-
def decode_memo(value) # nodoc
|
110
|
-
value && encode_string(value)
|
111
|
-
end
|
112
|
-
|
113
|
-
def unpack_number(value) # nodoc
|
114
|
-
decimal.zero? ? value.to_i : value.to_f
|
115
|
-
end
|
116
|
-
|
117
|
-
def unpack_currency(value) # nodoc
|
118
|
-
(value.unpack('q<')[0] / 10_000.0).to_f
|
119
|
-
end
|
120
|
-
|
121
|
-
def unpack_signed_long(value) # nodoc
|
122
|
-
value.unpack('l<')[0]
|
123
|
-
end
|
124
|
-
|
125
|
-
def unpack_float(value) # nodoc
|
126
|
-
value.to_f
|
127
|
-
end
|
128
|
-
|
129
|
-
def unpack_double(value) # nodoc
|
130
|
-
value.unpack('E')[0]
|
131
|
-
end
|
132
|
-
|
133
|
-
def boolean(value) # nodoc
|
134
|
-
value.strip =~ /^(y|t)$/i ? true : false
|
135
|
-
end
|
136
|
-
|
137
|
-
def encode_string(value, strip_output = false) # nodoc
|
138
|
-
output =
|
139
|
-
if supports_encoding? && table.supports_string_encoding?
|
140
|
-
value.to_s.force_encoding(@encoding).encode(*encoding_args)
|
141
|
-
elsif supports_encoding? && table.supports_iconv?
|
142
|
-
Iconv.conv('UTF-8', @encoding, value.to_s)
|
143
|
-
else
|
144
|
-
value
|
145
|
-
end
|
146
|
-
|
147
|
-
strip_output ? output.strip : output
|
148
|
-
end
|
149
|
-
|
150
|
-
def encoding_args # nodoc
|
151
|
-
[Encoding.default_external, {:undef => :replace, :invalid => :replace}]
|
152
|
-
end
|
153
|
-
|
154
|
-
def schema_data_type # nodoc
|
155
|
-
case type
|
156
|
-
when 'N', 'F'
|
157
|
-
decimal > 0 ? ':float' : ':integer'
|
158
|
-
when 'I'
|
159
|
-
':integer'
|
160
|
-
when 'Y'
|
161
|
-
':decimal, :precision => 15, :scale => 4'
|
162
|
-
when 'D'
|
163
|
-
':date'
|
164
|
-
when 'T'
|
165
|
-
':datetime'
|
166
|
-
when 'L'
|
167
|
-
':boolean'
|
168
|
-
when 'M'
|
169
|
-
':text'
|
170
|
-
when 'B'
|
171
|
-
if DBF::Table::FOXPRO_VERSIONS.keys.include?(@version)
|
172
|
-
':float'
|
173
|
-
else
|
174
|
-
':text'
|
175
|
-
end
|
176
|
-
else
|
177
|
-
":string, :limit => #{length}"
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
def clean(value) # nodoc
|
182
|
-
truncated_value = value.strip.partition("\x00").first
|
183
|
-
truncated_value.gsub(/[^\x20-\x7E]/, '')
|
184
|
-
end
|
185
|
-
|
186
|
-
def validate_length
|
187
|
-
raise LengthError, 'field length must be 0 or greater' if length < 0
|
188
|
-
end
|
189
|
-
|
190
|
-
def validate_name
|
191
|
-
raise NameError, 'column name cannot be empty' if @name.empty?
|
192
|
-
end
|
193
|
-
|
194
|
-
def supports_encoding?
|
195
|
-
@encoding && table.supports_encoding?
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|