Created
March 16, 2010 14:16
-
-
Save shawn42/334007 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
class Object | |
# Define a deep_freeze method in Object (based on code posted by flavorrific | |
# http://flavoriffic.blogspot.com/2008/08/freezing-deep-ruby-data-structures.html) | |
# that will call freeze on the top-level object instance | |
# the method is called on and any child object instances contained in the | |
# parent. This patch will also raise an IndexError if keys from | |
# ‘deeply frozen’ Hashes or Arrays are accessed that do not exist. | |
# adapted by shawn42 from | |
# http://www.semintelligent.com/blog/articles/29/freezing-ruby-data-structures-recursively | |
def deep_freeze | |
# added to prevent infinite recursion | |
return if @deep_frozen | |
@deep_frozen = true | |
# String doesn’t support each | |
if (self.class != String) && (self.respond_to? :each) | |
each { |v| | |
v.deep_freeze if v.respond_to?(:deep_freeze) | |
} | |
end | |
# Deep freeze instance variable values | |
if self.kind_of? Object | |
self.instance_variables.each { |v| | |
iv = self.instance_variable_get(v) | |
iv.deep_freeze | |
self.instance_variable_set(v, iv) | |
} | |
end | |
if self.kind_of? Hash | |
instance_eval(<<EOF) | |
def default(key) | |
raise IndexError, “Frozen hash: key ‘\#{key}’ does not exist!” | |
end | |
EOF | |
end | |
# Prevent user from accessing array elements that do not exist. | |
if self.kind_of? Array | |
instance_eval(<<EOF) | |
def at(index) | |
self.fetch(index) | |
end | |
def [](arg1, arg2 = nil) | |
results = Array.new | |
if ! arg2.nil? | |
# Start index and end index given | |
arg1.upto(arg1 + arg2) { |index| | |
results << self.fetch(index) | |
} | |
else | |
if arg1.kind_of? Range | |
# Range passed in | |
arg1.each { |index| | |
results << self.fetch(index) | |
} | |
else | |
results << self.fetch(arg1) | |
end | |
end | |
results | |
end | |
EOF | |
end | |
# Freeze the current structure | |
freeze | |
end | |
end | |
if $0 == __FILE__ | |
class Foo | |
attr_accessor :innerz | |
end | |
f = Foo.new | |
f.innerz = [] | |
f.deep_freeze | |
begin | |
f.innerz << 1 | |
rescue | |
# good | |
end | |
f = Foo.new | |
f.innerz = [f] | |
f.deep_freeze | |
begin | |
f.innerz[99] | |
rescue | |
# good, don't want default objects created for these keys | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment