dbf 1.0.10 → 1.0.11
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +2 -2
- data/.gitignore +1 -0
- data/History.txt +8 -0
- data/README.markdown +7 -11
- data/Rakefile +1 -3
- data/VERSION.yml +1 -1
- data/dbf.gemspec +6 -5
- data/lib/dbf.rb +1 -1
- data/lib/dbf/column.rb +22 -18
- data/lib/dbf/record.rb +10 -16
- data/spec/functional/dbf_shared.rb +8 -1
- data/spec/unit/record_spec.rb +33 -3
- metadata +4 -3
data/.autotest
CHANGED
@@ -2,10 +2,10 @@ Autotest.add_hook :initialize do |autotest|
|
|
2
2
|
autotest.clear_mappings
|
3
3
|
|
4
4
|
autotest.add_mapping(%r%^lib/dbf/(.*)\.rb$%) do |filename, m|
|
5
|
-
autotest.files_matching %r!spec/(unit|
|
5
|
+
autotest.files_matching %r!spec/(unit|functional)/#{m[1]}_spec.rb!
|
6
6
|
end
|
7
7
|
|
8
|
-
autotest.add_mapping(%r%^spec/(unit|
|
8
|
+
autotest.add_mapping(%r%^spec/(unit|functional)/.*\.rb$%) do |filename, m|
|
9
9
|
filename
|
10
10
|
end
|
11
11
|
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
.DS_Store
|
data/History.txt
CHANGED
data/README.markdown
CHANGED
@@ -2,20 +2,16 @@
|
|
2
2
|
|
3
3
|
DBF is a small fast library for reading dBase, xBase, Clipper and FoxPro database files
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
*
|
8
|
-
*
|
9
|
-
* To report bugs: <http://www.rubyforge.org/tracker/?group_id=2009>
|
10
|
-
* Questions: Email keithm@infused.org and put DBF somewhere in the subject
|
11
|
-
line
|
5
|
+
* Project page: <http://github.com/infused/dbf>
|
6
|
+
* API Documentation: <http://rdoc.info/projects/infused/dbf>
|
7
|
+
* Report bugs: <http://github.com/infused/dbf/issues>
|
8
|
+
* Questions: Email <mailto:keithm@infused.org> and put DBF somewhere in the subject line
|
12
9
|
|
13
10
|
## Features
|
14
11
|
|
15
12
|
* No external dependencies
|
16
13
|
* Fields are type cast to the appropriate Ruby types
|
17
|
-
* Ability to dump the database schema in the portable ActiveRecord::Schema
|
18
|
-
format
|
14
|
+
* Ability to dump the database schema in the portable ActiveRecord::Schema format
|
19
15
|
|
20
16
|
## Installation
|
21
17
|
|
@@ -30,7 +26,7 @@ Copyright (c) 2006-2009 Keith Morrison <keithm@infused.org>, <www.infused.org>
|
|
30
26
|
|
31
27
|
# Tables are enumerable
|
32
28
|
widget_ids = table.map { |row| row.id }
|
33
|
-
abc_names = table.select { |row| row.name =~ /^[a-cA-C] }
|
29
|
+
abc_names = table.select { |row| row.name =~ /^[a-cA-C]/ }
|
34
30
|
sorted = table.sort_by { |row| row.name }
|
35
31
|
|
36
32
|
# Print the 'name' field from record number 4
|
@@ -91,7 +87,7 @@ A small command-line utility called dbf is installed along with the gem.
|
|
91
87
|
|
92
88
|
(The MIT Licence)
|
93
89
|
|
94
|
-
Copyright (c) 2006-2009 Keith Morrison <keithm@infused.org
|
90
|
+
Copyright (c) 2006-2009 Keith Morrison <mailto:keithm@infused.org>, <http://www.infused.org>
|
95
91
|
|
96
92
|
Permission is hereby granted, free of charge, to any person
|
97
93
|
obtaining a copy of this software and associated documentation
|
data/Rakefile
CHANGED
@@ -4,10 +4,10 @@ $: << File.join(PROJECT_ROOT, 'lib')
|
|
4
4
|
require 'rubygems'
|
5
5
|
require 'jeweler'
|
6
6
|
require 'spec/rake/spectask'
|
7
|
+
require 'metric_fu'
|
7
8
|
|
8
9
|
Jeweler::Tasks.new do |s|
|
9
10
|
s.name = 'dbf'
|
10
|
-
s.version = '1.0.9'
|
11
11
|
s.description = 'A small fast library for reading dBase, xBase, Clipper and FoxPro database files.'
|
12
12
|
s.summary = 'Read xBase files'
|
13
13
|
s.platform = Gem::Platform::RUBY
|
@@ -16,11 +16,9 @@ Jeweler::Tasks.new do |s|
|
|
16
16
|
s.add_dependency('activesupport', ['>= 2.1.0'])
|
17
17
|
s.add_dependency('fastercsv', ['>= 1.4.0'])
|
18
18
|
s.homepage = 'http://github.com/infused/dbf'
|
19
|
-
s.rubyforge_project = 'dbf'
|
20
19
|
end
|
21
20
|
|
22
21
|
Jeweler::GemcutterTasks.new
|
23
|
-
Jeweler::RubyforgeTasks.new
|
24
22
|
|
25
23
|
task :default => :spec
|
26
24
|
|
data/VERSION.yml
CHANGED
data/dbf.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{dbf}
|
8
|
-
s.version = "1.0.
|
8
|
+
s.version = "1.0.11"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Keith Morrison"]
|
12
|
-
s.date = %q{2009-
|
12
|
+
s.date = %q{2009-12-05}
|
13
13
|
s.default_executable = %q{dbf}
|
14
14
|
s.description = %q{A small fast library for reading dBase, xBase, Clipper and FoxPro database files.}
|
15
15
|
s.email = %q{keithm@infused.org}
|
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
]
|
20
20
|
s.files = [
|
21
21
|
".autotest",
|
22
|
+
".gitignore",
|
22
23
|
"History.txt",
|
23
24
|
"README.markdown",
|
24
25
|
"Rakefile",
|
@@ -54,7 +55,6 @@ Gem::Specification.new do |s|
|
|
54
55
|
s.homepage = %q{http://github.com/infused/dbf}
|
55
56
|
s.rdoc_options = ["--charset=UTF-8"]
|
56
57
|
s.require_paths = ["lib"]
|
57
|
-
s.rubyforge_project = %q{dbf}
|
58
58
|
s.rubygems_version = %q{1.3.5}
|
59
59
|
s.summary = %q{Read xBase files}
|
60
60
|
s.test_files = [
|
@@ -86,3 +86,4 @@ Gem::Specification.new do |s|
|
|
86
86
|
s.add_dependency(%q<fastercsv>, [">= 1.4.0"])
|
87
87
|
end
|
88
88
|
end
|
89
|
+
|
data/lib/dbf.rb
CHANGED
data/lib/dbf/column.rb
CHANGED
@@ -13,15 +13,13 @@ module DBF
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def type_cast(value)
|
16
|
-
value = value.is_a?(Array) ? value.first : value
|
17
|
-
|
18
16
|
case type
|
19
17
|
when 'N' # number
|
20
|
-
|
18
|
+
unpack_number(value)
|
21
19
|
when 'D' # date
|
22
20
|
value.to_date unless value.blank?
|
23
21
|
when 'L' # logical
|
24
|
-
value
|
22
|
+
boolean(value)
|
25
23
|
when 'I' # integer
|
26
24
|
unpack_integer(value)
|
27
25
|
when 'T' # datetime
|
@@ -37,33 +35,39 @@ module DBF
|
|
37
35
|
DateTime.jd(days, seconds/3600, seconds/60 % 60, seconds % 60)
|
38
36
|
end
|
39
37
|
|
38
|
+
def unpack_number(value)
|
39
|
+
decimal.zero? ? unpack_integer(value) : value.to_f
|
40
|
+
end
|
41
|
+
|
40
42
|
def unpack_integer(value)
|
41
43
|
value.to_i
|
42
44
|
end
|
43
45
|
|
46
|
+
def boolean(value)
|
47
|
+
value.strip =~ /^(y|t)$/i ? true : false
|
48
|
+
end
|
49
|
+
|
44
50
|
def schema_definition
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
when "I"
|
51
|
+
"\"#{name.underscore}\", #{schema_data_type}\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
def schema_data_type
|
55
|
+
case type
|
56
|
+
when "N"
|
57
|
+
decimal > 0 ? ":float" : ":integer"
|
58
|
+
when "I"
|
53
59
|
":integer"
|
54
|
-
when "D"
|
60
|
+
when "D"
|
55
61
|
":date"
|
56
|
-
when "T"
|
62
|
+
when "T"
|
57
63
|
":datetime"
|
58
|
-
when "L"
|
64
|
+
when "L"
|
59
65
|
":boolean"
|
60
|
-
when "M"
|
66
|
+
when "M"
|
61
67
|
":text"
|
62
68
|
else
|
63
69
|
":string, :limit => #{length}"
|
64
70
|
end
|
65
|
-
|
66
|
-
"\"#{name.underscore}\", #{data_type}\n"
|
67
71
|
end
|
68
72
|
|
69
73
|
# strip all non-ascii and non-printable characters
|
data/lib/dbf/record.rb
CHANGED
@@ -14,12 +14,7 @@ module DBF
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def to_a
|
17
|
-
columns.map
|
18
|
-
underscored_column_name = column.name.underscore
|
19
|
-
value = @attributes[column.name.underscore]
|
20
|
-
|
21
|
-
value.is_a?(String) ? value.strip : value
|
22
|
-
end
|
17
|
+
columns.map { |column| @attributes[column.name.underscore] }
|
23
18
|
end
|
24
19
|
|
25
20
|
private
|
@@ -38,22 +33,20 @@ module DBF
|
|
38
33
|
def initialize_values
|
39
34
|
@attributes = columns.inject({}) do |hash, column|
|
40
35
|
if column.type == 'M'
|
41
|
-
starting_block =
|
36
|
+
starting_block = unpack_data(column.length).to_i
|
37
|
+
hash[column.name] = read_memo(starting_block)
|
42
38
|
hash[column.name.underscore] = read_memo(starting_block)
|
43
39
|
else
|
44
|
-
value =
|
40
|
+
value = unpack_data(column.length)
|
41
|
+
hash[column.name] = column.type_cast(value)
|
45
42
|
hash[column.name.underscore] = column.type_cast(value)
|
46
43
|
end
|
47
44
|
hash
|
48
45
|
end
|
49
46
|
end
|
50
47
|
|
51
|
-
def
|
52
|
-
@data.read(
|
53
|
-
end
|
54
|
-
|
55
|
-
def unpack_string(column)
|
56
|
-
unpack_column(column).to_s
|
48
|
+
def unpack_data(length)
|
49
|
+
@data.read(length).unpack("a#{length}").first
|
57
50
|
end
|
58
51
|
|
59
52
|
def read_memo(start_block)
|
@@ -65,7 +58,7 @@ module DBF
|
|
65
58
|
def build_fpt_memo(start_block)
|
66
59
|
@memo.seek(start_block * memo_block_size)
|
67
60
|
|
68
|
-
memo_type, memo_size, memo_string = @memo.read(memo_block_size).unpack("
|
61
|
+
memo_type, memo_size, memo_string = @memo.read(memo_block_size).unpack("NNa*")
|
69
62
|
return nil unless memo_type == 1 and memo_size > 0
|
70
63
|
|
71
64
|
if memo_size > memo_block_content_size
|
@@ -83,7 +76,8 @@ module DBF
|
|
83
76
|
when "83" # dbase iii
|
84
77
|
memo_string = ""
|
85
78
|
loop do
|
86
|
-
|
79
|
+
block = @memo.read(memo_block_size)
|
80
|
+
memo_string << block
|
87
81
|
break if block.rstrip.size < memo_block_size
|
88
82
|
end
|
89
83
|
when "8b" # dbase iv
|
@@ -37,9 +37,16 @@ describe DBF, :shared => true do
|
|
37
37
|
|
38
38
|
specify "column read accessors should return the attribute after typecast" do
|
39
39
|
@table.columns do |column|
|
40
|
-
record = table.records.first
|
40
|
+
record = @table.records.first
|
41
41
|
record.send(column.name).should == record[column.name]
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
specify "column attributes should be accessible in underscored form" do
|
46
|
+
@table.columns do |column|
|
47
|
+
record = @table.records.first
|
48
|
+
record.send(column_name).should == record.send(column_name.underscore)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
45
52
|
end
|
data/spec/unit/record_spec.rb
CHANGED
@@ -8,18 +8,20 @@ describe DBF::Record do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def mock_table(data = '')
|
11
|
+
@column1 = DBF::Column.new 'ColumnName', 'N', 1, 0
|
12
|
+
|
11
13
|
returning mock('table') do |table|
|
12
14
|
table.stub!(:memo_block_size).and_return(8)
|
13
15
|
table.stub!(:memo).and_return(nil)
|
14
|
-
table.stub!(:columns).and_return([])
|
15
|
-
table.stub!(:data)
|
16
|
+
table.stub!(:columns).and_return([@column1])
|
17
|
+
table.stub!(:data).and_return(data)
|
16
18
|
table.stub!(:has_memo_file?).and_return(true)
|
17
19
|
table.data.stub!(:read).and_return(data)
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
21
23
|
context "when initialized" do
|
22
|
-
it "should typecast number columns
|
24
|
+
it "should typecast number columns no decimal places to Integer" do
|
23
25
|
table = DBF::Table.new "#{DB_PATH}/dbase_83.dbf"
|
24
26
|
table.column("ID").type.should == "N"
|
25
27
|
table.column("ID").decimal.should == 0
|
@@ -90,5 +92,33 @@ describe DBF::Record do
|
|
90
92
|
record.to_a.should == ["Ten records stored in this database", 10.0, nil, false, "0.100000000000000000", nil]
|
91
93
|
end
|
92
94
|
end
|
95
|
+
|
96
|
+
describe '#==' do
|
97
|
+
before do
|
98
|
+
@record = example_record
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should be false if other does not have attributes' do
|
102
|
+
other = mock('object')
|
103
|
+
(@record == other).should be_false
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should be true if other attributes match' do
|
107
|
+
attributes = {:x => 1, :y => 2}
|
108
|
+
@record.stub!(:attributes).and_return(attributes)
|
109
|
+
other = mock('object', :attributes => attributes)
|
110
|
+
(@record == other).should be_true
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe 'unpack_data' do
|
115
|
+
before do
|
116
|
+
@record = example_record('abc')
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should unpack the data' do
|
120
|
+
@record.send(:unpack_data, 3).should == 'abc'
|
121
|
+
end
|
122
|
+
end
|
93
123
|
|
94
124
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dbf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keith Morrison
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-05 00:00:00 -08:00
|
13
13
|
default_executable: dbf
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -42,6 +42,7 @@ extra_rdoc_files:
|
|
42
42
|
- README.markdown
|
43
43
|
files:
|
44
44
|
- .autotest
|
45
|
+
- .gitignore
|
45
46
|
- History.txt
|
46
47
|
- README.markdown
|
47
48
|
- Rakefile
|
@@ -96,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
97
|
version:
|
97
98
|
requirements: []
|
98
99
|
|
99
|
-
rubyforge_project:
|
100
|
+
rubyforge_project:
|
100
101
|
rubygems_version: 1.3.5
|
101
102
|
signing_key:
|
102
103
|
specification_version: 3
|