【一人 bugs.ruby Advent Calendar 2021】[Misc #18125] A strange behavior when same name variable/method coexist issue.【15日目】

一人 bugs.ruby Advent Calendar 2021 15日目の記事になります。
今日は同名のメソッドと変数を定義した状態の話です。

[Misc #18125] A strange behavior when same name variable/method coexist issue.

次のように同名のメソッドと変数を定義した時に奇妙な動作になるけどこれは期待する動作?という質問です。

def deploy_to
  "deploy_to"
end

deploy_to = "#{deploy_to} new place"
#              ^ これがメソッドではなくて変数を参照している

p defined? deploy_to # => local_varible
p deploy_to          # => " new place"

これは期待する動作でこの場合は変数が定義され値が割り当てられる前のローカル変数 deploy_to を参照します。
Ruby の場合はメソッドの () を省略して記述する事ができるので名前参照がメソッドと変数で曖昧になってしまうんですが基本的には変数を優先して参照します。

def deploy_to
  "deploy_to"
end

# これはメソッドを参照する
pp deploy_to   # => "deploy_to"

deploy_to = 42

# 変数が定義された以降であれば変数を参照する
pp deploy_to   # => 42

なのでチケットに書かれているような deploy_to = "#{deploy_to} new place" の場合は変数が定義された後に "#{deploy_to} new place" が評価される流れになるので deploy_to = nil の状態で式展開が行われます。
こういう時にメソッドを参照したい場合は () を付けてメソッド呼び出しだと明示化する必要があります。

def deploy_to
  "deploy_to"
end

deploy_to = "#{deploy_to()} new place"
#              ^ これはメソッド呼び出しになる
p deploy_to  # => "deploy_to new place"

余談ですが eval などで動的に Ruby の式を評価すると『変数定義よりも前に処理しても』変数を参照します。

def deploy_to
  "deploy_to"
end

# これはメソッドを参照する
pp deploy_to   # => "deploy_to"

# これは変数を参照する
# 変数にはまだ価が割り当てられていないので nil を返す
pp eval("deploy_to")   # => nil

deploy_to = 42

binding.irb などでは内部で eval を使って式を評価しているのでメソッドと同名の変数を定義する場合は注意しましょう。