lib/sup/person.rb in sup-0.0.8 vs lib/sup/person.rb in sup-0.1
- old
+ new
@@ -3,47 +3,94 @@
class PersonManager
include Singleton
def initialize fn
@fn = fn
- @names = {}
- IO.readlines(fn).map { |l| l =~ /^(.*)?:\s+(\d+)\s+(.*)$/ && @names[$1] = [$2.to_i, $3] } if File.exists? fn
+ @@people = {}
+
+ ## read in stored people
+ IO.readlines(fn).map do |l|
+ l =~ /^(.*)?:\s+(\d+)\s+(.*)$/ or raise "can't parse: #{l}"
+ email, time, name = $1, $2, $3
+ @@people[email] = Person.new name, email, time, false
+ end if File.exists? fn
+
self.class.i_am_the_instance self
end
- def name_for email; @names.member?(email) ? @names[email][1] : nil; end
- def register email, name
- return unless name
+ def save
+ File.open(@fn, "w") do |f|
+ @@people.each do |email, p|
+ f.puts "#{p.email}: #{p.timestamp} #{p.name}"
+ end
+ end
+ end
- name = name.gsub(/^\s+|\s+$/, "").gsub(/\s+/, " ").gsub(/^['"]|['"]$/, "")
+ def self.people_for s, opts={}
+ return [] if s.nil?
+ s.split_on_commas.map { |ss| self.person_for ss, opts }
+ end
- ## all else being equal, prefer longer names, unless the prior name
- ## doesn't contain any capitalization
- oldcount, oldname = @names[email]
- @names[email] = [0, name] if oldname.nil? || oldname.length < name.length || (oldname !~ /[A-Z]/ && name =~ /[A-Z]/)
- @names[email][0] = Time.now.to_i
+ def self.person_for s, opts={}
+ p = Person.from_address(s) or return nil
+ p.definitive = true if opts[:definitive]
+ register p
end
+
+ def self.register p
+ oldp = @@people[p.email]
- def save; File.open(@fn, "w") { |f| @names.each { |email, (time, name)| f.puts "#{email}: #{time} #{name}" } }; end
+ if oldp.nil? || p.better_than?(oldp)
+ @@people[p.email] = p
+ end
+
+ @@people[p.email].touch!
+ @@people[p.email]
+ end
end
-class Person
- @@email_map = {}
+## don't create these by hand. rather, go through personmanager, to
+## ensure uniqueness and overriding.
+class Person
+ attr_accessor :name, :email, :timestamp
+ bool_accessor :definitive
- attr_accessor :name, :email
-
- def initialize name, email
+ def initialize name, email, timestamp=0, definitive=false
raise ArgumentError, "email can't be nil" unless email
+
+ if name
+ @name = name.gsub(/^\s+|\s+$/, "").gsub(/\s+/, " ")
+ if @name =~ /^(['"]\s*)(.*?)(\s*["'])$/
+ @name = $2
+ end
+ end
+
@email = email.gsub(/^\s+|\s+$/, "").gsub(/\s+/, " ").downcase
- PersonManager.register @email, name
- @name = PersonManager.name_for @email
+ @definitive = definitive
+ @timestamp = timestamp
end
- def == o; o && o.email == email; end
- alias :eql? :==
- def hash; [name, email].hash; end
+ ## heuristic: whether the name attached to this email is "real", i.e.
+ ## we should bother to store it.
+ def generic?
+ @email =~ /no\-?reply/
+ end
+ def better_than? o
+ return false if o.definitive? || generic?
+ return true if definitive?
+ o.name.nil? || (name && name.length > o.name.length && name =~ /[a-z]/)
+ end
+
+ def to_s; "#@name <#@email>" end
+
+ def touch!; @timestamp = Time.now.to_i end
+
+# def == o; o && o.email == email; end
+# alias :eql? :==
+# def hash; [name, email].hash; end
+
def shortname
case @name
when /\S+, (\S+)/
$1
when /(\S+) \S+/
@@ -91,11 +138,11 @@
else
@name
end.downcase
end
- def self.for s
+ def self.from_address s
return nil if s.nil?
## try and parse an email address and name
name, email =
case s
@@ -108,16 +155,10 @@
[$2, $1]
else
[nil, s]
end
- @@email_map[email] ||= Person.new name, email
- end
-
- def self.for_several s
- return [] if s.nil?
-
- s.split_on_commas.map { |ss| self.for ss }
+ Person.new name, email
end
end
end