2

I have ruby classes in which I'm trying to implement clone method. I want to be able to use a generalized clone method that all the classes can inherit from. The attributes of a class could be an array type, a hash or some other object.

can I make this more generic so that it deep clones? Possibly define a clone method in the superclass QueryModel? how would that work?

class Bool < QueryModel

  attr_accessor :name, :should, :must, :must_not

  def clone
    Bool.new(self.name, self.should.clone, self.must.clone, self.must_not.clone) 
  end


  def serialize
      result_hash = {}
      query_hash = {}

      if( instance_variable_defined?(:@should) )
      query_hash[:should] = @should.serialize
      end

      if( instance_variable_defined?(:@must) )
        query_hash[:must] = @must.serialize
      end

      if( instance_variable_defined?(:@must_not) )
        query_hash[:must_not] = @must_not.serialize
      end

      if( instance_variable_defined?(:@should) || instance_variable_defined?(:@must) || instance_variable_defined?(:@must_not) )
        return result_hash = query_hash
    end
  end
end

Here is where clone could possibly be used:

class Query < QueryModel

  attr_accessor :query_string, :query, :bool

  def serialize 
    result_hash = {}
    query_hash = {}

    if( instance_variable_defined?(:@query_string) )
      query_hash[:query_string] = @query_string.serialize
      #result_hash[:query] = query_hash
    end

    if( instance_variable_defined?(:@query) )
      query_hash[:query] = @query
    end

    if( !instance_variable_defined?(@bool) )
      if( instance_variable_defined?(:@query) || instance_variable_defined?(:@query_string) )
        result_hash[:query] = query_hash
        return result_hash
      end
    else
      bool =  @bool.clone
      result_hash[:query] = bool
    end

  end

end
Horse Voice
  • 8,138
  • 15
  • 69
  • 120

2 Answers2

0

If you are not afraid of new gems, the amoeba gem has everything you need for cloning AR objects. If you really only want to copy the objects attribures and not relations, the dup method is what you are looking for.

UPDATE: Sorry it was late yesterday and I thought you were using ActiveRecord somehow. For your pure ruby solution just use the Object#clone method without override and specify specify the behaviour of Object#clone like this:

class Bool
  def initialize_copy(original)
    super # this already clones instance vars that are not objects

    # your custom strategy for 
    # referenced objects can be here

  end
end

Here is what the docs say about this.

smallbutton
  • 3,377
  • 15
  • 27
  • Don't want to use other gems to do this. Need to learn how to do this the right way in pure ruby. How would dup help? Could you give an example? thank you! – Horse Voice Aug 03 '15 at 22:38
0

If you are solve problem using creational/prototype design pattern, you can do like below sample -

class ConcretePrototype
  def copy
  prototype = clone

    instance_variables.each do |ivar_name|
      prototype.instance_variable_set( ivar_name,
      instance_variable_get(ivar_name).clone)
    end

    prototype
  end
end

class Application
  def run
    concreate_prototype = ConcretePrototype.new
    concreate_prototype_2 = concreate_prototype.copy
    puts concreate_prototype.inspect
    puts concreate_prototype_2.inspect
  end
end

This way you can deep clone the object without any gem. reference - https://github.com/vatrai/design_patterns/blob/master/creational/prototype.rb

Vishnu Atrai
  • 2,370
  • 22
  • 24