<commit_before>class EmailValidator < ActiveModel::Validator
  BAD_DOMAINS = File.readlines("data/bad_domains.txt").map(&:chomp)

  def validate(record)
    parsed = Mail::Address.new(record.email)
    maybe_set_error(record, "is not a valid address because it ends with a dot or starts with a dot") do
      parsed.domain.present? && (parsed.domain.end_with?('.') || parsed.domain.start_with?('.'))
    end && return
    maybe_set_error(record, "cannot receive e-mails from this system") do
      SendgridHelper.spam_reported?(parsed.address)
    end && return
    maybe_set_error(record, "does not appear to be valid") do
      BAD_DOMAINS.include?(parsed.domain)
    end && return
    unless parsed.local &&
        parsed.domain &&
        parsed.address == record.email &&
        parsed.local != record.email &&
        has_mx_records(parsed.domain)
      set_error(record)
    end
  rescue Mail::Field::ParseError
    set_error(record)
  end

  def has_mx_records(domain)
    Resolv::DNS.new.getresource(domain, Resolv::DNS::Resource::IN::MX)
  rescue Resolv::ResolvError
    false
  rescue Resolv::ResolvTimeout
    true
  end

  def set_error(record)
    record.errors.add(:email, "is not a valid address")
  end

  def maybe_set_error(record, message)
    yield.tap do |value|
      record.errors.add(:email, message) if value
    end
  end
end<commit_msg>Moved validation logic out to individual methods for more clarity.<commit_after>class EmailValidator < ActiveModel::Validator
  BAD_DOMAINS = File.readlines("data/bad_domains.txt").map(&:chomp)

  def validate(record)
    parsed = Mail::Address.new(record.email)
    validate_address_domain(record, parsed) ||
      validate_spam_reporter(record, parsed) ||
      validate_bad_domain(record, parsed) ||
      validate_address_well_formed(record, parsed)
  rescue Mail::Field::ParseError
    set_error(record)
  end

  def has_mx_records(domain)
    Resolv::DNS.new.getresource(domain, Resolv::DNS::Resource::IN::MX)
  rescue Resolv::ResolvError
    false
  rescue Resolv::ResolvTimeout
    true
  end

  def set_error(record)
    record.errors.add(:email, "is not a valid address")
  end

  def maybe_set_error(record, message)
    yield.tap do |value|
      record.errors.add(:email, message) if value
    end
  end

  def validate_address_domain(record, parsed)
    maybe_set_error(record, "is not a valid address because it ends with a dot or starts with a dot") do
      parsed.domain.present? && (parsed.domain.end_with?('.') || parsed.domain.start_with?('.'))
    end
  end

  def validate_spam_reporter(record, parsed)
    maybe_set_error(record, "cannot receive e-mails from this system") do
      SendgridHelper.spam_reported?(parsed.address)
    end
  end

  def validate_bad_domain(record, parsed)
    maybe_set_error(record, "does not appear to be valid") do
      BAD_DOMAINS.include?(parsed.domain)
    end
  end

  def validate_address_well_formed(record, parsed)
    maybe_set_error(record, "is not a valid address") do
      not (parsed.local &&
           parsed.domain &&
           parsed.address == record.email &&
           parsed.local != record.email &&
           has_mx_records(parsed.domain))
    end
  end
end
{'fraction_non_alphanumeric': 0.10736579275905118, 'fraction_numerical': 0.0, 'mean_word_length': 3.618155619596542, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5411356', 'n_tokens_mistral': 1011, 'n_tokens_neox': 1027, 'n_words': 239}