Object#const_get

クラス名からクラスを得る方法は、リファレンスマニュアルによると eval を使う方法、Object#const_get を使う方法の二通りがあるようです。

#!/usr/local/bin/ruby

class Player
  attr_accessor :name, :age
  def initialize(name, age)
    @name = name
    @age = age
  end
end

player1 = Object.const_get('Player').new('rubyo', 19)
puts player1.name
puts player1.age

player2 = eval('Player').new('rubco', 18)
puts player2.name
puts player2.age

この時クラス名が Net::HTTP のようにネストしている場合の方法についてもマニュアルに解説がありました。

eval で文字列を"コード上のクラス名"として扱うことについては理解できました。一方の const_get は ri すると

------------------------------------------------------- Module#const_get
     mod.const_get(sym)    => obj
------------------------------------------------------------------------
     Returns the value of the named constant in _mod_.

        Math.const_get(:PI)   #=> 3.14159265358979

とありました。named 定数の値を取得する。引数はシンボル。この Math の例を見ると特定のモジュール内で定義されている定数を取得できる、という風に見れます。 Math モジュールの中には PI という定数が定義されていて、その値は 3.14159... であり、それを Math モジュールの外から取得する手段として const_get が用意されている、ということでしょう。

  • Math モジュールの中の
  • PI 定数を取得する
  • その値は 3.14159...

モジュールのクラスに相当する Module クラスには constans というメソッドがあり、これで定数一覧を取得できます。

$ irb
irb(main):001:0> Math.constants
=> ["E", "PI"]

と、確かに Math モジュールには PI 定数があることが分かります。

もとい、

Object.const_get('Player') #=> Player

はどう理解すれば良いかというと、先の Math のものをそのまま当てはめると

  • Object クラスの中の
  • Player 定数を取得する
  • その値は Player というクラス名( 'Player' という文字列ではなく、コード上でクラス名と解釈される Player という値)

と言う風になります。ということは Object クラスに Player という定数が定義されていることになるのでしょう。そこで、

#!/usr/local/bin/ruby

class Player
end

Object.constants.each {|const| puts const }

というコードを書き確かめてみました。

$ ruby const_get.rb | grep 'Player'
Player

確かに Player という定数が見つかりました。一方、class Player を定義していない段階で const_get してみます。

$ irb
irb(main):001:0> Object.const_get(:Player)
NameError: uninitialized constant Player
        from (irb):1:in `const_get'
        from (irb):1
irb(main):002:0> Object.const_get(:String)
=> String

組み込みクラスの String では結果が返るのに対して、定義されていないクラスの Player には結果が返りませんでした。

つまり、Object クラスは、そのアプリケーションの中で扱えるクラスのクラス名を定数として持つような機構になっている、と理解しました。