Ruby动态方法调用的问题

Ruby动态方法调用的问题,ruby,dynamic,Ruby,Dynamic,我在Elasticsearch的Ruby API之上构建了一些东西,并且有许多几乎相同的函数的常见API问题,这些函数实现对底层API的调用并执行错误处理。因此,我想有一个方法来执行与底层API调用相关联的混乱工作: def perform_api_request( method, params ) api_method = "#{@method_prefix}#{method}" puts api_method begin r = @es_conn.client.

我在Elasticsearch的Ruby API之上构建了一些东西,并且有许多几乎相同的函数的常见API问题,这些函数实现对底层API的调用并执行错误处理。因此,我想有一个方法来执行与底层API调用相关联的混乱工作:

 def perform_api_request( method, params ) 

  api_method = "#{@method_prefix}#{method}"
  puts api_method 
  begin 
    r = @es_conn.client.send(api_method, params )
  rescue => e 
    abort "there were errors calling #{method}:#{e}" unless extract_error(e) 
    return false 
  end 
  return true 
end 
我引用的是:

      perform_api_request 'delete_template', { name: @name }
这将产生:

indices.delete_template 
there were errors calling delete_template:undefined method \
   `indices.delete_template' for #<Elasticsearch::Transport::Client:0x0000000282d758>
index.delete\u模板
调用delete_template:undefined方法时出错\
`索引。删除“”的“”模板#
我已经尝试过self.send和其他各种方法,但都无法实现。我所有的努力都导致了“未定义的方法”


有人能指出我遗漏了什么吗?

你可以这样做:

r = api_method.split('.').inject(@es_conn.client) { |obj, m| obj.public_send(m) }
api_method = "#{@method_prefix}#{method}".split('.')
last  = api_method[-1]
r = api_method.inject(@es_conn.client) do |obj, m| 
  m == last ? obj.public_send(m, params) : obj.public_send(m) 
end
如果要支持任意方法链。这将允许在
@method\u prefix
method
中使用所需的任何点。如果您也想允许私有方法,那么:

r = api_method.split('.').inject(@es_conn.client) { |obj, m| obj.send(m) }
这假设您正在控制一切,并且不允许在
@method_prefix
method
中进行任何类型的外部输入;如果您允许外部输入,那么您确实希望将所有内容都列为白名单,以避免调用意外和危险的方法

编辑:如果需要将参数传递给最终调用,则需要执行以下操作:

r = api_method.split('.').inject(@es_conn.client) { |obj, m| obj.public_send(m) }
api_method = "#{@method_prefix}#{method}".split('.')
last  = api_method[-1]
r = api_method.inject(@es_conn.client) do |obj, m| 
  m == last ? obj.public_send(m, params) : obj.public_send(m) 
end

将参数添加到最终调用。可能有一种更优雅的方法;)

您可以这样做:

r = api_method.split('.').inject(@es_conn.client) { |obj, m| obj.public_send(m) }
api_method = "#{@method_prefix}#{method}".split('.')
last  = api_method[-1]
r = api_method.inject(@es_conn.client) do |obj, m| 
  m == last ? obj.public_send(m, params) : obj.public_send(m) 
end
如果要支持任意方法链。这将允许在
@method\u prefix
method
中使用所需的任何点。如果您也想允许私有方法,那么:

r = api_method.split('.').inject(@es_conn.client) { |obj, m| obj.send(m) }
这假设您正在控制一切,并且不允许在
@method_prefix
method
中进行任何类型的外部输入;如果您允许外部输入,那么您确实希望将所有内容都列为白名单,以避免调用意外和危险的方法

编辑:如果需要将参数传递给最终调用,则需要执行以下操作:

r = api_method.split('.').inject(@es_conn.client) { |obj, m| obj.public_send(m) }
api_method = "#{@method_prefix}#{method}".split('.')
last  = api_method[-1]
r = api_method.inject(@es_conn.client) do |obj, m| 
  m == last ? obj.public_send(m, params) : obj.public_send(m) 
end

将参数添加到最终调用。可能有一种更优雅的方法;)

方法名中没有点(send应该有一个符号)。send接受一个符号或字符串,但我接受你关于点的观点。我认为send的第一个参数应该只取最后一项(在本例中为“delete_template”),但我看不出如何将“index”引入调用中。确实如此——但我需要更多字符。哦,对了,字符串通过“send”转换为符号——我的错误。方法名称中没有点(和send应该被赋予一个符号)。send接受符号或字符串,但我接受你关于点的观点。我认为send的第一个参数应该只接受最后一项(在本例中为“delete_template”)但我看不出如何将“索引”转换到调用中。确实如此——但我需要更多字符。哦,对了,字符串通过“发送”转换为符号——我的错。