0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

rubyのautoloadについて

Posted at
  • Kernel.autoload
  • ActiveSupport::Autoload

Kernel.autoload

使い方

sample.rb
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
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)

おまけ
よいこは真似しないように。

ex.rb
autoload :Bar, 'bar'

$: << __dir__

Bar # ok

実験2

今までの実験は、mainオブジェクトにトップレベルの定数をloadしようとしていた
ネストした定数はどうか

引用

const_name には、 "::" 演算子を含めることはできません

つまり
autoload 'Fiz::Baz'.to_sym, './fiz/baz'

はだめ。

ex.rb
class Fiz
  autoload :Foo, './foo'
  autoload :Baz, './fiz/baz'
end

Fiz::Baz
Fiz::Foo # NameError
foo.rb
class Foo; end
fiz/baz.rb
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)

使い方

ex.rb
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
fiz/baz/fiz_baz.rb
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
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?