проблемы с Ruby Dynami c вызов метода - PullRequest
1 голос
/ 11 апреля 2020

Я создаю что-то поверх Ruby API Elasticsearch и имею обычную проблему 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>

Я пробовал self.send и другие различные подходы, но я не могу заставить это работать. Все мои усилия привели к «неопределенному методу».

Может кто-нибудь указать, что мне не хватает?

1 Ответ

0 голосов
/ 11 апреля 2020

Вы можете сделать что-то вроде этого:

r = api_method.split('.').inject(@es_conn.client) { |obj, m| obj.public_send(m) }

, если вы хотите поддерживать цепочки произвольных методов. Это позволит использовать любые точки в @method_prefix и method. Если вы тоже хотите разрешить закрытые методы, то:

r = api_method.split('.').inject(@es_conn.client) { |obj, m| obj.send(m) }

Это предполагает, что вы управляете всем и не допускаете какого-либо внешнего ввода в @method_prefix или method; если вы разрешаете ввод данных извне, то вам действительно нужно занести все в белый список, чтобы избежать вызова неожиданных и опасных методов.

Редактировать: если вам нужно передать параметры в последний вызов, вам нужно сделать что-то вроде этого:

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

, чтобы добавить параметр в последний вызов. Вероятно, есть более элегантный способ сделать это;)

...