From: Jeff Date: 2008-10-30T11:23:59+09:00 Subject: Question about case statement and lambdas 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