rubyのautoloadについて

- Kernel.autoload
- ActiveSupport::Autoload

## Kernel.autoload
### 使い方

```sample.rb
class Hoge
end

Hoge.autoload :Fuga, 'fuga'
```

### 引用
https://docs.ruby-lang.org/ja/latest/method/Kernel/m/autoload.html

> require と同様な方法で autoload する対象を指定します。

https://docs.ruby-lang.org/ja/latest/method/Kernel/m/require.html

> 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しようとしていた
ネストした定数はどうか

#### 引用
https://docs.ruby-lang.org/ja/latest/method/Kernel/m/autoload.html

> 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
```