首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何拦截类方法调用,而不仅仅是实例方法调用

如何拦截类方法调用,而不仅仅是实例方法调用
EN

Stack Overflow用户
提问于 2013-06-27 12:42:13
回答 1查看 763关注 0票数 0

有没有人可以帮我修改一下intercepting instance method calls的答案,让它既可以用于类方法调用,也可以用于类方法调用和实例方法调用?从我有限的Ruby元编程知识来看,我想这可能与使用class << self在某个地方打开单例类有关,但是我尝试过在不同的地方使用这段代码来做这件事,但我似乎无法理解它。不过,你能不能给我一个正确的方向,而不是直接的回答?我是一个狂热的粉丝,除非我完全超出了我的能力范围,否则我会自己解决问题。谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-06-27 15:06:27

以下是我根据您提供的链接中的答案修改的解决方案。我将钩子逻辑从超类移到了一个单独的模块中,这样当一个类需要钩子时,它只需要包含或扩展该模块并调用钩子方法。

  • before_each_method type, &block - type可以是:class:instance,块是在每个方法之前执行的代码。块将在特定环境下进行评估,例如方法,块中的别名是实例;对于类方法,块中的别名是before_each_method :instance, &block

的class.

  • before_class_method &block - self的别名

代码语言:javascript
运行
复制
module MethodHooker
  def self.included(base)
    base.extend(ClassMethods)
  end
  def self.extended(base)
    base.extend(ClassMethods)
  end
  module ClassMethods
    def before_each_method type, &block
      singleton = class << self; self; end
      case type
      when :instance
        this = self
        singleton.instance_eval do
          define_method :method_added do |name|
            last = instance_variable_get(:@__last_methods_added)
            return if last and last.include?(name)
            with = :"#{name}_with_before_each_method"
            without = :"#{name}_without_before_each_method"
            instance_variable_set(:@__last_methods_added, [name, with, without])
            this.class_eval do
              define_method with do |*args, &blk|
                instance_exec(name, args, blk, &block)
                send without, *args, &blk
              end
              alias_method without, name
              alias_method name, with
            end
            instance_variable_set(:@__last_methods_added, nil)
          end
        end
      when :class
        this = self
        singleton.instance_eval do
          define_method :singleton_method_added do |name|
            return if name == :singleton_method_added
            last = instance_variable_get(:@__last_singleton_methods_added)
            return if last and last.include?(name)
            with = :"#{name}_with_before_each_method"
            without = :"#{name}_without_before_each_method"
            instance_variable_set(:@__last_singleton_methods_added, [name, with, without])
            singleton.class_eval do
              define_method with do |*args, &blk|
                instance_exec(name, args, blk, &block)
                send without, *args, &blk
              end
              alias_method without, name
              alias_method name, with
            end
            instance_variable_set(:@__last_singleton_methods_added, nil)
          end
        end
      end
    end
    def before_class_method &block
      before_each_method :class, &block
    end
    def before_instance_method &block
      before_each_method :instance, &block
    end
  end
end

class Test
  extend MethodHooker
  before_each_method :instance do |method, args, block|
    p [method, args, block]
    puts "before instance method(#{method}) #{@var}"
  end
  before_class_method do |method, args, block|
    puts "before class method(#{method}) #{@class_instance_var}"
  end
  @class_instance_var = 'stackoverflow'
  def initialize
    @var = 1
  end
  def test(a, b, c)
    puts "instance method test"
  end
  def self.test1
    puts "class method test"
  end
end

Test.new.test(1, "arg2", [3]) {|t| t}
Test.test1

输出将类似于:

代码语言:javascript
运行
复制
[:initialize, [], nil]
before instance method(initialize)
[:test, [1, "arg2", [3]], #<Proc:0x00000001017d5eb8@/Users/test/before_method.rb:88>]
before instance method(test) 1
instance method test
before class method(test1) stackoverflow
class method test
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17334683

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档