🙆♀️
[Misc #21035] Module#autoload? と Module#const_defined? の挙動に関するチケット
[Misc #21035] Clarify or redefine Module#autoload? and Module#const_defined?
-
Module#autoload?とModule#const_defined?の挙動に関するチケット -
Module#autoload?やModule#const_defined?は一般的には次のような挙動になる
# foo.rb
module M
class Foo
end
end
# m.rb
module M
# Foo の手数を参照すると foo が require される
autoload :Foo, './foo'
# Foo は定義はされていないが定義されているように振る舞う
p constants # => [:Foo]
p const_defined?(:Foo) # => true
# まだ Foo がロードされていない場合はそのパス名を返す
p autoload?(:Foo) # => 'foo'
# 定数を参照すると autoload が発火し foo.rb を読み込む
Foo
# ロード後は autoload? の戻り値が変わる
p constants # => [:Foo]
p const_defined?(:Foo) # => true
p autoload?(:Foo) # => nil
end
- これなんですが以下のように
autoloadで指定したファイルが既にロード済みの場合にconst_defined?(:Foo)がfalseになったりautoload?(:Foo)がnilを返すケースがある、というのがチケットの内容になる
# main.rb
require "./foo"
# foo.rb
require "./m"
module M
autoload :Foo, './foo'
p constants # => [:Foo]
p const_defined?(:Foo) # => false
p autoload?(:Foo) # => nil
end
$ ruby main.rb
[:Foo]
false
nil
- 上記のような構成になっているときに
main.rbを読み込むとconst_defined?やautoload?が意図しない値を返すという事象 - これは
foo.rbが既にロード済みなのでFooがautoload中である、とみなしているみたいですね - どういうことかというと次のような
autoloadがある場合
autoload :Foo, './foo'
- いずれかのタイミングで
Fooを参照すると./fooがrequireされる - また
autoload以外でrequire "./foo"がされる(されている)と『autoloadが破棄される』という挙動になる
require "./foo"
module M
autoload :Foo, './foo'
# autoload は破棄されている
p const_defined?(:Foo) # => false
p autoload?(:Foo) # => nil
end
- これにより最初に上げたような挙動になるみたいですね
- その後も少し議論しているんですが最終的には起票者がどういう挙動になっているのかは理解したようでチケット自体は閉じられています
Discussion