Reputation: 3954
I am working on a solution for technical drawings (svg/ruby). I want to manipulate rectangles, and have an add!
method in this class:
class Rect
def add!(delta)
@x1+=delta
... # and so on
self
end
end
I also need an add
method returning a Rect
, but not manipulating self
:
def add(delta)
r=self.dup/clone/"copy" # <-- not realy the 3 and no quotes, just in text here
r.add! delta
end
dup
and clone
don't do my thing but:
def copy; Marshal.load(Marshal.dump(self)); end
does.
Why does such a basic functionality not exist in plain Ruby? Please just don't tell me that I could reverse add
and add!
, letting add
do the job, and add!
calling it.
Upvotes: 12
Views: 4892
Reputation: 1
Why can't you use something like this:
new_item = Item.new(old_item.attributes)
new_item.save!
This would copy all the attributes from existing item to new one, without issues. If you have other objects, you can just copy them individually.
I think it's the quickest way to copy an object
Upvotes: 0
Reputation: 397
Forget marshalling. The deep_dive gem will solve your problems.
https://rubygems.org/gems/deep_dive
Upvotes: 2
Reputation: 2372
I'm not sure why there's no deep copy method in Ruby, but I'll try to make an educated guess based on the information I could find (see links and quotes below the line).
Judging from this information, I could only infer that the reason Ruby does not have a deep copy method is because it's very rarely necessary and, in the few cases where it truly is necessary, there are other, relatively simple ways to accomplish the same task:
As you already know, using Marshal.dump
and Marshal.load
is currently the recommended way to do this. This is also the approach recommended by Programming Ruby (see excerpts below).
Alternatively, there are at least 3 available implementations found in these gems: deep_cloneable
, deep_clone
and ruby_deep_clone
; the first being the most popular.
Related Information
Here's a discussion over at comp.lang.ruby which might shed some light on this. There's another answer here with some associated discussions, but it all comes back to using Marshal
.
There weren't any mentions of deep copying in Programming Ruby, but there were a few mentions in The Ruby Programming Language. Here are a few related excerpts:
[…]
Another use for
Marshal.dump
andMarshal.load
is to create deep copies of objects:def deepcopy(o) Marshal.load(Marshal.dump(o)) end
[…]
… the binary format used by
Marshal.dump
andMarshal.load
is version-dependent, and newer versions of Ruby are not guaranteed to be able to read marshalled objects written by older versions of Ruby.[…]
Note that files and I/O streams, as well as Method and Binding objects, are too dynamic to be marshalled; there would be no reliable way to restore their state.
[…]
Instead of making a defensive deep copy of the array, just call
to_enum
on it, and pass the resulting enumerator instead of the array itself. In effect, you’re creating an enumerable but immutable proxy object for your array.
Upvotes: 6