Defining “method_called”.. How do I make a hook method which gets called every time any function of a class gets called?

前端 未结 3 1329
北海茫月
北海茫月 2020-12-23 23:43

I want to make a hook method which gets called everytime any function of a class gets called. I have tried method_added, but it executes only once at the time of class defin

3条回答
  •  时光说笑
    2020-12-23 23:52

    I recently wrote something that might be useful, though there are some provisos (see below). Here's the class you want to add your hook to:

    class Original  
      def regular_old_method msg
        puts msg
      end
    
    private
    
      def always_called method_called
        puts "'#{method_called.to_s.capitalize}' method's been called!"
      end
    end
    

    And here's the code for adding that hook:

    class << Original
      def new(*args)
        inner = self.allocate
        outer_name = self.name + 'Wrapper'
        outer_class = Class.new do
          def initialize inner_object
            @inner = inner_object
          end
          def method_missing method_called, *args
            @inner.send method_called, *args
            @inner.send :always_called, method_called
          end
        end
        outer_class_constant = Object.const_set(outer_name, outer_class)
        inner.send :initialize, *args
        outer_class_constant.new inner
      end
    end
    

    If you call it like this...

    o = Original.new
    o.regular_old_method "nothing unusual about this bit"
    

    You get the following output:

    nothing unusual about this bit

    'Regular_old_method' method's been called!

    This approach would be a bad idea if your code checked class names, because even though you've asked for an object of class 'Original', what you got back was an object of class 'OriginalWrapper'.

    Plus I imagine there could be other drawbacks to messing with the 'new' method, but my knowledge of Ruby metaprogramming doesn't stretch that far yet.

提交回复
热议问题