LoginSignup
1
1

More than 5 years have passed since last update.

[Ruby] 定数の探索経路-[2]

Last updated at Posted at 2017-07-25

定数が自前の親クラスやモジュールでも定義されていない 場合の動きを確認する.
具体的には クラスメソッドである const_missing の動きを見る.

なおモジュールの include, prepend については "前のエントリ" で見たので本エントリでは確認しない.

確認環境

  • Ruby v2.0.0p648
  • Ruby v2.3.7p456

[1]定数, const_missing が未定義の場合

undefine_const_missing.rb
module Mdl
end

class Cls1
  include Mdl
end

class Cls2 < Cls1
  def hoge
    puts "CONST_VAR: #{CONST_VAR}"
  end
end

# 継承チェーン
Cls2.ancestors # :=> [Cls2, Cls1, Mdl, Object, Kernel, BasicObject]

# エラー発生
Cls2.new.hoge # :=> NameError: uninitialized constant Cls2::CONST_VAR

[2]const_missing をモジュールと親クラスで定義し, 子クラスでも定義した場合

define_const_missing_module_parent_child.rb
module Mdl
  def Mdl.const_missing(id)
    puts "Mdl#const_missing"
  end
end

class Cls1
  include Mdl
  def Cls1.const_missing(id)
    puts "Cls1#const_missing"
  end
end

class Cls2 < Cls1
  def hoge
    puts "CONST_VAR: #{CONST_VAR}"
  end
  def Cls2.const_missing(id)
    puts "Cls2#const_missing"
  end
end

# 継承チェーン
Cls2.ancestors # :=> [Cls2, Cls1, Mdl, Object, Kernel, BasicObject]

# Cls2 で定義した cons_missing が実行される
Cls2.new.hoge # :=> Cls2#const_missing

[3]const_missing をモジュールと親クラスで定義し, 子クラスでは定義しない

define_const_missing_module_parent.rb
module Mdl
  def Mdl.const_missing(id)
    puts "Mdl#const_missing"
  end
end

class Cls1
  include Mdl
  def Cls1.const_missing(id)
    puts "Cls1#const_missing"
  end
end

class Cls2 < Cls1
  def hoge
    puts "CONST_VAR: #{CONST_VAR}"
  end
end

# 継承チェーン
Cls2.ancestors # :=> [Cls2, Cls1, Mdl, Object, Kernel, BasicObject]

# Cls1 で定義した cons_missing が実行される
Cls2.new.hoge # :=> Cls1#const_missing

[4]const_missing を Classクラスで定義し, モジュール, 親クラス, 子クラスでもインスタンスメソッドで定義する

define_const_missing_class_module_parent_child_instancemethod.rb
class Class
  def const_missing(id)
    puts "Class#const_missing"
  end
end

module Mdl
  def const_missing(id)
    puts "Mdl#const_missing"
  end
end

class Cls1
  include Mdl
  def const_missing(id)
    puts "Cls1#const_missing"
  end
end

class Cls2 < Cls1
  def hoge
    puts "CONST_VAR: #{CONST_VAR}"
  end
  def const_missing(id)
    puts "Cls2#const_missing"
  end
end

# 継承チェーン
Cls2.ancestors # :=> [Cls2, Cls1, Mdl, Object, Kernel, BasicObject]

# Class で定義した cons_missing が実行される
Cls2.new.hoge # :=> Class#const_missing

[5]const_missing を Classクラスで定義し, Objectクラスでインスタンスメソッドで定義する

define_const_missing_class_object_instancemethod.rb
class Class
  def const_missing(id)
    puts "Class#const_missing"
  end
end

class Object
  def const_missing(id)
    puts "Object#const_missing"
  end
end

class Cls2
  def hoge
    puts "CONST_VAR: #{CONST_VAR}"
  end
  def const_missing(id)
    puts "Cls2#const_missing"
  end
end

# 継承チェーン
Cls2.ancestors # :=> [Cls2, Object, Kernel, BasicObject]

# Class で定義した cons_missing が実行される
Cls2.new.hoge # :=> Class#const_missing

[6]const_missing を Classクラスで定義し, Objectクラスでクラスメソッドで定義する

define_const_missing_class_object_classmethod.rb
class Class
  def const_missing(id)
    puts "Class#const_missing"
  end
end

class Object
  def Object.const_missing(id)
    puts "Object#const_missing"
  end
end

class Cls2
  def hoge
    puts "CONST_VAR: #{CONST_VAR}"
  end
  def const_missing(id)
    puts "Cls2#const_missing"
  end
end

# 継承チェーン
Cls2.ancestors # :=> [Cls2, Object, Kernel, BasicObject]

# Object で定義した cons_missing が実行される
Cls2.new.hoge # :=> Object#const_missing

結論

  • 定数の探索は継承チェーンを辿って行われる
  • 定数が見つからない場合, const_missing が実行される
    • const_missing はクラスメソッドで実装されている必要がある
    • Classクラスのインスタンスメソッドは他のクラスのクラスメソッドとして処理される
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1