将类方法传递给另一个方法来调用

时间:2012-08-16 20:11:53

标签: ruby

我写的内容如下

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),但也许有一些陷阱......

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

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

method_caller(Test, :print, 2)

其他调用需要使用self作为接收器,这在您当前的实现中是隐含的。但最后所有这些都是send的一个不完整的临时重新实现,所以人们真的很想知道你想要实现的目标。

答案 2 :(得分:0)

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

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

或者将方法对象作为参数

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

顺便说一下,哪个对象响应#call(labmdas,...)