I'm interested in using dynamic (as opposed to lexical) scoped variables in Ruby.
It's seems there isn't a direct built-in way, as with let
in Lisp. One possible way to do dynamic scoped variable is suggested by Christian Neukirchen. He creates a "thread local hash" in his Dynamic
class. I wasn't too crazy about that.
Then I remembered that Ruby 1.9 has a tap
method. I see a lot of people using tap
to print debugging values in a chain of commands. I think it can be used to very nicely mimic a dynamically scoped variable.
Below is an an example of a situation in which one would want to use a dynamical scoped variable, and a solution using tap
.
If I had a blog to post this on, and get some feedback, I would do it there. Instead I come to S/O for criticism of this idea. Post your critique, I'll give the correct answer to the one with the most upvotes.
Situation
You have an ActiveRecord object representing an Account
, each account has_many
Transaction
s. A Transaction
has two attributes:
description
amount
You want to find the sum of all transactions
on the account
, keeping in mind that amount
can be either nil
or a Float
(no you can't critique that).
Your first idea is:
def account_value
transactions.inject(0){|acum, t| acum += t.amount}
end
This bombs the first time you have a nil amount:
TypeError: nil can't be coerced into Fixnum
Clean Solution
Use tap
to temporarily define amount = 0
. We only want this to be temporary in case we forget to set it back and save the transaction
with the 0 value still in place.
def account_value
transactions.inject(0){|acm, t| t.amount.tap{|amount| amount ||=0; acm+=amount}; acm}
end
Since the assignment-to-zero-if-nil of amount
is within the tap
bock, we don't have to worry about forgetting to set it back to nil
.
What are your thoughts?