Created
March 18, 2012 12:08
-
-
Save myabc/2070996 to your computer and use it in GitHub Desktop.
Spike: Extensible Deep Freeze
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
# I didn't want to monkey patch #deep_freeze into core classes, plus I wanted | |
# to have a way to easily add new classes without modifying a case statement or | |
# similar. Plus I wanted a way for people to be able to specify exceptions for | |
# their own classes without patching mine. | |
module IceNine | |
def self.deep_freeze(object) | |
return object if object.frozen? | |
f = Freezer[object.class.name] | |
f.deep_freeze(object) | |
end | |
class Freezer | |
def self.[](name) | |
mod, const = name.to_s.split('::', 2) | |
const_args = RUBY_VERSION > '1.9' ? [mod, false] : mod | |
mod && const_defined?(*const_args) ? const_get(*const_args)[const] : self | |
end | |
def self.deep_freeze(object) | |
object.instance_variables do |ivar| | |
IceNine.deep_freeze(object.instance_variable_get(ivar)) | |
end | |
object.freeze | |
end | |
class Array < self | |
def self.deep_freeze(object) | |
super object.each { |entry| IceNine.deep_freeze(entry) } | |
end | |
end | |
class Hash < self | |
def self.deep_freeze(object) | |
super object.each { |key, value| | |
IceNine.deep_freeze(key) | |
IceNine.deep_freeze(value) | |
} | |
end | |
end | |
class Singleton < self | |
def self.deep_freeze(object) | |
object | |
end | |
end | |
class Numeric < Singleton; end | |
class TrueClass < Singleton; end | |
class FalseClass < Singleton; end | |
class NilClass < Singleton; end | |
class Symbol < Singleton; end | |
end | |
end | |
hash = IceNine.deep_freeze('a' => '1') | |
puts "Hash is frozen: #{hash.frozen?}" | |
puts "Hash Keys are frozen: #{hash.keys.all?(&:frozen?)}" | |
puts "Hash Values are frozen: #{hash.values.all?(&:frozen?)}" | |
array = IceNine.deep_freeze([ 'a', 'b', 'c' ]) | |
puts "Array is frozen: #{array.frozen?}" | |
puts "Array Elements are frozen: #{array.all?(&:frozen?)}" | |
object = IceNine.deep_freeze(Object.new) | |
puts "Object is frozen: #{object.frozen?}" | |
symbol = IceNine.deep_freeze(:symbol) | |
puts "Symbol is frozen: #{symbol.frozen?} (should be false)" |
@myabc oh heh, I see you did the same thing here. Sorry, it's early :) I believe atm rbx needs the same work-around but I need to test against rbx-head, which I'm installing now.
Hmm, looks like rbx has some ivars in each object that I need to exclude from freezing to avoid modifying internal state.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@myabc I updated the original gist with something I think that will work on 1.9. Its a similar technique to something I did in virtus to work around the api differences, without introducing a separate code path to get similar behaviour.