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.
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe DBF::Database::Foxpro do
4
- let(:dbf_path) { fixture_path('foxprodb/FOXPRO-DB-TEST.DBC') }
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
- shared_examples_for 'Foxpro DBF' do
54
- specify "columns should be instances of DBF::FoxproColumn" do
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 fixture_path('dbase_30.dbf') }
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 fixture_path('dbase_31.dbf') }
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 fixture_path('dbase_83.dbf') }
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 fixture_path('dbase_8b.dbf') }
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 fixture_path('dbase_f5.dbf') }
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"
@@ -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 fixture_path('dbase_83.dbf') }
7
- let(:record_0) { YAML.load_file(fixture_path('dbase_83_record_0.yml')) }
8
- let(:record_9) { YAML.load_file(fixture_path('dbase_83_record_9.yml')) }
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 fixture_path('dbase_83_missing_memo.dbf') }
21
- let(:record_0) { YAML.load_file(fixture_path('dbase_83_missing_memo_record_0.yml')) }
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(fixture_path('dbase_83_missing_memo.dbf'))) }
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(fixture_path('dbase_83_missing_memo_record_0.yml')) }
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 fixture_path('dbase_8b.dbf') }
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) { {:x => 1, :y => 2} }
54
- let(:other) { double('object', :attributes => attributes) }
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 fixture_path('dbase_8b.dbf') }
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 fixture_path('cp1251.dbf') }
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
- if table.supports_string_encoding?
87
- expect(record.name.encoding).to eq Encoding.default_external
85
+ expect(record.name.encoding).to eq Encoding.default_external
88
86
 
89
- # russian a
90
- expect(record.name.encode("UTF-8").unpack("H4")).to eq ["d0b0"]
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 fixture_path('cp1251.dbf'), nil, 'cp866'}
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
- if table.supports_string_encoding?
101
- expect(record.name.encoding).to eq Encoding.default_external
97
+ expect(record.name.encoding).to eq Encoding.default_external
102
98
 
103
- # russian а encoded in cp1251 and read as if it was encoded in cp866
104
- expect(record.name.encode("UTF-8").unpack("H4")).to eq ["d180"]
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 fixture_path('dbase_8b.dbf') }
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
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe DBF::Table do
4
- let(:dbf_path) { fixture_path('dbase_83.dbf') }
5
- let(:memo_path) { fixture_path('dbase_83.dbt') }
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
- it 'accepts a block' do
138
- records = []
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
- expect(records).to eq table.find(:all, :weight => 0.0)
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(table.columns).to be_an(Array)
213
- expect(table.columns).to_not be_empty
214
- expect(table.columns.all? {|c| c.class == DBF::Column::Dbase}).to be_truthy
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
- correct_column_names = %w(ID CATCOUNT AGRPCOUNT PGRPCOUNT ORDER CODE NAME THUMBNAIL IMAGE PRICE COST DESC WEIGHT TAXABLE ACTIVE)
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
@@ -9,20 +9,24 @@ require 'yaml'
9
9
  require 'rspec'
10
10
  require 'fileutils'
11
11
 
12
- Encoding.default_external = "UTF-8" if defined?(Encoding)
12
+ RSpec.configure do |config|
13
+ config.disable_monkey_patching!
14
+ config.warnings = true
15
+ config.order = :random
13
16
 
14
- DB_PATH = File.dirname(__FILE__) + '/fixtures' unless defined?(DB_PATH)
17
+ config.expect_with :rspec do |expectations|
18
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
19
+ end
15
20
 
16
- RSpec.configure do |config|
17
- def ruby_supports_mathn?
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(filename)
27
- "#{DB_PATH}/#{filename}"
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.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-10-23 00:00:00.000000000 Z
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/base.rb
38
- - lib/dbf/column/dbase.rb
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.6
113
+ rubygems_version: 2.4.5.1
115
114
  signing_key:
116
115
  specification_version: 4
117
116
  summary: Read xBase files
@@ -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