lib/amoeba.rb in amoeba-0.1.2 vs lib/amoeba.rb in amoeba-1.0.0
- old
+ new
@@ -1,5 +1,6 @@
+require "active_record"
require "amoeba/version"
module Amoeba
module ClassMethods
def amoeba(&block)
@@ -18,30 +19,40 @@
def do_preproc
@do_preproc ||= false
@do_preproc
end
+ def known_macros
+ @known_macros ||= [:has_one, :has_many, :has_and_belongs_to_many]
+ @known_macros
+ end
+
def includes
@includes ||= []
@includes
end
def excludes
@excludes ||= []
@excludes
end
- def known_macros
- @known_macros ||= [:has_one, :has_many, :has_and_belongs_to_many]
- @known_macros
+ def clones
+ @clones ||= []
+ @clones
end
def null_fields
@null_fields ||= []
@null_fields
end
+ def coercions
+ @coercions ||= {}
+ @coercions
+ end
+
def prefixes
@prefixes ||= {}
@prefixes
end
@@ -85,10 +96,21 @@
@excludes << value if value
end
@excludes
end
+ def clone(value=nil)
+ @enabled ||= true
+ @clones ||= []
+ if value.is_a?(Array)
+ @clones = value
+ else
+ @clones << value if value
+ end
+ @clones
+ end
+
def recognize(value=nil)
@enabled ||= true
@known_macros ||= []
if value.is_a?(Array)
@known_macros = value
@@ -107,10 +129,29 @@
@null_fields << value if value
end
@null_fields
end
+ def set(defs=nil)
+ @do_preproc ||= true
+ @coercions ||= {}
+ if defs.is_a?(Array)
+ @coercions = {}
+
+ defs.each do |d|
+ d.each do |k,v|
+ @coercions[k] = v if v
+ end
+ end
+ else
+ defs.each do |k,v|
+ @coercions[k] = v if v
+ end
+ end
+ @coercions
+ end
+
def prepend(defs=nil)
@do_preproc ||= true
@prefixes ||= {}
if defs.is_a?(Array)
@prefixes = {}
@@ -192,36 +233,77 @@
copy_of_obj[:"#{settings.foreign_key}"] = nil
@result.send(:"#{relation_name}=", copy_of_obj)
end
when :has_many
- # copying the children of the regular has many will
- # effectively do what is desired anyway, the through
- # association is really just for convenience usage
- # on the model
- if settings.is_a?(ActiveRecord::Reflection::ThroughReflection)
- return
- end
+ clone = amoeba_conf.clones.include?(:"#{relation_name}")
- self.send(relation_name).each do |old_obj|
- copy_of_obj = old_obj.dup
- copy_of_obj[:"#{settings.foreign_key}"] = nil
+ # this could be DRYed up for better readability by
+ # duplicating the loop code, but I'm duplicating the
+ # loops to avoid that extra check on each iteration
+ if clone
+ # This is a M:M "has many through" where we
+ # actually copy and reassociate the new children
+ # rather than only maintaining the associations
+ self.send(relation_name).each do |old_obj|
+ copy_of_obj = old_obj.dup
- # associate this new child to the new parent object
- @result.send(relation_name) << copy_of_obj
+ # associate this new child to the new parent object
+ @result.send(relation_name) << copy_of_obj
+ end
+ else
+ # This is a regular 1:M "has many"
+ #
+ # copying the children of the regular has many will
+ # effectively do what is desired anyway, the through
+ # association is really just for convenience usage
+ # on the model
+ return if settings.is_a?(ActiveRecord::Reflection::ThroughReflection)
+
+ self.send(relation_name).each do |old_obj|
+ copy_of_obj = old_obj.dup
+ copy_of_obj[:"#{settings.foreign_key}"] = nil
+
+ # associate this new child to the new parent object
+ @result.send(relation_name) << copy_of_obj
+ end
end
+
when :has_and_belongs_to_many
- self.send(relation_name).each do |old_obj|
- # associate this new child to the new parent object
- @result.send(relation_name) << old_obj
+ clone = amoeba_conf.clones.include?(relation_name)
+
+ if clone
+ self.send(relation_name).each do |old_obj|
+ copy_of_obj = old_obj.dup
+
+ # associate this new child to the new parent object
+ @result.send(relation_name) << copy_of_obj
+ end
+ else
+ self.send(relation_name).each do |old_obj|
+ # associate this new child to the new parent object
+ @result.send(relation_name) << old_obj
+ end
end
end
end
def dup(options={})
@result = super()
+ amoeba_conf.clones.each do |clone_field|
+ r = self.class.reflect_on_association clone_field
+
+ # if this is a has many through and we're gonna deep
+ # copy the child records, exclude the regular join
+ # table from copying so we don't end up with the new
+ # and old children on the copy
+ if r.macro == :has_many && r.is_a?(ActiveRecord::Reflection::ThroughReflection)
+ amoeba_conf.exclude_field r.options[:through]
+ end
+ end
+
if amoeba_conf.enabled
if amoeba_conf.includes.count > 0
amoeba_conf.includes.each do |i|
r = self.class.reflect_on_association i
amo_process_association(i, r)
@@ -248,9 +330,14 @@
def preprocess_parent_copy
# nullify any fields the user has configured
amoeba_conf.null_fields.each do |n|
@result[n] = nil
+ end
+
+ # prepend any extra strings to indicate uniqueness of the new record(s)
+ amoeba_conf.coercions.each do |field,coercion|
+ @result[field] = "#{coercion}"
end
# prepend any extra strings to indicate uniqueness of the new record(s)
amoeba_conf.prefixes.each do |field,prefix|
@result[field] = "#{prefix}#{@result[field]}"