dbf 3.0.0 → 3.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 +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
|