0

我正在写如下内容

module Test
   def self.print(*args)
      p 'something'
      p args
   end
end

def print(*args)
  p "print something"
  p args
end

def method_caller(method_name, *args)
  send(method_name, *args)
end

method_caller(:print, 2) # this works fine
method_caller("print", 2, 3) # this one also
method_caller("Test.print", 2) # this doesn't work

基本上,我传递method_caller了一个方法的名称和一些参数,然后我使用该send方法来实际调用该方法。

我通常将方法的名称作为符号传递,但我将如何处理Test.print?我想在某些时候我可能会传入对象并让它们调用自己的方法。

我想调用的方法实际上可以在任何地方。

更新:

尝试每个建议,显式接收器看起来是一个很好的方法,因为很明显正在发生什么,但是 christianblais 的想法呢。我改变了它以避免eval这样的电话

def method_caller(method_name, *args)
  if method_name.is_a?(String)
    chain = method_name.split('.')
    obj, method_name = Object.const_get(chain[0...-1].join('.')), chain[-1]
    obj.send(method_name, *args)
  else
    send(method_name, args)
  end
end

这意味着我只能说method_caller("Test.print", 2),但也许有一些陷阱......

4

3 回答 3

1

这里有两件事。

1)您的示例不起作用,因为您尝试使用参数调用 Test.print 而您的方法定义不接受参数。 编辑:刚刚看到你的更新。现在好了。对不起!

2)这是邪恶的,但你总是可以像这样使用 eval :

module Test
   def self.print(*args)
     p 'something'
     p args
   end
end

def method_caller(method_name, *args)
  if method_name.is_a?(String)
    chain = method_name.split('.')
    eval(chain[0...-1].join('.')).send(chain.last, args)
  else
    send(method_name, args)
  end
end

method_caller(:print, 2) # this works fine
method_caller("print", 2, 3) # this one also
method_caller("Test.print", 2) # this doesn't work
于 2012-08-16T20:26:29.847 回答
1

那么,你为什么不给你的 method_caller 一个接收器参数呢?

def method_caller(receiver, method_name, *args)
  receiver.send(method_name, *args)
end

method_caller(Test, :print, 2)

其他调用需要self用作接收器,这在您当前的实现中是隐含的。但最后这一切给你的是一个不完整的临时重新实现send,所以人们真的想知道你想用它来实现什么。

于 2012-08-16T20:27:37.430 回答
0

传递作为字符串调用的方法是一个要求还是只是你的一个想法?一个更红宝石的解决方案是简单地传递一个块......

method_caller(2) { |*args| Object.print(*args) }

或将方法对象作为参数

method_caller(Object.method(:print), 2)

顺便说一句,它适用于任何响应 #call (labmdas, ...) 的对象

于 2012-08-17T14:23:42.430 回答