Реализуйте method_missing в Rails - PullRequest
0 голосов
/ 13 июля 2020

Я использую API OMDB, чтобы узнать об использовании сторонних API в Rails. Я настроил свое приложение, поэтому все, что мне нужно ввести, - это заголовок mov ie и 6 других атрибутов, которые заполняются из API OMDB. Все вызовы методов для получения данных из API очень похожи. Единственное, что изменяется, - это одно слово в имени метода и одно слово в теле метода. Вот один из таких вызовов:

app / services / omdb_service.rb

def get_image_by_title(title)
  response = HTTP.get("http://www.omdbapi.com/?t=#{title}&apikey=123456789").to_s
  parsed_response = JSON.parse(response)
  parsed_response['Poster']
end

Вещи, которые меняются, - это слово после get в имени метода и слово в parsed_response['Poster']. Они будут меняться в зависимости от того, какой атрибут я пытаюсь вернуть.

Я думал, что могу использовать method_missing, чтобы предотвратить дублирование, но мне это не удалось. Вот мой method_missing звонок:

app / services / omdb_service.rb

def method_missing(method, *args)
  if method.to_s.end_with?('_by_title')
    define_method(method) do | args |
      response = HTTP.get("http://www.omdbapi.com/?t=#{args[0]}&apikey=123456789").to_s
      parsed_response = JSON.parse(response)
      parsed_response['args[1]']
    end
  end
end

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

1 Ответ

2 голосов
/ 13 июля 2020

Прежде всего, позвольте мне подчеркнуть, что это не обязательно хороший вариант использования для method_missing, потому что, похоже, нет способа получить понятные имена методов, параметров и т. Д. Тем не менее, я постараюсь ответить на ваш вопрос как можно лучше.

Прежде всего, вам нужно адаптировать именование ваших методов к тем вещам, которые дает вам API, чтобы уменьшить количество параметров. В приведенном вами примере вы хотите изменить вызов метода на get_poster_by_t, потому что poster - это выход, а t - входная переменная на основе URL-адреса и ответа, которым вы поделились.

Следуя этому logi c, вам нужно будет написать пропущенный метод следующим образом:

def method_missing(method, *args)
  if method =~ /\Aget_([^_]+)_by_([^_]+)\z/
    response = HTTP.get("http://www.omdbapi.com/?#{$~[2]}=#{args[0]}&apikey=123456789").to_s
    parsed_response = JSON.parse(response)
    parsed_response[$~[1].capitalize]
  end
end

Затем вы также должны включить правила Ruby для реализации method_missing, а именно вызова super, если ваше правило не соответствует, а также отменяет respond_to_missing?. Это дает вам:

def method_missing(method, *args)
  if method.to_s =~ /\Aget_([^_]+)_by_([^_]+)\z/
    response = HTTP.get("http://www.omdbapi.com/?#{$~[2]}=#{args[0]}&apikey=123456789").to_s
    parsed_response = JSON.parse(response)
    parsed_response[$~[1].capitalize]
  else
    super
  end
end

def respond_to_missing?(method, *args)
  method.to_s =~ /\Aget_([^_]+)_by_([^_]+)\z/ || super
end

См. Также https://makandracards.com/makandra/9821-when-overriding-method_missing-remember-to-override-respond_to_missing-as-well.

Лично я бы не использовал здесь method_missing, а вместо этого go с вызовом выразительного метода - примерно так:

def get_field_by_param(field:, param:, value:)
  response = HTTP.get("http://www.omdbapi.com/?#{param}=#{value}&apikey=123456789").to_s
  parsed_response = JSON.parse(response)
  parsed_response[field]
end

Затем вы можете делать такие вещи, как get_field_by_param(field: "Poster", param: :t, value: "Whatever").

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...