简体   繁体   English

在实例方法中动态定义方法

[英]Dynamically define a method inside an instance method

I am working on a project of context-oriented programming in ruby. 我正在使用ruby进行上下文相关编程的项目。 And I come to this problem: 我遇到了这个问题:

Suppose that I have a class Klass: 假设我有一个班级Klass:

class Klass
    def my_method
        proceed
    end
end

I also have a proc stored inside a variable impl . 我还有一个存储在变量impl的proc。 And impl contains { puts "it works!" } 并且impl包含{ puts "it works!" } { puts "it works!" } . { puts "it works!" }

From somewhere outside Klass, I would like to define a method called proceed inside the method my_method . 我想在Klass之外的某个地方定义一个名为my_method的方法,称为proceed So that if a call Klass.new.my_method , I get the result "it works" . 这样,如果调用Klass.new.my_method ,我得到的结果是"it works"

So the final result should be something like that: 所以最终结果应该是这样的:

class Klass
    def my_method
        def proceed
            puts "it works!"
        end
        proceed
    end
end

Or if you have any other idea to make the call of proceed inside my_method working, it's also good. 或者,如果您有任何其他想法,使的呼叫proceed内部my_method工作,这也不错。 But the proceed of another method (let's say my_method_2 ) isn't the same as my_method . proceed另一种方法(假设my_method_2 )是不一样的my_method In fact, the proceed of my_method represent an old version of my_method . 事实上, proceedmy_method代表的是旧版本的my_method And the proceed of my_method_2 represent an old version of my_method_2 . proceedmy_method_2代表的是旧版本的my_method_2

Thanks for your help 谢谢你的帮助

Disclaimer: you are doing it wrong! 免责声明: 您做错了!

There must be more robust, elegant and rubyish way to achieve what you want. 必须有更健壮,优雅和红宝石的方式来实现您想要的。 If you still want to abuse metaprogramming, here you go: 如果您仍然想滥用元编程,请执行以下操作:

class Klass
  def self.proceeds
    @proceeds ||= {}
  end

  def def_proceed
    self.class.proceeds[caller.first[/`.*?'/]] = Proc.new
  end

  def proceed *args
    self.class.proceeds[caller.first[/`.*?'/]].(*args)
  end

  def m_1
    def_proceed { puts 1 }
    proceed
  end

  def m_2
    def_proceed { puts 2 }
    proceed
  end
end

inst = Klass.new

inst.m_1
#⇒ 1
inst.m_2
#⇒ 2

What you in fact need, is Module#prepend and call super from there. 实际上,您需要的是Module#prepend并从那里调用super

One way of doing that is to construct a hash whose keys are the names of the methods calling proceed and whose values are procs that represent the implementations of proceed for each method calling it. 这样做的一个方法是建立一个哈希的键是的调用方法的名称proceed ,其值是代表了实现特效proceed为每个方法调用它。

class Klass
  singleton_class.send(:attr_reader, :proceeds)
  @proceeds = {}
  def my_method1(*args)
    proceed(__method__,*args)
  end
  def my_method2(*args)
    proceed(__method__,*args)
  end
  def proceed(m, *args)
    self.class.proceeds[m].call(*args)
  end
end

def define_proceed(m, &block)
  Klass.proceeds[m] = Proc.new &block
end

define_proceed(:my_method1) { |*arr| arr.sum }
define_proceed(:my_method2) { |a,b| "%s-%s" % [a,b] }

k = Klass.new
k.my_method1(1,2,3)        #=> 6
k.my_method2("cat", "dog") #=> "cat-dog"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM