title: Wrapping a class method?
body: <p>I have a module I'd like to be able to wrap every method in a class, whether it be an instance method or a class method, but am having a bit of trouble trying to get it to work in both circumstances. Below is what I have right now, it works for wrapping instance methods but calling class methods doesn't seem to work. I assume the module proxy isn't installed correctly for overriding class methods, but I'm not sure what to do to fix that.</p>
  <p>I'm limited to ruby 2.7, btw.</p>
  <pre><code>module Wrapper
    def self.included(base)
      base.extend(ClassMethods)
    end
  
    module ClassMethods
      module Proxy
      end
  
      def wrap_method(name)
        puts &quot;wrapping #{name}&quot;
        Proxy.define_method(name) do |*args|
          puts &quot;in wrap_method, about to call #{name}&quot;
          super *args
        end
      end
  
      def wrap_methods
        # wrap any methods that were defined before this was called
        self.instance_methods(false).each {|name| wrap_method(name) }
        self.singleton_methods(false).each {|name| wrap_method(name) }
  
        # wrap any methods that are defined after this is called
        self.class.define_method(:singleton_method_added) do |name|
          if respond_to?(:wrap_method)
            wrap_method(name)
          end
        end
        self.class.define_method(:method_added) do |name|
          if respond_to?(:wrap_method)
            wrap_method(name)
          end
        end
        self.prepend(Proxy)
      end
    end
  end
  
  module Top
    module Second
      class Main
        include Wrapper
  
        wrap_methods
  
        def self.first_class_method
          puts &quot;in self.first_class_method&quot;
        end
  
        def self.second_class_method
          puts &quot;in self.second_class_method&quot;
        end
  
        def some_instance_method
          puts &quot;in some_instance_method&quot;
        end
  
      end
    end
  end
  
  Top::Second::Main.first_class_method
  Top::Second::Main.second_class_method
  Top::Second::Main.new.some_instance_method
  </code></pre>
  <p>Output:</p>
  <pre><code>wrapping first_class_method
  wrapping second_class_method
  wrapping some_instance_method
  in self.first_class_method
  in self.second_class_method
  in wrap_method, about to call some_instance_method
  in some_instance_method
  </code></pre>