class EmailAddress::Local

EmailAddress Local part consists of

Constants

BUSINESS_MAILBOXES

RFC-2142: MAILBOX NAMES FOR COMMON SERVICES, ROLES AND FUNCTIONS

CONVENTIONAL_MAILBOX_REGEX

Conventional : word(word)*

CONVENTIONAL_MAILBOX_WITHIN
CONVENTIONAL_TAG_REGEX
NETWORK_MAILBOXES
REDACTED_REGEX
RELAXED_MAILBOX_REGEX
RELAXED_MAILBOX_WITHIN

Relaxed: same characters, relaxed order

RELAXED_TAG_REGEX
ROLE_MAILBOXES
SERVICE_MAILBOXES
SPECIAL_MAILBOXES
STANDARD_LOCAL_REGEX
STANDARD_LOCAL_WITHIN

RFC5322 Token: token.“token”.token (dot-separated tokens)

Quoted Token can also have: SPACE \" \\ ( ) , : ; < > @ [ \ ] .
STANDARD_MAX_SIZE
SYSTEM_MAILBOXES

Attributes

comment[RW]
config[RW]
error_message[R]
local[R]
locale[RW]
mailbox[RW]
original[RW]
syntax[RW]
tag[RW]

Public Class Methods

new(local, config = {}, host = nil, locale = "en") click to toggle source
# File lib/email_address/local.rb, line 109
def initialize(local, config = {}, host = nil, locale = "en")
  @config = config.is_a?(Hash) ? Config.new(config) : config
  self.local = local
  @host = host
  @locale = locale
  @error = @error_message = nil
end
redacted?(local) click to toggle source

Returns true if the value matches the Redacted format

# File lib/email_address/local.rb, line 180
def self.redacted?(local)
  REDACTED_REGEX.match?(local)
end

Public Instance Methods

ascii?() click to toggle source

True if the the value contains only Latin characters (7-bit ASCII)

# File lib/email_address/local.rb, line 165
def ascii?
  !unicode?
end
canonical() click to toggle source

Returns a canonical form of the address

# File lib/email_address/local.rb, line 218
def canonical
  if @config[:mailbox_canonical]
    @config[:mailbox_canonical].call(mailbox)
  else
    mailbox.downcase
  end
end
canonical!() click to toggle source

Sets the part to be the canonical form

# File lib/email_address/local.rb, line 251
def canonical!
  self.local = canonical
end
conventional() click to toggle source

Returns a conventional form of the address

# File lib/email_address/local.rb, line 209
def conventional
  if tag
    [mailbox, tag].join(@config[:tag_separator])
  else
    mailbox
  end
end
conventional!() click to toggle source

Sets the part to be the conventional form

# File lib/email_address/local.rb, line 246
def conventional!
  self.local = conventional
end
conventional?() click to toggle source

True if the part matches the conventional format

# File lib/email_address/local.rb, line 334
def conventional?
  self.syntax = :invalid
  if tag
    return false unless mailbox =~ CONVENTIONAL_MAILBOX_REGEX &&
      tag =~ CONVENTIONAL_TAG_REGEX
  else
    return false unless CONVENTIONAL_MAILBOX_REGEX.match?(local)
  end
  valid_size? or return false
  valid_encoding? or return false
  self.syntax = :conventional
  true
end
error() click to toggle source
# File lib/email_address/local.rb, line 399
def error
  valid? ? nil : (@error || :local_invalid)
end
format(form = @config[:local_format] || :conventional) click to toggle source

Builds the local string according to configurations

# File lib/email_address/local.rb, line 194
def format(form = @config[:local_format] || :conventional)
  if @config[:local_format].is_a?(Proc)
    @config[:local_format].call(self)
  elsif form == :conventional
    conventional
  elsif form == :canonical
    canonical
  elsif form == :relaxed
    relax
  elsif form == :standard
    standard
  end
end
format?() click to toggle source

Returns the format of the address

# File lib/email_address/local.rb, line 296
def format?
  # if :custom
  if conventional?
    :conventional
  elsif relaxed?
    :relax
  elsif redacted?
    :redacted
  elsif standard?
    :standard
  else
    :invalid
  end
end
local=(raw) click to toggle source
# File lib/email_address/local.rb, line 117
def local=(raw)
  self.original = raw
  raw.downcase! if @config[:local_downcase].nil? || @config[:local_downcase]
  @local = raw

  if @config[:local_parse].is_a?(Proc)
    self.mailbox, self.tag, self.comment = @config[:local_parse].call(raw)
  else
    self.mailbox, self.tag, self.comment = parse(raw)
  end

  self.format
end
matches?(*rules) click to toggle source

Matches configured formated form against File glob strings given. Rules must end in @ to distinguish themselves from other email part matches.

# File lib/email_address/local.rb, line 381
def matches?(*rules)
  rules.flatten.each do |r|
    if r =~ /(.+)@\z/
      return r if File.fnmatch?($1, local)
    end
  end
  false
end
munge() click to toggle source

Returns the munged form of the address, like “ma*****”

# File lib/email_address/local.rb, line 261
def munge
  to_s.sub(/\A(.{1,2}).*/) { |m| $1 + @config[:munge_string] }
end
parse(raw) click to toggle source
# File lib/email_address/local.rb, line 131
def parse(raw)
  if raw =~ /\A"(.*)"\z/ # Quoted
    raw = $1
    raw = raw.gsub(/\\(.)/, '\1') # Unescape
  elsif @config[:local_fix] && @config[:local_format] != :standard
    raw = raw.delete(" ")
    raw = raw.tr(",", ".")
    # raw.gsub!(/([^\p{L}\p{N}]{2,10})/) {|s| s[0] } # Stutter punctuation typo
  end
  raw, comment = parse_comment(raw)
  mailbox, tag = parse_tag(raw)
  mailbox ||= ""
  [mailbox, tag, comment]
