Skip to content

Instantly share code, notes, and snippets.

@juliocesar
Created April 14, 2010 06:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save juliocesar/365525 to your computer and use it in GitHub Desktop.
Save juliocesar/365525 to your computer and use it in GitHub Desktop.
class Hash
def self.from_block &block
Hash[*BlockBuilder.build(&block)]
end
class BlockBuilder
@@collected = []
class << self
def build(&block)
instance_eval &block
copy = @@collected.clone and @@collected.clear and return copy
end
def method_missing(method, *args)
@@collected.concat [method.to_sym, args.first]
end
end
end
end
# Hash.from_block do
# apple 8
# banana 2
# carrot 6
# end
# => {:apple=>8, :banana=>2, :carrot=>6}
@puyo
Copy link

puyo commented Apr 16, 2010

I was thinking you should use something like BasicObject for BlockBuilder, but then I realised that there are all sorts of things in the lexical scope of that block that are gonna stuff it up.
Hash.from_block { p 1; q 2; r 3 }

=> { :q => 2, :3 => 3 }

Once people get over Ruby 1.8, you can do { apple: 8, banana: 2, carrot: 6 }.

@juliocesar
Copy link
Author

The point of BlockBuilder above is to sandbox the execution of the block away. So that method_missing there won't get in any other class' way.

@puyo
Copy link

puyo commented Apr 16, 2010

Yep, but all the methods in Class get in the way. puts Class.methods. Hash.from_block { extend 10 } raises an exception for example. But it's not just method calls that mess with the lexical scope of the block, there are also global functions like 'p', 'print', etc. that get in the way too, which is not a problem I can see any way around.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment