I'm using Rails 4 and trying to access a hash variable via string names.
For example, let's say I have policy model with a member hash who has the fields name and address.
I would like to be able to convert policy_member_name into policy[:member][:name].
However, this string may be longer than just 3 sections. I was able to access the value, but not be able to set it using the following:
ret = obj
keys.each do |key|
ret = ret[key.to_sym]
end
ret
where keys would be an array such as ['member', 'name'] and obj would be the object, such as Policy.first. However, this method only would return what value is at policy[:member][:name] and does not allow me to do policy[:member][:name]=.
Any help is appreciated, thanks.
EDIT:
I'd like to be able to call policy.member_name
to get policy[:member][:name]
and have policy.member_name= "Something"
to set policy[:member][:name]="Something"
答案 0 :(得分:2)
使用method_missing
:
class HashSnake
def initialize(hash)
@hash = hash
end
def method_missing(method, *args, &block)
parts = method.to_s.split('_').map(&:to_sym)
pointer = @hash
parts.each_with_index do |key, i|
if pointer.key? key
if pointer[key].is_a? Hash
if (i +1 == parts.length)
return pointer[key]
else
pointer = pointer[key]
end
else
return pointer[key]
end
# Checks if method is a setter
elsif key[-1] == '=' && pointer.key?(key[0..-2].to_sym)
pointer[key[0..-2].to_sym] = args[0]
end
end
end
end
obj = HashSnake.new(
member: {
foo: 'bar',
child: {
boo: 'goo'
}
}
)
obj.member_foo = 'bax'
puts obj.member_foo.inspect
# "bax"
puts obj.member_child_boo.inspect
# goo
答案 1 :(得分:0)
由于您只允许用户对某些哈希值进行读取或写入访问,因此创建将哈希值(字符串)的名称映射到哈希对象的哈希是没有困难的。例如:
h0 = { a: 1, b: 2 }
h1 = { c: 3, d: { e: 4, f: { g: 5 } } }
hash = { "h0"=>h0, "h1"=>h1 }
完成后,只需创建满足您需求的特定于域的语言(“DSL”)即可。可能有宝石可以开箱即用,或者可以根据您的要求进行修改。
以下是一种可能性的示例。 (我建议你在阅读代码之前先看看这些例子。)
<强>代码强>
class Array
def h(hash)
h = hash[first]
if last.is_a? Array
seth(h, *self[1..-2].map(&:to_sym), *last)
else
geth(h, *self[1..-1].map(&:to_sym))
end
end
private
def geth(h, *keys)
keys.reduce(h) { |h,k| h[k] }
end
def seth(h, *keys, last_key, type, val)
val =
case type
when "STR" then val.to_str
when "INT" then val.to_int
when "SYM" then val.to_sym
when "FLT" then val.to_f
end
geth(h, *keys)[last_key] = val
end
end
<强>实施例强>
以下内容适用于h0
,h1
和hash
。
["h0", "b"].h(hash)
#=> 2
["h1", "d", "f", "g"].h(hash)
#=> 5
["h0", "b", ["INT", 3]].h(hash)
#=> 3
h0 #=> {:a=>1, :b=>3}
["h1", "d", "f", "g", ["STR", "dog"]].h(hash)
#=> "dog"
h1 #=> {:c=>3, :d=>{:e=>4, :f=>{:g=>"dog"}}, :g=>"dog"}