ようへいの日々精進XP

よかろうもん

2018 年 06 月 18 日 (月)

ジョギング

  • 自宅→香椎神宮香椎浜 で 35 分くらい
  • 臀部の強い張り (ストレッチでなんとかしている)

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

関西地方で大きな地震

  • 大きな被害が出ていた
  • 親戚や友人の皆さんは特にケガもなくということで一安心
  • これから天気も悪くなるとのことなので, 引き続き気をつけてくださいmm

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

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 Foo
  NAME = "foo"

  def self.name
    const_get(:NAME)
  end
end

class Bar < Foo
  NAME = "bar"
end

puts Bar.name

bar が表示される

以下, irb にて確認.

irb(main):001:0> class Foo
irb(main):002:1>   NAME = "foo"
irb(main):003:1> 
irb(main):004:1*   def self.name
irb(main):005:2>     const_get(:NAME)
irb(main):006:2>   end
irb(main):007:1> end
=> :name
irb(main):008:0> 
irb(main):009:0* class Bar < Foo
irb(main):010:1>   NAME = "bar"
irb(main):011:1> end
=> "bar"
irb(main):012:0> 
irb(main):013:0* puts Bar.name
bar
=> nil

以下, 解説より抜粋.

  • Class#name はクラス名を文字列で返す
  • Foo#name クラスは Class#name をオーバーライドしているので, const_get が呼ばれることになる
  • const_get は, self に定義された定数を探索し, 自クラスに定義がない場合は, メソッドと同様に探索を行う

ドキュメントを見てみると, Class#name というメソッドが無いんだが...きっと, Module#name のことなんだろうなあということで, Module#name 前提でちょっと掘り下げる.

irb(main):001:0> class Foo; end
=> nil
irb(main):002:0> Foo.name
=> "Foo"
irb(main):003:0> Foo.inspect
=> "Foo"
irb(main):004:0> Foo.to_s
=> "Foo"

Module#nameModule#inspecModule#to_s と同義である. このメソッドが返す「クラス/モジュール名」とは, 正確には「クラスパス」を指す.

irb(main):005:0> class Foo
irb(main):006:1>   class Bar
irb(main):007:2>   end
irb(main):008:1>   Bar.name
irb(main):009:1> end
=> "Foo::Bar"
irb(main):010:0> Foo.name
=> "Foo"
irb(main):012:0> Foo::Bar.name
=> "Foo::Bar"
irb(main):013:0> class Foo
irb(main):014:1>   class Baz; end
irb(main):015:1> end
=> nil
irb(main):016:0> Foo::Baz.name
=> "Foo::Baz"

引き続き, const_get について.

irb(main):001:0> module Bar
irb(main):002:1>   BAR = 1
irb(main):003:1> end
=> 1
irb(main):004:0> class Object
irb(main):005:1>   include Bar
irb(main):006:1> end
=> Object
# Object では include されたモジュールの定義を探索する
irb(main):007:0> Object.const_get(:BAR)
=> 1
# 存在しない定数にアクセスしようとすると例外 (NameError) が発生する
irb(main):008:0> Object.const_get(:FOO)
NameError: uninitialized constant FOO
... 略 ...
# トップレベルに定数を定義して, その定数を参照する場合
irb(main):009:0> BAR = 10
=> 10
irb(main):011:0> Object.const_get(:BAR)
=> 10
# 完全修飾名で定数を指定した場合には, モジュールに定義されている定数を参照する
irb(main):013:0> Object.const_get('Bar::BAR')
=> 1
irb(main):007:0> class Baz
irb(main):008:1>   include Bar
irb(main):009:1> end
=> Baz
irb(main):010:0> Baz.const_get(:BAR)
=> 1
# 第二引数に false を付けると, 自身に定義された定数から探す
irb(main):011:0> Baz.const_get(:BAR, false)
NameError: uninitialized constant Baz::BAR
... 略 ...
irb(main):012:0> class Baz
irb(main):013:1>   BAR = 2
irb(main):014:1> end
=> 2
irb(main):015:0> Baz.const_get(:BAR)
=> 2
irb(main):016:0> Baz.const_get(:BAR, false)
=> 2
irb(main):017:0> Baz.const_get('Bar:BAR')
NameError: wrong constant name Bar:BAR
... 略 ...
irb(main):018:0> Baz.const_get('Bar::BAR')
=> 1

const_get は, 引数 (String か Symbol で指定) で指定された定数を取り出す. 存在していない定数を参照すると NameError の例外が発生する. 第二引数に false を指定すると, 自身に定義された定数から探す.

フムフム.