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*["'])$/
16 @email = email.gsub(/^\s+|\s+$/, "").gsub(/\s+/, " ").downcase
19 def to_s; "#@name <#@email>" end
21 # def == o; o && o.email == email; end
23 # def hash; [name, email].hash; end
46 def mediumname; @name || @email; end
51 "#{@name.inspect} <#{@email}>" # escape quotes
53 "#{@name} <#{@email}>"
60 ## when sorting addresses, sort by this
76 def self.from_address s
79 ## try and parse an email address and name
81 when /(.+?) ((\S+?)@\S+) \3/
82 ## ok, this first match cause is insane, but bear with me. email
83 ## addresses are stored in the to/from/etc fields of the index in a
84 ## weird format: "name address first-part-of-address", i.e. spaces
85 ## separating those three bits, and no <>'s. this is the output of
86 ## #indexable_content. here, we reverse-engineer that format to extract
89 ## we store things this way to allow searches on a to/from/etc field to
90 ## match any of those parts. a more robust solution would be to store a
91 ## separate, non-indexed field with the proper headers. but this way we
92 ## save precious bits, and it's backwards-compatible with older indexes.
94 when /["'](.*?)["'] <(.*?)>/, /([^,]+) <(.*?)>/
96 [a.gsub('\"', '"'), b]
97 when /<((\S+?)@\S+?)>/
105 Person.new name, email
108 def self.from_address_list ss
110 ss.split_on_commas.map { |s| self.from_address s }
113 ## see comments in self.from_address
114 def indexable_content
115 [name, email, email.split(/@/).first].join(" ")
118 def eql? o; email.eql? o.email end
119 def hash; email.hash end