Search code examples
ruby

Ruby Case statements and pinning, does not work with attr_reader


This code works:

class Hello
  def initialize
    @name = "Paul"
  end

  def say_name(maybe_name)
    name = self.name
    case maybe_name
    in ^name
      puts "Hello, Paul!"
    else
      puts "No match"
    end
  end

  private

  attr_reader :name
end

Hello.new.say_name("Paul") # "Hello, Paul!"

However if I remove name = self.name, I get a no local variable name for the pinned variable.

Is this a bug in Ruby, or the intention? I suppose it only works with local variables? If I remove this line, name is nil inside the say_hello method, but it is defined.


Solution

  • Is this a bug in Ruby, or the intention?

    That specific error is intentional. When referencing a local variable that doesn't exist, you get an exception.

    I suppose it only works with local variables?

    It works with any kind of variable, as mentioned in the docs: "you can also pin instance, global, and class variables". However, the plain ^variable syntax doesn't work with methods. To get your code working, you have to either reference the instance variable @name directly:

    case maybe_name
    in ^@name
      # ...
    end
    

    or use the ^(expression) syntax which allows to "pin the result of arbitrary expressions using parentheses": (with the "arbitrary expression" being a method call)

    case maybe_name
    in ^(name)
      # ...
    end