This is a variant on Bungus' answer, but here's a one-liner that is decidedly uglier, but doesn't extend Binding or anything:
foo = :bar
baz = :bin
hash = [:foo, :baz].inject({}) {|h, v| h[v] = eval(v.to_s); h }
# hash => {:baz=>:bin, :foo=>:bar}
You can also make it look kinda-sorta like a method call by abusing a block binding - again, a variant on Bungus' original answer:
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}
(I'll just tell myself that {[..]}
is the trash compactor symbol.)
If you use the binding_of_caller
gem, you can forgo the proc and explicit binding all together:
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}
Be warned, it's slow. In production code, you should probably never attempt to do this and instead just keep a hash of values so the programmer who has to maintain this after you doesn't hunt you down and kill you in your sleep.