ようへいの日々精進XP

よかろうもん

2018 年 05 月 20 日(日)

ジョギング

  • 今日はお休み
  • 足もだるいし, 体もキツかったので

日課

  • ついでに休み

香椎宮

  • お参りに行った
  • お昼ごはんは香椎宮近くの中華屋さんで, 美味しかった

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (6) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

定数探索

以下のコードを実行するとどうなるか.

class Cls1
  CONST = "AAA"

  def self.name
    const_get(:CONST)
  end
end

class Cls2 < Cls1
  CONST = "BBB"
end

puts Cls2.name

BBB と出力される

以下, irb による確認.

irb(main):001:0> class Cls1
irb(main):002:1>   CONST = "AAA"
irb(main):003:1> 
irb(main):004:1*   def self.name
irb(main):005:2>     const_get(:CONST)
irb(main):006:2>   end
irb(main):007:1> end
=> :name
irb(main):008:0> 
irb(main):009:0* class Cls2 < Cls1
irb(main):010:1>   CONST = "BBB"
irb(main):011:1> end
=> "BBB"
irb(main):012:0* puts Cls2.name
BBB
=> nil

以下, 解説より抜粋.

  • Cls1#nameClass#name をオーバーライトしている為, const_get が呼ばれる
  • const_get は, self に定義されている定数を探索する. 自クラスに定義がない場合は、メソッドと同様に探索を行う
  • 設問の 5 行目時点のインスタンスは Cls2 クラスで, Cls1#name は Cls2 クラスの定数の値 BBB を返します。

解説がイマイチ理解出来なかったので, 自分なり irb を使って確認.

Cls1#nameClass#name をオーバーライトしている為, const_get が呼ばれる

Class クラスに name というメソッドってあるのかな...と思ったら, 以下のように存在している.

irb(main):016:0> Class.methods.grep(/name/)
=> [:name]

これは, Module#name を継承している為, name メソッドを呼び出すことが出来る. このメソッド自体は, 以下の実行例のように, モジュールやクラスの名前を返す機能があるが, 設問ではオープンクラスしてこの機能を const_get の結果を返すように上書きしている.

irb(main):001:0> class Cls1; end
=> nil
irb(main):002:0> Cls1.name
=> "Cls1"
irb(main):003:0> class Cls1
irb(main):004:1>   def self.name
irb(main):005:2>       puts 'fooo'
irb(main):006:2>   end
irb(main):007:1> end
=> :name
irb(main):008:0> Cls1.name
fooo
=> nil

上記では, Class#namefooo を puts するように上書き (機能変更) している.

const_get は, self に定義されている定数を探索する. 自クラスに定義がない場合は、メソッドと同様に探索を行う

以下のように定数の探索が行われている.

irb(main):001:0> module Mod1
irb(main):002:1>   CONST = 'Mod1'
irb(main):003:1> end
=> "Mod1"
irb(main):004:0> 
irb(main):005:0* class Cls1
irb(main):006:1>   CONST = 'Cls1'
irb(main):007:1> end
=> "Cls1"
irb(main):008:0> 
irb(main):009:0* class Cls2 < Cls1
irb(main):010:1>   def self.name
irb(main):011:2>     const_get(:CONST)
irb(main):012:2>   end
irb(main):013:1> end
=> :name
irb(main):014:0> Cls2.name
=> "Cls1"
...
irb(main):001:0> module Mod1
irb(main):002:1>   CONST = 'Mod1'
irb(main):003:1> end
=> "Mod1"
irb(main):004:0> 
irb(main):005:0* class Cls1
irb(main):006:1>   CONST = 'Cls1'
irb(main):007:1> end
=> "Cls1"
irb(main):008:0> 
irb(main):009:0* class Cls2 < Cls1
irb(main):010:1>   include Mod1
irb(main):011:1>   def self.name
irb(main):012:2>     const_get(:CONST)
irb(main):013:2>   end
irb(main):014:1> end
=> :name
irb(main):015:0> Cls2.name
=> "Mod1"

フムフム.