使用define_method和以下ruby文档

时间:2012-11-19 20:26:45

标签: ruby metaprogramming

尽管尝试了很多次,但我无法使用define_method()创建方法并提供方法。

如果我理解可在此处找到的Module类的文档http://www.ruby-doc.org/core-1.9.3/Module.html,我应该可以执行以下任一操作:

define_method(symbol,method)→new_method

define_method(symbol){block}→proc

我可以使用define_method(symbol){block}然而我收到的似乎是一个方法(不是我链接到的文档中概述的proc):

class M
  define_method(:hello) { puts "Hello World!"}
end

M.new.hello

我的两个问题是:  1.做到这一点我似乎没有收到过程,尽管医生明确说明我会得到的。  2.我不知道如何为“define_method(symbol,method)→new_method”提供方法,我试着谷歌搜索无效,不知道如何使用这种形式的define_method。

如果有人能够对此有所了解,我将不胜感激! :)非常感谢!

2 个答案:

答案 0 :(得分:0)

define_method确实会返回ProcMethod,具体取决于使用情况。

在第一种情况下,返回Proc

class Test
  x = define_method :test_method { nil }
  puts x.inspect
end


Test.new.test_method

在控制台输出上运行以上内容:

#<Proc:0x007fe12104e228@test.rb:3 (lambda)>

第二种情况返回UnboundMethod,这是一种Method

class Test2 < Test
  y = define_method :test_method2, Test.instance_method(:test_method)
  puts y.inspect
end

Test2.new.test_method2

以上输出

#<UnboundMethod: Test#test_method>

这是一个非常人为的例子,定义一个传递给define_method的方法在这种情况下并没有用,我也不能想到它会出现的情况。

答案 1 :(得分:0)

您可以通过在类中定义一个方法来实现:

class TestClass
  def a_method
  end
  # Store the method in a class variable; define_method is a Module 
  # method and needs to be called from within this context
  @@x = define_method(:another_method, TestClass.new.method(:a_method))
  def x
    @@x
  end

  # And to get a block...
  @@y = define_method(:yet_another_method) {}
  def y
    @@y
  end
end

调用x方法,你会得到类似的结果:

TestClass.new.x
#<Method: TestClass#a_method>

调用y方法时,你会得到类似的结果:

TestClass.new.y
#<Proc:0x00000000aebc30@(irb):75 (lambda)>

这里棘手的部分是你需要一个来自同一个类(或超类)的对象的方法,你正在做define_method,否则它不起作用。例如,如果您替换@@x行:

...
@@x = define_method(:another_method, String.new.method(:gsub))
...

由于TypeError不是TestClass的子类,因此获得了以下String

TypeError: bind argument must be a subclass of String

观察此工作:

...
@@x = define_method(:another_method, Object.new.method(:object_id))
...

输出类似于:

TestClass.new.x
#<Method: Object(Kernel)#object_id>

我认为需要来自同一类层次结构的方法的原因是强制执行OO代码封装和隐私(否则您可以通过从另一个类传递方法来访问私有方法和变量)。