How can I intercept method call in ruby?

This is one way to do it:

class Superclass
  def before_each_method name
    p [:before_method, name]
  end

  def self.method_added name
    return if @__last_methods_added && @__last_methods_added.include?(name)
    with = :"#{name}_with_before_each_method"
    without = :"#{name}_without_before_each_method"
    @__last_methods_added = [name, with, without]
    define_method with do |*args, &block|
      before_each_method name
      send without, *args, &block
    end
    alias_method without, name
    alias_method name, with
    @__last_methods_added = nil
  end
end

class SubclassA < Superclass
  def my_new_method
    p :my_new_method
  end

  def my_new_other_method
    p :my_new_other_method
  end
end

SubclassA.new.my_new_method
SubclassA.new.my_new_other_method

This will create a wrapper method using the alias_method_chaining method as soon as the method you'd like to wrap is defined in the subclass.


This is my solution:

require 'active_support/all'

module BeforeEach
  extend ActiveSupport::Concern

  module InstanceMethods
    def before_each
      raise NotImplementedError('Please define before_each method')
    end
  end

  module ClassMethods
    def method_added(method)
      method = method.to_s.gsub(/_with(out)?_before$/, '')
      with_method, without_method = "#{method}_with_before", "#{method}_without_before"

      return if method == 'before_each' or method_defined?(with_method)

      define_method(with_method) do |*args, &block|
        before_each
        send(without_method, *args, &block)
      end
      alias_method_chain(method, :before)
    end
  end
end

To use it, just include BeforeEach into your class like so:

class Superclass
  include BeforeEach

  def before_each
    puts "Before Method" #this is supposed to be invoked by each extending class' method
  end
end

class Subclass < Superclass
  def my_method
    #when this method is called, before_each_method method is supposed to get invoked
  end
end

Subclass.new.my_method

# => Before Method

Hopefully this will work for you!

Tags:

Ruby