class Sequel::Plugins::DeepDup::DeepDupper

Attributes

associations[R]
instance[R]
omit_records[R]

Public Class Methods

new(instance, opts = {}) click to toggle source
# File lib/sequel_deep_dup.rb, line 10
def initialize instance, opts = {}
  @instance     = instance
  @associations = opts[:associations]
  @omit_records = opts[:omit_records] || []
end

Public Instance Methods

dup() click to toggle source
# File lib/sequel_deep_dup.rb, line 16
def dup
  copy = shallow_dup.extend(InstanceHooks::InstanceMethods)
  omit_records << instance
  dup_associations(instance, copy, associations)
  copy
end
dup_associations(instance, copy, includes = nil) click to toggle source
# File lib/sequel_deep_dup.rb, line 30
def dup_associations instance, copy, includes = nil
  includes &&= normalize_graph(includes)
  associations = instance.class.associations

  if includes
    (includes.keys - associations).each do |assoc|
      raise(Error, "no association named #{assoc} for #{instance}")
    end
  end

  associations.each do |name|
    next unless refl = instance.class.association_reflection(name)
    [*instance.send(name)].compact.each do |rec|
      if includes
        next unless includes.has_key?( refl_name = refl[:name] )
        instantiate_associated copy, refl, rec, includes[refl_name]
      else
        next copy.values.delete(refl[:key]) if refl[:type] == :many_to_one
        instantiate_associated(copy, refl, rec, nil)
      end
    end
  end
end
normalize_graph(*enum) click to toggle source
# File lib/sequel_deep_dup.rb, line 54
def normalize_graph(*enum)
  enum.inject({}) do |hash, assoc|
    case assoc
    when Symbol then hash[assoc] = {}
    when Hash   then assoc.each { |k, v| hash[k] = normalize_graph(v) }
    else hash.merge!(normalize_graph(*assoc) || next)
    end
    hash
  end
end
shallow_dup() click to toggle source
# File lib/sequel_deep_dup.rb, line 23
def shallow_dup
  klass      = instance.class
  attributes = instance.to_hash.dup
  [*klass.primary_key].each { |attr| attributes.delete(attr) }
  klass.new attributes
end

Private Instance Methods

instantiate_associated(copy, reflection, record, associations) click to toggle source
# File lib/sequel_deep_dup.rb, line 66
def instantiate_associated copy, reflection, record, associations
  return if omit_records.detect { |to_omit| record.pk == to_omit.pk && record.class == to_omit.class }

  unless reflection[:type] == :many_to_many
    record = DeepDupper.new(
      record,
      :omit_records => omit_records,
      :associations => associations
    ).dup
  end

  if reflection.returns_array?
    copy.send(reflection[:name]) << record
    copy.after_save_hook{ copy.send(reflection.add_method, record) }
  else
    copy.associations[reflection[:name]] = record
    copy.instance_variable_set :@set_associated_object_if_same, true

    if reflection[:type] == :many_to_one
      copy.before_save_hook {
        copy.send reflection.setter_method, record.save
      }
    else
      copy.after_save_hook{
        copy.send(reflection.setter_method, record)
      }
    end
  end
end