def deep_clone(*args, &block)
      options = args[0] || {}

      dictionary = options[:dictionary]
      dictionary ||= {} if options.delete(:use_dictionary)

      kopy = if dictionary
               find_in_dictionary_or_dup(dictionary)
             else
               dup
             end

      deep_exceptions = {}
      if options[:except]
        exceptions = Array.wrap(options[:except])
        exceptions.each do |attribute|
          dup_default_attribute_value_to(kopy, attribute, self) unless attribute.is_a?(Hash)
        end
        deep_exceptions = exceptions.select { |e| e.is_a?(Hash) }.inject({}) { |m, h| m.merge(h) }
      end

      deep_onlinesses = {}
      if options[:only]
        onlinesses = Array.wrap(options[:only])
        object_attrs = kopy.attributes.keys.collect(&:to_sym)
        exceptions = object_attrs - onlinesses
        exceptions.each do |attribute|
          dup_default_attribute_value_to(kopy, attribute, self) unless attribute.is_a?(Hash)
        end
        deep_onlinesses = onlinesses.select { |e| e.is_a?(Hash) }.inject({}) { |m, h| m.merge(h) }
      end

      kopy.instance_eval { extend ::DeepCloneable::SkipValidations } if options[:validate] == false

      if options[:include]
        normalized_includes_list(options[:include]).each do |association, conditions_or_deep_associations|
          conditions = {}

          if association.is_a? Hash
            conditions_or_deep_associations = association[association.keys.first]
            association = association.keys.first
          end

          if conditions_or_deep_associations.is_a?(Hash)
            conditions_or_deep_associations = conditions_or_deep_associations.dup
            conditions[:if]     = conditions_or_deep_associations.delete(:if)     if conditions_or_deep_associations[:if]
            conditions[:unless] = conditions_or_deep_associations.delete(:unless) if conditions_or_deep_associations[:unless]
          elsif conditions_or_deep_associations.is_a?(Array)
            conditions_or_deep_associations = conditions_or_deep_associations.dup
            conditions_or_deep_associations.delete_if { |entry| conditions.merge!(entry) if entry.is_a?(Hash) && (entry.key?(:if) || entry.key?(:unless)) }
          end

          dup_options = {}
          dup_options[:include] = conditions_or_deep_associations if conditions_or_deep_associations.present?
          dup_options[:except] = deep_exceptions[association] if deep_exceptions[association]
          dup_options[:only] = deep_onlinesses[association] if deep_onlinesses[association]
          dup_options[:dictionary] = dictionary if dictionary

          [:skip_missing_associations, :validate].each do |option|
            dup_options[option] = options[option] if options.key?(option)
          end

          if (association_reflection = self.class.reflect_on_association(association))
            association_type = association_reflection.macro
            association_type = "#{association_type}_through" if association_reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)

            duped_object = send(
              "dup_#{association_type}_association",
              { :reflection => association_reflection, :association => association, :copy => kopy, :conditions => conditions, :dup_options => dup_options },
              &block
            )

            kopy.send("#{association}=", duped_object)
          elsif !options[:skip_missing_associations]
            raise ::DeepCloneable::AssociationNotFoundException, "#{self.class}##{association}"
          end
        end
      end

      yield(self, kopy) if block

      kopy
    end
def deep_clone(*args, &block)
      options = args[0] || {}

      dictionary = options[:dictionary]
      dictionary ||= {} if options.delete(:use_dictionary)

      kopy = if dictionary
               find_in_dictionary_or_dup(dictionary)
             else
               dup
             end

      deep_exceptions = {}
      if options[:except]
        exceptions = Array.wrap(options[:except])
        exceptions.each do |attribute|
          dup_default_attribute_value_to(kopy, attribute, self) unless attribute.is_a?(Hash)
        end
        deep_exceptions = exceptions.select { |e| e.is_a?(Hash) }.inject({}) { |m, h| m.merge(h) }
      end

      deep_onlinesses = {}
      if options[:only]
        onlinesses = Array.wrap(options[:only])
        object_attrs = kopy.attributes.keys.collect(&:to_sym)
        exceptions = object_attrs - onlinesses
        exceptions.each do |attribute|
          dup_default_attribute_value_to(kopy, attribute, self) unless attribute.is_a?(Hash)
        end
        deep_onlinesses = onlinesses.select { |e| e.is_a?(Hash) }.inject({}) { |m, h| m.merge(h) }
      end

      kopy.instance_eval { extend ::DeepCloneable::SkipValidations } if options[:validate] == false

      if options[:include]
        normalized_includes_list(options[:include]).each do |association, conditions_or_deep_associations|
          conditions = {}

          if association.is_a? Hash
            conditions_or_deep_associations = association[association.keys.first]
            association = association.keys.first
          end

          if conditions_or_deep_associations.is_a?(Hash)
            conditions_or_deep_associations = conditions_or_deep_associations.dup
            conditions[:if]     = conditions_or_deep_associations.delete(:if)     if conditions_or_deep_associations[:if]
            conditions[:unless] = conditions_or_deep_associations.delete(:unless) if conditions_or_deep_associations[:unless]
          elsif conditions_or_deep_associations.is_a?(Array)
            conditions_or_deep_associations = conditions_or_deep_associations.dup
            conditions_or_deep_associations.delete_if { |entry| conditions.merge!(entry) if entry.is_a?(Hash) && (entry.key?(:if) || entry.key?(:unless)) }
          end

          dup_options = {}
          dup_options[:include] = conditions_or_deep_associations if conditions_or_deep_associations.present?
          dup_options[:except] = deep_exceptions[association] if deep_exceptions[association]
          dup_options[:only] = deep_onlinesses[association] if deep_onlinesses[association]
          dup_options[:dictionary] = dictionary if dictionary

          [:skip_missing_associations, :validate].each do |option|
            dup_options[option] = options[option] if options.key?(option)
          end

          if (association_reflection = self.class.reflect_on_association(association))
            association_type = association_reflection.macro
            association_type = "#{association_type}_through" if association_reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)

            duped_object = send(
              "dup_#{association_type}_association",
              { :reflection => association_reflection, :association => association, :copy => kopy, :conditions => conditions, :dup_options => dup_options },
              &block
            )

            kopy.send("#{association}=", duped_object)
          elsif !options[:skip_missing_associations]
            raise ::DeepCloneable::AssociationNotFoundException, "#{self.class}##{association}"
          end
        end
      end

      yield(self, kopy) if block

      kopy
    end
Deep dups an ActiveRecord model. See README.rdoc