67442


こんにちは。  
自分で一生懸命調べれば解決できるかも知れませんが、  
ここで質問した方が役に立つお話が聞けるかも知れないと思って質問します。

Rubyで下のようなコードを実行すると

[code]

    class A
      def method_missing(method, *args)
        puts "ZZZ" if method == :sleep
      end
    end
    
    a = A.new
    a.sleep
    a.send(:sleep)
    
[/code]

`a.sleep` は期待通り "ZZZ" を出力するのですが、次の行の  
`a.send(:sleep)` はフリーズします。

どうしてこうなるのでしょうか？


CC BY-SA 4.0
2020-06-09T05:38:01.887
67440
2020-06-09T06:11:33.577
32772
question
ruby
method_missingでsleepメソッドを呼んだ時にフリーズする理由


`send(:sleep)`だと、privateメソッドの `Kernel.#sleep`を呼べるためです。  
<https://docs.ruby-lang.org/ja/latest/method/Kernel/m/sleep.html>

Aクラスのインスタンスには`sleep`メソッドはprivateメソッドとして存在します。  
これは、Kernelモジュールに定義されたメソッドはprivateメソッドとしてAクラスにも定義されるためです。

これは例えば`method`メソッドを使うと確かめられます。

[code]

    class A
      def method_missing(method, *args)
        puts "ZZZ" if method == :sleep
      end
    end
    
    a = A.new
    
    p a.method(:sleep)
    # => #<Method: A(Kernel)#sleep(*)>
    
    p a.public_method(:sleep)
    # => -:10:in `public_method': method `sleep' for class `A' is  private (NameError)
    #   from -:10:in `<main>'
    
    
[/code]

そして、`a.sleep`の形式でのメソッド呼び出しはpublicメソッドしか呼び出せないため、privateメソッドである`Kernel.#sleep`を呼び出せず`method_missing`に処理が移ります。

対して`a.send(:sleep)`はprivateメソッドでも呼び出せるので、method_missingが呼ばれずに`Kernel.#sleep`が呼ばれます。

`send`を`public_send`に変えると`method_missing`を通るようになって、`public_send`でも"ZZZ"が表示されるようになると思います。


CC BY-SA 4.0
2020-06-09T06:04:33.193
67442
2020-06-09T06:04:33.193
21283
67440
answer


直接的な原因は`send(:sleep)`で`Kernel#sleep`が呼ばれてしまっていることにあるようです。その証拠に、`sleep`を`hoge`に置換すると思った通りに動作します。

[code]

    class A
      def method_missing(method, *args)
        puts "ZZZ" if method.to_sym == :hoge
      end
    end
    
    a = A.new
    a.hoge
    a.send(:hoge)
    # ZZZ
    # ZZZ
    
[/code]

色々試したのですが、どうやら「`send`で`Kernel`モジュールにあるメソッドと同名のメソッドを呼び出そうとすると、`method_missing`で補足されずに`Kernel`モジュール内のメソッドが呼ばれてしまうようです（`warn`メソッドで確認しました）。  
この挙動がRubyのバグなのかどうかはこれから確認してみますね。

* * *

私の確認不足で、単に`send`はプライベートメソッドを呼び出せる、`Kernel#sleep`や`Kernel#warn`はプライベートメソッドである、ということのようです。


CC BY-SA 4.0
2020-06-09T06:05:58.470
67443
2020-06-09T06:11:33.577
2020-06-09T06:11:33.577
442
442
67440
answer