🐕
[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