dbf 2.0.3 → 2.0.4

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.
@@ -15,15 +15,18 @@ module DBF
15
15
  "07" => "Visual Objects 1.x",
16
16
  "30" => "Visual FoxPro",
17
17
  "31" => "Visual FoxPro with AutoIncrement field",
18
+ "43" => "dBASE IV SQL table files, no memo",
19
+ "63" => "dBASE IV SQL system files, no memo",
18
20
  "7b" => "dBase IV with memo file",
19
21
  "83" => "dBase III with memo file",
20
22
  "87" => "Visual Objects 1.x with memo file",
21
23
  "8b" => "dBase IV with memo file",
22
24
  "8e" => "dBase IV with SQL table",
25
+ "cb" => "dBASE IV SQL table files, with memo",
23
26
  "f5" => "FoxPro with memo file",
24
27
  "fb" => "FoxPro without memo file"
25
28
  }
26
-
29
+
27
30
  FOXPRO_VERSIONS = {
28
31
  "30" => "Visual FoxPro",
29
32
  "31" => "Visual FoxPro with AutoIncrement field",
@@ -58,11 +61,11 @@ module DBF
58
61
  # @param [optional String, Encoding] encoding Name of the encoding or an Encoding object
59
62
  def initialize(data, memo = nil, encoding = nil)
60
63
  @data = open_data(data)
61
- get_header_info
62
- @encoding = encoding || @encoding
64
+ @version, @record_count, @header_length, @record_length, @encoding_key, @encoding = get_header_info
65
+ @encoding = encoding if encoding
63
66
  @memo = open_memo(data, memo)
64
67
  end
65
-
68
+
66
69
  # @return [TrueClass, FalseClass]
67
70
  def has_memo_file?
68
71
  !!@memo
@@ -75,7 +78,7 @@ module DBF
75
78
  @data.close
76
79
  @memo && @memo.close
77
80
  end
78
-
81
+
79
82
  # @return [TrueClass, FalseClass]
80
83
  def closed?
81
84
  if @memo
@@ -84,7 +87,7 @@ module DBF
84
87
  @data.closed?
85
88
  end
86
89
  end
87
-
90
+
88
91
  # @return String
89
92
  def filename
90
93
  File.basename @data.path
@@ -213,32 +216,28 @@ module DBF
213
216
  columns
214
217
  end
215
218
  end
216
-
219
+
217
220
  def supports_encoding?
218
221
  String.new.respond_to?(:encoding)
219
222
  end
220
-
223
+
221
224
  def supports_iconv?
222
225
  require 'iconv'
223
226
  true
224
227
  rescue
225
228
  false
226
229
  end
227
-
230
+
228
231
  def foxpro?
229
232
  FOXPRO_VERSIONS.keys.include? @version
230
233
  end
231
234
 
232
235
  private
233
-
236
+
234
237
  def column_class #nodoc
235
- @column_class ||= if foxpro?
236
- Column::Foxpro
237
- else
238
- Column::Dbase
239
- end
238
+ @column_class ||= foxpro? ? Column::Foxpro : Column::Dbase
240
239
  end
241
-
240
+
242
241
  def memo_class #nodoc
243
242
  @memo_class ||= if foxpro?
244
243
  Memo::Foxpro
@@ -250,7 +249,7 @@ module DBF
250
249
  end
251
250
  end
252
251
  end
253
-
252
+
254
253
  def column_count #nodoc
255
254
  @column_count ||= ((@header_length - DBF_HEADER_SIZE + 1) / DBF_HEADER_SIZE).to_i
256
255
  end
@@ -265,15 +264,19 @@ module DBF
265
264
  elsif memo
266
265
  memo_class.open(memo, version)
267
266
  elsif !data.is_a? StringIO
268
- dirname = File.dirname(data)
269
- basename = File.basename(data, '.*')
270
- files = Dir.glob("#{dirname}/#{basename}*.{fpt,FPT,dbt,DBT}")
267
+ files = Dir.glob(memo_search_path(data))
271
268
  files.any? ? memo_class.open(files.first, version) : nil
272
269
  else
273
270
  nil
274
271
  end
275
272
  end
276
273
 
274
+ def memo_search_path(io) #nodoc
275
+ dirname = File.dirname(io)
276
+ basename = File.basename(io, '.*')
277
+ "#{dirname}/#{basename}*.{fpt,FPT,dbt,DBT}"
278
+ end
279
+
277
280
  def find_all(options) #nodoc
278
281
  map do |record|
279
282
  if record && record.match?(options)
@@ -293,10 +296,11 @@ module DBF
293
296
 
294
297
  def get_header_info #nodoc
295
298
  @data.rewind
296
- @version, @record_count, @header_length, @record_length, @encoding_key = read_header
297
- @encoding = ENCODINGS[@encoding_key] if supports_encoding? || supports_iconv?
299
+ version, record_count, header_length, record_length, encoding_key = read_header
300
+ encoding = ENCODINGS[encoding_key] if supports_encoding? || supports_iconv?
301
+ [version, record_count, header_length, record_length, encoding_key, encoding]
298
302
  end
299
-
303
+
300
304
  def read_header #nodoc
301
305
  @data.read(DBF_HEADER_SIZE).unpack("H2 x3 V v2 x17H2")
302
306
  end
@@ -1,3 +1,3 @@
1
1
  module DBF
2
- VERSION = '2.0.3'
2
+ VERSION = '2.0.4'
3
3
  end
@@ -1,235 +1,245 @@
1
+ # encoding: ascii-8bit
2
+
1
3
  require "spec_helper"
2
4
 
3
5
  describe DBF::Column::Dbase do
4
-
6
+
5
7
  context "when initialized" do
6
8
  let(:column) { DBF::Column::Dbase.new "ColumnName", "N", 1, 0, "30" }
7
-
8
- it "sets the #name accessor" do
9
- column.name.should == "ColumnName"
9
+
10
+ it "sets :name accessor" do
11
+ expect(column.name).to eq "ColumnName"
10
12
  end
11
-
12
- it "sets the #type accessor" do
13
- column.type.should == "N"
13
+
14
+ it "sets :type accessor" do
15
+ expect(column.type).to eq "N"
14
16
  end
15
-
17
+
16
18
  it "sets the #length accessor" do
17
- column.length.should == 1
19
+ expect(column.length).to eq 1
18
20
  end
19
-
21
+
20
22
  it "sets the #decimal accessor" do
21
- column.decimal.should == 0
23
+ expect(column.decimal).to eq 0
22
24
  end
23
-
25
+
24
26
  describe 'with length of 0' do
25
27
  it 'raises DBF::Column::LengthError' do
26
28
  expect { DBF::Column::Dbase.new "ColumnName", "N", 0, 0, "30" }.to raise_error(DBF::Column::LengthError)
27
29
  end
28
30
  end
29
-
31
+
30
32
  describe 'with length less than 0' do
31
33
  it 'raises DBF::Column::LengthError' do
32
34
  expect { DBF::Column::Dbase.new "ColumnName", "N", -1, 0, "30" }.to raise_error(DBF::Column::LengthError)
33
35
  end
34
36
  end
35
-
37
+
36
38
  describe 'with empty column name' do
37
39
  it 'raises DBF::Column::NameError' do
38
40
  expect { DBF::Column::Dbase.new "\xFF\xFC", "N", 1, 0, "30" }.to raise_error(DBF::Column::NameError)
39
41
  end
40
42
  end
41
43
  end
42
-
44
+
43
45
  context '#type_cast' do
44
46
  context 'with type N (number)' do
45
47
  context 'and 0 decimals' do
46
48
  it 'casts value to Fixnum' do
47
49
  value = '135'
48
50
  column = DBF::Column::Dbase.new "ColumnName", "N", 3, 0, "30"
49
- column.type_cast(value).should be_a(Fixnum)
50
- column.type_cast(value).should == 135
51
+ expect(column.type_cast(value)).to be_a(Fixnum)
52
+ expect(column.type_cast(value)).to eq 135
51
53
  end
52
54
  end
53
-
55
+
54
56
  context 'and more than 0 decimals' do
55
57
  it 'casts value to Float' do
56
58
  value = '13.5'
57
59
  column = DBF::Column::Dbase.new "ColumnName", "N", 2, 1, "30"
58
- column.type_cast(value).should be_a(Float)
59
- column.type_cast(value).should == 13.5
60
+ expect(column.type_cast(value)).to be_a(Float)
61
+ expect(column.type_cast(value)).to eq 13.5
60
62
  end
61
63
  end
62
64
  end
63
-
65
+
64
66
  context 'with type F (float)' do
65
67
  it 'casts value to Float' do
66
68
  value = '135'
67
69
  column = DBF::Column::Dbase.new "ColumnName", "F", 3, 0, "30"
68
- column.type_cast(value).should be_a(Float)
69
- column.type_cast(value).should == 135.0
70
+ expect(column.type_cast(value)).to be_a(Float)
71
+ expect(column.type_cast(value)).to eq 135.0
70
72
  end
71
73
  end
72
-
74
+
73
75
  context 'with type I (integer)' do
74
76
  it "casts value to Fixnum" do
75
77
  value = "\203\171\001\000"
76
78
  column = DBF::Column::Dbase.new "ColumnName", "I", 3, 0, "30"
77
- column.type_cast(value).should == 96643
79
+ expect(column.type_cast(value)).to eq 96643
78
80
  end
79
81
  end
80
-
82
+
81
83
  context 'with type L (logical/boolean)' do
82
84
  let(:column) { DBF::Column::Dbase.new "ColumnName", "L", 1, 0, "30" }
83
-
85
+
84
86
  it "casts 'y' to true" do
85
- column.type_cast('y').should == true
87
+ expect(column.type_cast('y')).to eq true
86
88
  end
87
-
89
+
88
90
  it "casts 't' to true" do
89
- column.type_cast('t').should == true
91
+ expect(column.type_cast('t')).to eq true
90
92
  end
91
-
93
+
92
94
  it "casts value other than 't' or 'y' to false" do
93
- column.type_cast('n').should == false
95
+ expect(column.type_cast('n')).to eq false
94
96
  end
95
97
  end
96
-
98
+
97
99
  context 'with type T (datetime)' do
98
100
  let(:column) { DBF::Column::Dbase.new "ColumnName", "T", 16, 0, "30" }
99
-
101
+
100
102
  context 'with valid datetime' do
101
103
  it "casts to DateTime" do
102
- column.type_cast("Nl%\000\300Z\252\003").should == DateTime.parse("2002-10-10T17:04:56+00:00")
104
+ expect(column.type_cast("Nl%\000\300Z\252\003")).to eq DateTime.parse("2002-10-10T17:04:56+00:00")
103
105
  end
104
106
  end
105
-
107
+
106
108
  if ruby_supports_mathn?
107
109
  context 'when requiring mathn' do
108
110
  it "casts to DateTime" do
109
- lambda {
111
+ with_mathn = lambda do
110
112
  require 'mathn'
111
113
  column.type_cast("Nl%\000\300Z\252\003")
112
- }.call.should == DateTime.parse("2002-10-10T17:04:56+00:00")
114
+ end
115
+ expect(with_mathn.call).to eq DateTime.parse("2002-10-10T17:04:56+00:00")
113
116
  end
114
117
  end
115
118
  end
116
-
119
+
117
120
  context 'with invalid datetime' do
118
121
  it "casts to nil" do
119
- column.type_cast("Nl%\000\000A\000\999").should be_nil
122
+ expect(column.type_cast("Nl%\000\000A\000\999")).to be_nil
120
123
  end
121
124
  end
122
125
  end
123
-
126
+
124
127
  context 'with type D (date)' do
125
128
  let(:column) { DBF::Column::Dbase.new "ColumnName", "D", 8, 0, "30" }
126
-
129
+
127
130
  context 'with valid date' do
128
131
  it "casts to Date" do
129
- column.type_cast("20050712").should == Date.new(2005,7,12)
132
+ expect(column.type_cast("20050712")).to eq Date.new(2005,7,12)
130
133
  end
131
134
  end
132
-
135
+
133
136
  context 'with invalid date' do
134
137
  it "casts to nil" do
135
- column.type_cast("0").should be_nil
138
+ expect(column.type_cast("0")).to be_nil
136
139
  end
137
140
  end
138
141
  end
139
-
142
+
140
143
  context 'with type M (memo)' do
141
144
  it "casts to string" do
142
145
  column = DBF::Column::Dbase.new "ColumnName", "M", 3, 0, "30"
143
- column.type_cast('abc').should be_a(String)
146
+ expect(column.type_cast('abc')).to be_a(String)
147
+ end
148
+
149
+ it 'casts nil to nil' do
150
+ column = DBF::Column::Dbase.new "ColumnName", "M", 3, 0, "30"
151
+ expect(column.type_cast(nil)).to be_nil
144
152
  end
145
153
  end
146
154
  end
147
-
155
+
148
156
  context 'with type Y (currency)' do
149
157
  let(:column) { DBF::Column::Dbase.new "ColumnName", "Y", 8, 4, "31" }
150
-
158
+
151
159
  it 'casts to float' do
152
- column.type_cast(" \xBF\x02\x00\x00\x00\x00\x00").should == 18.0
160
+ expect(column.type_cast(" \xBF\x02\x00\x00\x00\x00\x00")).to eq 18.0
153
161
  end
154
162
  end
155
-
163
+
156
164
  context "#schema_definition" do
157
165
  context 'with type N (number)' do
158
166
  it "outputs an integer column" do
159
167
  column = DBF::Column::Dbase.new "ColumnName", "N", 1, 0, "30"
160
- column.schema_definition.should == "\"column_name\", :integer\n"
168
+ expect(column.schema_definition).to eq "\"column_name\", :integer\n"
161
169
  end
162
170
  end
163
-
171
+
164
172
  context "with type B (binary)" do
165
173
  context "with Foxpro dbf" do
166
174
  context "when decimal is greater than 0" do
167
175
  it "outputs an float column" do
168
176
  column = DBF::Column::Dbase.new "ColumnName", "B", 1, 2, "f5"
169
- column.schema_definition.should == "\"column_name\", :float\n"
177
+ expect(column.schema_definition).to eq "\"column_name\", :float\n"
170
178
  end
171
179
  end
172
-
180
+
173
181
  context "when decimal is 0" do
174
- column = DBF::Column::Dbase.new "ColumnName", "B", 1, 0, "f5"
175
- column.schema_definition.should == "\"column_name\", :integer\n"
182
+ it "outputs an integer column" do
183
+ column = DBF::Column::Dbase.new "ColumnName", "B", 1, 0, "f5"
184
+ expect(column.schema_definition).to eq "\"column_name\", :integer\n"
185
+ end
176
186
  end
177
187
  end
178
188
  end
179
-
189
+
180
190
  it "defines a float colmn if type is (N)umber with more than 0 decimals" do
181
191
  column = DBF::Column::Dbase.new "ColumnName", "N", 1, 2, "30"
182
- column.schema_definition.should == "\"column_name\", :float\n"
192
+ expect(column.schema_definition).to eq "\"column_name\", :float\n"
183
193
  end
184
-
194
+
185
195
  it "defines a date column if type is (D)ate" do
186
196
  column = DBF::Column::Dbase.new "ColumnName", "D", 8, 0, "30"
187
- column.schema_definition.should == "\"column_name\", :date\n"
197
+ expect(column.schema_definition).to eq "\"column_name\", :date\n"
188
198
  end
189
-
199
+
190
200
  it "defines a datetime column if type is (D)ate" do
191
201
  column = DBF::Column::Dbase.new "ColumnName", "T", 16, 0, "30"
192
- column.schema_definition.should == "\"column_name\", :datetime\n"
202
+ expect(column.schema_definition).to eq "\"column_name\", :datetime\n"
193
203
  end
194
-
204
+
195
205
  it "defines a boolean column if type is (L)ogical" do
196
206
  column = DBF::Column::Dbase.new "ColumnName", "L", 1, 0, "30"
197
- column.schema_definition.should == "\"column_name\", :boolean\n"
207
+ expect(column.schema_definition).to eq "\"column_name\", :boolean\n"
198
208
  end
199
-
209
+
200
210
  it "defines a text column if type is (M)emo" do
201
211
  column = DBF::Column::Dbase.new "ColumnName", "M", 1, 0, "30"
202
- column.schema_definition.should == "\"column_name\", :text\n"
212
+ expect(column.schema_definition).to eq "\"column_name\", :text\n"
203
213
  end
204
-
214
+
205
215
  it "defines a string column with length for any other data types" do
206
216
  column = DBF::Column::Dbase.new "ColumnName", "X", 20, 0, "30"
207
- column.schema_definition.should == "\"column_name\", :string, :limit => 20\n"
217
+ expect(column.schema_definition).to eq "\"column_name\", :string, :limit => 20\n"
208
218
  end
209
219
  end
210
-
211
- context "#name" do
220
+
221
+ context "#name" do
212
222
  it "contains only ASCII characters" do
213
223
  column = DBF::Column::Dbase.new "--\x1F-\x68\x65\x6C\x6C\x6F world-\x80--", "N", 1, 0, "30"
214
- column.name.should == "---hello world---"
224
+ expect(column.name).to eq "---hello world---"
215
225
  end
216
226
 
217
227
  it "is truncated at the null character" do
218
228
  column = DBF::Column::Dbase.new "--\x1F-\x68\x65\x6C\x6C\x6F \x00 world-\x80--", "N", 1, 0, "30"
219
- column.name.should == "---hello "
229
+ expect(column.name).to eq "---hello "
220
230
  end
221
231
  end
222
-
232
+
223
233
  context '#decode_date' do
224
234
  let(:column) { DBF::Column::Dbase.new "ColumnName", "N", 1, 0, "30" }
225
-
235
+
226
236
  it 'is nil if value is blank' do
227
- column.send(:decode_date, '').should be_nil
237
+ expect(column.send(:decode_date, '')).to be_nil
228
238
  end
229
-
239
+
230
240
  it 'interperets spaces as zeros' do
231
- column.send(:decode_date, '2010 715').should == Date.parse('20100715')
241
+ expect(column.send(:decode_date, '2010 715')).to eq Date.parse('20100715')
232
242
  end
233
243
  end
234
-
244
+
235
245
  end