email_address 0.1.16 → 0.2.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.
@@ -29,20 +29,22 @@
29
29
  # user.canonical_email #=> "patsmith@gmail.com"
30
30
  ################################################################################
31
31
 
32
- class EmailAddress::CanonicalEmailAddressType < ActiveRecord::Type::Value
32
+ module EmailAddress
33
+ class CanonicalEmailAddressType < ActiveRecord::Type::Value
33
34
 
34
- # From user input, setter
35
- def cast(value)
36
- super(EmailAddress.canonical(value))
37
- end
35
+ # From user input, setter
36
+ def cast(value)
37
+ super(Address.new(value).canonical)
38
+ end
38
39
 
39
- # From a database value
40
- def deserialize(value)
41
- value && EmailAddress.normal(value)
42
- end
40
+ # From a database value
41
+ def deserialize(value)
42
+ value && Address.new(value).normal
43
+ end
43
44
 
44
- # To a database value (string)
45
- def serialize(value)
46
- value && EmailAddress.normal(value)
45
+ # To a database value (string)
46
+ def serialize(value)
47
+ value && Address.new(value).normal
48
+ end
47
49
  end
48
50
  end
@@ -17,6 +17,11 @@ module EmailAddress
17
17
  # the SHA1 Digest, making it unique to your application so it can't easily be
18
18
  # discovered by comparing against a known list of email/sha1 pairs.
19
19
  #
20
+ # * sha256_secret ""
21
+ # This application-level secret is appended to the email_address to compute
22
+ # the SHA256 Digest, making it unique to your application so it can't easily be
23
+ # discovered by comparing against a known list of email/sha256 pairs.
24
+ #
20
25
  # For local part configuration:
21
26
  # * local_downcase: true
22
27
  # Downcase the local part. You probably want this for uniqueness.
@@ -104,6 +109,7 @@ module EmailAddress
104
109
  dns_lookup: :mx, # :mx, :a, :off
105
110
  dns_timeout: nil,
106
111
  sha1_secret: "",
112
+ sha256_secret: "",
107
113
  munge_string: "*****",
108
114
 
109
115
  local_downcase: true,
@@ -143,6 +149,7 @@ module EmailAddress
143
149
  },
144
150
  msn: {
145
151
  host_match: %w[msn. hotmail. outlook. live.],
152
+ exchanger_match: %w[outlook.com],
146
153
  mailbox_validator: ->(m, t) { m =~ /\A\w[\-\w]*(?:\.[\-\w]+)*\z/i }
147
154
  },
