Created
April 8, 2024 16:34
-
-
Save pocke/ba106e74efe42b87c8cf071f112a7a97 to your computer and use it in GitHub Desktop.
Get core exts
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
module Monkey | |
extend self | |
MODULE_NAME = Module.instance_method(:name) | |
MODULE_SINGLETON_CLASS_P = Module.instance_method(:singleton_class?) | |
MODULE_SINGLETON_CLASS = Module.instance_method(:singleton_class) | |
MODULE_INSTANCE_METHODS = Module.instance_method(:instance_methods) | |
MODULE_INSTANCE_METHOD = Module.instance_method(:instance_method) | |
CLASS_ATTACHED_OBJECT = Class.instance_method(:attached_object) rescue nil | |
IS_A = Object.instance_method(:is_a?) | |
def diff | |
clean = clean_env | |
dirty = dirty_env | |
clean.each do |mod_key, methods| | |
mod, singleton_p = mod_key | |
d = dirty[mod_key] | |
methods.each do |method_name, clean_info| | |
dirty_info = d[method_name] | |
if clean_info[:source_location] != dirty_info[:source_location] | |
puts "#{mod}#{singleton_p ? '.singleton_class' : ''}##{method_name} has changed" | |
puts " clean: #{clean_info[:source_location]}" | |
puts " dirty: #{dirty_info[:source_location]}" | |
end | |
end | |
d.each do |method_name, dirty_info| | |
next if methods.key?(method_name) | |
puts "#{mod}#{singleton_p ? '.singleton_class' : ''}##{method_name} has been added" | |
puts " dirty: #{dirty_info[:source_location]}" | |
end | |
end | |
end | |
def clean_env | |
with_unbundled_env do | |
Marshal.load(`ruby --disable-gems -r #{File.expand_path(__FILE__)} -e 'puts Marshal.dump(Monkey.collect)'`) | |
end | |
end | |
def dirty_env | |
collect | |
end | |
def collect | |
h = {} | |
modules.each do |m| | |
next if ARGF.class == m | |
singleton_p = MODULE_SINGLETON_CLASS_P.bind_call(m) | |
if MODULE_NAME.bind_call(m) && !singleton_p | |
mod_key = [m, false] | |
elsif singleton_p && (a = attached_object(m)) && IS_A.bind_call(a, Class) && MODULE_NAME.bind_call(a) | |
mod_key = [a, true] | |
else | |
next | |
end | |
next if Monkey == mod_key[0] | |
h[mod_key] = {} | |
MODULE_INSTANCE_METHODS.bind_call(m).each do |method_name| | |
method = MODULE_INSTANCE_METHOD.bind_call(m, method_name) | |
h[mod_key][method_name] = { | |
source_location: method.source_location, | |
} | |
end | |
end | |
h | |
end | |
def attached_object(klass) | |
return CLASS_ATTACHED_OBJECT.bind_call(klass) if CLASS_ATTACHED_OBJECT | |
modules.find do |m| | |
IS_A.bind_call(m, Class) && MODULE_SINGLETON_CLASS.bind_call(m) == klass | |
end | |
end | |
def modules | |
@modules ||= ObjectSpace.each_object(Module).to_a | |
end | |
def with_unbundled_env(&block) | |
if defined?(::Bundler) | |
Bundler.with_unbundled_env(&block) | |
else | |
block.call | |
end | |
end | |
end | |
Monkey.diff if defined?(::Gem) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Requirement
No
--disable-gems
Example