lib/mongoid/alize/to_callback.rb
require 'mongoid/compatibility'
module Mongoid
module Alize
class ToCallback < Callback
def attach
define_denorm_attrs
define_callback
alias_callback
set_callback
define_destroy_callback
alias_destroy_callback
set_destroy_callback
end
def define_callback
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
def #{callback_name}#{force_param}
#{iterable_relation}.each do |relation|
next if relation.attributes.frozen?
is_one = #{is_one?}
if is_one
field_values = #{field_values("self")}
else
field_values = #{field_values("self", :id => true)}
end
prefixed_name = #{prefixed_name}
if is_one
#{relation_set('prefixed_name', 'field_values')}
else
#{pull_from_inverse}
#{relation_push('prefixed_name', 'field_values')}
end
end
#{debug ? "puts \"#{callback_name}\"": ""}
true
end
protected :#{callback_name}
CALLBACK
end
def define_destroy_callback
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
def #{destroy_callback_name}
#{iterable_relation}.each do |relation|
next if relation.attributes.frozen?
is_one = #{is_one?}
prefixed_name = #{prefixed_name}
if is_one
#{relation_unset('prefixed_name')}
else
#{pull_from_inverse}
end
end
#{debug ? "puts \"#{destroy_callback_name}\"": ""}
true
end
protected :#{destroy_callback_name}
CALLBACK
end
def pull_from_inverse
<<-RUBIES
#{relation_pull('prefixed_name', '{ "_id" => self.id }')}
if _f = relation.send(prefixed_name)
_f.reject! do |hash|
hash["_id"] == self.id
end
end
RUBIES
end
def prefixed_name
if inverse_relation
":#{inverse_relation}_fields"
else
<<-RUBIES
(#{find_relation}.name.to_s + '_fields')
RUBIES
end
end
def relation_set(field, value)
Mongoid::Compatibility::Version.mongoid4_or_newer? ? "relation.set(#{field}.to_sym => #{value})" : "relation.set(#{field}, #{value})"
end
def relation_unset(field)
"relation.unset(#{field}.to_sym)"
end
def relation_pull(field, value)
Mongoid::Compatibility::Version.mongoid4_or_newer? ? "relation.pull(#{field}.to_sym => #{value})" : "relation.pull(#{field}, #{value})"
end
def relation_push(field, value)
Mongoid::Compatibility::Version.mongoid4_or_newer? ? "relation.push(#{field}.to_sym => #{value})" : "relation.push(#{field}, #{value})"
end
def is_one?
if Mongoid::Compatibility::Version.mongoid7_or_newer?
if inverse_relation
if self.inverse_metadata.relation.superclass == Mongoid::Association::One
"true"
else
"false"
end
else
<<-RUBIES
(#{find_relation}.relation.superclass == Mongoid::Association::One)
RUBIES
end
else
if inverse_relation
if self.inverse_metadata.relation.superclass == Mongoid::Relations::One
"true"
else
"false"
end
else
<<-RUBIES
(#{find_relation}.relation.superclass == Mongoid::Relations::One)
RUBIES
end
end
end
def find_relation
"relation.class.relations.values.find { |metadata| metadata.inverse(self) == :#{relation} && metadata.class_name == self.class.name }"
end
def iterable_relation
"[self.#{relation}].flatten.compact"
end
def set_callback
unless callback_attached?("save", aliased_callback_name)
klass.set_callback(:save, :after, aliased_callback_name)
end
end
def set_destroy_callback
unless callback_attached?("destroy", aliased_destroy_callback_name)
klass.set_callback(:destroy, :after, aliased_destroy_callback_name)
end
end
def alias_destroy_callback
unless callback_defined?(aliased_destroy_callback_name)
klass.send(:alias_method, aliased_destroy_callback_name, destroy_callback_name)
klass.send(:public, aliased_destroy_callback_name)
end
end
def aliased_destroy_callback_name
:"denormalize_destroy_#{direction}_#{relation}"
end
def destroy_callback_name
:"_#{aliased_destroy_callback_name}"
end
def direction
"to"
end
end
end
end