在 Rails 中实施 method_missing
Implement method_missing in Rails
我正在使用 OMDB API 了解如何在 Rails 中使用第 3 方 api。我已经设置了我的应用程序,所以我只需输入电影标题和 6 个其他属性,这些属性从 OMDB API 中填充。从 api 检索数据的所有方法调用都非常相似。唯一改变的是方法名中的一个词和方法中的一个词body。这是一个这样的调用:
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
电话有什么问题吗?
首先,让我强调一下,这不一定是 method_missing
的好用例,因为似乎没有办法获得不言自明的方法名称、参数等。不过,我会尽量回答你的问题。
首先,你需要对API给你的东西采用你的方法命名,以减少参数的数量。在您给出的示例中,您希望将方法调用更改为 get_poster_by_t
因为 poster
是输出而 t
是基于 URL 的输入变量以及您分享的回复。
按照这个逻辑,你必须这样写 missing 方法:
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
就我个人而言,我不会在这里使用 method_missing
,而是使用富有表现力的方法调用——像这样:
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")
的操作。
我正在使用 OMDB API 了解如何在 Rails 中使用第 3 方 api。我已经设置了我的应用程序,所以我只需输入电影标题和 6 个其他属性,这些属性从 OMDB API 中填充。从 api 检索数据的所有方法调用都非常相似。唯一改变的是方法名中的一个词和方法中的一个词body。这是一个这样的调用:
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
电话有什么问题吗?
首先,让我强调一下,这不一定是 method_missing
的好用例,因为似乎没有办法获得不言自明的方法名称、参数等。不过,我会尽量回答你的问题。
首先,你需要对API给你的东西采用你的方法命名,以减少参数的数量。在您给出的示例中,您希望将方法调用更改为 get_poster_by_t
因为 poster
是输出而 t
是基于 URL 的输入变量以及您分享的回复。
按照这个逻辑,你必须这样写 missing 方法:
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
就我个人而言,我不会在这里使用 method_missing
,而是使用富有表现力的方法调用——像这样:
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")
的操作。