Ruby on rails Ruby:使用字符串设置哈希值
我正在使用Rails 4,并试图通过字符串名访问哈希变量 例如,假设我有一个策略模型,其中一个成员散列包含字段名称和地址 我希望能够将policy_member_name转换为policy[:member][:name] 但是,此字符串可能长于3个部分。我能够访问该值,但无法使用以下命令设置该值:Ruby on rails Ruby:使用字符串设置哈希值,ruby-on-rails,ruby,hash,Ruby On Rails,Ruby,Hash,我正在使用Rails 4,并试图通过字符串名访问哈希变量 例如,假设我有一个策略模型,其中一个成员散列包含字段名称和地址 我希望能够将policy_member_name转换为policy[:member][:name] 但是,此字符串可能长于3个部分。我能够访问该值,但无法使用以下命令设置该值: ret = obj keys.each do |key| ret = ret[key.to_sym] end ret 其中keys是一个数组,比如['member','nam
ret = obj
keys.each do |key|
ret = ret[key.to_sym]
end
ret
其中keys是一个数组,比如['member','name'],obj是对象,比如Policy.first。但是,此方法只返回策略[:member][:name]上的值,不允许我执行策略[:member][:name]=
谢谢你的帮助
编辑:
我希望能够调用
policy.member\u name
来获取策略[:member][:name]
并拥有策略。member\u name=“Something”
来设置策略[:member][:name]=“Something”
这很容易用方法实现
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
由于您只允许用户对某些散列进行读写访问,因此创建将这些散列(字符串)的名称映射到散列对象的散列不会有任何困难。例如:
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"}
你能给我们已知的输入和期望的输出吗?旁注:在我看来,你是在为一些可能没有你想象的那么重要的事情牺牲性能。即使是非常接近您想要的,也会遭受性能代价,因为它依赖于方法\u missing
。。。此外,它可能更容易混淆,而不是有用——例如,当:policy.member=Users.find(1)时会发生什么;policy.member_name='Joe';放置policy.member
…?我需要它的原因是我正在使用gembest\u in\u place
,以便在适当的位置编辑字段。您是建议根本不使用OpenStructs
,还是仅仅建议不需要点符号?或者您是否知道另一种就地编辑OpenStructs
的方法?谢谢@Myst的评论总结得很好。你真的需要这个吗?在性能方面有相当大的成本,我甚至不想考虑堆栈跟踪是什么样子。