What I liked about Ruby over Java or C++ most are the different types of programming ideas that I've had to wrap my head around. Just yesterday, I was looking at Ruby's ERB (Embedded RuBy) library. It executes ruby embedded in text (plain text or html). Most commonly, Rails uses ERB as a way to translate view templates into html to be displayed to the browser.
I had the problem of trying to render templates outside of controllers, which was why I was looking at ERB. I couldn't get the ERB to read the variables I had defined in the function. I mean...that's the way it worked in the controllers!
@title = "The web and all that jazz"
template = "<html><body><%= @title %></body></html>"
erb = ERB.new(template)
html = erb.result
It didn't take. It ends up that you'd have to pass ERB the current binding as well, because it assumes TOPLEVEL_BINDING. I think ERB uses eval() heavily, which in turn uses binding.
html = erb.result(binding)
binding() is a kernel method that returns the binding--essentially the scope which code is being executed. Not only that, binding() returns the binding as an object, so you can store it for future use, and even pass it around. That means that you can request the scope of a block of code (the variables that are available to it) at that time in execution, and use it at another time, when that scope might have already expired.
So in the erb example, result() was assuming scope at the very top level of the application, rather than the local scope. And that's why it couldn't find @title.
I only found one extensive article on binding. It has great examples on binding.
Being able to pass around bindings seems odd to me. It's like being able to pass scope around, and I wonder if it violates encapsulation...or maybe it's ok to violate it once in a while? But then again, I remembered that closures and blocks in ruby also have bindings. The scope in which a block is define is remembered, and can be passed around; and it's part of their power. So every time you do an array each() and pass it a block, you're passing around bindings as well. It's so much easier than messing around with function pointers.