1class Domain < ActiveRecord::Base
 
2  PATTERN = /\A(?:\*|\*\.[a-z]{2,}|(?:\*\.)*(?:[a-z0-9][a-z0-9-]{0,61}[a-z0-9]\.)+[a-z]{2,})\z/
 
3
 
4  with_options class_name: "::Domain" do
 
5    belongs_to :canonical_domain, required: false
 
6    has_many :aliases, foreign_key: "canonical_domain_id", dependent: :destroy
 
7  end
 
8
 
 9  validates :name, presence: true
 
10  validates :name, uniqueness: { case_sensitive: false }
 
11  validates :name, format: { with: PATTERN }
 
12  validates :name, length: { maximum: 100 }
 
 
14  validates :strip_characters, length: { maximum: 10 }
 
15  validates :strip_extension, length: { maximum: 10 }
 
 
17  validate if: :aliased_domain? do
 
18    if aliased_domain? && !canonical_domain.present?
 
19      errors.add(:aliased_domain, :not_found)
 
20    end
 
21  end
 
 
23  attr_writer :aliased_domain
 
 
25  before_validation if: :aliased_domain? do
 
26    self.canonical_domain = find_canonical_domain
 
27    self.strip_characters = nil
 
28    self.strip_extension  = nil
 
29  end
 
 
31  before_validation unless: :aliased_domain? do
 
32    self.canonical_domain = nil
 
33  end
 
 
35  class << self
 
36    def default_scope
 
37      preload(:canonical_domain)
 
38    end
 
 
40    def by_name
 
41      order(:name)
 
42    end
 
 
44    def normalize(email)
 
45      unless email.is_a?(Mail::Address)
 
46        email = Mail::Address.new(email)
 
47      end
 
 
49      rule(email.domain).normalize(email)
 
50    rescue Mail::Field::ParseError
 
51      email
 
52    end
 
 
54    private
 
  • UncommunicativeVariableName - has the variable name 'c' » reek
56    def candidates(domain)
 
57      [domain].tap { |c| domain.scan(?.) { c << %[*.#{$'}] } } + %w[*]
 
58    end
 
  • UncommunicativeVariableName - has the variable name 'c' » reek
60    def rules(domain)
 
61      candidates(domain).lazy.map { |c| find_by(name: c) }
 
62    end
 
  • UncommunicativeVariableName - has the variable name 'd' » reek
64    def rule(domain)
 
65      rules(domain).detect(-> { default_domain }) { |d| d.present? }
 
66    end
 
  • UncommunicativeVariableName - has the variable name 'e' » reek
68    def default_domain
 
69      begin
 
70        find_or_create_by(name: "*", strip_extension: "+")
 
71      rescue ActiveRecord::RecordNotUnique => e
 
72        retry
 
73      end
 
74    end
 
75  end
 
  • Attribute - is a writable attribute » reek
  • Complexity 1 » saikuro
77  def aliased_domain
 
78    @aliased_domain || canonical_domain.try(:name)
 
79  end
 
  • Complexity 1 » saikuro
81  def aliased_domain?
 
82    aliased_domain.present?
 
83  end
 
  • Complexity 1 » saikuro
85  def aliased_domains
 
86    aliases.by_name.pluck(:name).join(", ")
 
87  end
 
  • Complexity 1 » saikuro
89  def alias?
 
90    canonical_domain.present?
 
91  end
 
  • Complexity 1 » saikuro
93  def alias
 
94    canonical_domain.name
 
95  end
 
  • Complexity 1 » saikuro
97  def name=(value)
 
98    super(value.to_s.downcase.strip)
 
 99  end
 
  • Complexity 2 » saikuro
101  def strip_characters?
 
102    alias? ? canonical_domain.strip_characters? : super
 
103  end
 
  • Complexity 2 » saikuro
105  def strip_characters
 
106    alias? ? canonical_domain.strip_characters : super
 
107  end
 
  • Complexity 2 » saikuro
109  def strip_extension?
 
110    alias? ? canonical_domain.strip_extension? : super
 
111  end
 
  • Complexity 2 » saikuro
113  def strip_extension
 
114    alias? ? canonical_domain.strip_extension : super
 
115  end
 
  • Complexity 2 » saikuro
117  def normalize(email)
 
118    "#{local(email)}@#{domain(email)}"
 
119  rescue Mail::Field::ParseError
 
120    email
 
121  end
 
 
123  private
 
  • Complexity 1 » saikuro
125  def find_canonical_domain
 
126    self.class.find_by(name: aliased_domain)
 
127  end
 
  • Complexity 4 » saikuro
129  def local(email)
 
130    email.local.dup.tap do |normalized|
 
131      if strip_characters?
 
132        normalized.gsub!(characters_regexp, "")
 
133      end
 
 
135      if strip_extension?
 
136        normalized.gsub!(extension_regexp, "\\1")
 
137      end
 
138    end
 
139  end
 
  • Complexity 2 » saikuro
141  def domain(email)
 
142    alias? ? canonical_domain.name : email.domain
 
143  end
 
  • Complexity 1 » saikuro
145  def characters_regexp
 
146    Regexp.union(strip_characters.chars)
 
147  end
 
  • Complexity 1 » saikuro
149  def extension_regexp
 
150    range = Regexp.escape(strip_extension)
 
151    /\A([^#{range}]+)[#{range}].+\z/
 
152  end
 
153end