class ActiveFedora::Reflection::AssociationReflection

:nodoc:
Active Record class.
Holds all the meta-data about an association as it was specified in the

def association_class

def association_class
  raise NotImplementedError
end

def automatic_inverse_of

returns either false or the inverse association name that it finds.
def automatic_inverse_of
  if can_find_inverse_of_automatically?(self)
    inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_fedora.name.demodulize).to_sym
    begin
      reflection = klass._reflect_on_association(inverse_name)
    rescue NameError
      # Give up: we couldn't compute the klass type so we won't be able
      # to find any associations either.
      reflection = false
    end
    return inverse_name if valid_inverse_reflection?(reflection)
  end
  false
end

def belongs_to?

Returns +true+ if +self+ is a +belongs_to+ reflection.
def belongs_to?
  false
end

def calculate_constructable(_macro, _options)

def calculate_constructable(_macro, _options)
  true
end

def can_find_inverse_of_automatically?(reflection)

inverse, so we exclude reflections with scopes.
Anything with a scope can additionally ruin our attempt at finding an

inverse association.
:foreign_key which prevent us from correctly guessing the
Third, we must not have options such as :polymorphic or
have has_many, has_one, belongs_to associations.
inverse_of option cannot be set to false. Second, we must
us from being able to guess the inverse automatically. First, the
Checks to see if the reflection doesn't have any options that prevent
def can_find_inverse_of_automatically?(reflection)
  reflection.options[:inverse_of] != false &&
    VALID_AUTOMATIC_INVERSE_MACROS.include?(reflection.macro) &&
    !INVALID_AUTOMATIC_INVERSE_OPTIONS.any? { |opt| reflection.options[opt] }
  # && !reflection.scope
end

def check_validity!

def check_validity!
  check_validity_of_inverse!
end

def check_validity_of_inverse!

def check_validity_of_inverse!
  return if options[:polymorphic] || !(has_inverse? && inverse_of.nil?)
  raise InverseOfAssociationNotFoundError, self
end

def collect_join_chain

ThroughReflection.
A chain of reflections from this one back to the owner. For more see the explanation in
def collect_join_chain
  [self]
end

def collection?

+has_and_belongs_to_many+, +false+ otherwise.
association. Returns +true+ if the +macro+ is either +has_many+ or
Returns whether or not this association reflection is for a collection
def collection?
  false
end

def constructable? # :nodoc:

:nodoc:
def constructable? # :nodoc:
  @constructable
end

def create_association(*options)

creation method. Returns the newly created object.
with ActiveFedora::Base#save. +options+ will be passed to the class's
Creates a new instance of the associated class, and immediately saves it
def create_association(*options)
  klass.create(*options)
end

def derive_foreign_key

def derive_foreign_key
  if belongs_to?
    "#{name}_id"
  elsif has_and_belongs_to_many?
    "#{name.to_s.singularize}_ids"
  elsif options[:as]
    "#{options[:as]}_id"
  elsif inverse_of&.collection?
    # for a has_many that is the inverse of a has_and_belongs_to_many
    "#{options[:inverse_of].to_s.singularize}_ids"
  else
    # for a has_many that is the inverse of a belongs_to
    active_fedora.name.foreign_key
  end
end

def foreign_key

def foreign_key
  @foreign_key ||= options[:foreign_key] || derive_foreign_key
end

def has_and_belongs_to_many?

def has_and_belongs_to_many?
  false
end

def has_inverse?

def has_inverse?
  inverse_name
end

def has_many?

def has_many?
  false
end

def initialize(name, scope, options, active_fedora)

def initialize(name, scope, options, active_fedora)
  super
  @constructable = calculate_constructable(macro, options)
end

def inverse_name

def inverse_name
  options.fetch(:inverse_of) do
    if @automatic_inverse_of == false
      nil
    else
      @automatic_inverse_of ||= automatic_inverse_of
    end
  end
end

def inverse_of

def inverse_of
  return unless inverse_name
  @inverse_of ||= klass._reflect_on_association inverse_name
end

def macro

has_many :clients returns :has_many

Returns the macro type.
def macro
  raise NotImplementedError
end

def predicate

Returns the RDF predicate as defined by the :predicate option
def predicate
  options[:predicate]
end

def predicate_for_solr

def predicate_for_solr
  predicate.fragment || predicate.to_s.rpartition(/\//).last
end

def solr_key

def solr_key
  @solr_key ||= ActiveFedora.index_field_mapper.solr_name(predicate_for_solr, :symbol)
end

def valid_inverse_reflection?(reflection)

from calling +klass+, +reflection+ will already be set to false.
Note: klass will always be valid because when there's a NameError

with the current reflection's klass name.
make sure that the reflection's active_record name matches up
+automatic_inverse_of+ method is a valid reflection. We must
Checks if the inverse reflection that is returned from the
def valid_inverse_reflection?(reflection)
  reflection &&
    klass.name == reflection.active_fedora.name &&
    can_find_inverse_of_automatically?(reflection)
end

def validate?

* the association is a +has_many+ association
* you use autosave; :autosave => true
* you explicitly enable validation; :validate => true

:validate => false, validation will take place when:
Unless you explicitly disable validation with

the parent's validation.
Returns whether or not the association should be validated as part of
def validate?
  !options[:validate].nil? ? options[:validate] : (options[:autosave] == true || macro == :has_many)
end