我知道我可以使用ostruct
从哈希创建绑定,如下所示:
require 'ostruct'
not_in_locals = "we don't want this"
locals = {a: 1, b: 2}
my_binding = OpenStruct.new(locals).instance_eval { binding }
p my_binding
p eval("a", my_binding) #good, we want this
p eval("b", my_binding) #good, we want this
p eval("not_in_locals", my_binding) #bad, don't want it to access this, but it can
您可以在此处查看输出,该输出确认代码中的注释:https://eval.in/132925
正如您所看到的,问题是Binding还绑定了Hash中 not 的本地上下文中的变量。我想要一个从Hash创建Binding对象的方法,它除了来自Hash的键之外什么都没有绑定。
答案 0 :(得分:1)
你可以尝试这样的事情。它绕过了一个直接的eval()调用,用于辅助类方法调用。 helper类方法名为evaluate(),但它只适用于非常简单的值(目前只测试过的字符串和整数)并且依赖于inspect()。
但是,如果您正在处理的值的类型是提前知道的,则可以将其修改为有效。
class HashBinding
def initialize(hash)
@hash = hash
end
def evaluate(str)
binding_code = @hash.to_a.map do |k,v|
"#{k} = #{v.inspect};"
end.join(" ")
eval "#{binding_code}; #{str}"
end
end
not_in_hash = 'I am not in the hash'
hash = { :foo => 'foo value', :baz => 42}
hash_binding = HashBinding.new(hash)
hash_binding.evaluate('puts "foo = #{foo}"')
hash_binding.evaluate('puts "baz = #{baz}"')
hash_binding.evaluate('puts "not_in_hash = #{not_in_hash}"')
输出结果为:
ruby binding_of_hash.rb
foo = foo value
baz = 42
binding_of_hash.rb:10:in `eval': undefined local variable or method `not_in_hash' for #<HashBinding:0x007fcc0b9ec1e8> (NameError)
from binding_of_hash.rb:10:in `eval'
from binding_of_hash.rb:10:in `evaluate'
from binding_of_hash.rb:20:in `<main>'
答案 1 :(得分:0)
这是另一个“不那么”的hacky尝试,它不依赖于“检查”序列化。
require 'json'
class HashBinding
attr_accessor :hash
def initialize(hash)
# Require symbol keys
@hash = Hash[hash.map {|k,v| [k.to_sym, v]}]
end
def evaluate(str)
binding_code = @hash.to_a.map do |k,v|
"#{k} = @hash[:#{k}];"
end.join(" ")
eval "#{binding_code}; #{str}"
end
end
not_in_hash = 'I am not in the hash'
hash = { :foo => 'foo value', :baz => 42, 'str' => "a string value"}
hash_binding = HashBinding.new(hash)
hash_binding.evaluate('puts "foo = #{foo}"')
hash_binding.evaluate('puts "baz = #{baz}"')
hash_binding.evaluate('puts "str = #{str}"')
hash_binding.evaluate('puts "not_in_hash = #{not_in_hash}"')