Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #260 from jphager2/issue-253
add deep_freeze refinement to support
- Loading branch information
Showing
6 changed files
with
188 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
module Pakyow | ||
module Support | ||
module DeepFreeze | ||
refine Object.singleton_class do | ||
def unfreezable_variables | ||
@unfreezable_variables ||= [] | ||
end | ||
|
||
private | ||
|
||
def unfreezable(*ivars) | ||
ivars = ivars.map { |ivar| "@#{ivar}".to_sym } | ||
unfreezable_variables.concat(ivars) | ||
unfreezable_variables.uniq! | ||
end | ||
end | ||
|
||
refine Object do | ||
def deep_freeze | ||
return self if frozen? | ||
|
||
self.freeze | ||
|
||
freezable_variables.each do |name| | ||
instance_variable_get(name).deep_freeze | ||
end | ||
|
||
self | ||
end | ||
|
||
private | ||
|
||
def freezable_variables | ||
instance_variables - self.class.unfreezable_variables | ||
end | ||
end | ||
|
||
refine Array do | ||
def deep_freeze | ||
return self if frozen? | ||
|
||
self.freeze | ||
|
||
each(&:deep_freeze) | ||
|
||
self | ||
end | ||
end | ||
|
||
refine Hash do | ||
def deep_freeze | ||
return self if frozen? | ||
|
||
frozen_hash = {} | ||
|
||
each_pair do |key, value| | ||
frozen_hash[key.deep_freeze] = value.deep_freeze | ||
end | ||
|
||
self.replace(frozen_hash) | ||
|
||
self.freeze | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
require "pakyow/support/deep_freeze" | ||
|
||
using Pakyow::Support::DeepFreeze | ||
|
||
class MyObject | ||
unfreezable :fire | ||
|
||
attr_reader :fire, :water | ||
|
||
def initialize | ||
@fire = 'fire' | ||
@water = 'water' | ||
end | ||
end | ||
|
||
RSpec.describe Pakyow::Support::DeepFreeze do | ||
let :obj_with_unfreezable { | ||
MyObject.new | ||
} | ||
|
||
describe "deep_freeze" do | ||
it "returns the object" do | ||
obj = Object.new | ||
|
||
expect(obj.deep_freeze.object_id).to be(obj.object_id) | ||
end | ||
|
||
it "deep freezes an Object without ivars" do | ||
obj = Object.new | ||
obj.deep_freeze | ||
|
||
expect(obj).to be_frozen | ||
end | ||
|
||
it "deep freezes an Object with ivars" do | ||
ivar_value = Object.new | ||
obj = Object.new | ||
obj.instance_variable_set(:@ivar_name, ivar_value) | ||
|
||
obj.deep_freeze | ||
|
||
expect(obj).to be_frozen | ||
expect(ivar_value).to be_frozen | ||
end | ||
|
||
it "deep freezes ivars" do | ||
objects = Array.new(5) { Object.new } | ||
objects.reduce do |parent, child| | ||
parent.instance_variable_set(:@child, child) | ||
end | ||
|
||
objects.first.deep_freeze | ||
|
||
objects.each do |obj| | ||
expect(obj).to be_frozen | ||
end | ||
end | ||
|
||
it "deep freezes ivars without loop" do | ||
objects = Array.new(5, Object.new) | ||
objects.reduce do |parent, child| | ||
parent.instance_variable_set(:@child, child) | ||
end | ||
|
||
objects.first.deep_freeze | ||
|
||
objects.each do |obj| | ||
expect(obj).to be_frozen | ||
end | ||
end | ||
|
||
it "deep freezes array items" do | ||
objects = Array.new(5) { Object.new } | ||
|
||
objects.deep_freeze | ||
|
||
objects.each do |obj| | ||
expect(obj).to be_frozen | ||
end | ||
|
||
expect(objects).to be_frozen | ||
end | ||
|
||
it "deep freezes hash keys values" do | ||
object = { one: Object.new, 'two': Object.new, Object.new => Object.new } | ||
|
||
object.deep_freeze | ||
|
||
object.each_pair do |key, value| | ||
expect(key).to be_frozen | ||
expect(value).to be_frozen | ||
end | ||
|
||
expect(object).to be_frozen | ||
end | ||
|
||
it "doesn't freeze unfreezeable" do | ||
obj_with_unfreezable.deep_freeze | ||
|
||
expect(obj_with_unfreezable).to be_frozen | ||
expect(obj_with_unfreezable.water).to be_frozen | ||
expect(obj_with_unfreezable.fire).not_to be_frozen | ||
end | ||
|
||
it "returns an array of unfreezeable ivars" do | ||
vars = MyObject.unfreezable_variables | ||
|
||
expect(vars).to be_instance_of(Array) | ||
end | ||
end | ||
end | ||
|