mail_address 0.1.0 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f5ef3594c8c1db655ecc152730b2ed9629f07aaf
4
- data.tar.gz: 37e80811b0d7247e94af0590cb57a25cdfc7d149
3
+ metadata.gz: ad0921e631ebcc827050a1a1c2572df665eca7f3
4
+ data.tar.gz: 398cf4fe10f1bebc20231b2cbb4d8dcca60a1dc5
5
5
  SHA512:
6
- metadata.gz: aa9949bdae33cf62b3d1230aa8e05195ea00c94ab65dae4aae3a02d6195f74af8d7c32249a0455b24644e4f0d8eba99bb7bafc1d68831942bc65dc91eb461099
7
- data.tar.gz: 40a48078f26c3e9e410c4944a4a79f1385d68c8b8f314808dbd3753e967331df760255a5dcc7153bcc36bbadf7b7c5b7207ef9de6f730bff6a14dcddd6785e7c
6
+ metadata.gz: 9b6da43a7b73f7df6d262188cdff389a7f077fe4c03707bf180d07aed408bb967ac05f21f8b9e9b9a9d341e7b6893659e2f7f2d323f7fc28648c49c44a32fb66
7
+ data.tar.gz: 56f4ee85472296c2e8fb48bd1fdd8a895462b4a629533faeebf3b274b9a5b600305c412dc38b940ef54cba2301decd8638a852f00dff595f91401f7faa2a1b52
data/.rspec CHANGED
@@ -1 +1,2 @@
1
1
  --color
2
+ --format documentation
@@ -2,42 +2,37 @@ module MailAddress
2
2
 
3
3
  class Address
4
4
 
5
- def initialize(phrase, address, comment)
5
+ def initialize(phrase, address)
6
6
  @phrase = phrase
7
7
  @address = address
8
- @comment = comment
9
8
  end
10
- attr_accessor :phrase, :address, :comment
9
+ attr_accessor :phrase, :address
11
10
 
12
11
  ATEXT = '[\-\w !#$%&\'*+/=?^`{|}~]'
13
12
 
14
13
  def format
15
14
  addr = []
16
15
  if !@phrase.nil? && @phrase.length > 0 then
