我甚至不确定我问的问题是否正确。我可能错误地处理了这个问题,但基本上我在这里遇到了这种情况:
obj = get_user(params)
obj.profile => {:name => "John D", :age => 40, :sex => "male"} #Has to be of class Hash
obj.profile.name => "John D"
obj.profile[:name] => "John D"
obj.profile.job => nil
所以,基本上,我必须满足所有这些条件,我甚至不确定如何实现这一点(我今天刚刚学习Ruby)。
注意访问内部变量的点符号,否则我只会让profile是一个符号散列。所以我尝试了两种方法,它们只会让我达到
方法1:使配置文件成为OpenStruct
因此,这允许我使用点符号访问姓名、年龄和性别,如果密钥不存在,它会自动返回nil,但是obj.profile的类型是OpenStruct,而不是Hash
方法2:使配置文件成为自己的类
有了这个,我将它们设置为实例变量,如果它们不存在,我可以使用method_missing返回nil。但是,我再次遇到obj.profile不是正确的类型/类的问题
我有什么东西不见了吗?有没有办法区分
obj.profile
obj.profile.name
在getter函数中,并返回散列或其他?
我可以更改我的自定义类为配置文件返回的内容吗,这样它就会返回一个Hash?
我甚至尝试过在get函数中检查obj.profile的args和**kwargs,但它们似乎都没有帮助,或者如果我调用obj.profiletsomething
如果它绝对必须是Hash
:
require 'pp'
module JSHash
refine Hash do
def method_missing(name, *args, &block)
if !args.empty? || block
super(name, *args, &block)
else
self[name]
end
end
end
end
using JSHash
profile = {:name => "John D", :age => 40, :sex => "male"}
pp profile.name # "John D"
pp profile[:name] # "John D"
pp profile.job # nil
pp profile.class # Hash
但最好不要成为Hash
,除非它绝对需要:
require 'pp'
class Profile < Hash
def initialize(hash)
self.merge!(hash)
end
def method_missing(name, *args, &block)
if !args.empty? || block
super(name, *args, &block)
else
self[name]
end
end
end
profile = Profile.new({:name => "John D", :age => 40, :sex => "male"})
pp profile.name
pp profile[:name]
pp profile.job
只需几个哈希键,就可以轻松地定义singleton方法,如:
def define_getters(hash)
hash.instance_eval do
def name
get_val(__method__)
end
def job
get_val(__method__)
end
def get_val(key)
self[key.to_sym]
end
end
end
profile = person.profile #=> {name: "John Doe", age: 40, gender: "M"}
define_getters(profile)
person.profile.name #=> "John Doe"
person.profile.job #=> nil
也反映了变化的值(如果你想知道的话):
person.profile[:name] = "Ralph Lauren"
person.profile.name #=> "Ralph Lauren"
使用这种方法,您不必重写method_missing
、创建从Hash
继承的新类,也不必对Hash
类进行猴子补丁。
但是,为了能够通过方法调用访问未知密钥并返回nil
而不是错误,必须涉及method_missing
。
这个Hash
覆盖将完成您想要做的事情。您所需要做的就是将它包含在您已经加载的一个类文件中。
class Hash
def method_missing(*args)
if args.size == 1
self[args[0].to_sym]
else
self[args[0][0..-2].to_sym] = args[1] # last char is chopped because the equal sign is included in the string, print out args[0] to see for yourself
end
end
end
请参阅以下IRB输出进行确认:
1.9.3-p194 :001 > test_hash = {test: "testing"}
=> {:test=>"testing"}
1.9.3-p194 :002 > test_hash.test
=> "testing"
1.9.3-p194 :003 > test_hash[:test]
=> "testing"
1.9.3-p194 :004 > test_hash.should_return_nil
=> nil
1.9.3-p194 :005 > test_hash.test = "hello"
=> "hello"
1.9.3-p194 :006 > test_hash[:test]
=> "hello"
1.9.3-p194 :007 > test_hash[:test] = "success"
=> "success"
1.9.3-p194 :008 > test_hash.test
=> "success"
1.9.3-p194 :009 > test_hash.some_new_key = "some value"
=> "some value"
1.9.3-p194 :011 > test_hash[:some_new_key]
=> "some value"