148
155
  yahoo: {
@@ -187,9 +194,14 @@ module EmailAddress
187
194
  # Customize your own error message text.
188
195
  def self.error_messages(hash = {}, locale = "en", *extra)
189
196
  hash = extra.first if extra.first.is_a? Hash
190
- unless hash.empty?
197
+
198
+ @errors[locale] ||= {}
199
+ @errors[locale]["email_address"] ||= {}
200
+
201
+ unless hash.nil? || hash.empty?
191
202
  @errors[locale]["email_address"] = @errors[locale]["email_address"].merge(hash)
192
203
  end
204
+
193
205
  @errors[locale]["email_address"]
194
206
  end
195
207
 
@@ -200,7 +212,7 @@ module EmailAddress
200
212
  end
201
213
 
202
214
  def initialize(overrides = {})
203
- @config = EmailAddress::Config.all_settings(overrides)
215
+ @config = Config.all_settings(overrides)
204
216
  end
205
217
 
206
218
  def []=(setting, value)
@@ -29,20 +29,22 @@
29
29
  # user.canonical_email #=> "patsmith@gmail.com"
30
30
  ################################################################################
31
31
 
32
- class EmailAddress::EmailAddressType < ActiveRecord::Type::Value
32
+ module EmailAddress
33
+ class EmailAddressType < ActiveRecord::Type::Value
33
34
 
34
- # From user input, setter
35
- def cast(value)
36
- super(EmailAddress.normal(value))
37
- end
35
+ # From user input, setter
36
+ def cast(value)
37
+ super(Address.new(value).normal)
38
+ end
38
39
 
39
- # From a database value
40
- def deserialize(value)
41
- value && EmailAddress.normal(value)
42
- end
43
- #
44
- # To a database value (string)
45
- def serialize(value)
46
- value && EmailAddress.normal(value)
40
+ # From a database value
41
+ def deserialize(value)
42
+ value && Address.new(value).normal
43
+ end
44
+
45
+ # To a database value (string)
46
+ def serialize(value)
47
+ value && Address.new(value).normal
48
+ end
47
49
  end
48
50
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "resolv"
4
- require "netaddr"
5
4
  require "socket"
6
5
 
7
6
  module EmailAddress
@@ -24,7 +23,7 @@ module EmailAddress
24
23
 
25
24
  def initialize(host, config = {})
26
25
  @host = host
27
- @config = config.is_a?(Hash) ? EmailAddress::Config.new(config) : config
26
+ @config = config.is_a?(Hash) ? Config.new(config) : config
28
27
  @dns_disabled = @config[:host_validation] == :syntax || @config[:dns_lookup] == :off
29
28
  end
30
29
 
@@ -38,7 +37,7 @@ module EmailAddress
38
37
  # Returns the provider name based on the MX-er host names, or nil if not matched
39
38
  def provider
40
39
  return @provider if defined? @provider
41
- EmailAddress::Config.providers.each do |provider, config|
40
+ Config.providers.each do |provider, config|
42
41
  if config[:exchanger_match] && matches?(config[:exchanger_match])
43
42
  return @provider = provider
44
43
  end
@@ -58,8 +57,8 @@ module EmailAddress
58
57
 
59
58
  ress = begin
60
59
  dns.getresources(@host, Resolv::DNS::Resource::IN::MX)
61
- rescue Resolv::ResolvTimeout
62
- []
60
+ rescue Resolv::ResolvTimeout
61
+ []
63
62
  end
64
63
 
65
64
  records = ress.map { |r|
@@ -76,7 +75,7 @@ module EmailAddress
76
75
 
77
76
  # Returns Array of domain names for the MX'ers, used to determine the Provider
78
77
  def domains
79
- @_domains ||= mxers.map { |m| EmailAddress::Host.new(m.first).domain_name }.sort.uniq
78
+ @_domains ||= mxers.map { |m| Host.new(m.first).domain_name }.sort.uniq
80
79
  end
81
80
 
82
81
  # Returns an array of MX IP address (String) for the given email domain
@@ -105,22 +104,9 @@ module EmailAddress
105
104
 
106
105
  # Given a cidr (ip/bits) and ip address, returns true on match. Caches cidr object.
107
106
  def in_cidr?(cidr)
108
- if cidr.include?(":")
109
- c = NetAddr::IPv6Net.parse(cidr)
110
- return true if mx_ips.find do |ip|
111
- next unless ip.include?(":")
112
- rel = c.rel NetAddr::IPv6Net.parse(ip)
113
- !rel.nil? && rel >= 0
114
- end
115
- elsif cidr.include?(".")
116
- c = NetAddr::IPv4Net.parse(cidr)
117
- return true if mx_ips.find do |ip|
118
- next if ip.include?(":")
119
- rel = c.rel NetAddr::IPv4Net.parse(ip)
120
- !rel.nil? && rel >= 0
121
- end
122
- end
123
- false
107
+ net = IPAddr.new(cidr)
108
+ found = mx_ips.detect { |ip| net.include?(IPAddr.new(ip)) }
109
+ !!found
124
110
  end
125
111
  end
126
112
  end
@@ -1,6 +1,5 @@
1
1
  require "simpleidn"
2
2
  require "resolv"
3
- require "netaddr"
4
3
  require "net/smtp"
5
4
 
6
5
  module EmailAddress
@@ -34,15 +33,15 @@ module EmailAddress
34
33
  attr_reader :host_name
35
34
  attr_accessor :dns_name, :domain_name, :registration_name,
36
35
  :tld, :tld2, :subdomains, :ip_address, :config, :provider,
37
- :comment, :error_message, :reason
36
+ :comment, :error_message, :reason, :locale
38
37
  MAX_HOST_LENGTH = 255
39
38
 
40
39
  # Sometimes, you just need a Regexp...
41
- DNS_HOST_REGEX = / [\p{L}\p{N}]+ (?: (?: \-{1,2} | \.) [\p{L}\p{N}]+ )*/x
40
+ DNS_HOST_REGEX = / [\p{L}\p{N}]+ (?: (?: -{1,2} | \.) [\p{L}\p{N}]+ )*/x
42
41
 
43
42
  # The IPv4 and IPv6 were lifted from Resolv::IPv?::Regex and tweaked to not
44
43
  # \A...\z anchor at the edges.
45
- IPv6_HOST_REGEX = /\[IPv6:
44
+ IPV6_HOST_REGEX = /\[IPv6:
46
45
  (?: (?:(?x-mi:
47
46
  (?:[0-9A-Fa-f]{1,4}:){7}
48
47
  [0-9A-Fa-f]{1,4}
@@ -61,7 +60,7 @@ module EmailAddress
61
60
  (?: \d+)\.(?: \d+)\.(?: \d+)\.(?: \d+)
62
61
  )))\]/ix
63
62
 
64
- IPv4_HOST_REGEX = /\[((?x-mi:0
63
+ IPV4_HOST_REGEX = /\[((?x-mi:0
65
64
  |1(?:[0-9][0-9]?)?
66
65
  |2(?:[0-4][0-9]?|5[0-5]?|[6-9])?
67
66
  |[3-9][0-9]?))\.((?x-mi:0
@@ -80,14 +79,15 @@ module EmailAddress
80
79
 
81
80
  # Matches Host forms: DNS name, IPv4, or IPv6 formats
82
81
  STANDARD_HOST_REGEX = /\A (?: #{DNS_HOST_REGEX}
83
- | #{IPv4_HOST_REGEX} | #{IPv6_HOST_REGEX}) \z/ix
82
+ | #{IPV4_HOST_REGEX} | #{IPV6_HOST_REGEX}) \z/ix
84
83
 
85
84
  # host name -
86
85
  # * host type - :email for an email host, :mx for exchanger host
87
- def initialize(host_name, config = {})
86
+ def initialize(host_name, config = {}, locale = "en")
88
87
  @original = host_name ||= ""
88
+ @locale = locale
89
89
  config[:host_type] ||= :email
90
- @config = config.is_a?(Hash) ? EmailAddress::Config.new(config) : config
90
+ @config = config.is_a?(Hash) ? Config.new(config) : config
91
91
  @error = @error_message = nil
92
92
  parse(host_name)
93
93
  end
@@ -104,7 +104,7 @@ module EmailAddress
104
104
  dns_name
105
105
  end
106
106
  end
107
- alias to_s name
107
+ alias_method :to_s, :name
108
108
 
109
109
  # The canonical host name is the simplified, DNS host name
110
110
  def canonical
@@ -149,7 +149,7 @@ module EmailAddress
149
149
  if @config[:host_remove_spaces]
150
150
  @host_name = @host_name.delete(" ")
151
151
  end
152
- @dns_name = if /[^[:ascii:]]/.match(host_name)
152
+ @dns_name = if /[^[:ascii:]]/.match?(host_name)
153
153
  ::SimpleIDN.to_ascii(host_name)
154
154
  else
155
155
  host_name
@@ -209,7 +209,7 @@ module EmailAddress
209
209
  def find_provider # :nodoc:
210
210
  return provider if provider
211
211
 
212
- EmailAddress::Config.providers.each do |provider, config|
212
+ Config.providers.each do |provider, config|
213
213
  if config[:host_match] && matches?(config[:host_match])
214
214
  return set_provider(provider, config)
215
215
  end
@@ -217,12 +217,6 @@ module EmailAddress
217
217
 
218
218
  return set_provider(:default) unless dns_enabled?
219
219
 
220
- provider = exchangers.provider
221
- if provider != :default
222
- set_provider(provider,
223
- EmailAddress::Config.provider(provider))
224
- end
225
-
226
220
  self.provider ||= set_provider(:default)
227
221
  end
228
222
 
@@ -235,7 +229,11 @@ module EmailAddress
235
229
  def parts
236
230
  {host_name: host_name, dns_name: dns_name, subdomain: subdomains,
237
231
  registration_name: registration_name, domain_name: domain_name,
238
- tld2: tld2, tld: tld, ip_address: ip_address,}
232
+ tld2: tld2, tld: tld, ip_address: ip_address}
233
+ end
234
+
235
+ def hosted_provider
236
+ Exchanger.cached(dns_name).provider
239
237
  end
240
238
 
241
239
  ############################################################################
@@ -248,7 +246,7 @@ module EmailAddress
248
246
  end
249
247
 
250
248
  def ip?
251
- ip_address.nil? ? false : true
249
+ !!ip_address
252
250
  end
253
251
 
254
252
  def ipv4?
@@ -292,7 +290,7 @@ module EmailAddress
292
290
  # Does "sub.example.com" match ".com" and ".example.com" top level names?
293
291
  # Matches TLD (uk) or TLD2 (co.uk)
294
292
  def tld_matches?(rule)
295
- rule.match(/\A\.(.+)\z/) && ($1 == tld || $1 == tld2) ? true : false
293
+ rule.match(/\A\.(.+)\z/) && ($1 == tld || $1 == tld2) # ? true : false
296
294
  end
297
295
 
298
296
  def provider_matches?(rule)
@@ -312,13 +310,8 @@ module EmailAddress
312
310
  # the passed CIDR string ("10.9.8.0/24" or "2001:..../64")
313
311
  def ip_matches?(cidr)
314
312
  return false unless ip_address
315
- return cidr if !cidr.include?("/") && cidr == ip_address
316
- if cidr.include?(":") && ip_address.include?(":")
317
- return cidr if NetAddr::IPv6Net.parse(cidr).contains(NetAddr::IPv6.parse(ip_address))
318
- elsif cidr.include?(".") && ip_address.include?(".")
319
- return cidr if NetAddr::IPv4Net.parse(cidr).contains(NetAddr::IPv4.parse(ip_address))
320
- end
321
- false
313
+ net = IPAddr.new(cidr)
314
+ net.include?(IPAddr.new(ip_address))
322
315
  end
323
316
 
324
317
  ############################################################################
@@ -335,16 +328,16 @@ module EmailAddress
335
328
  # Returns: [official_hostname, alias_hostnames, address_family, *address_list]
336
329
  def dns_a_record
337
330
  @_dns_a_record = "0.0.0.0" if @config[:dns_lookup] == :off
338
- @_dns_a_record ||= Socket.gethostbyname(dns_name)
331
+ @_dns_a_record ||= Addrinfo.getaddrinfo(dns_name, 80) # Port 80 for A rec, 25 for MX
339
332
  rescue SocketError # not found, but could also mean network not work
340
333
  @_dns_a_record ||= []
341
334
  end
342
335
 
343
- # Returns an array of EmailAddress::Exchanger hosts configured in DNS.
336
+ # Returns an array of Exchanger hosts configured in DNS.
344
337
  # The array will be empty if none are configured.
345
338
  def exchangers
346
339
  # return nil if @config[:host_type] != :email || !self.dns_enabled?
347
- @_exchangers ||= EmailAddress::Exchanger.cached(dns_name, @config)
340
+ @_exchangers ||= Exchanger.cached(dns_name, @config)
348
341
  end
349
342
 
350
343
  # Returns a DNS TXT Record
@@ -355,8 +348,8 @@ module EmailAddress
355
348
  records = begin
356
349
  dns.getresources(alternate_host || dns_name,
357
350
  Resolv::DNS::Resource::IN::TXT)
358
- rescue Resolv::ResolvTimeout
359
- []
351
+ rescue Resolv::ResolvTimeout
352
+ []
360
353
  end
361
354
 
362
355
  records.empty? ? nil : records.map(&:data).join(" ")
@@ -461,21 +454,9 @@ module EmailAddress
461
454
  end
462
455
 
463
456
  def localhost?
464
- if ip_address
465
- rel =
466
- if ip_address.include?(":")
467
- NetAddr::IPv6Net.parse("" + "::1").rel(
468
- NetAddr::IPv6Net.parse(ip_address)
469
- )
470
- else
471
- NetAddr::IPv4Net.parse("" + "127.0.0.0/8").rel(
472
- NetAddr::IPv4Net.parse(ip_address)
473
- )
474
- end
475
- !rel.nil? && rel >= 0
476
- else
477
- host_name == "localhost"
478
- end
457
+ return true if host_name == "localhost"
458
+ return false unless ip_address
459
+ IPAddr.new(ip_address).loopback?
479
460
  end
480
461
 
481
462
  # Connects to host to test it can receive email. This should NOT be performed
@@ -499,7 +480,7 @@ module EmailAddress
499
480
  def set_error(err, reason = nil)
500
481
  @error = err
501
482
  @reason = reason
502
- @error_message = EmailAddress::Config.error_message(err)
483
+ @error_message = Config.error_message(err, locale)
503
484
  false
504
485
  end
505
486
 
@@ -67,50 +67,51 @@ module EmailAddress
67
67
  # [CFWS]
68
68
  ############################################################################
69
69
  class Local
70
- attr_reader :local
70
+ attr_reader :local
71
71
  attr_accessor :mailbox, :comment, :tag, :config, :original
72
- attr_accessor :syntax
72
+ attr_accessor :syntax, :locale
73
73
 
74
74
  # RFC-2142: MAILBOX NAMES FOR COMMON SERVICES, ROLES AND FUNCTIONS
75
- BUSINESS_MAILBOXES = %w(info marketing sales support)
76
- NETWORK_MAILBOXES = %w(abuse noc security)
77
- SERVICE_MAILBOXES = %w(postmaster hostmaster usenet news webmaster www uucp ftp)
78
- SYSTEM_MAILBOXES = %w(help mailer-daemon root) # Not from RFC-2142
79
- ROLE_MAILBOXES = %w(staff office orders billing careers jobs) # Not from RFC-2142
80
- SPECIAL_MAILBOXES = BUSINESS_MAILBOXES + NETWORK_MAILBOXES + SERVICE_MAILBOXES +
81
- SYSTEM_MAILBOXES + ROLE_MAILBOXES
82
- STANDARD_MAX_SIZE = 64
75
+ BUSINESS_MAILBOXES = %w[info marketing sales support]
76
+ NETWORK_MAILBOXES = %w[abuse noc security]
77
+ SERVICE_MAILBOXES = %w[postmaster hostmaster usenet news webmaster www uucp ftp]
78
+ SYSTEM_MAILBOXES = %w[help mailer-daemon root] # Not from RFC-2142
79
+ ROLE_MAILBOXES = %w[staff office orders billing careers jobs] # Not from RFC-2142
80
+ SPECIAL_MAILBOXES = BUSINESS_MAILBOXES + NETWORK_MAILBOXES + SERVICE_MAILBOXES +
81
+ SYSTEM_MAILBOXES + ROLE_MAILBOXES
82
+ STANDARD_MAX_SIZE = 64
83
83
 
84
84
  # Conventional : word([.-+'_]word)*
85
- CONVENTIONAL_MAILBOX_REGEX = /\A [\p{L}\p{N}_]+ (?: [\.\-\+\'_] [\p{L}\p{N}_]+ )* \z/x
86
- CONVENTIONAL_MAILBOX_WITHIN = /[\p{L}\p{N}_]+ (?: [\.\-\+\'_] [\p{L}\p{N}_]+ )*/x
85
+ CONVENTIONAL_MAILBOX_REGEX = /\A [\p{L}\p{N}_]+ (?: [.\-+'_] [\p{L}\p{N}_]+ )* \z/x
86
+ CONVENTIONAL_MAILBOX_WITHIN = /[\p{L}\p{N}_]+ (?: [.\-+'_] [\p{L}\p{N}_]+ )*/x
87
87
 
88
88
  # Relaxed: same characters, relaxed order
89
- RELAXED_MAILBOX_WITHIN = /[\p{L}\p{N}_]+ (?: [\.\-\+\'_]+ [\p{L}\p{N}_]+ )*/x
90
- RELAXED_MAILBOX_REGEX = /\A [\p{L}\p{N}_]+ (?: [\.\-\+\'_]+ [\p{L}\p{N}_]+ )* \z/x
89
+ RELAXED_MAILBOX_WITHIN = /[\p{L}\p{N}_]+ (?: [.\-+'_]+ [\p{L}\p{N}_]+ )*/x
90
+ RELAXED_MAILBOX_REGEX = /\A [\p{L}\p{N}_]+ (?: [.\-+'_]+ [\p{L}\p{N}_]+ )* \z/x
91
91
 
92
92
  # RFC5322 Token: token."token".token (dot-separated tokens)
93
93
  # Quoted Token can also have: SPACE \" \\ ( ) , : ; < > @ [ \ ] .
94
94
  STANDARD_LOCAL_WITHIN = /
95
- (?: [\p{L}\p{N}\!\#\$\%\&\'\*\+\-\/\=\?\^\_\`\{\|\}\~\(\)]+
96
- | \" (?: \\[\" \\] | [\x20-\x21\x23-\x2F\x3A-\x40\x5B\x5D-\x60\x7B-\x7E\p{L}\p{N}] )+ \" )
97
- (?: \. (?: [\p{L}\p{N}\!\#\$\%\&\'\*\+\-\/\=\?\^\_\`\{\|\}\~\(\)]+
98
- | \" (?: \\[\" \\] | [\x20-\x21\x23-\x2F\x3A-\x40\x5B\x5D-\x60\x7B-\x7E\p{L}\p{N}] )+ \" ) )* /x
95
+ (?: [\p{L}\p{N}!\#$%&'*+\-\/=?\^_`{|}~()]+
96
+ | " (?: \\[" \\] | [\x20-\x21\x23-\x2F\x3A-\x40\x5B\x5D-\x60\x7B-\x7E\p{L}\p{N}] )+ " )
97
+ (?: \. (?: [\p{L}\p{N}!\#$%&'*+\-\/=?\^_`{|}~()]+
98
+ | " (?: \\[" \\] | [\x20-\x21\x23-\x2F\x3A-\x40\x5B\x5D-\x60\x7B-\x7E\p{L}\p{N}] )+ " ) )* /x
99
99
 
100
100
  STANDARD_LOCAL_REGEX = /\A #{STANDARD_LOCAL_WITHIN} \z/x
101
101
 
102
102
  REDACTED_REGEX = /\A \{ [0-9a-f]{40} \} \z/x # {sha1}
103
103
 
104
- CONVENTIONAL_TAG_REGEX = # AZaz09_!'+-/=
105
- %r/^([\w\!\'\+\-\/\=]+)$/i.freeze
106
- RELAXED_TAG_REGEX = # AZaz09_!#$%&'*+-/=?^`{|}~
107
- %r/^([\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+)$/i.freeze
104
+ CONVENTIONAL_TAG_REGEX = # AZaz09_!'+-/=
105
+ %r{^([\w!'+\-/=.]+)$}i
106
+ RELAXED_TAG_REGEX = # AZaz09_!#$%&'*+-/=?^`{|}~
107
+ %r/^([\w.!\#$%&'*+\-\/=?\^`{|}~]+)$/i
108
108
 
109
- def initialize(local, config={}, host=nil)
110
- @config = config.is_a?(Hash) ? EmailAddress::Config.new(config) : config
111
- self.local = local
112
- @host = host
113
- @error = @error_message = nil
109
+ def initialize(local, config = {}, host = nil, locale = "en")
110
+ @config = config.is_a?(Hash) ? Config.new(config) : config
111
+ self.local = local
112
+ @host = host
113
+ @locale = locale
114
+ @error = @error_message = nil
114
115
  end
115
116
 
116
117
  def local=(raw)
@@ -121,23 +122,23 @@ module EmailAddress
121
122
  if @config[:local_parse].is_a?(Proc)
122
123
  self.mailbox, self.tag, self.comment = @config[:local_parse].call(raw)
123
124
  else
124
- self.mailbox, self.tag, self.comment = self.parse(raw)
125
+ self.mailbox, self.tag, self.comment = parse(raw)
125
126
  end
126
127
 
127
128
  self.format
128
129
  end
129
130
 
130
131
  def parse(raw)
131
- if raw =~ /\A\"(.*)\"\z/ # Quoted
132
+ if raw =~ /\A"(.*)"\z/ # Quoted
132
133
  raw = $1
133
134
  raw = raw.gsub(/\\(.)/, '\1') # Unescape
134
135
  elsif @config[:local_fix] && @config[:local_format] != :standard
135
- raw = raw.gsub(' ','')
136
- raw = raw.gsub(',','.')
137
- #raw.gsub!(/([^\p{L}\p{N}]{2,10})/) {|s| s[0] } # Stutter punctuation typo
136
+ raw = raw.delete(" ")
137
+ raw = raw.tr(",", ".")
138
+ # raw.gsub!(/([^\p{L}\p{N}]{2,10})/) {|s| s[0] } # Stutter punctuation typo
138
139
  end
139
- raw, comment = self.parse_comment(raw)
140
- mailbox, tag = self.parse_tag(raw)
140
+ raw, comment = parse_comment(raw)
141
+ mailbox, tag = parse_tag(raw)
141
142
  mailbox ||= ""
142
143
  [mailbox, tag, comment]
143
144
  end
@@ -156,28 +157,28 @@ module EmailAddress
156
157
  end
157
158
 
158
159
  def parse_tag(raw)
159
- separator = @config[:tag_separator] ||= '+'
160
+ separator = @config[:tag_separator] ||= "+"
160
161
  raw.split(separator, 2)
161
162
  end
162
163
 
163
164
  # True if the the value contains only Latin characters (7-bit ASCII)
164
165
  def ascii?
165
- ! self.unicode?
166
+ !unicode?
166
167
  end
167
168
 
168
169
  # True if the the value contains non-Latin Unicde characters
169
170
  def unicode?
170
- self.local =~ /[^\p{InBasicLatin}]/ ? true : false
171
+ /[^\p{InBasicLatin}]/.match?(local)
171
172
  end
172
173
 
173
174
  # Returns true if the value matches the Redacted format
174
175
  def redacted?
175
- self.local =~ REDACTED_REGEX ? true : false
176
+ REDACTED_REGEX.match?(local)
176
177
  end
177
178
 
178
179
  # Returns true if the value matches the Redacted format
179
180
  def self.redacted?(local)
180
- local =~ REDACTED_REGEX ? true : false
181
+ REDACTED_REGEX.match?(local)
181
182
  end
182
183
 
183
184
  # Is the address for a common system or business role account?
@@ -190,81 +191,80 @@ module EmailAddress
190
191
  end
191
192
 
192
193
  # Builds the local string according to configurations
193
- def format(form=@config[:local_format]||:conventional)
194
+ def format(form = @config[:local_format] || :conventional)
194
195
  if @config[:local_format].is_a?(Proc)
195
196
  @config[:local_format].call(self)
196
197
  elsif form == :conventional
197
- self.conventional
198
+ conventional
198
199
  elsif form == :canonical
199
- self.canonical
200
+ canonical
200
201
  elsif form == :relaxed
201
- self.relax
202
+ relax
202
203
  elsif form == :standard
203
- self.standard
204
+ standard
204
205
  end
205
206
  end
206
207
 
207
208
  # Returns a conventional form of the address
208
209
  def conventional
209
- if self.tag
210
- [self.mailbox, self.tag].join(@config[:tag_separator])
210
+ if tag
211
+ [mailbox, tag].join(@config[:tag_separator])
211
212
  else
212
- self.mailbox
213
+ mailbox
213
214
  end
214
215
  end
215
216
 
216
217
  # Returns a canonical form of the address
217
218
  def canonical
218
219
  if @config[:mailbox_canonical]
219
- @config[:mailbox_canonical].call(self.mailbox)
220
+ @config[:mailbox_canonical].call(mailbox)
220
221
  else
221
- self.mailbox.downcase
222
+ mailbox.downcase
222
223
  end
223
224
  end
224
225
 
225
226
  # Relaxed format: mailbox and tag, no comment, no extended character set
226
227
  def relax
227
- form = self.mailbox
228
- form += @config[:tag_separator] + self.tag if self.tag
229
- form = form.gsub(/[ \"\(\),:<>@\[\]\\]/,'')
230
- form
228
+ form = mailbox
229
+ form += @config[:tag_separator] + tag if tag
230
+ form.gsub(/[ "(),:<>@\[\]\\]/, "")
231
231
  end
232
232
 
233
233
  # Returns a normalized version of the standard address parts.
234
234
  def standard
235
- form = self.mailbox
236
- form += @config[:tag_separator] + self.tag if self.tag
237
- form += "(" + self.comment + ")" if self.comment
238
- form = form.gsub(/([\\\"])/, '\\\1') # Escape \ and "
239
- if form =~ /[ \"\(\),:<>@\[\\\]]/ # Space and "(),:;<>@[\]
240
- form = %Q("#{form}")
235
+ form = mailbox
236
+ form += @config[:tag_separator] + tag if tag
237
+ form += "(" + comment + ")" if comment
238
+ form = form.gsub(/([\\"])/, '\\\1') # Escape \ and "
239
+ if /[ "(),:<>@\[\\\]]/.match?(form) # Space and "(),:;<>@[\]
240
+ form = %("#{form}")
241
241
  end
242
242
  form
243
243
  end
244
244
 
245
245
  # Sets the part to be the conventional form
246
246
  def conventional!
247
- self.local = self.conventional
247
+ self.local = conventional
248
248
  end
249
249
 
250
250
  # Sets the part to be the canonical form
251
251
  def canonical!
252
- self.local = self.canonical
252
+ self.local = canonical
253
253
  end
254
254
 
255
255
  # Dropps unusual parts of Standard form to form a relaxed version.
256
256
  def relax!
257
- self.local = self.relax
257
+ self.local = relax
258
258
  end
259
259
 
260
260
  # Returns the munged form of the address, like "ma*****"
261
261
  def munge
262
- self.to_s.sub(/\A(.{1,2}).*/) { |m| $1 + @config[:munge_string] }
262
+ to_s.sub(/\A(.{1,2}).*/) { |m| $1 + @config[:munge_string] }
263
263
  end
264
264
 
265
265
  # Mailbox with trailing numbers removed
266
266
  def root_name
267
- self.mailbox =~ /\A(.+?)\d+\z/ ? $1 : self.mailbox
267
+ mailbox =~ /\A(.+?)\d+\z/ ? $1 : mailbox
268
268
  end
269
269
 
270
270
  ############################################################################
@@ -272,19 +272,19 @@ module EmailAddress
272
272
  ############################################################################
273
273
 
274
274
  # True if the part is valid according to the configurations
275
- def valid?(format=@config[:local_format]||:conventional)
275
+ def valid?(format = @config[:local_format] || :conventional)
276
276
  if @config[:mailbox_validator].is_a?(Proc)
277
- @config[:mailbox_validator].call(self.mailbox, self.tag)
277
+ @config[:mailbox_validator].call(mailbox, tag)
278
278
  elsif format.is_a?(Proc)
279
279
  format.call(self)
280
280
  elsif format == :conventional
281
- self.conventional?
281
+ conventional?
282
282
  elsif format == :relaxed
283
- self.relaxed?
283
+ relaxed?
284
284
  elsif format == :redacted
285
- self.redacted?
285
+ redacted?
286
286
  elsif format == :standard
287
- self.standard?
287
+ standard?
288
288
  elsif format == :none
289
289
  true
290
290
  else
@@ -295,13 +295,13 @@ module EmailAddress
295
295
  # Returns the format of the address
296
296
  def format?
297
297
  # if :custom
298
- if self.conventional?
298
+ if conventional?
299
299
  :conventional
300
- elsif self.relaxed?
300
+ elsif relaxed?
301
301
  :relax
302
- elsif self.redacted?
302
+ elsif redacted?
303
303
  :redacted
304
- elsif self.standard?
304
+ elsif standard?
305
305
  :standard
306
306
  else
307
307
  :invalid
@@ -309,38 +309,38 @@ module EmailAddress
309
309
  end
310
310
 
311
311
  def valid_size?
312
- return set_error(:local_size_long) if self.local.size > STANDARD_MAX_SIZE
313
- if @host && @host.hosted_service?
312
+ return set_error(:local_size_long) if local.size > STANDARD_MAX_SIZE
313
+ if @host&.hosted_service?
314
314
  return false if @config[:local_private_size] && !valid_size_checks(@config[:local_private_size])
315
- else
316
- return false if @config[:local_size] && !valid_size_checks(@config[:local_size])
315
+ elsif @config[:local_size] && !valid_size_checks(@config[:local_size])
316
+ return false
317
317
  end
318
318
  return false if @config[:mailbox_size] && !valid_size_checks(@config[:mailbox_size])
319
319
  true
320
320
  end
321
321
 
322
322
  def valid_size_checks(range)
323
- return set_error(:local_size_short) if self.mailbox.size < range.first
324
- return set_error(:local_size_long) if self.mailbox.size > range.last
323
+ return set_error(:local_size_short) if mailbox.size < range.first
324
+ return set_error(:local_size_long) if mailbox.size > range.last
325
325
  true
326
326
  end
327
327
 
328
- def valid_encoding?(enc=@config[:local_encoding]||:ascii)
329
- return false if enc == :ascii && self.unicode?
328
+ def valid_encoding?(enc = @config[:local_encoding] || :ascii)
329
+ return false if enc == :ascii && unicode?
330
330
  true
331
331
  end
332
332
 
333
333
  # True if the part matches the conventional format
334
334
  def conventional?
335
335
  self.syntax = :invalid
336
- if self.tag
337
- return false unless self.mailbox =~ CONVENTIONAL_MAILBOX_REGEX &&
338
- self.tag =~ CONVENTIONAL_TAG_REGEX
336
+ if tag
337
+ return false unless mailbox =~ CONVENTIONAL_MAILBOX_REGEX &&
338
+ tag =~ CONVENTIONAL_TAG_REGEX
339
339
  else
340
- return false unless self.local =~ CONVENTIONAL_MAILBOX_REGEX
340
+ return false unless CONVENTIONAL_MAILBOX_REGEX.match?(local)
341
341
  end
342
- self.valid_size? or return false
343
- self.valid_encoding? or return false
342
+ valid_size? or return false
343
+ valid_encoding? or return false
344
344
  self.syntax = :conventional
345
345
  true
346
346
  end
@@ -348,12 +348,12 @@ module EmailAddress
348
348
  # Relaxed conventional is not so strict about character order.
349
349
  def relaxed?
350
350
  self.syntax = :invalid
351
- self.valid_size? or return false
352
- self.valid_encoding? or return false
353
- if self.tag
354
- return false unless self.mailbox =~ RELAXED_MAILBOX_REGEX &&
355
- self.tag =~ RELAXED_TAG_REGEX
356
- elsif self.local =~ RELAXED_MAILBOX_REGEX
351
+ valid_size? or return false
352
+ valid_encoding? or return false
353
+ if tag
354
+ return false unless mailbox =~ RELAXED_MAILBOX_REGEX &&
355
+ tag =~ RELAXED_TAG_REGEX
356
+ elsif RELAXED_MAILBOX_REGEX.match?(local)
357
357
  self.syntax = :relaxed
358
358
  true
359
359
  else
@@ -364,9 +364,9 @@ module EmailAddress
364
364
  # True if the part matches the RFC standard format
365
365
  def standard?
366
366
  self.syntax = :invalid
367
- self.valid_size? or return false
368
- self.valid_encoding? or return false
369
- if self.local =~ STANDARD_LOCAL_REGEX
367
+ valid_size? or return false
368
+ valid_encoding? or return false
369
+ if STANDARD_LOCAL_REGEX.match?(local)
370
370
  self.syntax = :standard
371
371
  true
372
372
  else
@@ -379,26 +379,23 @@ module EmailAddress
379
379
  def matches?(*rules)
380
380
  rules.flatten.each do |r|
381
381
  if r =~ /(.+)@\z/
382
- return r if File.fnmatch?($1, self.local)
382
+ return r if File.fnmatch?($1, local)
383
383
  end
384
384
  end
385
385
  false
386
386
  end
387
387
 
388
- def set_error(err, reason=nil)
388
+ def set_error(err, reason = nil)
389
389
  @error = err
390
- @reason= reason
391
- @error_message = EmailAddress::Config.error_message(err)
390
+ @reason = reason
391
+ @error_message = Config.error_message(err, locale)
392
392
  false
393
393
  end
394
394
 
395
- def error_message
396
- @error_message
397
- end
395
+ attr_reader :error_message
398
396
 
399
397
  def error
400
- self.valid? ? nil : ( @error || :local_invalid)
398
+ valid? ? nil : (@error || :local_invalid)
401
399
  end
402
-
403
400
  end
404
401
  end