17
- addr.push(
18
- @phrase.match(/^(?:\s*#{ATEXT}\s*)+$/) ? @phrase
19
- : @phrase.match(/(?<!\\)"/) ? @phrase
20
- : %Q("#{@phrase}")
21
- )
22
- addr.push "<#{@address}>" if !@address.nil? && @address.length > 0
16
+ if @phrase.match(/\A\(/) && @phrase.match(/\)\z/)
17
+ addr.push(@address) if !@address.nil? && @address.length > 0
18
+ addr.push(@phrase)
19
+ else
20
+ addr.push(
21
+ @phrase.match(/^(?:\s*#{ATEXT}\s*)+$/) ? @phrase
22
+ : @phrase.match(/(?<!\\)"/) ? @phrase
23
+ : %Q("#{@phrase}")
24
+ )
25
+ addr.push "<#{@address}>" if !@address.nil? && @address.length > 0
26
+ end
23
27
  elsif !@address.nil? && @address.length > 0 then
24
28
  addr.push(@address)
25
29
  end
26
-
27
- if (!@comment.nil? && @comment.match(/\S/)) then
28
- @comment.sub!(/^\s*\(?/, '(')
29
- @comment.sub!(/\)?\s*$/, ')')
30
- end
31
-
32
- addr.push(@comment) if !@comment.nil? && @comment.length > 0
33
30
  addr.join(' ')
34
31
  end
35
32
 
36
33
  def name
37
34
  phrase = @phrase.dup
38
- addr = @address.dup
39
-
40
- phrase = @comment.dup unless !phrase.nil? && phrase.length > 0
35
+ addr = @address ? @address.dup : ""
41
36
 
42
37
  name = Address._extract_name(phrase)
43
38
 
@@ -89,21 +84,8 @@ module MailAddress
89
84
 
90
85
  name.sub!(/^\((.*)\)$/, '\1') # remove outermost parenthesis
91
86
  name.sub!(/^"(.*)"$/, '\1') # remove outer quotation marks
92
- name.gsub!(/\(.*?\)/, '') # remove minimal embedded comments
93
87
  name.gsub!(/\\/, '') # remove all escapes
94
88
  name.sub!(/^"(.*)"$/, '\1') # remove internal quotation marks
95
- name.sub!(/^([^\s]+) ?, ?(.*)$/, '\2 \1') # reverse "Last, First M." if applicable
96
- name.sub!(/,.*/, '')
97
-
98
- # Change casing only when the name contains only upper or only
99
- # lower cased characters.
100
- unless ( name.match(/[A-Z]/) && name.match(/[a-z]/) ) then
101
- # Set the case of the name to first char upper rest lower
102
- name.gsub!(/\b(\w+)/io) {|w| $1.capitalize } # Upcase first letter on name
103
- name.gsub!(/\bMc(\w)/io) { |w| "Mc#{$1.capitalize}" } # Scottish names such as 'McLeod'
104
- name.gsub!(/\bo'(\w)/io) { |w| "O'#{$1.capitalize}" } # Irish names such as 'O'Malley, O'Reilly'
105
- name.gsub!(/\b(x*(ix)?v*(iv)?i*)\b/io) { |w| $1.upcase } # Roman numerals, eg 'Level III Support'
106
- end
107
89
 
108
90
  # some cleanup
109
91
  name.gsub!(/\[[^\]]*\]/, '')
@@ -5,41 +5,59 @@ module MailAddress
5
5
  lines = addresses.grep(String)
6
6
  line = lines.join('')
7
7
 
8
- phrase, comment, address, objs = [], [], [], []
9
- depth, idx = 0, 0
8
+ # undisclosed-recipient
9
+ if line.match(/undisclosed[ \-]recipients?: ?;?/i)
10
+ return [ MailAddress::Address.new(line, nil) ]
11
+ end
12
+
13
+ # obviously invalid email address
14
+ unless line.match(/[a-z0-9\.\-"_\+]@/i)
15
+ return [ MailAddress::Address.new(line, nil) ]
16
+ end
17
+
18
+ phrase, address, objs = [], [], []
19
+ depth, idx, end_paren_idx = 0, 0, 0
10
20
 
11
21
  tokens = _tokenize lines
12
22
  len = tokens.length
13
23
  _next = _find_next idx, tokens, len
14
24
 
15
25
  for idx in 0 ... len do
26
+
27
+ if (end_paren_idx > 0 && end_paren_idx >= idx)
28
+ next
29
+ end
30
+
16
31
  token = tokens[idx]
17
32
  substr = token[0, 1]
18
- if (substr == '(') then
19
- comment.push(token)
20
- elsif (token == '<') then
33
+
34
+ if (substr == '(' && !address.empty?) then
35
+ end_paren_idx = _find_next_paren(idx, tokens, len)
36
+ raise "cannot find end paren" if end_paren_idx == -1 # end paren must exists after address
37
+ rem = tokens[idx .. end_paren_idx]
38
+ phrase.push(rem.join(''))
39
+ elsif (substr == '<') then
21
40
  depth += 1
22
- elsif (token == '>') then
41
+ elsif (substr == '>') then
23
42
  depth -= 1 if depth > 0
24
- elsif (token == ',' || token == ';') then
43
+ elsif (substr == ',' || substr == ';') then
25
44
  raise "Unmatched '<>' in line" if depth > 0
26
- o = _complete(phrase, address, comment)
45
+ o = _complete(phrase, address)
27
46
 
28
47
  objs.push(o) if o
29
48
  depth = 0
49
+ end_paren_idx = 0
30
50
  _next = _find_next idx+1, tokens, len
31
51
  elsif (depth > 0) then
52
+ token.strip!
32
53
  address.push(token)
33
54
  elsif (_next == '<') then
34
55
  phrase.push(token)
35
56
  elsif ( token.match(/^[.\@:;]/) || address.empty? || address[-1].match(/^[.\@:;]/) ) then
57
+ token.strip!
36
58
  address.push(token)
37
59
  else
38
- raise "Unmatched '<>' in line" if depth > 0
39
- o = _complete(phrase, address, comment)
40
- objs.push(o) if o
41
- depth = 0
42
- address.push(token)
60
+ phrase.push(token)
43
61
  end
44
62
  end
45
63
  objs
@@ -56,37 +74,14 @@ module MailAddress
56
74
 
57
75
  while (line != '')
58
76
  field = ''
59
- if ( line.sub!(/^\s*\(/, '(') ) # (...)
60
- depth = 0
61
-
62
- catch :PAREN do
63
- while line.sub!(/\A(\(([^\(\)\\]|\\.)*)/, '') do
64
- field << $1
65
- depth += 1
66
- while line.sub!(/\A(([^\(\)\\]|\\.)*\)\s*)/, '') do
67
- field << $1
68
- depth -= 1
69
- throw :PAREN if depth == 0
70
- field << $1 if line.sub!(/\A(([^\(\)\\]|\\.)+)/, '')
71
- end
72
- end
73
- end
74
- raise "Unmatched () '#{field}' '#{line}'" if depth > 0
75
-
76
- field.sub!(/\s+\Z/, '')
77
- words.push(field)
78
-
79
- next
80
- end
81
-
82
77
  tmp = nil
83
78
  if (
84
- line.sub!(/\A("(?:[^"\\]+|\\.)*")\s*/, '') || # "..."
85
- line.sub!(/\A(\[(?:[^\]\\]+|\\.)*\])\s*/, '') || # [...]
86
- line.sub!(/\A([^\s()<>\@,;:\\".\[\]]+)\s*/, '') ||
87
- line.sub!(/\A([()<>\@,;:\\".\[\]])\s*/, '')
79
+ line.sub!(/\A("(?:[^"\\]+|\\.)*")(\s*)/, '') || # "..."
80
+ line.sub!(/\A(\[(?:[^\]\\]+|\\.)*\])(\s*)/, '') || # [...]
81
+ line.sub!(/\A([^\s()<>\@,;:\\".\[\]]+)(\s*)/, '') ||
82
+ line.sub!(/\A([()<>\@,;:\\".\[\]])(\s*)/, '')
88
83
  )
89
- words.push($1)
84
+ words.push("#{$1}#{$2}")
90
85
  next
91
86
  end
92
87
  raise "Unrecognized line: #{line}"
@@ -98,17 +93,27 @@ module MailAddress
98
93
 
99
94
  def self._find_next(idx, tokens, len)
100
95
  while (idx < len)
101
- c = tokens[idx]
96
+ c = tokens[idx].strip
102
97
  return c if c == ',' || c == ';' || c == '<'
103
98
  idx += 1
104
99
  end
105
100
  ""
106
101
  end
107
102
 
108
- def self._complete (phrase, address, comment)
109
- phrase.length > 0 || comment.length > 0 || address.length > 0 or return nil
110
- new_address = MailAddress::Address.new(phrase.join(' '), address.join(''), comment.join(' '))
111
- phrase.clear; address.clear; comment.clear
103
+ # find next ending parenthesis
104
+ def self._find_next_paren(idx, tokens, len)
105
+ while (idx < len)
106
+ c = tokens[idx].strip
107
+ return idx if c.include?(')')
108
+ idx += 1
109
+ end
110
+ -1
111
+ end
112
+
113
+ def self._complete (phrase, address)
114
+ phrase.length > 0 || address.length > 0 or return nil
115
+ new_address = MailAddress::Address.new(phrase.join('').strip, address.join(''))
116
+ phrase.clear; address.clear
112
117
  new_address
113
118
  end
114
119
 
@@ -1,3 +1,3 @@
1
1
  module MailAddress
2
- VERSION = "0.1.0"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -4,14 +4,163 @@ require 'pp'
4
4
 
5
5
  describe MailAddress do
6
6
 
7
- it "normal case" do
8
- line = "John 'M' Doe <john@example.com> (this is a comment), 大阪 太郎 <osaka@example.jp>"
7
+ it "normal case (commonly used)" do
8
+ # address only
9
+ line = 'johndoe@example.com'
9
10
  results = MailAddress.parse(line)
11
+ expect(results[0].format).to eq('johndoe@example.com')
12
+ expect(results[0].address).to eq('johndoe@example.com')
13
+ expect(results[0].name).to be_nil
14
+ expect(results[0].phrase).to eq("")
15
+ expect(results[0].host).to eq("example.com")
16
+ expect(results[0].user).to eq('johndoe')
17
+
18
+ # <address> only
19
+ line = '<johndoe@example.com>'
20
+ results = MailAddress.parse(line)
21
+ expect(results[0].format).to eq('johndoe@example.com')
22
+ expect(results[0].address).to eq('johndoe@example.com')
23
+ expect(results[0].name).to be_nil
24
+ expect(results[0].phrase).to eq("")
25
+ expect(results[0].host).to eq("example.com")
26
+ expect(results[0].user).to eq('johndoe')
27
+
28
+ # name + <address> (single byte only)
29
+ line = 'John Doe <johndoe@example.com>'
30
+ results = MailAddress.parse(line)
31
+ expect(results[0].format).to eq('John Doe <johndoe@example.com>')
32
+ expect(results[0].address).to eq('johndoe@example.com')
33
+ expect(results[0].name).to eq("John Doe")
34
+ expect(results[0].phrase).to eq("John Doe")
35
+ expect(results[0].host).to eq("example.com")
36
+ expect(results[0].user).to eq('johndoe')
37
+
38
+ # name + <address> (multi byte)
39
+ line = 'ジョン ドゥ <johndoe@example.com>'
40
+ results = MailAddress.parse(line)
41
+ expect(results[0].format).to eq('"ジョン ドゥ" <johndoe@example.com>')
42
+ expect(results[0].address).to eq('johndoe@example.com')
43
+ expect(results[0].name).to eq("ジョン ドゥ")
44
+ expect(results[0].phrase).to eq("ジョン ドゥ")
45
+ expect(results[0].host).to eq("example.com")
46
+ expect(results[0].user).to eq('johndoe')
47
+
48
+ line = 'Amazon.co.jp アソシエイト・プログラム <associates@amazon.co.jp>'
49
+ results = MailAddress.parse(line)
50
+ expect(results[0].format).to eq('"Amazon.co.jp アソシエイト・プログラム" <associates@amazon.co.jp>')
51
+ expect(results[0].address).to eq('associates@amazon.co.jp')
52
+ expect(results[0].name).to eq("Amazon.co.jp アソシエイト・プログラム")
53
+ expect(results[0].phrase).to eq("Amazon.co.jp アソシエイト・プログラム")
54
+ expect(results[0].host).to eq("amazon.co.jp")
55
+ expect(results[0].user).to eq('associates')
56
+
57
+ # name (includes parens) + <address>
58
+ line = 'Example (Twitterより) <notify@twitter.com>'
59
+ results = MailAddress.parse(line)
60
+ expect(results[0].format).to eq('"Example (Twitterより)" <notify@twitter.com>')
61
+ expect(results[0].address).to eq('notify@twitter.com')
62
+ expect(results[0].name).to eq("Example (Twitterより)")
63
+ expect(results[0].phrase).to eq("Example (Twitterより)")
64
+ expect(results[0].host).to eq("twitter.com")
65
+ expect(results[0].user).to eq('notify')
66
+
67
+ # name + <address> (multi byte) name is quoted
68
+ line = '"ジョン ドゥ" <johndoe@example.com>'
69
+ results = MailAddress.parse(line)
70
+ expect(results[0].format).to eq('"ジョン ドゥ" <johndoe@example.com>')
71
+ expect(results[0].address).to eq('johndoe@example.com')
72
+ expect(results[0].name).to eq("ジョン ドゥ")
73
+ expect(results[0].phrase).to eq('"ジョン ドゥ"')
74
+ expect(results[0].host).to eq("example.com")
75
+ expect(results[0].user).to eq('johndoe')
76
+
77
+ # address + (note)
78
+ line = 'johndoe@example.com (John Doe)'
79
+ results = MailAddress.parse(line)
80
+ expect(results[0].format).to eq('johndoe@example.com (John Doe)')
81
+ expect(results[0].address).to eq('johndoe@example.com')
82
+ expect(results[0].name).to eq("John Doe")
83
+ expect(results[0].phrase).to eq("(John Doe)")
84
+ expect(results[0].host).to eq("example.com")
85
+ expect(results[0].user).to eq('johndoe')
86
+
87
+ # address + (note) # nested paren
88
+ line = 'johndoe@example.com (John (Mid) Doe)'
89
+ results = MailAddress.parse(line)
90
+ expect(results[0].format).to eq('johndoe@example.com (John (Mid) Doe)')
91
+ expect(results[0].address).to eq('johndoe@example.com')
92
+ expect(results[0].name).to eq("John (Mid) Doe")
93
+ expect(results[0].phrase).to eq("(John (Mid) Doe)")
94
+ expect(results[0].host).to eq("example.com")
95
+ expect(results[0].user).to eq('johndoe')
10
96
 
11
- expect(results[0].format).to eq("John 'M' Doe <john@example.com> (this is a comment)")
97
+ # address + (note) # note has special char
98
+ line = 'johndoe@example.com (John@Doe)'
99
+ results = MailAddress.parse(line)
100
+ expect(results[0].format).to eq('johndoe@example.com (John@Doe)')
101
+ expect(results[0].address).to eq('johndoe@example.com')
102
+ expect(results[0].name).to eq("John@Doe")
103
+ expect(results[0].phrase).to eq("(John@Doe)")
104
+ expect(results[0].host).to eq("example.com")
105
+ expect(results[0].user).to eq('johndoe')
106
+
107
+ line = 'johndoe@example.com (John, Doe)'
108
+ results = MailAddress.parse(line)
109
+ expect(results[0].format).to eq('johndoe@example.com (John, Doe)')
110
+ expect(results[0].address).to eq('johndoe@example.com')
111
+ expect(results[0].name).to eq("John, Doe")
112
+ expect(results[0].phrase).to eq("(John, Doe)")
113
+ expect(results[0].host).to eq("example.com")
114
+ expect(results[0].user).to eq('johndoe')
115
+
116
+ # name + <address> + (note)
117
+ line = 'John Doe <johndoe@example.com> (Extra)'
118
+ results = MailAddress.parse(line)
119
+ expect(results[0].format).to eq('"John Doe (Extra)" <johndoe@example.com>')
120
+ expect(results[0].address).to eq('johndoe@example.com')
121
+ expect(results[0].name).to eq("John Doe (Extra)")
122
+ expect(results[0].phrase).to eq("John Doe (Extra)")
123
+ expect(results[0].host).to eq("example.com")
124
+ expect(results[0].user).to eq('johndoe')
125
+
126
+ # name + <address> (name has starting paren but doesn't have ending paren)
127
+ line = 'John(Doe <johndoe@example.com>'
128
+ results = MailAddress.parse(line)
129
+ expect(results[0].format).to eq('"John(Doe" <johndoe@example.com>')
130
+ expect(results[0].address).to eq('johndoe@example.com')
131
+ expect(results[0].name).to eq("John(Doe")
132
+ expect(results[0].phrase).to eq("John(Doe")
133
+ expect(results[0].host).to eq("example.com")
134
+ expect(results[0].user).to eq('johndoe')
135
+
136
+ # ditto
137
+ line = 'John ( Doe <johndoe@example.com>'
138
+ results = MailAddress.parse(line)
139
+ expect(results[0].format).to eq('"John ( Doe" <johndoe@example.com>')
140
+ expect(results[0].address).to eq('johndoe@example.com')
141
+ expect(results[0].name).to eq("John ( Doe")
142
+ expect(results[0].phrase).to eq("John ( Doe")
143
+ expect(results[0].host).to eq("example.com")
144
+ expect(results[0].user).to eq('johndoe')
145
+
146
+ # "address1" <address2>
147
+ line = '"michael@example.jp" <johndoe@example.com>'
148
+ results = MailAddress.parse(line)
149
+ expect(results[0].format).to eq('"michael@example.jp" <johndoe@example.com>')
150
+ expect(results[0].address).to eq('johndoe@example.com')
151
+ expect(results[0].name).to eq("michael@example.jp")
152
+ expect(results[0].phrase).to eq('"michael@example.jp"')
153
+ expect(results[0].host).to eq("example.com")
154
+ expect(results[0].user).to eq('johndoe')
155
+ end
156
+
157
+ it "normal case (multiple address)" do
158
+ line = "John 'M' Doe <john@example.com>, 大阪 太郎 <osaka@example.jp>"
159
+ results = MailAddress.parse(line)
160
+
161
+ expect(results[0].format).to eq("John 'M' Doe <john@example.com>")
12
162
  expect(results[0].address).to eq("john@example.com")
13
163
  expect(results[0].name).to eq("John 'M' Doe")
14
- expect(results[0].comment).to eq("(this is a comment)")
15
164
  expect(results[0].phrase).to eq("John 'M' Doe")
16
165
  expect(results[0].host).to eq("example.com")
17
166
  expect(results[0].user).to eq("john")
@@ -19,23 +168,44 @@ describe MailAddress do
19
168
  # Perl module Mail::Address returns '大阪 太郎 <osaka@example.jp>' (no double quote)
20
169
  # because regular expression \w matches even multibyte characters.
21
170
  expect(results[1].format).to eq("\"大阪 太郎\" <osaka@example.jp>")
22
-
23
171
  expect(results[1].address).to eq("osaka@example.jp")
24
172
  expect(results[1].name).to eq("大阪 太郎")
25
- expect(results[1].comment).to eq("")
26
173
  expect(results[1].phrase).to eq("大阪 太郎")
27
174
  expect(results[1].host).to eq("example.jp")
28
175
  expect(results[1].user).to eq("osaka")
29
176
  end
30
177
 
31
- it "unparsable with mail gem (includes '[')" do
178
+ it "normal case (rfc-violated(RFC822) but commonly used in AU/DoCoMo)" do
179
+ # dot before @
180
+ line = 'John Doe <"johndoe."@example.com>'
181
+ results = MailAddress.parse(line)
182
+
183
+ expect(results[0].format).to eq('John Doe <"johndoe."@example.com>')
184
+ expect(results[0].address).to eq('"johndoe."@example.com')
185
+ expect(results[0].name).to eq("John Doe")
186
+ expect(results[0].phrase).to eq("John Doe")
187
+ expect(results[0].host).to eq("example.com")
188
+ expect(results[0].user).to eq('"johndoe."')
189
+
190
+ # contains '..'
191
+ line = 'John Doe <"john..doe"@example.com>'
192
+ results = MailAddress.parse(line)
193
+
194
+ expect(results[0].format).to eq('John Doe <"john..doe"@example.com>')
195
+ expect(results[0].address).to eq('"john..doe"@example.com')
196
+ expect(results[0].name).to eq("John Doe")
197
+ expect(results[0].phrase).to eq("John Doe")
198
+ expect(results[0].host).to eq("example.com")
199
+ expect(results[0].user).to eq('"john..doe"')
200
+ end
201
+
202
+ it "unparsable with mail gem (includes non-permitted char'[')" do
32
203
  line = "Ello [Do Not Reply] <do-not-reply@ello.co>"
33
204
  results = MailAddress.parse(line)
34
205
  expect(results[0].format).to eq("\"Ello [Do Not Reply]\" <do-not-reply@ello.co>")
35
206
  expect(results[0].address).to eq("do-not-reply@ello.co")
36
207
  expect(results[0].name).to eq("Ello")
37
208
  expect(results[0].phrase).to eq("Ello [Do Not Reply]")
38
- expect(results[0].comment).to eq("")
39
209
  expect(results[0].host).to eq("ello.co")
40
210
  expect(results[0].user).to eq("do-not-reply")
41
211
  end
@@ -46,98 +216,164 @@ describe MailAddress do
46
216
  expect(results[0].format).to eq("\"大阪 太郎\" <osaka@example.jp>")
47
217
  expect(results[0].address).to eq("osaka@example.jp")
48
218
  expect(results[0].name).to eq("大阪 太郎")
49
- expect(results[0].comment).to eq("")
50
219
  expect(results[0].phrase).to eq("大阪 太郎")
51
220
  expect(results[0].host).to eq("example.jp")
52
221
  expect(results[0].user).to eq("osaka")
53
222
  end
54
223
 
55
- it "unparsable with mail gem (???)" do
56
- line = "大阪 太郎(ABC XYZ) <osaka@example.com>"
224
+ it "local part only" do
225
+ # if local part only, do not treat as an email address
226
+ line = "localpartonly"
57
227
  results = MailAddress.parse(line)
58
- expect(results[0].format).to eq("\"大阪 太郎\" <osaka@example.com> (ABC XYZ)")
59
- expect(results[0].address).to eq("osaka@example.com")
60
- expect(results[0].name).to eq("大阪 太郎")
61
- expect(results[0].comment).to eq("(ABC XYZ)")
62
- expect(results[0].phrase).to eq("大阪 太郎")
63
- expect(results[0].host).to eq("example.com")
64
- expect(results[0].user).to eq("osaka")
228
+ expect(results[0].format).to eq("localpartonly")
229
+ expect(results[0].address).to be_nil
230
+ expect(results[0].name).to eq("localpartonly")
231
+ expect(results[0].phrase).to eq("localpartonly")
232
+ expect(results[0].host).to be_nil
233
+ expect(results[0].user).to eq("")
234
+ end
235
+
236
+ it "a lot of types of undisclosed recipients" do
237
+ array = [
238
+ 'undisclosed-recipients: ;',
239
+ 'undisclosed-recipients:;',
240
+ 'undisclosed recipients: ;',
241
+ 'Undisclosed recipients: ;',
242
+ 'Undisclosed recipients:;',
243
+ 'Undisclosed-recipients: ;',
244
+ 'Undisclosed-recipients:;',
245
+ ]
246
+
247
+ array.each do |line|
248
+ results = MailAddress.parse(line)
249
+ expect(results[0].format).to eq(%Q("#{line}"))
250
+ expect(results[0].address).to be_nil
251
+ expect(results[0].name).to eq(line)
252
+ expect(results[0].phrase).to eq(line)
253
+ expect(results[0].host).to be_nil
254
+ expect(results[0].user).to eq("")
255
+ end
256
+
257
+ array = [
258
+ '<"Undisclosed-Recipient:;"@587.jah.ne.jp>',
259
+ '<"Undisclosed-Recipient:"@nifty.com;>',
260
+ ]
261
+
262
+ array.each do |line|
263
+ results = MailAddress.parse(line)
264
+ expect(results[0].format).to eq(line)
265
+ expect(results[0].address).to be_nil
266
+ expect(results[0].name).to eq(line)
267
+ expect(results[0].phrase).to eq(line)
268
+ expect(results[0].host).to be_nil
269
+ expect(results[0].user).to eq("")
270
+ end
271
+
272
+ # valid address
273
+ line = '"Undisclosed" <"recipients:"@nifty.com>'
274
+ results = MailAddress.parse(line)
275
+ expect(results[0].format).to eq(line)
276
+ expect(results[0].address).to eq('"recipients:"@nifty.com')
277
+ expect(results[0].name).to eq("Undisclosed")
278
+ expect(results[0].phrase).to eq('"Undisclosed"')
279
+ expect(results[0].host).to eq("nifty.com")
280
+ expect(results[0].user).to eq('"recipients:"')
65
281
  end
66
282
 
67
- it "unparsable with mail gem (???)" do
68
- line = "大阪 太郎 <osaka@example.jp> (日本)"
283
+ it "specify mime-encoded address" do
284
+ line = "=?ISO-2022-JP?B?GyRCQmc6ZRsoQiAbJEJCQE86GyhC?= <osaka@example.jp>"
69
285
  results = MailAddress.parse(line)
70
- expect(results[0].format).to eq("\"大阪 太郎\" <osaka@example.jp> (日本)")
286
+ expect(results[0].format).to eq("=?ISO-2022-JP?B?GyRCQmc6ZRsoQiAbJEJCQE86GyhC?= <osaka@example.jp>")
71
287
  expect(results[0].address).to eq("osaka@example.jp")
72
- expect(results[0].name).to eq("大阪 太郎")
73
- expect(results[0].comment).to eq("(日本)")
74
- expect(results[0].phrase).to eq("大阪 太郎")
288
+ expect(results[0].name).to be_nil
289
+ expect(results[0].phrase).to eq("=?ISO-2022-JP?B?GyRCQmc6ZRsoQiAbJEJCQE86GyhC?=")
75
290
  expect(results[0].host).to eq("example.jp")
76
291
  expect(results[0].user).to eq("osaka")
77
292
  end
78
293
 
79
- it "no address" do
80
- line = "localpartonly"
81
- results = MailAddress.parse(line)
82
- expect(results[0].format).to eq("localpartonly")
83
- expect(results[0].address).to eq("localpartonly")
84
- expect(results[0].name).to be_nil
85
- expect(results[0].comment).to eq("")
86
- expect(results[0].phrase).to eq("")
87
- expect(results[0].host).to be_nil
88
- expect(results[0].user).to eq("localpartonly")
294
+ it "obviously invalid address (has no '@')" do
295
+ array = [
296
+ 'recipient list not shown: ;',
297
+ '各位:;'
298
+ ]
299
+
300
+ array.each do |line|
301
+ results = MailAddress.parse(line)
302
+ expect(results[0].format).to eq(%Q("#{line}"))
303
+ expect(results[0].address).to be_nil
304
+ expect(results[0].name).to eq(line)
305
+ expect(results[0].phrase).to eq(line)
306
+ expect(results[0].host).to be_nil
307
+ expect(results[0].user).to eq("")
308
+ end
309
+
310
+ end
311
+
312
+
313
+ it "corrupted address" do
314
+ line = 'john <john@example.com' # lack of right angle bracket
315
+ expect {
316
+ results = MailAddress.parse(line)
317
+ }.to raise_error(StandardError)
318
+
319
+ line = 'john <john@example.com> (last' # lack of right parenthesis
320
+ expect {
321
+ results = MailAddress.parse(line)
322
+ }.to raise_error(StandardError)
89
323
  end
90
324
 
91
325
  it 'Perl Module Pod test data' do
92
326
  data = [
93
- [ '"Joe & J. Harvey" <ddd @Org>, JJV @ BBN',
94
- '"Joe & J. Harvey" <ddd@Org>',
95
- 'Joe & J. Harvey'],
96
- [ '"Joe & J. Harvey" <ddd @Org>',
97
- '"Joe & J. Harvey" <ddd@Org>',
98
- 'Joe & J. Harvey'],
99
- [ 'JJV @ BBN',
100
- 'JJV@BBN',
101
- ''],
102
- [ '"spickett@tiac.net" <Sean.Pickett@zork.tiac.net>',
103
- '"spickett@tiac.net" <Sean.Pickett@zork.tiac.net>',
104
- 'Spickett@Tiac.Net'],
105
- [ 'rls@intgp8.ih.att.com (-Schieve,R.L.)',
106
- 'rls@intgp8.ih.att.com (-Schieve,R.L.)',
107
- 'R.L. -Schieve'],
108
- [ 'bodg fred@tiuk.ti.com',
109
- 'bodg',
110
- ''],
327
+ # [ '"Joe & J. Harvey" <ddd @Org>, JJV @ BBN',
328
+ # '"Joe & J. Harvey" <ddd@Org>',
329
+ # 'Joe & J. Harvey'],
330
+ # [ '"Joe & J. Harvey" <ddd @Org>',
331
+ # '"Joe & J. Harvey" <ddd@Org>',
332
+ # 'Joe & J. Harvey'],
333
+ # [ 'JJV @ BBN',
334
+ # 'JJV@BBN',
335
+ # ''],
336
+ # [ '"spickett@tiac.net" <Sean.Pickett@zork.tiac.net>',
337
+ # '"spickett@tiac.net" <Sean.Pickett@zork.tiac.net>',
338
+ # 'Spickett@Tiac.Net'],
339
+ # [ 'rls@intgp8.ih.att.com (-Schieve,R.L.)',
340
+ # 'rls@intgp8.ih.att.com (-Schieve,R.L.)',
341
+ # 'R.L. -Schieve'],
342
+
343
+ # [ 'bodg fred@tiuk.ti.com', #### doesn't support this type of email address
344
+ # 'bodg',
345
+ # ''],
346
+
111
347
  [ 'm-sterni@mars.dsv.su.se',
112
348
  'm-sterni@mars.dsv.su.se',
113
349
  ''],
114
- [ 'jrh%cup.portal.com@portal.unix.portal.com',
115
- 'jrh%cup.portal.com@portal.unix.portal.com',
116
- 'Cup Portal Com'],
117
- [ "astrachan@austlcm.sps.mot.com ('paul astrachan/xvt3')",
118
- "astrachan@austlcm.sps.mot.com ('paul astrachan/xvt3')",
119
- 'Paul Astrachan/Xvt3'],
120
- [ 'TWINE57%SDELVB.decnet@SNYBUFVA.CS.SNYBUF.EDU (JAMES R. TWINE - THE NERD)',
121
- 'TWINE57%SDELVB.decnet@SNYBUFVA.CS.SNYBUF.EDU (JAMES R. TWINE - THE NERD)',
122
- 'James R. Twine - The Nerd'],
350
+ # [ 'jrh%cup.portal.com@portal.unix.portal.com',
351
+ # 'jrh%cup.portal.com@portal.unix.portal.com',
352
+ # 'Cup Portal Com'],
353
+ # [ "astrachan@austlcm.sps.mot.com ('paul astrachan/xvt3')",
354
+ # "astrachan@austlcm.sps.mot.com ('paul astrachan/xvt3')",
355
+ # 'Paul Astrachan/Xvt3'],
356
+ # [ 'TWINE57%SDELVB.decnet@SNYBUFVA.CS.SNYBUF.EDU (JAMES R. TWINE - THE NERD)',
357
+ # 'TWINE57%SDELVB.decnet@SNYBUFVA.CS.SNYBUF.EDU (JAMES R. TWINE - THE NERD)',
358
+ # 'James R. Twine - The Nerd'],
123
359
  [ 'David Apfelbaum <da0g+@andrew.cmu.edu>',
124
360
  'David Apfelbaum <da0g+@andrew.cmu.edu>',
125
361
  'David Apfelbaum'],
126
- [ '"JAMES R. TWINE - THE NERD" <TWINE57%SDELVB%SNYDELVA.bitnet@CUNYVM.CUNY.EDU>',
127
- '"JAMES R. TWINE - THE NERD" <TWINE57%SDELVB%SNYDELVA.bitnet@CUNYVM.CUNY.EDU>',
128
- 'James R. Twine - The Nerd'],
362
+ # [ '"JAMES R. TWINE - THE NERD" <TWINE57%SDELVB%SNYDELVA.bitnet@CUNYVM.CUNY.EDU>',
363
+ # '"JAMES R. TWINE - THE NERD" <TWINE57%SDELVB%SNYDELVA.bitnet@CUNYVM.CUNY.EDU>',
364
+ # 'James R. Twine - The Nerd'],
129
365
  [ 'bilsby@signal.dra (Fred C. M. Bilsby)',
130
366
  'bilsby@signal.dra (Fred C. M. Bilsby)',
131
367
  'Fred C. M. Bilsby'],
132
- [ '/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/@mhs-relay.ac.uk',
133
- '/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/@mhs-relay.ac.uk',
134
- 'Owen Smith'],
368
+ # [ '/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/@mhs-relay.ac.uk', ### not supported
369
+ # '/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/@mhs-relay.ac.uk',
370
+ # 'Owen Smith'],
135
371
  [ 'apardon@rc1.vub.ac.be (Antoon Pardon)',
136
372
  'apardon@rc1.vub.ac.be (Antoon Pardon)',
137
373
  'Antoon Pardon'],
138
- ['"Stephen Burke, Liverpool" <BURKE@vxdsya.desy.de>',
139
- '"Stephen Burke, Liverpool" <BURKE@vxdsya.desy.de>',
140
- 'Stephen Burke'],
374
+ # ['"Stephen Burke, Liverpool" <BURKE@vxdsya.desy.de>',
375
+ # '"Stephen Burke, Liverpool" <BURKE@vxdsya.desy.de>',
376
+ # 'Stephen Burke'],
141
377
  ['Andy Duplain <duplain@btcs.bt.co.uk>',
142
378
  'Andy Duplain <duplain@btcs.bt.co.uk>',
143
379
  'Andy Duplain'],
@@ -159,39 +395,39 @@ describe MailAddress do
159
395
  ['ftpmail-adm@info2.rus.uni-stuttgart.de',
160
396
  'ftpmail-adm@info2.rus.uni-stuttgart.de',
161
397
  ''],
162
- ['Paul Manser (0032 memo) <a906187@tiuk.ti.com>',
163
- 'Paul Manser <a906187@tiuk.ti.com> (0032 memo)',
164
- 'Paul Manser'],
165
- ['"gregg (g.) woodcock" <woodcock@bnr.ca>',
166
- '"gregg (g.) woodcock" <woodcock@bnr.ca>',
167
- 'Gregg Woodcock'],
398
+ # ['Paul Manser (0032 memo) <a906187@tiuk.ti.com>',
399
+ # 'Paul Manser <a906187@tiuk.ti.com> (0032 memo)',
400
+ # 'Paul Manser'],
401
+ # ['"gregg (g.) woodcock" <woodcock@bnr.ca>',
402
+ # '"gregg (g.) woodcock" <woodcock@bnr.ca>',
403
+ # 'Gregg Woodcock'],
168
404
  ['Clive Bittlestone <clyvb@asic.sc.ti.com>',
169
405
  'Clive Bittlestone <clyvb@asic.sc.ti.com>',
170
406
  'Clive Bittlestone'],
171
407
  ['Graham.Barr@tiuk.ti.com',
172
408
  'Graham.Barr@tiuk.ti.com',
173
409
  'Graham Barr'],
174
- ['"Graham Bisset, UK Net Support, +44 224 728109" <GRAHAM@dyce.wireline.slb.com.ti.com.>',
175
- '"Graham Bisset, UK Net Support, +44 224 728109" <GRAHAM@dyce.wireline.slb.com.ti.com.>',
176
- 'Graham Bisset'],
177
- ['a909937 (Graham Barr (0004 bodg))',
178
- 'a909937 (Graham Barr (0004 bodg))',
179
- 'Graham Barr'],
180
- ['a909062@node_cb83.node_cb83 (Colin x Maytum (0013 bro5))',
181
- 'a909062@node_cb83.node_cb83 (Colin x Maytum (0013 bro5))',
182
- 'Colin x Maytum'],
183
- ['a909062@node_cb83.node_cb83 (Colin Maytum (0013 bro5))',
184
- 'a909062@node_cb83.node_cb83 (Colin Maytum (0013 bro5))',
185
- 'Colin Maytum'],
410
+ # ['"Graham Bisset, UK Net Support, +44 224 728109" <GRAHAM@dyce.wireline.slb.com.ti.com.>',
411
+ # '"Graham Bisset, UK Net Support, +44 224 728109" <GRAHAM@dyce.wireline.slb.com.ti.com.>',
412
+ # 'Graham Bisset'],
413
+ # ['a909937 (Graham Barr (0004 bodg))',
414
+ # 'a909937 (Graham Barr (0004 bodg))',
415
+ # 'Graham Barr'],
416
+ # ['a909062@node_cb83.node_cb83 (Colin x Maytum (0013 bro5))',
417
+ # 'a909062@node_cb83.node_cb83 (Colin x Maytum (0013 bro5))',
418
+ # 'Colin x Maytum'],
419
+ # ['a909062@node_cb83.node_cb83 (Colin Maytum (0013 bro5))',
420
+ # 'a909062@node_cb83.node_cb83 (Colin Maytum (0013 bro5))',
421
+ # 'Colin Maytum'],
186
422
  ['Derek.Roskell%dero@msg.ti.com',
187
423
  'Derek.Roskell%dero@msg.ti.com',
188
424
  'Derek Roskell'],
189
425
  ['":sysmail"@ Some-Group. Some-Org, Muhammed.(I am the greatest) Ali @(the)Vegas.WBA',
190
426
  '":sysmail"@Some-Group.Some-Org',
191
427
  ''],
192
- ["david d `zoo' zuhn <zoo@aggregate.com>",
193
- "david d `zoo' zuhn <zoo@aggregate.com>",
194
- "David D `Zoo' Zuhn"],
428
+ # ["david d `zoo' zuhn <zoo@aggregate.com>",
429
+ # "david d `zoo' zuhn <zoo@aggregate.com>",
430
+ # "David D `Zoo' Zuhn"],
195
431
  ['"Christopher S. Arthur" <csa@halcyon.com>',
196
432
  '"Christopher S. Arthur" <csa@halcyon.com>',
197
433
  'Christopher S. Arthur'],
@@ -207,9 +443,9 @@ describe MailAddress do
207
443
  ['hjl@nynexst.com (H.J. Lu)',
208
444
  'hjl@nynexst.com (H.J. Lu)',
209
445
  'H.J. Lu'],
210
- ['@oleane.net:hugues@afp.com a!b@c.d foo!bar!foobar!root',
211
- '@oleane.net:hugues@afp.com',
212
- 'Oleane Net:Hugues'],
446
+ # ['@oleane.net:hugues@afp.com a!b@c.d foo!bar!foobar!root',
447
+ # '@oleane.net:hugues@afp.com',
448
+ # 'Oleane Net:Hugues'],
213
449
  # ['(foo@bar.com (foobar), ned@foo.com (nedfoo) ) <kevin@goess.org>',
214
450
  # 'kevin@goess.org (foo@bar.com (foobar), ned@foo.com (nedfoo) )',
215
451
  # ''],
@@ -228,7 +464,7 @@ describe MailAddress do
228
464
  test_src = d[0]
229
465
  exp_format = d[1]
230
466
  exp_name = d[2]
231
- p "#{i} #{test_src}"
467
+ # p "#{i} #{test_src}"
232
468
  result = MailAddress.parse(test_src)[0]
233
469
 
234
470
  result_format = result.format || ""
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,15 @@
1
+ require 'simplecov'
1
2
  require 'coveralls'
2
3
  Coveralls.wear!
3
4
 
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
+ SimpleCov::Formatter::HTMLFormatter,
7
+ Coveralls::SimpleCov::Formatter
8
+ ]
9
+ SimpleCov.start do
10
+ add_filter '.bundle/'
11
+ end
12
+
4
13
  require 'rubygems'
5
14
  require 'mail_address'
6
15
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mail_address
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kizashi Nagata
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-10 00:00:00.000000000 Z
11
+ date: 2015-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler