37632


とある問題を解くために以下のようなコードをかきました。  
しかし、gravityメソッドが勝手にprivate扱いされてしまいます。  
'#'の付いている行をすべてコメントアウトすると期待通りに動きました。  
どなたか詳しい方、なぜgravityがprivate扱いされてしまうのか教えてください  
処理系は2.3.1です。

* * *
[code]

    line = gets.chomp.split(' ')
    $W = line[0].to_i
    $H = line[1].to_i
    $N = line[2].to_i
    $sen = Array.new
    $H.times do
    　　　$sen << gets.chomp.split("")
    end
    $sen.reverse!
    $sen = $sen.transpose
    
    def gravity #落ちる
    　　　$sen.each do |y|
    　　　　　　y.delete('0')
    　　　　　　($H-y.length).times do
    　　　　　　　　　y << '0'
    　　　　　　end
    　　　end
    end #
    $sen.gravity #
    p $sen
    
[/code]


CC BY-SA 3.0
2017-08-30T14:39:49.863
37623
2017-08-31T03:22:49.430
2017-08-30T15:28:49.253
13199
24965
question
ruby
Rubyで勝手にprivate method扱いされる


「なぜgravityがprivate扱いされてしまうのか教えてください」という質問については、Ruby公式マニュアルに[「トップレベルで定義したメソッドはmainオブジェクトのprivateメソッドとして定義されます。」](https://docs.ruby-
lang.org/ja/2.3.0/class/main.html)と書かれています。


CC BY-SA 3.0
2017-08-30T21:13:28.553
37627
2017-08-30T21:13:28.553
4010
37623
answer


このコードの本質的な問題は`gravity`メソッドの呼び出し方が不適切なことです。本来は`undefined
method`になるほうが好ましいように思えるのですが、後述するRubyの動作により、プライベートメソッドの呼び出しのエラーになってしまいます。

単純な解決策としては`$sen.gravity`ではなく、`gravity`として呼び出してください。

また、メソッド定義じゃなくしたら動作した、とありますが、このコードだとメソッド定義する必要がないので、それも一つの解決策だと思います。

* * *

マニュアルには確かに「トップレベルで定義したメソッドは main オブジェクトの private メソッドと
して定義されます。」と書いてあるのですが、質問のコードの挙動とは矛盾しているので説明になってません。

マニュアルの通りであれば、`gravity`は`main`オブジェクトのメソッドなのですから、`$sen.gravity`は`undefined
method`になるはずです。ところが実際には`private method 'gravity' called`のエラーになります。

実際には、トップレベルで定義したメソッドはKernelモジュールのプライベートなインスタンスメソッドとして定義されます。KernelモジュールはObjectクラスがincludeしておりObjectクラスは全てのクラスのスーパークラスなので、トップレベルで定義したメソッドは全てのクラスにおいてプライベートなインスタンスメソッドとして参照できることになります。

[code]

    def m
      p self.class
    end
    
    [].__send(:m) #=> Array
    {}.__send(:m) #=> Hash
    #無理矢理呼び出す
    
    def hoge
      puts "hoge"
    end
    
    class Hoge
      def fuga
        hoge
      end 
    end
    
    Hoge.new.fuga #=> "hogeを表示"
    Hoge.new.hoge #=> private method `hoge' called for #<Hoge:0x00000804ce1f10> (NoMethodError)
    
[/code]

* * *


CC BY-SA 3.0
2017-08-31T03:22:49.430
37632
2017-08-31T03:22:49.430
5793
37623
answer