by Dan DeMeyere - @dandemeyere
I've been slowly making my way through the Dave Thomas series of Advanced Ruby vodcasts. The series has been very enlightening as I'm learning a lot of powerful tools that Ruby offers as a programming language. A particular topic that he covered that sort of blew my mind was Ruby bindings and lambda.
Lambda is something I've been working with for a while. The two main ways we utilize Lambda in the thredUP app is with named scopes and dynamic hash values. Examples:
The examples above are pretty standard usage of lambda. What I didn't know is that you could do something like this:
I think this is particularly useful in the event you're lambda block takes in options. Typically I see that people construct an options Hash object and then pass it in. By denoting the asterisk (*) before the last parameter, it allows you to just pass in all your options within your method call. If you have a lot of options, the call will look unwieldy and the Hash object creation is probably best.
Yesterday was the first day I had ever heard the term bindings within the context of Ruby. Although I'm still trying to think of useful implementations of bindings inside of our thredUP app, the knowledge of how to use them should become a handy tool when brainstorming solutions in the future. My understanding of a binding is that it allows you to hook into's a block execution and retain the ability to enter into that block through the hook at will. Ruby-doc says that bindings 'encapsulate the execution context and retain this context for future use'. I like my definition better.
So once you create a binding, you're able to invoke said binding using the Kernal#eval method. Here is a simple example:
One could easily argue against the practicality of this example, but it was the best I could come up with in a couple of minutes. This particular binding gives you access to an instance variable of a class without setting up an attribute accessor. Also, since eval() is used, dynamic construction of objects opens up a little world of possibilites. If the EMPLOYEES constant contained classes instead of strings, eval() could dynamically create new objects for those classes (or access methods of those classes) within another class (such as Thredup) with the use of a binding.
It's a bit mind-numbing to think about good use cases of bindings, but it's a nice addition for developer's toolbox. You never know when you might have to throw every tool in your toolbox at a problem to arrive at a solution - so every tool counts!
I came across something that I thought was really interesting. A method can accept a block if you denote the parameter name with the '&' symbol. The block will come in as a Proc.new() object (almost identical to a lambda) and will therefore require the .call() method to invoke the block that was passed in. For once, I have a practical example of how valuable this is:
This cache_me method could be used as a tool to cache or retrieve (fetch) a metric based on a cache key and an expiration. The key and expiry could also be combined into one dynamic key if you want to add some syntactic sugar to your metric pie.