如何拦截ruby中的方法调用?

我目前有一个超类,它有一个函数,我希望所有的子类都在它的每个函数中调用。 该函数应该像rails中的before_filter函数一样,但我不确定如何实现before_filter。 这是一个例子

class Superclass def before_each_method 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 

这是一种方法:

 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 

只要在子类中定义了要包装的方法,就会使用alias_method_chaining方法创建一个包装器方法。

这是我的解决方案:

 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 

要使用它,只需将BeforeEach包含在您的类中,如下所示:

 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 

希望这对你有用!

 class BalanceChart < BalanceFind include ExecutionHooks attr_reader :options def initialize(options = {}) @options = options @begin_at = @options[:begin_at] end def months_used range.map{|date| I18n.l date, format: :month_year}.uniq! end before_hook :months_data, :months_used, :debits_amount end module ExecutionHooks def self.included(base) base.send :extend, ClassMethods end module ClassMethods def before @hooks.each do |name| m = instance_method(name) define_method(name) do |*args, &block| return if @begin_at.blank? ## the code you can execute before methods m.bind(self).(*args, &block) ## your old code in the method of the class end end end def before_hook(*method_name) @hooks = method_name before end def hooks @hooks ||= [] end end end