In a project I’m working on at the moment, I saw some rather unusual code at the top of a number of views – it looked like it was trying to set a default value in the event the variable wasn’t defined, for example:
name = undefined_to_false(name)
and the definition of undefined_to_false:
def undefined_to_false(variable)
if !defined?(variable)
return false
else
return variable
end
end
My first reaction to that method was that it couldn’t work – if I have an undefined variable and attempt to pass it into the undefined_to_false method, I will get a “NameError: undefined local variable or method” before ruby attempts to pass it into that method. The only was around this was to pass in a Proc.
I pulled up irb and confirmed that this method would not work, yet it was being used in a production system. Rcov confirmed that the return false never got called in any tests. Given this information I removed the method and every reference to it – if any of the callers of this method actually needed this method, I figured we would have already had NameErrors.
Then someone complained that their view wasn’t working anymore, and I started to wonder if there was some other magic that made this work. I had confirmed that passing an undefined variable into a method cannot work which meant that the variable must have been defined before it called that method.
A colleague confirmed that
name = undefined_to_false(name)
did in fact work when name was previously undefined (and it was undefined in a number of views). Then it occurred to me:
a = a
In an assignment, the variable on the left hand side will become defined prior to evaluation of the right hand side. Thus, even if a was not defined prior to that line, it will be by the time of evaluation and therefore will not generate a NameError.
So I replaced all the old occurrences of a = undefined_to_false(a) with just a ||= false, although to be more correct I could have replaced them all with a = a but that just looks silly – and smells bad.
Filed under: Uncategorized | No Comments