ようへいの日々精進XP

よかろうもん

2018 年 01 月 29 日(月)

ジョギング

  • 香椎浜 x 2 周
  • フォームを気にしつつ走ったらギクシャクしてて辛かった

日課

  • (腕立て x 50 + 腹筋 30) x 3
  • 腕立ての回数を増やした

寒い

  • 毎日寒い...

今日のるびぃ ~ private メソッドを含むクラスを継承した場合... ~

メソッドの可視性を定義するメソッドは以下の三つ.

  • public
  • protected
  • private

特に何も指定しなければ public メソッドとして定義される.

[1] pry(main)> class Foo
[1] pry(main)*   def foo
[1] pry(main)*     'foo'
[1] pry(main)*   end  
[1] pry(main)* end  
=> :foo
[2] pry(main)> Foo.new.respond_to?(:foo)
=> true
[4] pry(main)> Foo.new.public_methods.grep(/foo/)
=> [:foo]

尚, Object#respond_to? はこちらによると, 以下のようなメソッド.

レシーバが引数で指定した名前のpublicメソッドを持っているか調べるメソッドです。第2引数にtrueを指定すれば、指定した名前のprivateメソッドを持っているかを調べることができます。

private や protected メソッドは明示的に指定する必要がある.

[1] pry(main)> class Foo
[1] pry(main)*   def my_public_method
[1] pry(main)*     'my_public_method'
[1] pry(main)*   end  
[1] pry(main)*   protected
[1] pry(main)*   def my_protected_method
[1] pry(main)*     'my_protected_method'
[1] pry(main)*   end  
[1] pry(main)*   private
[1] pry(main)*   def my_private_method
[1] pry(main)*     'my_private_method'
[1] pry(main)*   end  
[1] pry(main)* end  
=> :my_private_method
[2] pry(main)> f = Foo.new
=> #<Foo:0x00559b1a07c3e8>
[3] pry(main)> f.my_public_method
=> "my_public_method"
[4] pry(main)> f.my_protected_method
NoMethodError: protected method `my_protected_method' called for #<Foo:0x00559b1a07c3e8>
[5] pry(main)> f.my_p
f.my_protected_method  f.my_public_method     
[5] pry(main)> f.my_private_method
NoMethodError: private method `my_private_method' called for #<Foo:0x00559b1a07c3e8>

上記のように, private と protected なメソッドは外部から呼び出すことは出来ない. 他にも, 以下のように private メソッドはレシーバ付きで呼び出すことが出来ない等のメソッド毎に可視性が異なる.

[6] pry(main)> class Foo
[6] pry(main)*   def oreore_method
[6] pry(main)*     self.my_private_method
[6] pry(main)*   end  
[6] pry(main)* end  
=> :oreore_method
[7] pry(main)> f = Foo.new
=> #<Foo:0x00559b19fb0ba8>
[8] pry(main)> f.oreore_method
NoMethodError: private method `my_private_method' called for #<Foo:0x00559b19fb0ba8>

ところで, 継承したクラス内でスーパークラス内の private なメソッドを呼び出した場合にどのようになるのか.

[1] pry(main)> class Foo
[1] pry(main)*   private
[1] pry(main)*   def my_private_method
[1] pry(main)*     'my_private_method'
[1] pry(main)*   end  
[1] pry(main)* end  
=> :my_private_method
[2] pry(main)> class FooExt < Foo
[2] pry(main)*   def my_private_method2
[2] pry(main)*     my_private_method
[2] pry(main)*   end  
[2] pry(main)* end  
=> :my_private_method2
[3] pry(main)> FooExt.new.my_private_method2
=> "my_private_method"
[4] pry(main)> class FooExt < Foo
[4] pry(main)*   def my_private_method
[4] pry(main)*     super
[4] pry(main)*   end  
[4] pry(main)* end  
=> :my_private_method
[5] pry(main)> FooExt.new.my_private_method
=> "my_private_method"
[6] pry(main)> Foo.new.my_private_method
NoMethodError: private method `my_private_method' called for #<Foo:0x0055e53facd828>

ほう. 継承元の my_private_method を呼び出すと NoMethodError になるものの, 継承したクラスからスーパークラスの private メソッドを呼び出した場合には, 可視性は無効となり上記のようにメソッドが呼び出せている.

ふむふむ.