This is a variant of Bungus' answer, but here is a single-line font that is clearly uglier but doesn't extend the binding or anything else:
foo = :bar baz = :bin hash = [:foo, :baz].inject({}) {|h, v| h[v] = eval(v.to_s); h }
You can also make it look like sorting like a method call, abusing the block binding - again, a variant with the original Bungus 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 will just tell myself that {[..]} is a garbage compactor.)
If you use the binding_of_caller , you can refuse proc and explicitly bind 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
Be careful, this is slow. In production code, you probably never try to do this, but instead just keep a hash of values, so the programmer should support this after you don't track you down and kill you in a dream.