ジョギング
日課
- (腕立て 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#name
は Module#inspec
や Module#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
を指定すると, 自身に定義された定数から探す.
フムフム.