class EmailParser

Constants

ESCAPE_REQUIRED_SYMBOLS
LETTER_AND_DIGIT
OPTIONS
QUOTE_NOT_REQUIRED_CHARS
QUOTE_NOT_REQUIRED_SYMBOLS
QUOTE_REQUIRED_CHARS
QUOTE_REQUIRED_SYMBOLS
VERSION

Public Class Methods

new(options = {}) click to toggle source
# File lib/email_parser.rb, line 36
def initialize(options = {})
  options = options.dup
  OPTIONS.each do |k|
    v = options.delete(k)
    instance_variable_set("@#{k}", v.nil? ? false : v)
  end

  unless options.empty?
    raise "Unknown EmailParser option: #{options.inspect}"
  end

  raise NotImplementedError("Sorry, `allow_address_literal == true` is not supported yet") if allow_address_literal
end
parse(src, **options) click to toggle source
# File lib/email_parser.rb, line 28
def self.parse(src, **options)
  new(**options).parse(src)
end
valid?(src, **options) click to toggle source
# File lib/email_parser.rb, line 32
def self.valid?(src, **options)
  new(**options).valid?(src)
end

Public Instance Methods

parse(src) click to toggle source
# File lib/email_parser.rb, line 57
def parse(src)
  s = StringScanner.new(src)
  se = [:mailbox]

  raise ParseError unless push!(se, local_part(s))
  raise ParseError unless push!(se, s.scan(/@/))
  raise ParseError unless push!(se, domain_or_address_literal(s))
  raise ParseError unless s.eos?

  se
end
valid?(src) click to toggle source
# File lib/email_parser.rb, line 50
def valid?(src)
  parse(src)
  true
rescue ParseError
  false
end

Private Instance Methods

atom(s) click to toggle source
# File lib/email_parser.rb, line 108
def atom(s)
  se = [:atom]
  return unless push!(se, s.scan(QUOTE_NOT_REQUIRED_CHARS))

  se
end
domain(s) click to toggle source

tools.ietf.org/html/rfc1035 p7

# File lib/email_parser.rb, line 158
def domain(s)
  se = [:domain]
  return unless push!(se, subdomain(s))

  se
end
domain_or_address_literal(s) click to toggle source
# File lib/email_parser.rb, line 148
def domain_or_address_literal(s)
  if s.scan(/\[/)
    return unless allow_address_literal
    # TODO: parse address literal
  else
    domain(s)
  end
end
dot(s) click to toggle source
# File lib/email_parser.rb, line 101
def dot(s)
  se = [:dot]
  return unless push!(se, s.scan(/\./))

  se
end
dot_string(s) click to toggle source
# File lib/email_parser.rb, line 115
def dot_string(s)
  se = [:dot_string]

  case
  when push!(se, dot(s))
    return unless allow_local_begin_with_dot
  when push!(se, atom(s))
    # noop
  else
    return
  end

  dot_seq = 0

  loop do
    case
    when push!(se, dot(s))
      dot_seq += 1
      return if dot_seq > 1 && !allow_dot_sequence_in_local

      next
    when push!(se, atom(s))
      dot_seq = 0
    else
      break
    end
  end

  return if dot_seq > 0 && !allow_local_end_with_dot

  se
end
dquote(s) click to toggle source
# File lib/email_parser.rb, line 94
def dquote(s)
  se = [:dquote]
  return unless push!(se, s.scan(/"/))

  se
end
label(s) click to toggle source
# File lib/email_parser.rb, line 178
def label(s)
  buffer = ""

  unless allow_domain_label_begin_with_number
    return unless push!(buffer, s.scan(/[a-zA-Z]/))
  end

  push!(buffer, s.scan(/[a-zA-Z0-9]+/))
  push!(buffer, s.scan(/(-[a-zA-Z0-9]+)+/))

  [:label, buffer]
end
local_part(s) click to toggle source
# File lib/email_parser.rb, line 77
def local_part(s)
  se = [:local_part]
  return unless push!(se, quoted_string(s) || dot_string(s))

  se
end
push!(array, val) click to toggle source
# File lib/email_parser.rb, line 70
def push!(array, val)
  return if val.nil?

  array << val
  val
end
quoted_string(s) click to toggle source
# File lib/email_parser.rb, line 84
def quoted_string(s)
  se = [:quoted_string]

  return unless push!(se, dquote(s))
  return unless push!(se, s.scan(QUOTE_REQUIRED_CHARS))
  return unless push!(se, dquote(s))

  se
end
subdomain(s) click to toggle source
# File lib/email_parser.rb, line 165
def subdomain(s)
  se = [:subdomain]

  return unless push!(se, label(s))

  loop do
    break unless push!(se, dot(s))
    raise ParseError unless push!(se, label(s))
  end

  se
end