class ActiveRecord::Associations::Builder::HasAndBelongsToMany

:nodoc:
:nodoc:

def self.add_left_association(name, options)

def self.add_left_association(name, options)
  belongs_to name, required: false, **options
  self.left_reflection = _reflect_on_association(name)
end

def self.add_right_association(name, options)

def self.add_right_association(name, options)
  rhs_name = name.to_s.singularize.to_sym
  belongs_to rhs_name, required: false, **options
  self.right_reflection = _reflect_on_association(rhs_name)
end

def self.compute_type(class_name)

def self.compute_type(class_name)
  left_model.compute_type class_name
end

def self.retrieve_connection

def self.retrieve_connection
  left_model.retrieve_connection
end

def self.suppress_composite_primary_key(pk)

def self.suppress_composite_primary_key(pk)
  pk unless pk.is_a?(Array)
end

def self.table_name

def self.table_name
  # Table name needs to be resolved lazily
  # because RHS class might not have been loaded
  @table_name ||= table_name_resolver.call
end

def belongs_to_options(options)

def belongs_to_options(options)
  rhs_options = {}
  if options.key? :class_name
    rhs_options[:foreign_key] = options[:class_name].to_s.foreign_key
    rhs_options[:class_name] = options[:class_name]
  end
  if options.key? :association_foreign_key
    rhs_options[:foreign_key] = options[:association_foreign_key]
  end
  rhs_options
end

def initialize(association_name, lhs_model, options)

def initialize(association_name, lhs_model, options)
  @association_name = association_name
  @lhs_model = lhs_model
  @options = options
end

def middle_options(join_model)

def middle_options(join_model)
  middle_options = {}
  middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
  if options.key? :foreign_key
    middle_options[:foreign_key] = options[:foreign_key]
  end
  middle_options
end

def middle_reflection(join_model)

def middle_reflection(join_model)
  middle_name = [lhs_model.name.downcase.pluralize,
                 association_name.to_s].sort.join("_").gsub("::", "_").to_sym
  middle_options = middle_options join_model
  HasMany.create_reflection(lhs_model,
                            middle_name,
                            nil,
                            middle_options)
end

def table_name

def table_name
  if options[:join_table]
    options[:join_table].to_s
  else
    class_name = options.fetch(:class_name) {
      association_name.to_s.camelize.singularize
    }
    klass = lhs_model.send(:compute_type, class_name.to_s)
    [lhs_model.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
  end
end

def through_model

def through_model
  join_model = Class.new(ActiveRecord::Base) {
    class << self
      attr_accessor :left_model
      attr_accessor :name
      attr_accessor :table_name_resolver
      attr_accessor :left_reflection
      attr_accessor :right_reflection
    end
    def self.table_name
      # Table name needs to be resolved lazily
      # because RHS class might not have been loaded
      @table_name ||= table_name_resolver.call
    end
    def self.compute_type(class_name)
      left_model.compute_type class_name
    end
    def self.add_left_association(name, options)
      belongs_to name, required: false, **options
      self.left_reflection = _reflect_on_association(name)
    end
    def self.add_right_association(name, options)
      rhs_name = name.to_s.singularize.to_sym
      belongs_to rhs_name, required: false, **options
      self.right_reflection = _reflect_on_association(rhs_name)
    end
    def self.retrieve_connection
      left_model.retrieve_connection
    end
    private
      def self.suppress_composite_primary_key(pk)
        pk unless pk.is_a?(Array)
      end
  }
  join_model.name                = "HABTM_#{association_name.to_s.camelize}"
  join_model.table_name_resolver = -> { table_name }
  join_model.left_model          = lhs_model
  join_model.add_left_association :left_side, anonymous_class: lhs_model
  join_model.add_right_association association_name, belongs_to_options(options)
  join_model
end