activemdb 0.1.0 → 0.2.0
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.
- data/Manifest.txt +5 -0
- data/README.txt +23 -9
- data/Rakefile +1 -1
- data/db/.DS_Store +0 -0
- data/db/not_an_mdb.txt +0 -0
- data/db/retreat.mdb +0 -0
- data/lib/active_mdb.rb +3 -2
- data/lib/active_mdb/base.rb +126 -0
- data/lib/active_mdb/column.rb +39 -2
- data/lib/active_mdb/mdb.rb +16 -6
- data/lib/active_mdb/mdb_tools.rb +54 -12
- data/test/test_activemdb.rb +55 -0
- data/test/test_base.rb +86 -0
- data/test/test_helper.rb +3 -1
- data/test/test_mdb.rb +3 -10
- data/test/test_mdb_tools.rb +38 -2
- data/test/test_record.rb +24 -24
- data/test/test_table.rb +50 -50
- metadata +10 -4
data/Manifest.txt
CHANGED
@@ -2,9 +2,13 @@ History.txt
|
|
2
2
|
Manifest.txt
|
3
3
|
README.txt
|
4
4
|
Rakefile
|
5
|
+
db/.DS_Store
|
6
|
+
db/not_an_mdb.txt
|
7
|
+
db/retreat.mdb
|
5
8
|
db/sample.mdb
|
6
9
|
irb.rc
|
7
10
|
lib/active_mdb.rb
|
11
|
+
lib/active_mdb/base.rb
|
8
12
|
lib/active_mdb/column.rb
|
9
13
|
lib/active_mdb/mdb.rb
|
10
14
|
lib/active_mdb/mdb_tools.rb
|
@@ -12,6 +16,7 @@ lib/active_mdb/record.rb
|
|
12
16
|
lib/active_mdb/table.rb
|
13
17
|
support/a.insert
|
14
18
|
test/test_activemdb.rb
|
19
|
+
test/test_base.rb
|
15
20
|
test/test_helper.rb
|
16
21
|
test/test_mdb.rb
|
17
22
|
test/test_mdb_tools.rb
|
data/README.txt
CHANGED
@@ -4,24 +4,38 @@ http://rubyforge.org/projects/activemdb/
|
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
7
|
-
|
7
|
+
Library for getting info out of MS Access (.mdb) files, which uses ActiveRecord-ish reflection to parse table and column names.
|
8
8
|
|
9
|
-
Intended for exploration and migration, not production. ActiveMDB provides a
|
9
|
+
Intended for exploration and migration, not production. And it's *READ ONLY*, so don't try to get fresh. ActiveMDB provides a wrapper of varying thickness around the utilities from Brian Bruns's MDB Tools project (http://mdbtools.sourceforge.net/). Kudos to Mr. Bruns.
|
10
10
|
|
11
11
|
== FEATURES/PROBLEMS:
|
12
12
|
|
13
|
-
*
|
14
|
-
*
|
13
|
+
* MDBTools - Straightforward wrapper around the CLI tools that you get with libmdb
|
14
|
+
* ActiveMDB::Base - Subclass to make your models, just like the big shots do.
|
15
|
+
|
15
16
|
|
16
17
|
== SYNOPSIS:
|
17
18
|
|
18
|
-
|
19
|
-
|
19
|
+
# When your Access database schema conforms to the 37s stylebook:
|
20
|
+
class Bacon < ActiveMDB::Base
|
21
|
+
set_mdb_file 'db/wherefore.mdb'
|
22
|
+
end
|
20
23
|
|
21
24
|
# in the find_* methods, the entries in the hash
|
22
25
|
# get turned into "WHERE #{key} like %#{value}%" conditions,
|
23
|
-
#
|
24
|
-
|
26
|
+
# which fails when the column is a boolean, which is a regression from 0.1.0.
|
27
|
+
# I could fix this tonight, but my son is yelling at me to come out for dinner.
|
28
|
+
best_bacon = Bacon.find_all(:rind => 'creamy', :sodium_content => 'Awesome!' )
|
29
|
+
|
30
|
+
# When it doesn't:
|
31
|
+
class Employee < ActiveMDB::Base
|
32
|
+
set_mdb_file 'db/sample.mdb'
|
33
|
+
set_table_name 'Employee'
|
34
|
+
set_primary_key 'Emp_Id'
|
35
|
+
end
|
36
|
+
|
37
|
+
paula = Employee.find_first(:Department => 'Engineering', :Specialty => 'paulaBeans')
|
38
|
+
|
25
39
|
|
26
40
|
== REQUIREMENTS:
|
27
41
|
|
@@ -29,7 +43,7 @@ Intended for exploration and migration, not production. ActiveMDB provides a thi
|
|
29
43
|
|
30
44
|
== INSTALL:
|
31
45
|
|
32
|
-
* Sadly, no easy install at this time.
|
46
|
+
* Sadly, no easy install of MDB Tools at this time. It compiles on Mac OS X 10.4.x, both PPC and Intel. Haven't tested on Linuxes yet, but that's what Parallels is for, right?
|
33
47
|
|
34
48
|
== LICENSE:
|
35
49
|
|
data/Rakefile
CHANGED
@@ -8,7 +8,7 @@ Hoe.new('activemdb', ActiveMDB::VERSION) do |p|
|
|
8
8
|
p.rubyforge_name = 'activemdb'
|
9
9
|
p.author = 'Matthew King'
|
10
10
|
p.email = 'automatthew@gmail.com'
|
11
|
-
p.summary = '
|
11
|
+
p.summary = 'ActiveRecordy wrapper around MDB Tools, which lets POSIX platforms read MS Access (.mdb) files'
|
12
12
|
p.description = p.paragraphs_of('README.txt', 2).join("\n\n")
|
13
13
|
p.url = p.paragraphs_of('README.txt',0).first.split(/\n/)[2..-1]
|
14
14
|
# p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
data/db/.DS_Store
ADDED
Binary file
|
data/db/not_an_mdb.txt
ADDED
File without changes
|
data/db/retreat.mdb
ADDED
Binary file
|
data/lib/active_mdb.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
$:.unshift(File.dirname(__FILE__))
|
2
2
|
module ActiveMDB
|
3
|
-
VERSION = '0.
|
3
|
+
VERSION = '0.2.0'
|
4
4
|
end
|
5
5
|
|
6
6
|
|
7
7
|
require 'rubygems'
|
8
|
-
require 'active_support
|
8
|
+
require 'active_support'
|
9
9
|
require 'active_mdb/mdb_tools'
|
10
10
|
load 'active_mdb/mdb.rb'
|
11
11
|
load 'active_mdb/table.rb'
|
12
12
|
load 'active_mdb/record.rb'
|
13
13
|
load 'active_mdb/column.rb'
|
14
|
+
load 'active_mdb/base.rb'
|
14
15
|
require 'faster_csv'
|
15
16
|
|
16
17
|
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module ActiveMDB
|
2
|
+
class Base
|
3
|
+
|
4
|
+
def initialize(attributes=nil)
|
5
|
+
@attributes = attributes unless attributes.nil?
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
cattr_accessor :pluralize_table_names, :instance_writer => false
|
11
|
+
@@pluralize_table_names = true
|
12
|
+
|
13
|
+
class << self # Class methods
|
14
|
+
attr_accessor :mdb_file
|
15
|
+
attr_reader :mdb
|
16
|
+
|
17
|
+
def set_mdb_file(file)
|
18
|
+
@mdb_file = file
|
19
|
+
@mdb = MDB.new(file)
|
20
|
+
end
|
21
|
+
|
22
|
+
def table_name
|
23
|
+
table_name = Inflector.underscore(Inflector.demodulize(self.to_s))
|
24
|
+
table_name = Inflector.pluralize(table_name) if pluralize_table_names
|
25
|
+
table_name
|
26
|
+
end
|
27
|
+
|
28
|
+
# borrowed from ActiveRecord
|
29
|
+
def set_table_name(value = nil, &block)
|
30
|
+
define_attr_method :table_name, value, &block
|
31
|
+
end
|
32
|
+
alias :table_name= :set_table_name
|
33
|
+
|
34
|
+
# Returns an array of column objects for the table associated with this class.
|
35
|
+
def columns
|
36
|
+
unless @columns
|
37
|
+
@columns = @mdb.columns(table_name)
|
38
|
+
# @columns.each {|column| column.primary = column.name == primary_key}
|
39
|
+
end
|
40
|
+
@columns
|
41
|
+
end
|
42
|
+
|
43
|
+
def column_names
|
44
|
+
@mdb.column_names(table_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def primary_key
|
48
|
+
'id'
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_primary_key(value = nil, &block)
|
52
|
+
define_attr_method :primary_key, value, &block
|
53
|
+
end
|
54
|
+
alias :primary_key= :set_primary_key
|
55
|
+
|
56
|
+
def table_exists?
|
57
|
+
@mdb.tables.include? table_name
|
58
|
+
end
|
59
|
+
|
60
|
+
def count
|
61
|
+
@mdb.count(table_name, primary_key)
|
62
|
+
end
|
63
|
+
|
64
|
+
def find_first(conditions_hash)
|
65
|
+
# rekey_hash(conditions_hash)
|
66
|
+
sql_search(conditions_hash).first
|
67
|
+
end
|
68
|
+
|
69
|
+
def find_all(conditions_hash)
|
70
|
+
sql_search(conditions_hash)
|
71
|
+
end
|
72
|
+
|
73
|
+
# borrowed from ActiveRecord
|
74
|
+
def define_attr_method(name, value=nil, &block)
|
75
|
+
sing = class << self; self; end
|
76
|
+
sing.send :alias_method, "original_#{name}", name
|
77
|
+
if block_given?
|
78
|
+
sing.send :define_method, name, &block
|
79
|
+
else
|
80
|
+
# use eval instead of a block to work around a memory leak in dev
|
81
|
+
# mode in fcgi
|
82
|
+
sing.class_eval "def #{name}; #{value.to_s.inspect}; end"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# relies on stuff that doesn't work right now
|
87
|
+
def rekey_hash(conditions_hash)
|
88
|
+
conditions_hash.each do |key,value|
|
89
|
+
column = self[key.to_s]
|
90
|
+
if column.boolean?
|
91
|
+
key = column.name + '!'
|
92
|
+
else
|
93
|
+
key = column.name
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# the conditions hash keys are column names, the values are search values
|
99
|
+
# e.g. sql_search(:first_name => 'Matthew', :last_name => 'King')
|
100
|
+
def sql_search(conditions_hash)
|
101
|
+
conditions = MDBTools.compile_conditions(conditions_hash)
|
102
|
+
MDBTools.sql_select(mdb_file, table_name, nil, conditions).collect! { |record| instantiate(record) }
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def instantiate(record)
|
108
|
+
new(record)
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def method_missing(method_id, *args, &block)
|
117
|
+
method_name = method_id.to_s
|
118
|
+
if @attributes.include?(method_name)
|
119
|
+
value = @attributes[method_name]
|
120
|
+
else
|
121
|
+
super
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
data/lib/active_mdb/column.rb
CHANGED
@@ -4,14 +4,51 @@ class Column
|
|
4
4
|
attr_reader :method_name, :name, :type, :size
|
5
5
|
|
6
6
|
def initialize(name, type, size)
|
7
|
-
@name = name
|
8
|
-
@method_name, @
|
7
|
+
@name, @type = name, type
|
8
|
+
@method_name, @size = methodize(name), size.to_i
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.new_from_describe(describe_hash)
|
12
12
|
self.new(describe_hash["Column Name"], describe_hash["Type"], describe_hash["Size"])
|
13
13
|
end
|
14
14
|
|
15
|
+
# return Ruby class corresponding to data type.
|
16
|
+
# Borrowed from ActiveRecord
|
17
|
+
def klass
|
18
|
+
case type
|
19
|
+
when 'Text', 'Character' then String
|
20
|
+
when 'Long Integer' then Fixnum
|
21
|
+
when 'Currency', 'Float' then Float
|
22
|
+
when 'DateTime (Short)' then Time
|
23
|
+
when 'Boolean' then Object
|
24
|
+
when 'Decimal' then BigDecimal
|
25
|
+
when 'Binary' then String
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Casts value (which is a String) to an appropriate instance.
|
30
|
+
# Totally borrowed from ActiveRecord
|
31
|
+
def type_cast(value)
|
32
|
+
return nil if value.nil?
|
33
|
+
case type
|
34
|
+
when 'Text', 'Character' then value
|
35
|
+
when 'Long Integer' then value.to_i rescue value ? 1 : 0
|
36
|
+
when 'Currency', 'Float' then value.to_f
|
37
|
+
when 'DateTime (Short)' then self.class.string_to_time(value)
|
38
|
+
when 'Boolean' then self.class.value_to_boolean(value)
|
39
|
+
when 'Decimal' then self.class.value_to_decimal(value)
|
40
|
+
when 'Binary' then self.class.binary_to_string(value)
|
41
|
+
else value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.value_to_boolean(value)
|
46
|
+
if value == true || value == false
|
47
|
+
value
|
48
|
+
else
|
49
|
+
%w(true t 1).include?(value.to_s.downcase)
|
50
|
+
end
|
51
|
+
end
|
15
52
|
|
16
53
|
def boolean?
|
17
54
|
self.type == 'boolean'
|
data/lib/active_mdb/mdb.rb
CHANGED
@@ -3,25 +3,35 @@
|
|
3
3
|
class MDB
|
4
4
|
include MDBTools
|
5
5
|
|
6
|
-
attr_reader :mdb_file, :prefix, :exclude, :
|
6
|
+
attr_reader :mdb_file, :prefix, :exclude, :tables
|
7
7
|
|
8
8
|
def initialize(mdb_file, options = {})
|
9
9
|
@mdb_file = check_file(mdb_file)
|
10
10
|
@prefix = options[:prefix] || ''
|
11
11
|
@exclude, @include = options[:exclude], options[:include]
|
12
12
|
@export_syntax = options[:sql_syntax] || 'mysql'
|
13
|
-
@
|
14
|
-
@tables = create_table_objects
|
13
|
+
@tables = mdb_tables(@mdb_file, :exclude => @exclude, :include => @include)
|
14
|
+
# @tables = create_table_objects
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
@
|
17
|
+
def count(table_name, attribute)
|
18
|
+
MDBTools.faked_count(@mdb_file, table_name, attribute)
|
19
19
|
end
|
20
20
|
|
21
|
+
def columns(table_name)
|
22
|
+
MDBTools.describe_table(@mdb_file, table_name).map do |column|
|
23
|
+
Column.new_from_describe(column)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def column_names(table_name)
|
28
|
+
MDBTools.field_names_for(@mdb_file, table_name)
|
29
|
+
end
|
21
30
|
|
22
31
|
|
23
32
|
private
|
24
|
-
|
33
|
+
|
34
|
+
# Deprecated.
|
25
35
|
def create_table_objects
|
26
36
|
tables = {}
|
27
37
|
@table_names.each do |table|
|
data/lib/active_mdb/mdb_tools.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module MDBTools
|
2
|
-
|
2
|
+
|
3
|
+
extend self
|
3
4
|
|
4
5
|
DELIMITER = '::'
|
5
6
|
LINEBREAK = "\n"
|
@@ -15,6 +16,14 @@ module MDBTools
|
|
15
16
|
mdb_file
|
16
17
|
end
|
17
18
|
|
19
|
+
def valid_file?(file)
|
20
|
+
!mdb_version(file).blank?
|
21
|
+
end
|
22
|
+
|
23
|
+
def mdb_version(file)
|
24
|
+
`mdb-ver #{file} 2> /dev/null`.chomp
|
25
|
+
end
|
26
|
+
|
18
27
|
def check_table(mdb_file, table_name)
|
19
28
|
unless mdb_tables(mdb_file).include?(table_name)
|
20
29
|
raise ArgumentError, "mdbtools does not think a table named \"#{table_name}\" exists"
|
@@ -22,6 +31,7 @@ module MDBTools
|
|
22
31
|
table_name
|
23
32
|
end
|
24
33
|
|
34
|
+
|
25
35
|
def mdb_tables(mdb_file, options = {})
|
26
36
|
included, excluded = options[:include], options[:exclude]
|
27
37
|
return `mdb-tables -1 #{mdb_file}`.split(LINEBREAK) if not (included || excluded)
|
@@ -37,19 +47,49 @@ module MDBTools
|
|
37
47
|
tables
|
38
48
|
end
|
39
49
|
|
40
|
-
def sql_select(mdb_file, table_name, attributes = nil, conditions
|
41
|
-
attributes
|
42
|
-
|
50
|
+
def sql_select(mdb_file, table_name, attributes = nil, conditions=nil)
|
51
|
+
if attributes.respond_to?(:join)
|
52
|
+
fields = attributes.join(' ')
|
53
|
+
else
|
54
|
+
attributes ||= '*'
|
55
|
+
end
|
56
|
+
where = conditions ? "where #{conditions}" : ""
|
57
|
+
sql = "select #{attributes} from #{table_name} #{where}"
|
43
58
|
mdb_sql(mdb_file, sql)
|
44
59
|
end
|
45
60
|
|
61
|
+
def mdb_sql(mdb_file,sql)
|
62
|
+
command = "mdb-sql -Fp -d '#{DELIMITER}' #{mdb_file}\n"
|
63
|
+
array = []
|
64
|
+
IO.popen(command, 'r+') do |pipe|
|
65
|
+
pipe << "#{sql}\ngo\n"
|
66
|
+
pipe.close_write
|
67
|
+
pipe.readline
|
68
|
+
fields = pipe.readline.chomp.split(DELIMITER)
|
69
|
+
pipe.each do |row|
|
70
|
+
hash = {}
|
71
|
+
row = row.chomp.split(DELIMITER)
|
72
|
+
fields.each_index do |i|
|
73
|
+
hash[fields[i]] = row[i]
|
74
|
+
end
|
75
|
+
array << hash
|
76
|
+
end
|
77
|
+
end
|
78
|
+
array
|
79
|
+
end
|
46
80
|
|
47
|
-
def
|
48
|
-
# puts sql
|
81
|
+
def old_mdb_sql(mdb_file, sql)
|
49
82
|
result = `echo -n #{sql} | mdb-sql -Fp -H -d '#{DELIMITER}' #{mdb_file}`.strip
|
50
|
-
|
83
|
+
delimited_to_arrays(result)
|
84
|
+
end
|
85
|
+
|
86
|
+
def field_names_for(mdb_file, table)
|
87
|
+
fields = `echo -n 'select * from #{table} where 1 = 2' | mdb-sql -Fp -d '#{DELIMITER}' #{mdb_file}`.chomp.sub(/^\n+/, '')
|
88
|
+
fields.split(DELIMITER)
|
51
89
|
end
|
52
90
|
|
91
|
+
|
92
|
+
|
53
93
|
def compile_conditions(conditions_hash, *args)
|
54
94
|
conditions = conditions_hash.sort_by{|k,v| k.to_s}.map do |column_name, value|
|
55
95
|
if block_given?
|
@@ -60,6 +100,10 @@ module MDBTools
|
|
60
100
|
end.join(' AND ')
|
61
101
|
end
|
62
102
|
|
103
|
+
def faked_count(*args)
|
104
|
+
sql_select(*args).size
|
105
|
+
end
|
106
|
+
|
63
107
|
def mdb_export(mdb_file, table_name, options = {})
|
64
108
|
defaults = { :format => 'sql',
|
65
109
|
:headers => false,
|
@@ -83,10 +127,8 @@ module MDBTools
|
|
83
127
|
end
|
84
128
|
|
85
129
|
def describe_table(mdb_file, table_name)
|
86
|
-
command = "describe table \"#{table_name}\""
|
87
|
-
|
88
|
-
arrays = delimited_to_arrays(description)
|
89
|
-
arrays_to_hashes(arrays.shift, arrays)
|
130
|
+
command = "describe table \"#{table_name}\""
|
131
|
+
mdb_sql(mdb_file,command)
|
90
132
|
end
|
91
133
|
|
92
134
|
def mdb_schema(mdb_file, table_name)
|
@@ -118,7 +160,7 @@ module MDBTools
|
|
118
160
|
|
119
161
|
|
120
162
|
def methodize(table_name)
|
121
|
-
underscore table_name
|
163
|
+
Inflector.underscore table_name
|
122
164
|
end
|
123
165
|
|
124
166
|
def backends
|
data/test/test_activemdb.rb
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", 'lib', 'active_mdb')
|
2
|
+
require 'test/unit'
|
3
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
4
|
+
|
5
|
+
class RealWorldTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
RETREAT = File.join(File.dirname(__FILE__), '..', 'db', 'retreat.mdb')
|
8
|
+
|
9
|
+
class Family < ActiveMDB::Base
|
10
|
+
set_mdb_file RETREAT
|
11
|
+
set_table_name 'tblFamilyData'
|
12
|
+
end
|
13
|
+
|
14
|
+
class Cabin < ActiveMDB::Base
|
15
|
+
set_mdb_file RETREAT
|
16
|
+
set_table_name 'tCabins'
|
17
|
+
end
|
18
|
+
|
19
|
+
def setup
|
20
|
+
@retreat = MDB.new(RETREAT)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_tables
|
24
|
+
tables = ["JobAssignmentsByCabin","Switchboard Items","tblAdultChildCode","tblCities","tblFamilyData","tblGender","tblIndividData","tblStatusChurch","tblStatusIndiv","tCabinAssignments","tCabins","tCampRates","tCampScholarships","tJobs","tJobsR","tParkAreas","tPayments","tRetreatEnrollment","tSponsors","tblStatusFamily"]
|
25
|
+
assert_equal tables, @retreat.tables
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_column_names
|
29
|
+
column_names = ["FamKey","LName", "HisName", "HerName", "HmAddress", "AddressNumber", "StreetDirection", "StreetName", "HmAddress2", "City", "State", "Zip", "HmPhone", "UnLstHmPho?"]
|
30
|
+
assert_equal column_names, Family.column_names
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_columns
|
34
|
+
column = Family.columns[2]
|
35
|
+
assert_kind_of Column, column
|
36
|
+
assert_respond_to column, 'type'
|
37
|
+
assert_respond_to column, 'name'
|
38
|
+
assert_respond_to column, 'size'
|
39
|
+
Family.columns.each do |c|
|
40
|
+
assert_not_nil c.name
|
41
|
+
assert_not_nil c.type
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_column_klass
|
46
|
+
column = Family.columns[1]
|
47
|
+
assert_equal String, column.klass
|
48
|
+
Family.columns.each do |c|
|
49
|
+
assert_not_nil c.klass
|
50
|
+
assert_kind_of Class, c.klass
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
end
|
data/test/test_base.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", 'lib', 'active_mdb')
|
2
|
+
require 'test/unit'
|
3
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
4
|
+
|
5
|
+
class BaseTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
class NonExistentTable < ActiveMDB::Base
|
8
|
+
set_mdb_file TEST_DB
|
9
|
+
end
|
10
|
+
class Employee < ActiveMDB::Base
|
11
|
+
set_mdb_file TEST_DB
|
12
|
+
set_table_name 'Employee'
|
13
|
+
set_primary_key 'Emp_Id'
|
14
|
+
end
|
15
|
+
class Room < ActiveMDB::Base
|
16
|
+
set_mdb_file TEST_DB
|
17
|
+
set_table_name 'Room'
|
18
|
+
set_primary_key 'Room'
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
def test_setting_mdb_file
|
24
|
+
assert_equal TEST_DB, Employee.mdb_file
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_mdb_creation
|
28
|
+
mdb = Employee.mdb
|
29
|
+
assert_not_nil mdb
|
30
|
+
assert_respond_to mdb, :tables
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_get_table_name
|
34
|
+
assert_equal 'non_existent_tables', NonExistentTable.table_name
|
35
|
+
ActiveMDB::Base.pluralize_table_names = false
|
36
|
+
assert_equal 'non_existent_table', NonExistentTable.table_name
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_set_table_name
|
40
|
+
Employee.set_table_name('foo')
|
41
|
+
assert_equal 'foo', Employee.table_name
|
42
|
+
assert_equal 'Room', Room.table_name
|
43
|
+
Employee.set_table_name('Employee')
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_table_exists
|
47
|
+
assert !NonExistentTable.table_exists?
|
48
|
+
assert Room.table_exists?
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_get_and_set_primary_key
|
52
|
+
assert_equal 'Emp_Id', Employee.primary_key
|
53
|
+
Employee.set_primary_key 'employee_id'
|
54
|
+
assert_equal 'employee_id', Employee.primary_key
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_count
|
58
|
+
assert_equal 92, Room.count
|
59
|
+
assert_equal 53, Employee.count
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_instantiate
|
63
|
+
hash = [{"Department"=>"Engineering", "Gender"=>"M", "Room"=>"6072", "Title"=>"Programmer", "Emp_Id"=>"1045", "First_Name"=>"Robert", "Last_Name"=>"Weinfeld"}]
|
64
|
+
record = Employee.send(:instantiate, hash)
|
65
|
+
assert_equal hash, record.instance_variable_get('@attributes')
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_sql_search
|
69
|
+
record = Employee.sql_search(:Room => '6072').first
|
70
|
+
assert_kind_of Employee, record
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_attribute_magic
|
74
|
+
record = Employee.sql_search(:Room => '6072').first
|
75
|
+
assert_equal '6072', record.Room
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def test_find_all
|
80
|
+
assert_equal 2, Employee.find_all(:First_Name => 'G').size
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'test/unit'
|
2
|
+
TEST_DB = File.join(File.dirname(__FILE__), '..', 'db', 'sample.mdb')
|
3
|
+
NOT_A_DB = File.join(File.dirname(__FILE__), '..', 'db', 'not_an_mdb.txt')
|
2
4
|
|
3
5
|
class Test::Unit::TestCase
|
4
6
|
|
5
|
-
TEST_DB = File.join(File.dirname(__FILE__), '..', 'db', 'sample.mdb')
|
6
7
|
|
7
8
|
|
8
9
|
protected
|
@@ -11,6 +12,7 @@ class Test::Unit::TestCase
|
|
11
12
|
excluded = options[:exclude]
|
12
13
|
included = options[:include]
|
13
14
|
assert_nothing_raised { @db = MDB.new(TEST_DB, :exclude => excluded, :include => included ) }
|
15
|
+
assert_not_nil @db
|
14
16
|
end
|
15
17
|
|
16
18
|
end
|
data/test/test_mdb.rb
CHANGED
@@ -3,8 +3,6 @@ require 'test/unit'
|
|
3
3
|
require File.join(File.dirname(__FILE__), 'test_helper')
|
4
4
|
|
5
5
|
class MDBTest < Test::Unit::TestCase
|
6
|
-
|
7
|
-
|
8
6
|
|
9
7
|
def setup
|
10
8
|
|
@@ -12,20 +10,15 @@ class MDBTest < Test::Unit::TestCase
|
|
12
10
|
|
13
11
|
def test_table_exclusion
|
14
12
|
create_mdb(:exclude => ['Inventory'])
|
15
|
-
assert !@db.
|
13
|
+
assert !@db.tables.include?('Inventory')
|
16
14
|
end
|
17
15
|
|
18
16
|
def test_table_inclusion
|
19
17
|
create_mdb(:include => ['Inventory', 'Room'])
|
20
|
-
assert_equal ['Inventory', 'Room'], @db.
|
18
|
+
assert_equal ['Inventory', 'Room'], @db.tables.sort
|
21
19
|
end
|
22
20
|
|
23
|
-
|
24
|
-
create_mdb
|
25
|
-
assert_respond_to @db, 'computer'
|
26
|
-
assert_respond_to @db, 'employee'
|
27
|
-
assert_respond_to @db, 'room'
|
28
|
-
end
|
21
|
+
|
29
22
|
|
30
23
|
|
31
24
|
|
data/test/test_mdb_tools.rb
CHANGED
@@ -28,6 +28,16 @@ class MDBToolsTest < Test::Unit::TestCase
|
|
28
28
|
assert_raise(ArgumentError) { check_file README}
|
29
29
|
end
|
30
30
|
|
31
|
+
def test_valid_file
|
32
|
+
assert valid_file?(TEST_DB)
|
33
|
+
assert !valid_file?(NOT_A_DB)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_mdb_version
|
37
|
+
assert_equal 'JET3', mdb_version(TEST_DB)
|
38
|
+
assert_equal '', mdb_version(NOT_A_DB)
|
39
|
+
end
|
40
|
+
|
31
41
|
def test_check_table
|
32
42
|
assert_nothing_raised { check_table TEST_DB, 'Employee'}
|
33
43
|
assert_raises(ArgumentError) { check_table TEST_DB, 'foobarbaz' }
|
@@ -59,6 +69,28 @@ class MDBToolsTest < Test::Unit::TestCase
|
|
59
69
|
assert_match /DROP TABLE/, @schema
|
60
70
|
end
|
61
71
|
|
72
|
+
def test_describe_table
|
73
|
+
descriptions = describe_table(TEST_DB, 'Employee')
|
74
|
+
assert_kind_of Array, descriptions
|
75
|
+
assert_kind_of Hash, descriptions.first
|
76
|
+
assert_equal 3, descriptions.first.size
|
77
|
+
assert_not_nil descriptions.first['Type']
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_mdb_sql
|
81
|
+
result = [{"Department"=>"Human Resources", "Gender"=>"F", "Room"=>"6150", "Title"=>"Vice President", "Emp_Id"=>"1025", "First_Name"=>"Kathy", "Last_Name"=>"Ragerie"}]
|
82
|
+
assert_equal result, mdb_sql(TEST_DB, "select * from Employee where Room = '6150'")
|
83
|
+
bees = mdb_sql(TEST_DB, "select * from Employee where Last_Name like 'B%'")
|
84
|
+
assert_kind_of Array, bees
|
85
|
+
b = bees.first
|
86
|
+
assert_kind_of Hash, b
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_field_names_for
|
90
|
+
fields = ["Last_Name","First_Name", "Gender", "Title", "Department", "Room", "Emp_Id"]
|
91
|
+
assert_equal fields, field_names_for(TEST_DB, 'Employee')
|
92
|
+
end
|
93
|
+
|
62
94
|
|
63
95
|
# def test_csv_to_hashes
|
64
96
|
# employee_hash = csv_to_hashes(@employees_csv)
|
@@ -66,8 +98,8 @@ class MDBToolsTest < Test::Unit::TestCase
|
|
66
98
|
# end
|
67
99
|
|
68
100
|
def test_sql_select
|
69
|
-
|
70
|
-
|
101
|
+
yo = {"Department"=>"Engineering", "Gender"=>"F", "Room"=>"6044", "Title"=>"Programmer", "Emp_Id"=>"1000", "First_Name"=>"Yolanda", "Last_Name"=>"Torbati"}
|
102
|
+
assert_equal yo, sql_select(TEST_DB, 'Employee', ['*'], "First_Name LIKE 'Yolanda'" ).first
|
71
103
|
end
|
72
104
|
|
73
105
|
def test_compile_conditions
|
@@ -79,6 +111,10 @@ class MDBToolsTest < Test::Unit::TestCase
|
|
79
111
|
sql_select(TEST_DB, 'Employee', nil, compile_conditions(:first_name => 'Yolanda'))
|
80
112
|
end
|
81
113
|
|
114
|
+
def test_count
|
115
|
+
assert_equal 92, faked_count(TEST_DB, 'Room', 'Room', nil)
|
116
|
+
end
|
117
|
+
|
82
118
|
def test_export_table_to_sql
|
83
119
|
# this test is dependent on specific content in the sample database
|
84
120
|
export = mdb_export(TEST_DB, 'Computer', :format => 'sql').split(LINEBREAK)
|
data/test/test_record.rb
CHANGED
@@ -1,24 +1,24 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "..", 'lib', 'active_mdb')
|
2
|
-
require 'test/unit'
|
3
|
-
require File.join(File.dirname(__FILE__), 'test_helper')
|
4
|
-
|
5
|
-
class RecordTest < Test::Unit::TestCase
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
1
|
+
# require File.join(File.dirname(__FILE__), "..", 'lib', 'active_mdb')
|
2
|
+
# require 'test/unit'
|
3
|
+
# require File.join(File.dirname(__FILE__), 'test_helper')
|
4
|
+
#
|
5
|
+
# class RecordTest < Test::Unit::TestCase
|
6
|
+
#
|
7
|
+
# def setup
|
8
|
+
# create_mdb
|
9
|
+
# @employee = @db.employee
|
10
|
+
# @line = ["Torbati","Yolanda", "F", "Programmer", "Engineering", "6044", "1000"]
|
11
|
+
# assert_nothing_raised { @record = Record.new(@employee, @line) }
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# def test_reflection
|
15
|
+
# assert_respond_to @record, 'gender'
|
16
|
+
# assert_respond_to @record, 'emp_id'
|
17
|
+
# assert_equal 'Yolanda', @record.first_name
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# def test_display
|
21
|
+
#
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# end
|
data/test/test_table.rb
CHANGED
@@ -1,50 +1,50 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "..", 'lib', 'active_mdb')
|
2
|
-
require 'test/unit'
|
3
|
-
require File.join(File.dirname(__FILE__), 'test_helper')
|
4
|
-
|
5
|
-
class TableTest < Test::Unit::TestCase
|
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
|
-
end
|
1
|
+
# require File.join(File.dirname(__FILE__), "..", 'lib', 'active_mdb')
|
2
|
+
# require 'test/unit'
|
3
|
+
# require File.join(File.dirname(__FILE__), 'test_helper')
|
4
|
+
#
|
5
|
+
# class TableTest < Test::Unit::TestCase
|
6
|
+
#
|
7
|
+
#
|
8
|
+
# def setup
|
9
|
+
# create_mdb
|
10
|
+
# @employee = @db.employee
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# def test_columns
|
14
|
+
# columns = @employee.columns
|
15
|
+
# assert_kind_of Array, columns
|
16
|
+
# assert_kind_of Column, columns.first
|
17
|
+
# assert_equal 7, columns.size
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# def test_create_record_struct
|
21
|
+
# assert_kind_of Class, @employee.record_struct
|
22
|
+
# members = @employee.record_struct.members
|
23
|
+
# assert_equal 7, members.size
|
24
|
+
# assert members.include?('emp_id')
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# def test_to_csv
|
28
|
+
# csv_text = @employee.to_csv
|
29
|
+
# assert_kind_of String, csv_text
|
30
|
+
# arrays = csv_text.split(MDBTools::LINEBREAK)
|
31
|
+
#
|
32
|
+
# # grab the headers and test for content
|
33
|
+
# assert arrays.shift.include?('Emp_Id')
|
34
|
+
# assert_equal 53, arrays.size
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# def test_find_first
|
38
|
+
# y = @employee.find_first(:first_name => 'Yolanda')
|
39
|
+
# assert_kind_of Record, y
|
40
|
+
# assert_equal 'Yolanda', y.first_name
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# def test_find_all
|
44
|
+
# a_names = @employee.find_all(:last_name => 'A')
|
45
|
+
# assert_kind_of Array, a_names
|
46
|
+
# assert_kind_of Record, a_names.first
|
47
|
+
# assert_equal 2, a_names.size
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# end
|
metadata
CHANGED
@@ -3,15 +3,15 @@ rubygems_version: 0.9.2
|
|
3
3
|
specification_version: 1
|
4
4
|
name: activemdb
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-
|
8
|
-
summary:
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2007-04-05 00:00:00 -05:00
|
8
|
+
summary: ActiveRecordy wrapper around MDB Tools, which lets POSIX platforms read MS Access (.mdb) files
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
11
|
email: automatthew@gmail.com
|
12
12
|
homepage: http://rubyforge.org/projects/activemdb/
|
13
13
|
rubyforge_project: activemdb
|
14
|
-
description: Intended for exploration and migration, not production. ActiveMDB provides a
|
14
|
+
description: Intended for exploration and migration, not production. And it's *READ ONLY*, so don't try to get fresh. ActiveMDB provides a wrapper of varying thickness around the utilities from Brian Bruns's MDB Tools project (http://mdbtools.sourceforge.net/). Kudos to Mr. Bruns.
|
15
15
|
autorequire:
|
16
16
|
default_executable:
|
17
17
|
bindir: bin
|
@@ -33,9 +33,13 @@ files:
|
|
33
33
|
- Manifest.txt
|
34
34
|
- README.txt
|
35
35
|
- Rakefile
|
36
|
+
- db/.DS_Store
|
37
|
+
- db/not_an_mdb.txt
|
38
|
+
- db/retreat.mdb
|
36
39
|
- db/sample.mdb
|
37
40
|
- irb.rc
|
38
41
|
- lib/active_mdb.rb
|
42
|
+
- lib/active_mdb/base.rb
|
39
43
|
- lib/active_mdb/column.rb
|
40
44
|
- lib/active_mdb/mdb.rb
|
41
45
|
- lib/active_mdb/mdb_tools.rb
|
@@ -43,6 +47,7 @@ files:
|
|
43
47
|
- lib/active_mdb/table.rb
|
44
48
|
- support/a.insert
|
45
49
|
- test/test_activemdb.rb
|
50
|
+
- test/test_base.rb
|
46
51
|
- test/test_helper.rb
|
47
52
|
- test/test_mdb.rb
|
48
53
|
- test/test_mdb_tools.rb
|
@@ -50,6 +55,7 @@ files:
|
|
50
55
|
- test/test_table.rb
|
51
56
|
test_files:
|
52
57
|
- test/test_activemdb.rb
|
58
|
+
- test/test_base.rb
|
53
59
|
- test/test_helper.rb
|
54
60
|
- test/test_mdb.rb
|
55
61
|
- test/test_mdb_tools.rb
|