当我这样做调用API时,我得到了哈希。我狡猾地将Hash转换为具有某些对象的相同属性,即方法:D。
而不是item['name']
我可以item.name
。真棒!
以下是Twitter作为代理的一些代码:
module Twitter
class Base
include HTTParty
base_uri 'api.twitter.com'
format :json
default_params api_password: ENV['TWITTER_PASSWORD']
end
refine Base::Hash do
def method_missing(method, *args, &block)
self.has_key?(method.to_s)? self[method.to_s] : super
end
def respond_to?(method, include_private = false)
self.has_key?(method.to_s) || super
end
end
end
然后我可以制作推文模型:
module Twitter
class Tweet < Twitter::Base
class << self
def all
get '/v1.1/tweet'
end
end
end
end
那很酷。这个例子不起作用。它是我真正想要做的一个非常愚蠢的版本:使哈希行为像一个对象。现在你知道发生了什么,让我们告诉你问题:
什么有效:
tweet.first['text']
# => 'this is the text from a hash.'
tweet.first.text
# => 'this is the text from a hash.'
tweet.first.respond_to? text
# => true
什么行不通:
tweet.map(&:text)
# => #<NoMethodError: undefined method `text' for #<Hash:0x007fb1322a1468>>
tweet.sort_by(&:created_at)
# => #<NoMethodError: undefined method `created_at' for #<Hash:0x007fb1322a1468>>
我的元编程大脑被炸了。我已经走到了这一步。有没有人对我可以做的其他事情有任何想法,以便使用#map
和#sort_by
等方法来处理块?
更新:
我决定了解#sort_by
失败的原因。仍然无法回答这个问题,但这是我的调查:
tweet = Twitter::Tweet.all
tweet.sort_by(&:created_at)
# => undefined method `created_at' for #<Hash:0x007f9ae28ccfb0>
这增加了一些背景。现在找出tweet
的上下文中的#sort_by
:
tweet.method(:sort_by)
# => #<Method: Array(Enumerable)#sort_by>
现在我们有更多的背景。
解决:
考虑到Array
是瓶颈,我决定采用这种方式:
def all
respone = get '/v1/tweet.json'
array = []
response.each do |res|
array << RecursiveOpenStruct.new(res)
end
array
end
但是 不适合应用程序扩展。我打算使用after_action
,但发现我需要一张桌子。我甚至没有按下tableless model path。
因此我决定重新开启HTTParty
并重做#get
以满足自己的需要。第一步是更新Gemfile以确保我坐在一个版本然后我这样做了:
module HTTParty
module ClassMethods
def get(path, options={}, &block)
response = perform_request Net::HTTP::Get, path, options, &block
methodize_array response if response.is_a? Array
end
def methodize_array(response)
array = []
response.each do |res|
array << RecursiveOpenStruct.new(res)
end
array
end
end
end
现在我可以通过一个可扩展且有效的API调用哈希方法。如果有人有任何意见,请告诉我。
答案 0 :(得分:2)
使用openstruct,内置:
# require 'ostruct'
hash = {a: 1, b: 2}
object = OpenStruct.new hash
object.a # => 1
如果您有嵌套结构,use a gem like this或do it yourself like this
然后,您就可以使用所有sort_by
或map
方法,并且肯定会获得更好的效果。
答案 1 :(得分:0)
也许尝试Hashie并在Twitter结果中加入MethodAccess
扩展名。以下是文档中的示例:
class MyHash < Hash
include Hashie::Extensions::MethodAccess
end
h = MyHash.new
h.abc = 'def'
h.abc # => 'def'
h.abc? # => true