end
parse_comment(raw) click to toggle source

“(comment)mailbox” or “mailbox(comment)”, only one comment RFC Doesn’t say what to do if 2 comments occur, so last wins

# File lib/email_address/local.rb, line 148
def parse_comment(raw)
  c = nil
  if raw =~ /\A\((.+?)\)(.+)\z/
    c, raw = [$2, $1]
  end
  if raw =~ /\A(.+)\((.+?)\)\z/
    raw, c = [$1, $2]
  end
  [raw, c]
end
parse_tag(raw) click to toggle source
# File lib/email_address/local.rb, line 159
def parse_tag(raw)
  separator = @config[:tag_separator] ||= "+"
  raw.split(separator, 2)
end
redacted?() click to toggle source

Returns true if the value matches the Redacted format

# File lib/email_address/local.rb, line 175
def redacted?
  REDACTED_REGEX.match?(local)
end
relax() click to toggle source

Relaxed format: mailbox and tag, no comment, no extended character set

# File lib/email_address/local.rb, line 227
def relax
  form = mailbox
  form += @config[:tag_separator] + tag if tag
  form.gsub(/[ "(),:<>@\[\]\\]/, "")
end
relax!() click to toggle source

Dropps unusual parts of Standard form to form a relaxed version.

# File lib/email_address/local.rb, line 256
def relax!
  self.local = relax
end
relaxed?() click to toggle source

Relaxed conventional is not so strict about character order.

# File lib/email_address/local.rb, line 349
def relaxed?
  self.syntax = :invalid
  valid_size? or return false
  valid_encoding? or return false
  if tag
    return false unless RELAXED_MAILBOX_REGEX.match?(mailbox) &&
      RELAXED_TAG_REGEX.match?(tag)
    self.syntax = :relaxed
    true
  elsif RELAXED_MAILBOX_REGEX.match?(local)
    self.syntax = :relaxed
    true
  else
    false
  end
end
root_name() click to toggle source

Mailbox with trailing numbers removed

# File lib/email_address/local.rb, line 266
def root_name
  mailbox =~ /\A(.+?)\d+\z/ ? $1 : mailbox
end
set_error(err, reason = nil) click to toggle source
# File lib/email_address/local.rb, line 390
def set_error(err, reason = nil)
  @error = err
  @reason = reason
  @error_message = Config.error_message(err, locale)
  false
end
special?() click to toggle source

Is the address for a common system or business role account?

# File lib/email_address/local.rb, line 185
def special?
  SPECIAL_MAILBOXES.include?(mailbox)
end
standard() click to toggle source

Returns a normalized version of the standard address parts.

# File lib/email_address/local.rb, line 234
def standard
  form = mailbox
  form += @config[:tag_separator] + tag if tag
  form += "(" + comment + ")" if comment
  form = form.gsub(/([\\"])/, '\\\1') # Escape \ and "
  if /[ "(),:<>@\[\\\]]/.match?(form) # Space and "(),:;<>@[\]
    form = %("#{form}")
  end
  form
end
standard?() click to toggle source

True if the part matches the RFC standard format

# File lib/email_address/local.rb, line 367
def standard?
  self.syntax = :invalid
  valid_size? or return false
  valid_encoding? or return false
  if STANDARD_LOCAL_REGEX.match?(local)
    self.syntax = :standard
    true
  else
    false
  end
end
to_s() click to toggle source
# File lib/email_address/local.rb, line 189
def to_s
  self.format
end
unicode?() click to toggle source

True if the the value contains non-Latin Unicde characters

# File lib/email_address/local.rb, line 170
def unicode?
  /[^\p{InBasicLatin}]/.match?(local)
end
valid?(format = @config[:local_format] || :conventional) click to toggle source

True if the part is valid according to the configurations

# File lib/email_address/local.rb, line 275
def valid?(format = @config[:local_format] || :conventional)
  if @config[:mailbox_validator].is_a?(Proc)
    @config[:mailbox_validator].call(mailbox, tag)
  elsif format.is_a?(Proc)
    format.call(self)
  elsif format == :conventional
    conventional?
  elsif format == :relaxed
    relaxed?
  elsif format == :redacted
    redacted?
  elsif format == :standard
    standard?
  elsif format == :none
    true
  else
    raise "Unknown format #{format}"
  end
end
valid_encoding?(enc = @config[:local_encoding] || :ascii) click to toggle source
# File lib/email_address/local.rb, line 328
def valid_encoding?(enc = @config[:local_encoding] || :ascii)
  return false if enc == :ascii && unicode?
  true
end
valid_size?() click to toggle source
# File lib/email_address/local.rb, line 311
def valid_size?
  return set_error(:local_size_long) if local.size > STANDARD_MAX_SIZE
  if @host&.hosted_service?
    return false if @config[:local_private_size] && !valid_size_checks(@config[:local_private_size])
  elsif @config[:local_size] && !valid_size_checks(@config[:local_size])
    return false
  end
  return false if @config[:mailbox_size] && !valid_size_checks(@config[:mailbox_size])
  true
end
valid_size_checks(range) click to toggle source
# File lib/email_address/local.rb, line 322
def valid_size_checks(range)
  return set_error(:local_size_short) if mailbox.size < range.first
  return set_error(:local_size_long) if mailbox.size > range.last
  true
end