繁体   English   中英

在 Rails 中实现 method_missing

[英]Implement method_missing in Rails

我正在使用 OMDB API 来了解如何在 Rails 中使用 3rd Party api。 我已经设置了我的应用程序,所以我只需要输入电影标题,并且从 OMDB API 填充其他 6 个属性。 从 api 检索数据的所有方法调用都非常相似。 唯一改变的是方法名称中的一个单词和方法体中的一个单词。 这是一个这样的电话:

应用程序/服务/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调用:

应用程序/服务/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调用有什么问题?

首先,让我强调一下,这不一定是method_missing的好用例,因为似乎没有办法获得不言自明的方法名称、参数等。 不过,我会尽量回答你的问题。

首先,你需要对API给你的东西采用你的方法命名,以减少参数的数量。 在您给出的示例中,您希望将方法调用更改为get_poster_by_t因为poster是 output 而t是基于 URL 和您共享的响应的输入变量。

按照这个逻辑,您必须像这样编写缺少的方法:

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")类的操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM