【问题标题】:Dynamically define a method inside an instance method在实例方法中动态定义方法
【发布时间】:2017-09-01 09:14:59
【问题描述】:

我正在开发一个使用 ruby​​ 进行面向上下文编程的项目。我遇到了这个问题:

假设我有一个类 Klass:

class Klass
    def my_method
        proceed
    end
end

我还有一个存储在变量impl 中的过程。而impl 包含{ puts "it works!" }

在 Klass 之外的某个地方,我想在方法 my_method 中定义一个名为 proceed 的方法。所以如果调用Klass.new.my_method,我会得到"it works"的结果。

所以最终的结果应该是这样的:

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

或者,如果您有任何其他想法可以在 my_method 中调用 proceed,这也很好。但是另一种方法的proceed(比如说my_method_2)与my_method 不同。 事实上,my_methodproceed 代表了旧版本的my_method。而my_method_2proceed 代表my_method_2 的旧版本。

感谢您的帮助

【问题讨论】:

  • 不能在变量中存储块。
  • 你的问题我不清楚。为什么需要定义一个定义方法的方法?为什么不能一开始就定义一个方法或调用正确的方法?
  • 对不起,我说错了,我的意思是一个程序。我编辑了我的问题。事实上,我的程序通过根据上下文添加、删除、更新方法来修改一个类。有时,新版本的方法会使用旧版本的方法。所以proceed方法代表这个旧版本。
  • 请注意,将来可能会弃用方法体内的方法定义表达式,以便为向 Ruby 添加本地过程做准备。

标签: ruby methods dynamic


【解决方案1】:

免责声明: 你做错了!

必须以更健壮、更优雅、更优雅的方式来实现你想要的。如果您仍然想滥用元编程,请继续:

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

您实际上需要的是Module#prepend 并从那里调用super

【讨论】:

  • 确实如此。我也想用 Hash 来实现一些东西,但是很懒。您的免责声明也很重要。
  • 我会调查prepend。谢谢!
【解决方案2】:

这样做的一种方法是构造一个散列,其键是调用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"

【讨论】:

    猜你喜欢
    • 2012-07-04
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 2012-02-17
    • 1970-01-01
    • 2011-11-15
    • 1970-01-01
    相关资源
    最近更新 更多