9 IO.readlines(fn).map { |l| l =~ /^(.*)?:\s+(\d+)\s+(.*)$/ && @names[$1] = [$2.to_i, $3] } if File.exists? fn
10 self.class.i_am_the_instance self
13 def name_for email; @names[email][1]; end
14 def register email, name
17 name = name.gsub(/^\s+|\s+$/, "").gsub(/\s+/, " ")
19 ## all else being equal, prefer longer names, unless the prior name
20 ## doesn't contain any capitalization
21 oldcount, oldname = @names[email]
22 @names[email] = [0, name] if oldname.nil? || oldname.length < name.length || (oldname !~ /[A-Z]/ && name =~ /[A-Z]/)
23 @names[email][0] = Time.now.to_i
26 def save; File.open(@fn, "w") { |f| @names.each { |email, (time, name)| f.puts "#{email}: #{time} #{name}" } }; end
32 attr_accessor :name, :email
34 def initialize name, email
35 raise ArgumentError, "email can't be nil" unless email
36 @email = email.gsub(/^\s+|\s+$/, "").gsub(/\s+/, " ").downcase
37 PersonManager.register @email, name
38 @name = PersonManager.name_for @email
41 def == o; o && o.email == email; end
43 def hash; [name, email].hash; end
66 def mediumname; @name || @email; end
71 "#{@name.inspect} <#@email>" # escape quotes
80 ## when sorting addresses, sort by this
99 ## try and parse an email address and name
102 when /["'](.*?)["'] <(.*?)>/, /([^,]+) <(.*?)>/
104 [a.gsub('\"', '"'), b]
105 when /<((\S+?)@\S+?)>/
113 @@email_map[email] ||= Person.new name, email
116 def self.for_several s
120 s.split_on_commas.map { |ss| self.for ss }
121 rescue StandardError => e
122 raise "#{e.message}: for #{s.inspect}"