- Kernel.autoload
- ActiveSupport::Autoload
Kernel.autoload
使い方
class Hoge
end
Hoge.autoload :Fuga, 'fuga'
引用
require と同様な方法で autoload する対象を指定します。
feature が絶対パスのときは feature からロードします。 feature が相対パスのときは組み込み変数 $: に示されるパスを順番に探し、最初に見付かったファイルを ロードします。
実験
% ruby -e 'puts $:'
/Users/nishisuke/.rbenv/rbenv.d/exec/gem-rehash
/Users/nishisuke/.rbenv/versions/2.6.3/lib/ruby/site_ruby/2.6.0
/Users/nishisuke/.rbenv/versions/2.6.3/lib/ruby/site_ruby/2.6.0/x86_64-darwin18
/Users/nishisuke/.rbenv/versions/2.6.3/lib/ruby/site_ruby
/Users/nishisuke/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby/2.6.0
/Users/nishisuke/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby/2.6.0/x86_64-darwin18
/Users/nishisuke/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby
/Users/nishisuke/.rbenv/versions/2.6.3/lib/ruby/2.6.0
/Users/nishisuke/.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18
pwdが含まれないことに注意。
ちなみに
$:
$LOAD_PATH
$-I
が検索パスを返す。
話に戻ると
% ls
bar.rb fiz.rb foo.rb ex.rb
autoload :Foo, '/foo'
autoload :Bar, 'bar'
autoload :Fiz, './fiz'
Fiz # ok
Bar # `require': cannot load such file -- bar (LoadError)
Foo # `require': cannot load such file -- /foo (LoadError)
おまけ
よいこは真似しないように。
autoload :Bar, 'bar'
$: << __dir__
Bar # ok
実験2
今までの実験は、mainオブジェクトにトップレベルの定数をloadしようとしていた
ネストした定数はどうか
引用
const_name には、 "::" 演算子を含めることはできません
つまり
autoload 'Fiz::Baz'.to_sym, './fiz/baz'
はだめ。
class Fiz
autoload :Foo, './foo'
autoload :Baz, './fiz/baz'
end
Fiz::Baz
Fiz::Foo # NameError
class Foo; end
class Fiz
class Baz
end
end
ActiveSupport::Autoload
branch: 6-0-stable
commit: 186edaedfc
module ActiveSupport
module Autoload
def self.extended(base) # :nodoc:
base.class_eval do
@_autoloads = {}
@_under_path = nil
@_at_path = nil
@_eager_autoload = false
end
end
def autoload(const_name, path = @_at_path)
unless path
full = [name, @_under_path, const_name.to_s].compact.join("::")
path = Inflector.underscore(full)
end
if @_eager_autoload
@_autoloads[const_name] = path
end
super const_name, path
end
def autoload_under(path)
@_under_path, old_path = path, @_under_path
yield
ensure
@_under_path = old_path
end
def autoload_at(path)
@_at_path, old_path = path, @_at_path
yield
ensure
@_at_path = old_path
end
def eager_autoload
old_eager, @_eager_autoload = @_eager_autoload, true
yield
ensure
@_eager_autoload = old_eager
end
def eager_load!
@_autoloads.each_value { |file| require file }
end
def autoloads
@_autoloads
end
end
end
autoload(const_name, path = @_at_path)
使い方
require 'bundler/inline'
gemfile do
gem 'activesupport'
end
require 'active_support/dependencies/autoload'
class Fiz
extend ActiveSupport::Autoload
autoload :Baz
end
$: << __dir__
Fiz::Baz
Kernel.autoload
と異なりfileを自動で推察してくれる。
ActiveSupport::Autoloadを使うクラスはgemとしてloadされる前提っぽい?
ので素のruby fileで動かす場合 $: << __dir__
が必要。
gemとしてloadされれば探索パスに入れられるため。
def autoload_under(path)
moduleのネストとディレクトリ階層が違う時に使える。
require 'bundler/inline'
gemfile do
gem 'activesupport'
end
require 'active_support/dependencies/autoload'
class Fiz
extend ActiveSupport::Autoload
autoload_under 'baz' do
autoload :FizBaz
end
end
$: << __dir__
Fiz::FizBaz
class Fiz
class FizBaz
end
end
def autoload_at(path)
filepathと定数名が違う時に便利
require 'bundler/inline'
gemfile do
gem 'activesupport'
end
require 'active_support/dependencies/autoload'
class Fiz
extend ActiveSupport::Autoload
autoload_at 'fiz/stranger' do
autoload :FizBazFoo
end
end
$: << __dir__
Fiz::FizBazFoo