dbf 2.0.10 → 2.0.11
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 +28 -25
- data/lib/dbf/column/base.rb +85 -59
- data/lib/dbf/column/foxpro.rb +1 -1
- data/lib/dbf/database/foxpro.rb +43 -26
- data/lib/dbf/encodings.rb +59 -59
- data/lib/dbf/header.rb +1 -1
- data/lib/dbf/memo/base.rb +7 -7
- data/lib/dbf/memo/dbase3.rb +6 -5
- data/lib/dbf/memo/dbase4.rb +2 -2
- data/lib/dbf/memo/foxpro.rb +4 -4
- data/lib/dbf/record.rb +18 -16
- data/lib/dbf/schema.rb +1 -0
- data/lib/dbf/table.rb +61 -76
- data/lib/dbf/version.rb +1 -1
- data/spec/dbf/column_spec.rb +19 -12
- data/spec/dbf/table_spec.rb +38 -37
- metadata +2 -2
data/lib/dbf/encodings.rb
CHANGED
@@ -1,63 +1,63 @@
|
|
1
1
|
module DBF
|
2
2
|
ENCODINGS = {
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
3
|
+
'01' => 'cp437', # U.S. MS-DOS
|
4
|
+
'02' => 'cp850', # International MS-DOS
|
5
|
+
'03' => 'cp1252', # Windows ANSI
|
6
|
+
'08' => 'cp865', # Danish OEM
|
7
|
+
'09' => 'cp437', # Dutch OEM
|
8
|
+
'0a' => 'cp850', # Dutch OEM*
|
9
|
+
'0b' => 'cp437', # Finnish OEM
|
10
|
+
'0d' => 'cp437', # French OEM
|
11
|
+
'0e' => 'cp850', # French OEM*
|
12
|
+
'0f' => 'cp437', # German OEM
|
13
|
+
'10' => 'cp850', # German OEM*
|
14
|
+
'11' => 'cp437', # Italian OEM
|
15
|
+
'12' => 'cp850', # Italian OEM*
|
16
|
+
'13' => 'cp932', # Japanese Shift-JIS
|
17
|
+
'14' => 'cp850', # Spanish OEM*
|
18
|
+
'15' => 'cp437', # Swedish OEM
|
19
|
+
'16' => 'cp850', # Swedish OEM*
|
20
|
+
'17' => 'cp865', # Norwegian OEM
|
21
|
+
'18' => 'cp437', # Spanish OEM
|
22
|
+
'19' => 'cp437', # English OEM (Britain)
|
23
|
+
'1a' => 'cp850', # English OEM (Britain)*
|
24
|
+
'1b' => 'cp437', # English OEM (U.S.)
|
25
|
+
'1c' => 'cp863', # French OEM (Canada)
|
26
|
+
'1d' => 'cp850', # French OEM*
|
27
|
+
'1f' => 'cp852', # Czech OEM
|
28
|
+
'22' => 'cp852', # Hungarian OEM
|
29
|
+
'23' => 'cp852', # Polish OEM
|
30
|
+
'24' => 'cp860', # Portuguese OEM
|
31
|
+
'25' => 'cp850', # Portuguese OEM*
|
32
|
+
'26' => 'cp866', # Russian OEM
|
33
|
+
'37' => 'cp850', # English OEM (U.S.)*
|
34
|
+
'40' => 'cp852', # Romanian OEM
|
35
|
+
'4d' => 'cp936', # Chinese GBK (PRC)
|
36
|
+
'4e' => 'cp949', # Korean (ANSI/OEM)
|
37
|
+
'4f' => 'cp950', # Chinese Big5 (Taiwan)
|
38
|
+
'50' => 'cp874', # Thai (ANSI/OEM)
|
39
|
+
'57' => 'cp1252', # ANSI
|
40
|
+
'58' => 'cp1252', # Western European ANSI
|
41
|
+
'59' => 'cp1252', # Spanish ANSI
|
42
|
+
'64' => 'cp852', # Eastern European MS-DOS
|
43
|
+
'65' => 'cp866', # Russian MS-DOS
|
44
|
+
'66' => 'cp865', # Nordic MS-DOS
|
45
|
+
'67' => 'cp861', # Icelandic MS-DOS
|
46
|
+
'6a' => 'cp737', # Greek MS-DOS (437G)
|
47
|
+
'6b' => 'cp857', # Turkish MS-DOS
|
48
|
+
'6c' => 'cp863', # French-Canadian MS-DOS
|
49
|
+
'78' => 'cp950', # Taiwan Big 5
|
50
|
+
'79' => 'cp949', # Hangul (Wansung)
|
51
|
+
'7a' => 'cp936', # PRC GBK
|
52
|
+
'7b' => 'cp932', # Japanese Shift-JIS
|
53
|
+
'7c' => 'cp874', # Thai Windows/MS-DOS
|
54
|
+
'86' => 'cp737', # Greek OEM
|
55
|
+
'87' => 'cp852', # Slovenian OEM
|
56
|
+
'88' => 'cp857', # Turkish OEM
|
57
|
+
'c8' => 'cp1250', # Eastern European Windows
|
58
|
+
'c9' => 'cp1251', # Russian Windows
|
59
|
+
'ca' => 'cp1254', # Turkish Windows
|
60
|
+
'cb' => 'cp1253', # Greek Windows
|
61
|
+
'cc' => 'cp1257', # Baltic Windows
|
62
62
|
}
|
63
63
|
end
|
data/lib/dbf/header.rb
CHANGED
data/lib/dbf/memo/base.rb
CHANGED
@@ -9,13 +9,13 @@ module DBF
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def initialize(data, version)
|
12
|
-
@data
|
12
|
+
@data = data
|
13
|
+
@version = version
|
13
14
|
end
|
14
15
|
|
15
16
|
def get(start_block)
|
16
|
-
|
17
|
-
|
18
|
-
end
|
17
|
+
return nil unless start_block > 0
|
18
|
+
build_memo start_block
|
19
19
|
end
|
20
20
|
|
21
21
|
def close
|
@@ -28,15 +28,15 @@ module DBF
|
|
28
28
|
|
29
29
|
private
|
30
30
|
|
31
|
-
def offset(start_block) #nodoc
|
31
|
+
def offset(start_block) # nodoc
|
32
32
|
start_block * block_size
|
33
33
|
end
|
34
34
|
|
35
|
-
def content_size(memo_size) #nodoc
|
35
|
+
def content_size(memo_size) # nodoc
|
36
36
|
(memo_size - block_size) + BLOCK_HEADER_SIZE
|
37
37
|
end
|
38
38
|
|
39
|
-
def block_content_size #nodoc
|
39
|
+
def block_content_size # nodoc
|
40
40
|
@block_content_size ||= block_size - BLOCK_HEADER_SIZE
|
41
41
|
end
|
42
42
|
|
data/lib/dbf/memo/dbase3.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
module DBF
|
2
2
|
module Memo
|
3
3
|
class Dbase3 < Base
|
4
|
-
def build_memo(start_block) #nodoc
|
4
|
+
def build_memo(start_block) # nodoc
|
5
5
|
@data.seek offset(start_block)
|
6
|
-
memo_string =
|
7
|
-
|
6
|
+
memo_string = ''
|
7
|
+
loop do
|
8
8
|
block = @data.read(BLOCK_SIZE).gsub(/(\000|\032)/, '')
|
9
9
|
memo_string << block
|
10
|
-
|
10
|
+
break if block.size < BLOCK_SIZE
|
11
|
+
end
|
11
12
|
memo_string
|
12
13
|
end
|
13
14
|
end
|
14
15
|
end
|
15
|
-
end
|
16
|
+
end
|
data/lib/dbf/memo/dbase4.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module DBF
|
2
2
|
module Memo
|
3
3
|
class Dbase4 < Base
|
4
|
-
def build_memo(start_block) #nodoc
|
4
|
+
def build_memo(start_block) # nodoc
|
5
5
|
@data.seek offset(start_block)
|
6
|
-
@data.read(@data.read(BLOCK_HEADER_SIZE).unpack(
|
6
|
+
@data.read(@data.read(BLOCK_HEADER_SIZE).unpack('x4L').first)
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
data/lib/dbf/memo/foxpro.rb
CHANGED
@@ -3,10 +3,10 @@ module DBF
|
|
3
3
|
class Foxpro < Base
|
4
4
|
FPT_HEADER_SIZE = 512
|
5
5
|
|
6
|
-
def build_memo(start_block) #nodoc
|
6
|
+
def build_memo(start_block) # nodoc
|
7
7
|
@data.seek offset(start_block)
|
8
8
|
|
9
|
-
memo_type, memo_size, memo_string = @data.read(block_size).unpack(
|
9
|
+
memo_type, memo_size, memo_string = @data.read(block_size).unpack('NNa*')
|
10
10
|
return nil unless memo_type == 1 && memo_size > 0
|
11
11
|
|
12
12
|
if memo_size > block_content_size
|
@@ -22,7 +22,7 @@ module DBF
|
|
22
22
|
|
23
23
|
private
|
24
24
|
|
25
|
-
def block_size #nodoc
|
25
|
+
def block_size # nodoc
|
26
26
|
@block_size ||= begin
|
27
27
|
@data.rewind
|
28
28
|
@data.read(FPT_HEADER_SIZE).unpack('x6n').first || 0
|
@@ -30,4 +30,4 @@ module DBF
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
33
|
-
end
|
33
|
+
end
|
data/lib/dbf/record.rb
CHANGED
@@ -9,7 +9,9 @@ module DBF
|
|
9
9
|
# @memo [DBF::Memo]
|
10
10
|
def initialize(data, columns, version, memo)
|
11
11
|
@data = StringIO.new(data)
|
12
|
-
@columns
|
12
|
+
@columns = columns
|
13
|
+
@version = version
|
14
|
+
@memo = memo
|
13
15
|
end
|
14
16
|
|
15
17
|
# Equality
|
@@ -24,7 +26,7 @@ module DBF
|
|
24
26
|
#
|
25
27
|
# @return [Array]
|
26
28
|
def to_a
|
27
|
-
@columns.map {|column| attributes[column.name]}
|
29
|
+
@columns.map { |column| attributes[column.name] }
|
28
30
|
end
|
29
31
|
|
30
32
|
# Do all search parameters match?
|
@@ -32,17 +34,17 @@ module DBF
|
|
32
34
|
# @param [Hash] options
|
33
35
|
# @return [Boolean]
|
34
36
|
def match?(options)
|
35
|
-
options.all? {|key, value| self[key] == value}
|
37
|
+
options.all? { |key, value| self[key] == value }
|
36
38
|
end
|
37
39
|
|
38
40
|
# Reads attributes by column name
|
39
41
|
#
|
40
42
|
# @param [String, Symbol] key
|
41
|
-
def [](
|
42
|
-
key =
|
43
|
-
if attributes.
|
43
|
+
def [](name)
|
44
|
+
key = name.to_s
|
45
|
+
if attributes.key?(key)
|
44
46
|
attributes[key]
|
45
|
-
elsif index = underscored_column_names.index(key)
|
47
|
+
elsif (index = underscored_column_names.index(key))
|
46
48
|
attributes[@columns[index].name]
|
47
49
|
end
|
48
50
|
end
|
@@ -51,7 +53,8 @@ module DBF
|
|
51
53
|
#
|
52
54
|
# @return [Hash]
|
53
55
|
def attributes
|
54
|
-
@attributes ||=
|
56
|
+
@attributes ||=
|
57
|
+
Hash[@columns.map { |column| [column.name, init_attribute(column)] }]
|
55
58
|
end
|
56
59
|
|
57
60
|
# Overrides standard Object.respond_to? to return true if a
|
@@ -69,8 +72,8 @@ module DBF
|
|
69
72
|
|
70
73
|
private
|
71
74
|
|
72
|
-
def method_missing(method, *args) #nodoc
|
73
|
-
if index = underscored_column_names.index(method.to_s)
|
75
|
+
def method_missing(method, *args) # nodoc
|
76
|
+
if (index = underscored_column_names.index(method.to_s))
|
74
77
|
attributes[@columns[index].name]
|
75
78
|
else
|
76
79
|
super
|
@@ -78,15 +81,15 @@ module DBF
|
|
78
81
|
end
|
79
82
|
|
80
83
|
def underscored_column_names # nodoc
|
81
|
-
@underscored_column_names ||= @columns.map
|
84
|
+
@underscored_column_names ||= @columns.map(&:underscored_name)
|
82
85
|
end
|
83
86
|
|
84
|
-
def init_attribute(column) #nodoc
|
87
|
+
def init_attribute(column) # nodoc
|
85
88
|
value = column.memo? ? memo(column) : unpack_data(column)
|
86
89
|
column.type_cast(value)
|
87
90
|
end
|
88
91
|
|
89
|
-
def memo(column) #nodoc
|
92
|
+
def memo(column) # nodoc
|
90
93
|
if @memo
|
91
94
|
@memo.get(memo_start_block(column))
|
92
95
|
else
|
@@ -96,15 +99,14 @@ module DBF
|
|
96
99
|
end
|
97
100
|
end
|
98
101
|
|
99
|
-
def memo_start_block(column) #nodoc
|
102
|
+
def memo_start_block(column) # nodoc
|
100
103
|
format = 'V' if %w(30 31).include?(@version)
|
101
104
|
unpack_data(column, format).to_i
|
102
105
|
end
|
103
106
|
|
104
|
-
def unpack_data(column, format=nil) #nodoc
|
107
|
+
def unpack_data(column, format = nil) # nodoc
|
105
108
|
format ||= "a#{column.length}"
|
106
109
|
@data.read(column.length).unpack(format).first
|
107
110
|
end
|
108
|
-
|
109
111
|
end
|
110
112
|
end
|
data/lib/dbf/schema.rb
CHANGED
data/lib/dbf/table.rb
CHANGED
@@ -11,33 +11,33 @@ module DBF
|
|
11
11
|
DBF_HEADER_SIZE = 32
|
12
12
|
|
13
13
|
VERSIONS = {
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
14
|
+
'02' => 'FoxBase',
|
15
|
+
'03' => 'dBase III without memo file',
|
16
|
+
'04' => 'dBase IV without memo file',
|
17
|
+
'05' => 'dBase V without memo file',
|
18
|
+
'07' => 'Visual Objects 1.x',
|
19
|
+
'30' => 'Visual FoxPro',
|
20
|
+
'31' => 'Visual FoxPro with AutoIncrement field',
|
21
|
+
'43' => 'dBASE IV SQL table files, no memo',
|
22
|
+
'63' => 'dBASE IV SQL system files, no memo',
|
23
|
+
'7b' => 'dBase IV with memo file',
|
24
|
+
'83' => 'dBase III with memo file',
|
25
|
+
'87' => 'Visual Objects 1.x with memo file',
|
26
|
+
'8b' => 'dBase IV with memo file',
|
27
|
+
'8e' => 'dBase IV with SQL table',
|
28
|
+
'cb' => 'dBASE IV SQL table files, with memo',
|
29
|
+
'f5' => 'FoxPro with memo file',
|
30
|
+
'fb' => 'FoxPro without memo file'
|
31
31
|
}
|
32
32
|
|
33
33
|
FOXPRO_VERSIONS = {
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
'30' => 'Visual FoxPro',
|
35
|
+
'31' => 'Visual FoxPro with AutoIncrement field',
|
36
|
+
'f5' => 'FoxPro with memo file',
|
37
|
+
'fb' => 'FoxPro without memo file'
|
38
38
|
}
|
39
39
|
|
40
|
-
attr_reader
|
40
|
+
attr_reader :header
|
41
41
|
attr_accessor :encoding # Source encoding (for ex. :cp1251)
|
42
42
|
|
43
43
|
# Opens a DBF::Table
|
@@ -62,16 +62,14 @@ module DBF
|
|
62
62
|
# @param [optional String, StringIO] memo Path to the memo file or a StringIO object
|
63
63
|
# @param [optional String, Encoding] encoding Name of the encoding or an Encoding object
|
64
64
|
def initialize(data, memo = nil, encoding = nil)
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
raise DBF::FileNotFoundError.new("file not found: #{data}")
|
74
|
-
end
|
65
|
+
@data = open_data(data)
|
66
|
+
@data.rewind
|
67
|
+
@header = Header.new(@data.read(DBF_HEADER_SIZE), supports_encoding?)
|
68
|
+
@encoding = encoding || header.encoding
|
69
|
+
@memo = open_memo(data, memo)
|
70
|
+
yield self if block_given?
|
71
|
+
rescue Errno::ENOENT
|
72
|
+
raise DBF::FileNotFoundError, "file not found: #{data}"
|
75
73
|
end
|
76
74
|
|
77
75
|
# @return [TrueClass, FalseClass]
|
@@ -106,7 +104,7 @@ module DBF
|
|
106
104
|
#
|
107
105
|
# @yield [nil, DBF::Record]
|
108
106
|
def each
|
109
|
-
header.record_count.times {|i| yield record(i)}
|
107
|
+
header.record_count.times { |i| yield record(i) }
|
110
108
|
end
|
111
109
|
|
112
110
|
# Retrieve a record by index number.
|
@@ -117,9 +115,8 @@ module DBF
|
|
117
115
|
# @return [DBF::Record, NilClass]
|
118
116
|
def record(index)
|
119
117
|
seek_to_record(index)
|
120
|
-
if
|
121
|
-
|
122
|
-
end
|
118
|
+
return nil if deleted_record?
|
119
|
+
DBF::Record.new(@data.read(header.record_length), columns, version, @memo)
|
123
120
|
end
|
124
121
|
|
125
122
|
alias_method :row, :record
|
@@ -171,10 +168,11 @@ module DBF
|
|
171
168
|
# table.find :first, :first_name => "Keith"
|
172
169
|
#
|
173
170
|
# The <b>command</b> may be a record index, :all, or :first.
|
174
|
-
# <b>options</b> is optional and, if specified, should be a hash where the
|
175
|
-
# to column names in the database. The values will be
|
176
|
-
# in the database. If you specify more
|
177
|
-
#
|
171
|
+
# <b>options</b> is optional and, if specified, should be a hash where the
|
172
|
+
# keys correspond to column names in the database. The values will be
|
173
|
+
# matched exactly with the value in the database. If you specify more
|
174
|
+
# than one key, all values must match in order for the record to be
|
175
|
+
# returned. The equivalent SQL would be "WHERE key1 = 'value1'
|
178
176
|
# AND key2 = 'value2'".
|
179
177
|
#
|
180
178
|
# @param [Fixnum, Symbol] command
|
@@ -185,7 +183,7 @@ module DBF
|
|
185
183
|
when Fixnum
|
186
184
|
record(command)
|
187
185
|
when Array
|
188
|
-
command.map {|i| record(i)}
|
186
|
+
command.map { |i| record(i) }
|
189
187
|
when :all
|
190
188
|
find_all(options, &block)
|
191
189
|
when :first
|
@@ -204,7 +202,7 @@ module DBF
|
|
204
202
|
#
|
205
203
|
# @return [String]
|
206
204
|
def column_names
|
207
|
-
columns.map
|
205
|
+
columns.map(&:name)
|
208
206
|
end
|
209
207
|
|
210
208
|
# Is string encoding supported?
|
@@ -219,7 +217,7 @@ module DBF
|
|
219
217
|
''.respond_to?(:encoding)
|
220
218
|
end
|
221
219
|
|
222
|
-
def supports_iconv? #nodoc
|
220
|
+
def supports_iconv? # nodoc
|
223
221
|
require 'iconv'
|
224
222
|
true
|
225
223
|
rescue
|
@@ -228,10 +226,10 @@ module DBF
|
|
228
226
|
|
229
227
|
private
|
230
228
|
|
231
|
-
def build_columns #nodoc
|
229
|
+
def build_columns # nodoc
|
232
230
|
columns = []
|
233
231
|
@data.seek(DBF_HEADER_SIZE)
|
234
|
-
|
232
|
+
until ["\0", "\r"].include?(first_byte = @data.read(1))
|
235
233
|
column_data = first_byte + @data.read(DBF_HEADER_SIZE - 1)
|
236
234
|
name, type, length, decimal = column_data.unpack('a10 x a x4 C2')
|
237
235
|
columns << column_class.new(self, name, type, length, decimal)
|
@@ -239,55 +237,43 @@ module DBF
|
|
239
237
|
columns
|
240
238
|
end
|
241
239
|
|
242
|
-
|
243
|
-
def foxpro? #nodoc
|
240
|
+
def foxpro? # nodoc
|
244
241
|
FOXPRO_VERSIONS.keys.include? version
|
245
242
|
end
|
246
243
|
|
247
|
-
def column_class #nodoc
|
244
|
+
def column_class # nodoc
|
248
245
|
@column_class ||= foxpro? ? Column::Foxpro : Column::Dbase
|
249
246
|
end
|
250
247
|
|
251
|
-
def memo_class #nodoc
|
248
|
+
def memo_class # nodoc
|
252
249
|
@memo_class ||= if foxpro?
|
253
250
|
Memo::Foxpro
|
254
251
|
else
|
255
|
-
|
256
|
-
Memo::Dbase3
|
257
|
-
else
|
258
|
-
Memo::Dbase4
|
259
|
-
end
|
252
|
+
version == '83' ? Memo::Dbase3 : Memo::Dbase4
|
260
253
|
end
|
261
254
|
end
|
262
255
|
|
263
|
-
def
|
264
|
-
@column_count ||= ((header.header_length - DBF_HEADER_SIZE + 1) / DBF_HEADER_SIZE).to_i
|
265
|
-
end
|
266
|
-
|
267
|
-
def open_data(data) #nodoc
|
256
|
+
def open_data(data) # nodoc
|
268
257
|
data.is_a?(StringIO) ? data : File.open(data, 'rb')
|
269
258
|
end
|
270
259
|
|
271
|
-
def open_memo(data, memo = nil) #nodoc
|
272
|
-
if memo
|
273
|
-
|
274
|
-
|
275
|
-
memo_class.open(memo, version)
|
260
|
+
def open_memo(data, memo = nil) # nodoc
|
261
|
+
if memo
|
262
|
+
meth = memo.is_a?(StringIO) ? :new : :open
|
263
|
+
memo_class.send(meth, memo, version)
|
276
264
|
elsif !data.is_a? StringIO
|
277
|
-
files = Dir.glob(memo_search_path
|
265
|
+
files = Dir.glob(memo_search_path data)
|
278
266
|
files.any? ? memo_class.open(files.first, version) : nil
|
279
|
-
else
|
280
|
-
nil
|
281
267
|
end
|
282
268
|
end
|
283
269
|
|
284
|
-
def memo_search_path(io) #nodoc
|
270
|
+
def memo_search_path(io) # nodoc
|
285
271
|
dirname = File.dirname(io)
|
286
272
|
basename = File.basename(io, '.*')
|
287
273
|
"#{dirname}/#{basename}*.{fpt,FPT,dbt,DBT}"
|
288
274
|
end
|
289
275
|
|
290
|
-
def find_all(options) #nodoc
|
276
|
+
def find_all(options) # nodoc
|
291
277
|
map do |record|
|
292
278
|
if record && record.match?(options)
|
293
279
|
yield record if block_given?
|
@@ -296,25 +282,24 @@ module DBF
|
|
296
282
|
end.compact
|
297
283
|
end
|
298
284
|
|
299
|
-
def find_first(options) #nodoc
|
300
|
-
detect {|record| record && record.match?(options)}
|
285
|
+
def find_first(options) # nodoc
|
286
|
+
detect { |record| record && record.match?(options) }
|
301
287
|
end
|
302
288
|
|
303
|
-
def deleted_record? #nodoc
|
289
|
+
def deleted_record? # nodoc
|
304
290
|
@data.read(1).unpack('a') == ['*']
|
305
291
|
end
|
306
292
|
|
307
|
-
def seek(offset) #nodoc
|
293
|
+
def seek(offset) # nodoc
|
308
294
|
@data.seek header.header_length + offset
|
309
295
|
end
|
310
296
|
|
311
|
-
def seek_to_record(index) #nodoc
|
297
|
+
def seek_to_record(index) # nodoc
|
312
298
|
seek(index * header.record_length)
|
313
299
|
end
|
314
300
|
|
315
|
-
def csv_class #nodoc
|
301
|
+
def csv_class # nodoc
|
316
302
|
@csv_class ||= CSV.const_defined?(:Reader) ? FCSV : CSV
|
317
303
|
end
|
318
304
|
end
|
319
|
-
|
320
305
|
end
|