🐕
[Bug #21193] Object.const_source_location が参照できなくなったというバグ報告
[Bug #21193] Inherited callback returns nil
for Object.const_source_location
- 開発版の Ruby 3.5-dev で
.inherited
時にObject.const_source_location
で参照できなくなったというバグ報告
class A
def self.inherited(other)
p other # => B
super
p Object.const_source_location(other.name)
# Ruby 3.4 => ["test.rb", 8]
# Ruby 3.5 => nil
end
end
class B < A
end
-
.inherited
は『自身が継承されたとき』に呼ばれるフックメソッド- 上記の場合だと
class B < A
でA
を継承したタイミングで呼ばれている -
.inherited
の引数は継承先のクラスが渡される
- 上記の場合だと
- これなんですが [Misc #21143] Speficy order of execution const_added vs inherited によって
.const_added
と.inherited
の実行順を変えたのが影響しているみたいですね - Ruby 3.4 では
.const_added -> .inherited
の順で呼ばれていたものを上記のチケットで.inherited -> .const_added
の順にされました
$caller = []
module M
class C
def self.inherited(subclass)
$caller << ".inherited: #{subclass}"
end
end
def self.const_added(cname)
$caller << ".const_added: #{cname}"
end
class D < C; end
end
pp $caller
# Ruby 3.4 => [".const_added: D", ".inherited: M::D"]
# Ruby 3.5 => [".inherited: M::D", ".const_added: D"]
- これにより今回の問題が発生するようになったみたいですね
- 実際に Shopify's では以下のように
.inherited
で.const_source_location
に依存しているコードがあるらしく挙動が壊れてしまったみたい
def self.inherited(config)
return super unless config.superclass == Config
# 継承した config の定義元によって何かしらロードするような処理を仕込んでいる
if (class_name = config.name) &&
(config_location = Object.const_source_location(class_name)) &&
(parent_dirname = File.dirname(config_location[0]))
config_dirname = File.join(parent_dirname, "config")
config.autoload(:Something, File.join(config_dirname, "something.rb"))
end
super
end
- これに対していくつか議論されているんですが最終的には互換性を維持するために [Misc #21143] Speficy order of execution const_added vs inherited の対応を元に戻す対応がされました
- なので最終的には
.const_added -> .inherited
の呼び出し順は Ruby 3.4 の状態を維持するように戻りました
- なので最終的には
- もともと [Misc #21143] の方は
.const_added
.inherited
の呼び出し順をちゃんと明文化したい、みたいなモチベーションだったのでそれに合わせて挙動を明文化される対応も行われた
Discussion