mwhuss-contact_csv 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/History.txt +10 -0
- data/License.txt +20 -0
- data/Manifest.txt +33 -0
- data/README.txt +63 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +71 -0
- data/config/requirements.rb +17 -0
- data/lib/contact_csv.rb +9 -0
- data/lib/contact_csv/contact.rb +36 -0
- data/lib/contact_csv/contact_csv.rb +4 -0
- data/lib/contact_csv/contact_manager.rb +61 -0
- data/lib/contact_csv/lookup_tables/lookup_table.rb +27 -0
- data/lib/contact_csv/lookup_tables/outlook_csv.rb +116 -0
- data/lib/contact_csv/lookup_tables/outlook_doc_csv.rb +122 -0
- data/lib/contact_csv/version.rb +9 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/outlook_contacts.csv +10 -0
- data/test/outlook_contacts_dos.csv +10 -0
- data/test/test_contact.rb +35 -0
- data/test/test_contact_manager.rb +26 -0
- data/test/test_helper.rb +2 -0
- data/test/test_lookup_table.rb +59 -0
- data/website/index.html +107 -0
- data/website/index.txt +54 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.rhtml +48 -0
- metadata +95 -0
data/History.txt
ADDED
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Marshall Huss
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
History.txt
|
2
|
+
License.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
config/hoe.rb
|
7
|
+
config/requirements.rb
|
8
|
+
lib/contact_csv.rb
|
9
|
+
lib/contact_csv/contact.rb
|
10
|
+
lib/contact_csv/contact_csv.rb
|
11
|
+
lib/contact_csv/contact_manager.rb
|
12
|
+
lib/contact_csv/lookup_tables/lookup_table.rb
|
13
|
+
lib/contact_csv/lookup_tables/outlook_csv.rb
|
14
|
+
lib/contact_csv/lookup_tables/outlook_doc_csv.rb
|
15
|
+
lib/contact_csv/version.rb
|
16
|
+
script/destroy
|
17
|
+
script/generate
|
18
|
+
script/txt2html
|
19
|
+
setup.rb
|
20
|
+
tasks/deployment.rake
|
21
|
+
tasks/environment.rake
|
22
|
+
tasks/website.rake
|
23
|
+
test/outlook_contacts.csv
|
24
|
+
test/outlook_contacts_dos.csv
|
25
|
+
test/test_contact.rb
|
26
|
+
test/test_contact_manager.rb
|
27
|
+
test/test_helper.rb
|
28
|
+
test/test_lookup_table.rb
|
29
|
+
website/index.html
|
30
|
+
website/index.txt
|
31
|
+
website/javascripts/rounded_corners_lite.inc.js
|
32
|
+
website/stylesheets/screen.css
|
33
|
+
website/template.rhtml
|
data/README.txt
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# === ContactCsv
|
2
|
+
#
|
3
|
+
# ==== Supported CSV
|
4
|
+
# * Outlook 2003 CSV (Windows)
|
5
|
+
#
|
6
|
+
# ==== Reading in CSV
|
7
|
+
#
|
8
|
+
# To import contacts you use a ContactManager...
|
9
|
+
#
|
10
|
+
#
|
11
|
+
# contact_manager = ContactCsv::ContactManager.new
|
12
|
+
#
|
13
|
+
# contact_manager.read('/path/to/file.csv')
|
14
|
+
# or
|
15
|
+
# contact_manager.parse('csv,data,string')
|
16
|
+
#
|
17
|
+
#
|
18
|
+
# ==== Getting the contacts
|
19
|
+
#
|
20
|
+
# contact_manager.contacts.each do |contact|
|
21
|
+
# puts contact.name
|
22
|
+
# puts contact.email
|
23
|
+
# puts contact.extras['Spouse']
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# See the Contact class for a complete list of attributes.
|
27
|
+
#
|
28
|
+
#
|
29
|
+
# ==== Lookup Tables
|
30
|
+
#
|
31
|
+
# A lookup table is used to map the csv columns to Contact class attributes. You can create your own lookup tables
|
32
|
+
# by using the LookupTable class and passing it in inside an array to the ContactManager class.
|
33
|
+
#
|
34
|
+
# # These are the column headers in the csv
|
35
|
+
# headers = ["First Name","Last Name","Email Address"]
|
36
|
+
#
|
37
|
+
# # These map the column headers to the attribute of the Contact class
|
38
|
+
# legend = {
|
39
|
+
# 'First Name' => :first_name,
|
40
|
+
# 'Last Name ' => :last_name,
|
41
|
+
# 'Email Address' => :email
|
42
|
+
# }
|
43
|
+
#
|
44
|
+
# lookup_table = LookupTable.new(headers, legend)
|
45
|
+
#
|
46
|
+
# # The lookup table is passed into the ContactManager
|
47
|
+
# contact_manager = ContactCsv::ContactManager.new([lookup_table])
|
48
|
+
# or
|
49
|
+
# contact_manager.lookup_tables << lookup_table
|
50
|
+
#
|
51
|
+
#
|
52
|
+
# If you think you have composed a good lookup table email it to me (mwhuss@gmail.com) and I will include it in the gem.
|
53
|
+
#
|
54
|
+
#
|
55
|
+
# ==== To Do
|
56
|
+
# * Add lookup table for Outlook 2003 CSV (DOS)
|
57
|
+
# * Add lookup table for GMail CSV
|
58
|
+
#
|
59
|
+
#
|
60
|
+
#
|
61
|
+
|
62
|
+
|
63
|
+
|
data/Rakefile
ADDED
data/config/hoe.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'contact_csv/version'
|
2
|
+
|
3
|
+
AUTHOR = 'Marshall Huss' # can also be an array of Authors
|
4
|
+
EMAIL = "mwhuss@gmail.com"
|
5
|
+
DESCRIPTION = "Simple gem for reading in contact csv files that you can export from email clients like Outlook or GMail"
|
6
|
+
GEM_NAME = 'contact_csv' # what ppl will type to install your gem
|
7
|
+
RUBYFORGE_PROJECT = 'contactcsv' # The unix name for your project
|
8
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
|
+
|
11
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
12
|
+
@config = nil
|
13
|
+
RUBYFORGE_USERNAME = "mwhuss"
|
14
|
+
def rubyforge_username
|
15
|
+
unless @config
|
16
|
+
begin
|
17
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
18
|
+
rescue
|
19
|
+
puts <<-EOS
|
20
|
+
ERROR: No rubyforge config file found: #{@config_file}
|
21
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
22
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
23
|
+
EOS
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
end
|
27
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
REV = nil
|
32
|
+
# UNCOMMENT IF REQUIRED:
|
33
|
+
# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
|
34
|
+
VERS = ContactCsv::VERSION::STRING + (REV ? ".#{REV}" : "")
|
35
|
+
RDOC_OPTS = ['--quiet', '--title', 'contact_csv documentation',
|
36
|
+
"--opname", "index.html",
|
37
|
+
"--line-numbers",
|
38
|
+
"--main", "README",
|
39
|
+
"--inline-source"]
|
40
|
+
|
41
|
+
class Hoe
|
42
|
+
def extra_deps
|
43
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
44
|
+
@extra_deps
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Generate all the Rake tasks
|
49
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
50
|
+
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
51
|
+
p.developer(AUTHOR, EMAIL)
|
52
|
+
p.description = DESCRIPTION
|
53
|
+
p.summary = DESCRIPTION
|
54
|
+
p.url = HOMEPATH
|
55
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
56
|
+
p.test_globs = ["test/**/test_*.rb"]
|
57
|
+
p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
|
58
|
+
|
59
|
+
# == Optional
|
60
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
61
|
+
p.extra_deps = [ ['fastercsv'] ] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
62
|
+
|
63
|
+
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
68
|
+
#PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
69
|
+
PATH = RUBYFORGE_PROJECT
|
70
|
+
hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
71
|
+
hoe.rsync_args = '-av --delete --ignore-errors'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w[rake hoe newgem rubigen].each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
|
16
|
+
|
17
|
+
require 'contact_csv'
|
data/lib/contact_csv.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'fastercsv'
|
5
|
+
require 'contact_csv/contact_csv.rb'
|
6
|
+
require 'contact_csv/contact.rb'
|
7
|
+
require 'contact_csv/contact_manager.rb'
|
8
|
+
require 'contact_csv/lookup_tables/lookup_table.rb'
|
9
|
+
require 'contact_csv/lookup_tables/outlook_csv.rb'
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# === Contact
|
2
|
+
#
|
3
|
+
# Object that represents a Contact from an address book. This class is meant to support the most common attributes.
|
4
|
+
#
|
5
|
+
class ContactCsv::Contact
|
6
|
+
|
7
|
+
attr_accessor :first_name, :middle_name, :last_name, :email, :title, :extras
|
8
|
+
|
9
|
+
# Initializes a Contact objest and will take a hash of the attributes with values
|
10
|
+
#
|
11
|
+
# Contact.new(:first_name => "Willy", :last_name => "Wonka")
|
12
|
+
def initialize(attributes={})
|
13
|
+
@extras = {}
|
14
|
+
@first_name = attributes[:first_name]
|
15
|
+
@middle_name = attributes[:middle_name]
|
16
|
+
@last_name = attributes[:last_name]
|
17
|
+
@email = attributes[:email]
|
18
|
+
@title = attributes[:title]
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns a hash of all attributes that could not be mapped to a Contact class attribute
|
22
|
+
def extras
|
23
|
+
@extras
|
24
|
+
end
|
25
|
+
|
26
|
+
# Adds an unmappable attribute
|
27
|
+
def add_extra(extra)
|
28
|
+
@extras.merge!(extra)
|
29
|
+
end
|
30
|
+
|
31
|
+
# First name and last name
|
32
|
+
def full_name
|
33
|
+
[@first_name, @last_name].join(' ')
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# === ContctManager
|
2
|
+
#
|
3
|
+
# The ContactManager handles finding the appropriate lookup table and creating the array of Contact objects
|
4
|
+
#
|
5
|
+
#
|
6
|
+
class ContactCsv::ContactManager
|
7
|
+
include ContactCsv
|
8
|
+
include ContactCsv::LookupTables
|
9
|
+
|
10
|
+
attr_accessor :contacts, :lookup_tables
|
11
|
+
|
12
|
+
# Initializes a ContactManager, accepts an Array of LookupTables
|
13
|
+
def initialize(lookup_tables=[])
|
14
|
+
@lookup_tables = lookup_tables + [OutlookCsv.lookup_table]
|
15
|
+
@contacts = []
|
16
|
+
end
|
17
|
+
|
18
|
+
# Reads a CSV file and creates a contact list
|
19
|
+
def read(file_path)
|
20
|
+
csv = FasterCSV.read(file_path, :headers => true)
|
21
|
+
create_contacts(csv)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Reads a CSV string and creates a contact list
|
25
|
+
def parse(csv_string)
|
26
|
+
csv = FasterCSV.parse(csv_string, :headers => true)
|
27
|
+
create_contacts(csv)
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Creates a contact list from a CSV object
|
34
|
+
def create_contacts(csv)
|
35
|
+
@contacts = []
|
36
|
+
lookup_table = find_lookup_table(csv, lookup_tables)
|
37
|
+
raise LookupTableNotFoundError if lookup_table.nil?
|
38
|
+
csv.each do |row|
|
39
|
+
c = Contact.new
|
40
|
+
row.each do |r|
|
41
|
+
col = lookup_table.lookup(r[0])
|
42
|
+
c.send("#{col.to_s}=", r[1]) if !col.nil? && c.respond_to?(col.to_sym)
|
43
|
+
c.add_extra({ r[0] => r[1] })
|
44
|
+
end
|
45
|
+
@contacts << c
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# Determines the lookup table that matches the file
|
51
|
+
def find_lookup_table(csv, lookup_tables)
|
52
|
+
tables = lookup_tables + [OutlookCsv.lookup_table]
|
53
|
+
tables.each do |table|
|
54
|
+
return table if table.headers == csv.headers
|
55
|
+
end
|
56
|
+
return nil
|
57
|
+
end
|
58
|
+
|
59
|
+
class LookupTableNotFoundError < StandardError; end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# === LookupTable
|
2
|
+
#
|
3
|
+
# This class is so users can define their own lookup tables if it isn't supported natively. The headers is an
|
4
|
+
# Array of Strings that define the column names for the CSV file. Legend is a hash that maps the column strings
|
5
|
+
# to a Contact class attribute. Look at the Contact class for a list of available attributes.
|
6
|
+
#
|
7
|
+
#
|
8
|
+
class ContactCsv::LookupTables::LookupTable
|
9
|
+
|
10
|
+
attr_accessor :legend, :headers
|
11
|
+
|
12
|
+
# Initializes a LookupTable taking an Array of headers and a Hash that maps the column headers to the Contact object attributes
|
13
|
+
def initialize(headers, legend)
|
14
|
+
raise InvalidInputFormatError unless headers.is_a?(Array) && legend.is_a?(Hash)
|
15
|
+
@headers = headers
|
16
|
+
@legend = legend
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
# Returns the corresponding Contact attribute mapped to the specific Outlook CSV column name
|
21
|
+
def lookup(column)
|
22
|
+
@legend[column]
|
23
|
+
end
|
24
|
+
|
25
|
+
class InvalidInputFormatError < StandardError; end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# === OutlookCsv
|
2
|
+
#
|
3
|
+
# Basic class to define the headers and legend for reading Outlook 2003 CSV (Windows) files
|
4
|
+
#
|
5
|
+
#
|
6
|
+
class ContactCsv::LookupTables::OutlookCsv
|
7
|
+
include ContactCsv::LookupTables
|
8
|
+
|
9
|
+
# Returns a Hash of how the columns map to the Contact attributes
|
10
|
+
def self.legend
|
11
|
+
{
|
12
|
+
'Title' => :title,
|
13
|
+
'First Name' => :first_name,
|
14
|
+
'Middle Name' => :middle_name,
|
15
|
+
'Last Name' => :last_name,
|
16
|
+
'E-mail Address' => :email
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns an Array of all the headers for a Outlook CSV file
|
21
|
+
def self.headers
|
22
|
+
[ "Title",
|
23
|
+
"First Name",
|
24
|
+
"Middle Name",
|
25
|
+
"Last Name",
|
26
|
+
"Suffix",
|
27
|
+
"Company",
|
28
|
+
"Department",
|
29
|
+
"Job Title",
|
30
|
+
"Business Street",
|
31
|
+
"Business Street 2",
|
32
|
+
"Business Street 3",
|
33
|
+
"Business City",
|
34
|
+
"Business State",
|
35
|
+
"Business Postal Code",
|
36
|
+
"Business Country",
|
37
|
+
"Home Street",
|
38
|
+
"Home Street 2",
|
39
|
+
"Home Street 3",
|
40
|
+
"Home City",
|
41
|
+
"Home State",
|
42
|
+
"Home Postal Code",
|
43
|
+
"Home Country",
|
44
|
+
"Other Street",
|
45
|
+
"Other Street 2",
|
46
|
+
"Other Street 3",
|
47
|
+
"Other City",
|
48
|
+
"Other State",
|
49
|
+
"Other Postal Code",
|
50
|
+
"Other Country",
|
51
|
+
"Assistant's Phone",
|
52
|
+
"Business Fax",
|
53
|
+
"Business Phone",
|
54
|
+
"Business Phone 2",
|
55
|
+
"Callback",
|
56
|
+
"Car Phone",
|
57
|
+
"Company Main Phone",
|
58
|
+
"Home Fax","Home Phone",
|
59
|
+
"Home Phone 2",
|
60
|
+
"ISDN",
|
61
|
+
"Mobile Phone",
|
62
|
+
"Other Fax",
|
63
|
+
"Other Phone",
|
64
|
+
"Pager",
|
65
|
+
"Primary Phone",
|
66
|
+
"Radio Phone",
|
67
|
+
"TTY/TDD Phone",
|
68
|
+
"Telex","Account",
|
69
|
+
"Anniversary",
|
70
|
+
"Assistant's Name",
|
71
|
+
"Billing Information",
|
72
|
+
"Birthday",
|
73
|
+
"Business Address PO Box",
|
74
|
+
"Categories","Children",
|
75
|
+
"Directory Server",
|
76
|
+
"E-mail Address",
|
77
|
+
"E-mail Type",
|
78
|
+
"E-mail Display Name",
|
79
|
+
"E-mail 2 Address",
|
80
|
+
"E-mail 2 Type",
|
81
|
+
"E-mail 2 Display Name",
|
82
|
+
"E-mail 3 Address",
|
83
|
+
"E-mail 3 Type",
|
84
|
+
"E-mail 3 Display Name",
|
85
|
+
"Gender",
|
86
|
+
"Government ID Number",
|
87
|
+
"Hobby",
|
88
|
+
"Home Address PO Box",
|
89
|
+
"Initials",
|
90
|
+
"Internet Free Busy",
|
91
|
+
"Keywords","Language",
|
92
|
+
"Location",
|
93
|
+
"Manager's Name",
|
94
|
+
"Mileage",
|
95
|
+
"Notes",
|
96
|
+
"Office Location",
|
97
|
+
"Organizational ID Number",
|
98
|
+
"Other Address PO Box",
|
99
|
+
"Priority","Private",
|
100
|
+
"Profession",
|
101
|
+
"Referred By",
|
102
|
+
"Sensitivity",
|
103
|
+
"Spouse",
|
104
|
+
"User 1",
|
105
|
+
"User 2",
|
106
|
+
"User 3",
|
107
|
+
"User 4",
|
108
|
+
"Web Page"]
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns a LookupTable object
|
112
|
+
def self.lookup_table
|
113
|
+
LookupTable.new(self.headers, self.legend)
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|