4 attr_accessor :name, :email
6 def initialize name, email
7 raise ArgumentError, "email can't be nil" unless email
10 @name = name.gsub(/^\s+|\s+$/, "").gsub(/\s+/, " ")
11 if @name =~ /^(['"]\s*)(.*?)(\s*["'])$/
18 @email = email.gsub(/^\s+|\s+$/, "").gsub(/\s+/, " ").downcase
21 def to_s; "#@name <#@email>" end
23 # def == o; o && o.email == email; end
25 # def hash; [name, email].hash; end
48 def mediumname; @name || @email; end
53 "#{@name.inspect} <#{@email}>" # escape quotes
55 "#{@name} <#{@email}>"
62 ## when sorting addresses, sort by this
78 def self.from_address s
81 ## try and parse an email address and name
83 when /(.+?) ((\S+?)@\S+) \3/
84 ## ok, this first match cause is insane, but bear with me. email
85 ## addresses are stored in the to/from/etc fields of the index in a
86 ## weird format: "name address first-part-of-address", i.e. spaces
87 ## separating those three bits, and no <>'s. this is the output of
88 ## #indexable_content. here, we reverse-engineer that format to extract
91 ## we store things this way to allow searches on a to/from/etc field to
92 ## match any of those parts. a more robust solution would be to store a
93 ## separate, non-indexed field with the proper headers. but this way we
94 ## save precious bits, and it's backwards-compatible with older indexes.
96 when /["'](.*?)["'] <(.*?)>/, /([^,]+) <(.*?)>/
98 [a.gsub('\"', '"'), b]
99 when /<((\S+?)@\S+?)>/
107 Person.new name, email
110 def self.from_address_list ss
112 ss.split_on_commas.map { |s| self.from_address s }
115 ## see comments in self.from_address
116 def indexable_content
117 [name, email, email.split(/@/).first].join(" ")
120 def eql? o; email.eql? o.email end
121 def hash; email.hash end