Skip to content

Commit

Permalink
Merge pull request #91 from djberg96/deep_clone_and_delete
Browse files Browse the repository at this point in the history
Add deep_clone and deep_delete
  • Loading branch information
bdunne authored Jul 17, 2020
2 parents 7467dfc + d4f8eae commit a6065e6
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ MoreCoreExtensions are a set of core extensions beyond those provided by ActiveS
* core_ext/array/deletes.rb
* `#delete_blanks` - Deletes all items where the value is blank
* `#delete_nils` - Deletes all items where the value is nil
* `#deep_delete` - Deletes nested hash key elements
* core_ext/array/duplicates.rb
* `#duplicates` - Returns an Array of the duplicates found
* core_ext/array/element_counts.rb
Expand Down Expand Up @@ -61,6 +62,7 @@ MoreCoreExtensions are a set of core extensions beyond those provided by ActiveS
* core_ext/hash/deletes.rb
* `#delete_blanks` - Deletes all keys where the value is blank
* `#delete_nils` - Deletes all keys where the value is nil
* `#deep_delete` - Deletes nested hash key elements
* core_ext/hash/nested.rb (see [Shared](#shared))
* `#delete_blank_paths` - Deletes all paths where the value is blank
* core_ext/hash/sorting.rb (see [Shared](#shared))
Expand Down Expand Up @@ -129,6 +131,7 @@ MoreCoreExtensions are a set of core extensions beyond those provided by ActiveS
#### Shared

* core_ext/shared/nested.rb
* `#deep_clone` - Performs a Marshal based deep clone
* `#delete_path` - Delete the value at the specified nesting
* `#fetch_path` - Fetch the value at the specified nesting
* `#find_path` - Detect which nesting holds the specified value
Expand Down
9 changes: 9 additions & 0 deletions lib/more_core_extensions/core_ext/array/deletes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ def delete_nils
def delete_blanks
delete_if { |i| i.blank? }
end

# Deletes all keys and subkeys that match +key+.
#
# [{:a => {:b => 2, :c => 3}}].deep_delete(:b) # => [{:a => {:c => 3}}]
#
def deep_delete(key)
each { |i| i.deep_delete(key) if i.respond_to?(:deep_delete) }
self
end
end
end

Expand Down
10 changes: 10 additions & 0 deletions lib/more_core_extensions/core_ext/hash/deletes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ def delete_nils
def delete_blanks
delete_if { |k, v| v.blank? }
end

# Deletes all keys and subkeys that match +key+.
#
# {:a => {:b => 2, :c => 3}}.deep_delete(:b) # => {:a => {:c => 3}}
#
def deep_delete(key)
key = [key] unless key.kind_of?(Array)
key.each { |k| delete(k) }
each_value { |v| v.deep_delete(key) if v.respond_to?(:deep_delete) }
end
end
end

Expand Down
15 changes: 15 additions & 0 deletions lib/more_core_extensions/core_ext/shared/nested.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,21 @@ def find_path(val)
end
[]
end

# Create a deep clone of the object. This is similar to deep_dup
# but uses a Marshal based approach instead.
#
# h1 = {:a => "hello"}
# h2 = h1.deep_clone
#
# h1[:a] << " world"
#
# h1[:a] # "hello world"
# h2[:a] # "hello"
#
def deep_clone
Marshal.load(Marshal.dump(self))
end
end
end
end
6 changes: 6 additions & 0 deletions spec/core_ext/array/deletes_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@
expect([nil].delete_blanks).to eq([])
expect([1, [], nil].delete_blanks).to eq([1])
end

it "#deep_delete" do
expect([{}].deep_delete(:c)).to eq([{}])
expect([{:a => {:b => [1, 2], :c => 3}}].deep_delete(:c)).to eq([{:a => {:b => [1, 2]}}])
expect([{:a => {:b => {:c => 1}, :c => 3}}].deep_delete(:c)).to eq([{:a => {:b => {}}}])
end
end
6 changes: 6 additions & 0 deletions spec/core_ext/hash/deletes_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@
expect({:c => nil}.delete_blanks).to eq({})
expect({:a => 1, :b => [], :c => nil}.delete_blanks).to eq({:a => 1})
end

it "#deep_delete" do
expect({}.deep_delete(:c)).to eq({})
expect({:a => {:b => [1, 2], :c => 3}}.deep_delete(:c)).to eq({:a => {:b => [1, 2]}})
expect({:a => {:b => {:c => 1}, :c => 3}}.deep_delete(:c)).to eq({:a => {:b => {}}})
end
end
35 changes: 35 additions & 0 deletions spec/core_ext/shared/nested_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,39 @@
end
end
end

describe "#deep_clone" do
before do
@nested_hash = {'outer' => {:name => 'test', :value => [1, 2], :token => 1}}
@nested_array = [{'outer' => {:name => 'test', :value => [1, 2], :token => 1}}]
end

context "Hash#deep_clone" do
it "deep clones a hash as expected" do
expect(@nested_hash.deep_clone).to eq(@nested_hash)
end

it "doesn't modify the clone if the original is modified" do
clone = @nested_hash.deep_clone
@nested_hash['outer'][:name] << 'stuff'

expect(@nested_hash['outer'][:name]).to eq('teststuff')
expect(clone['outer'][:name]).to eq('test')
end
end

context "Array#deep_clone" do
it "deep clones an array as expected" do
expect(@nested_array.deep_clone).to eq(@nested_array)
end

it "doesn't modify the clone if the original is modified" do
clone = @nested_array.deep_clone
@nested_array[0]['outer'][:name] << 'stuff'

expect(@nested_array[0]['outer'][:name]).to eq('teststuff')
expect(clone[0]['outer'][:name]).to eq('test')
end
end
end
end

0 comments on commit a6065e6

Please sign in to comment.