我不确定我是否在问正确的问题。我可能不正确地接近这个问题,但基本上我有这种情况:
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 而不是哈希
方法2:使个人资料成为自己的类
通过这个我将它们设置为实例变量,如果它们不存在,我可以使用 method_missing 返回nil。但是,我再次遇到 obj.profile 不是正确类型/类的问题
有什么我想念的吗?有没有办法可以区分
obj.profile
obj.profile.name
在getter函数中并返回哈希或其他?
我可以更改自定义类为配置文件返回的内容,因此它会返回Hash吗?
我甚至尝试在 obj.profile 的get函数中检查 args 和** kwargs,它们似乎都没有帮助,或者如果我调用它们就填充 obj.profile.something
答案 0 :(得分:1)
如果绝对必须是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
答案 1 :(得分:1)
对于少数哈希键,您可以轻松定义单例方法,如下所示:
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
。
答案 2 :(得分:1)
此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"