这是 Bungus 答案的一个变体,但这是一个明显更丑陋的单线,但不扩展 Binding 或任何东西:
foo = :bar
baz = :bin
hash = [:foo, :baz].inject({}) {|h, v| h[v] = eval(v.to_s); h }
# hash => {:baz=>:bin, :foo=>:bar}
您还可以通过滥用块绑定使其看起来有点像方法调用 - 再次,Bungus 原始答案的变体:
module Kernel
def compact(&block)
args = block.call.map &:to_sym
lvars = block.binding.send(:eval, "local_variables").map &:to_sym
(args & lvars).inject({}) do |h, v|
h[v] = block.binding.send(:eval, v.to_s); h
end
end
end
foo = :bar
baz = :bin
compact {[ :foo, :bar, :baz ]}
# {:foo=>:bar, :baz=>:bin}
(我只会告诉自己那{[..]}
是垃圾压实机的符号。)
如果您使用binding_of_caller
gem,您可以同时放弃 proc和显式绑定:
require 'binding_of_caller'
module Kernel
def compact(*args)
lvars = binding.of_caller(1).send(:eval, "local_variables").map &:to_sym
(args.map(&:to_sym) & lvars).inject({}) do |h, v|
h[v] = binding.of_caller(2).send(:eval, v.to_s); h
end
end
end
foo = :bar
baz = :bin
compact :foo, :bar, :baz
# {:foo=>:bar, :baz=>:bin}
请注意,它很慢。在生产代码中,您可能永远不应该尝试这样做,而只是保留一个值的哈希值,这样在您之后必须维护它的程序员就不会追捕您并在您的睡眠中杀死您。