if var.responds_to?(…)

If an if‘s condition is a responds_to? test, in the then branch the type of a variable is guaranteed to be restricted to the types that respond to that method:

  1. if a.responds_to?(:abs)
  2. # here a's type will be reduced to those responding to the 'abs' method
  3. end

Additionally, in the else branch the type of the variable is guaranteed to be restricted to the types that don’t respond to that method:

  1. a = some_condition ? 1 : "hello"
  2. # a : Int32 | String
  3. if a.responds_to?(:abs)
  4. # here a will be Int32, since Int32#abs exists but String#abs doesn't
  5. else
  6. # here a will be String
  7. end

The above doesn’t work with instance variables or class variables. To work with these, first assign them to a variable:

  1. if @a.responds_to?(:abs)
  2. # here @a is not guaranteed to respond to `abs`
  3. end
  4. a = @a
  5. if a.responds_to?(:abs)
  6. # here a is guaranteed to respond to `abs`
  7. end
  8. # A bit shorter:
  9. if (a = @a).responds_to?(:abs)
  10. # here a is guaranteed to respond to `abs`
  11. end