I fear this has an obvious answer that I’m just not figuring out.
Sometimes I dive into the Rails source code to see how something works
(don’t worry, this isn’t a Rails question). I have been looking at
the implementation of the named_scope feature in Rails, and found some
dense Ruby indeed. As an exercise, I decided to refactor it to be
more readable and to force me to understand what it’s doing. A series
of simple refactorings has led to a change in behavior, and I’m not
sure why.
Along the way, I ended up with this method (extracted from the
original implementation):
Starting point
def create_lambda_for_scope(name, options, &block)
lambda do |parent_scope, *args|
Scope.new(parent_scope, case options
when Hash
options
when Proc
options.call(*args)
end, &block)
end
end
All tests still pass at this point… but that inline case statement
bugs me, so I refactor it out to a temporary variable:
Attempt #2
def create_lambda_for_scope(name, options, &block)
lambda do |parent_scope, *args|
arg = case options
when Proc
options.call(*args)
when Hash
options
end
Scope.new(parent_scope, arg, &block)
end
end
Tests still pass, yessss! But, I still hate seeing that case
statement. So I now do this:
Attempt #3:
arg = (options.is_a?(Proc) ? options.call(*args) : options) Scope.new(parent_scope, arg, &block)Test still pass, I’m about to declare victory. But I can’t resist one
more simplification to remove the temporary. Since the case statement
is so simple, it looks to me like, if options is a Hash, don’t do
anything, but if it’s a Proc, then call it.
So I decide to just get rid of the temporary and simply assign a new
value to options only if it’s a Proc:
Attempt #4
options = options.call(*args) if options.is_a?(Proc) Scope.new(parent_scope, options, &block)Kaboom, several tests now fail.
Is there something I don’t understand about the difference between #3
and #4? I’m guessing it’s something to do with the fact that I’m
building a lambda here, so there’s closure scope to be concerned
about… but still, #3 and #4 look semantically the same to me.
Any insight or ideas would be appreciated.
Thanks!
Jeff