Skip to content

Instantly share code, notes, and snippets.

@pmarreck
Created July 18, 2012 20:41
Show Gist options
  • Save pmarreck/3138743 to your computer and use it in GitHub Desktop.
Save pmarreck/3138743 to your computer and use it in GitHub Desktop.
Ruby ObjectSpace "snapshotter", useful for detecting things like monkeypatches
# Voilà. A way to detect monkeypatches in Ruby.
class Module
@@_class_instance_method_map = {}
@@_class_singleton_method_map = {}
def self.object_space_snapshot
@@_class_instance_method_map = {}
@@_class_singleton_method_map = {}
ObjectSpace.each_object(Module) do |o|
@@_class_instance_method_map[o] = o.instance_methods(false).map{|m| [m, o.instance_method(m).hash] }
@@_class_singleton_method_map[o] = o.singleton_methods(false).map{|m| [m, o.method(m).hash] }
end
end
def self.object_space_differences
ObjectSpace.each_object(Module) do |o|
if @@_class_instance_method_map.key? o
nm = o.instance_methods(false)
nsm = o.singleton_methods(false)
omh = @@_class_instance_method_map[o]
osmh = @@_class_singleton_method_map[o]
om = omh.map(&:first)
osm = osmh.map(&:first)
added = nm - om
added_s = nsm - osm
remov = om - nm
remov_s = osm - nsm
chang = nm.select do |m|
oha = omh.find{|om| m==om[0] }
oh = oha ? oha[1] : false
if oh
o.instance_method(m).hash != oh
else
false
end
end
chang_s = nsm.select do |m|
osha = osmh.find{|om| m==om[0] }
osh = osha ? osha[1] : false
if osh
o.method(m).hash != osh
else
false
end
end
added.each{|a| puts "instance method '#{a}' was added to #{o}"} if added.size > 0
added_s.each{|a| puts "singleton (class) method '#{a}' was added to #{o}"} if added_s.size > 0
remov.each{|r| puts "instance method '#{r}' was removed from #{o}"} if remov.size > 0
remov_s.each{|r| puts "singleton (class) method '#{r}' was removed from #{o}"} if remov_s.size > 0
chang.each{|c| puts "instance method '#{c}' was CHANGED in #{o}"} if chang.size > 0
chang_s.each{|c| puts "singleton (class) method '#{c}' was CHANGED in #{o}"} if chang_s.size > 0
else
puts "#{o.class} #{o} was added"
end
end
end
end
Module.object_space_snapshot
class A
def hello
puts "hello"
end
end
Module.object_space_differences
Module.object_space_snapshot
module B
class C
end
end
class A
alias_method :new_hello, :hello
def hello
puts "hello"
end
def self.hello
puts "class hello"
end
end
A.new.new_hello
Module.object_space_differences
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment