railsのrake taskを深ぼる

## version
gem 'rails', '~> 6.0.0.rc1'

rails6のrc1です注意。


## rakeとは

https://github.com/ruby/rake

taskをrubyのdslで定義できるもの

Rakefileにタスク定義を書く

```Rakefile
task :hoge do
  puts :hello
end
```

## railsにおけるraketask

```
rails-sample-6/ [master]% bundle exec rake -T
rake about                              # List versions of all Rails frameworks and the environment
rake app:template                       # Applies the template supplied by LOCATION=(/path/to/template) or URL
rake app:update                         # Update configs and some other initially generated files (or use just update:configs or update:bin)
rake cache_digests:dependencies      
......
...
```

いっぱい出てくる
だけど、Rakefileを見てみると

```Rakefile
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require_relative 'config/application'

Rails.application.load_tasks
```

こんなけ

`require_relative 'config/application'`

は 'config/application' を読み込む
これはactivemodelとかGemとかを読み込むファイル。

`Rails.application.load_tasks`
を掘っていく

```
[2] pry(main)> $ Rails.application.load_tasks

def load_tasks(app = self)
  require "rake"
  run_tasks_blocks(app)
  self
end

[3] pry(main)> $ Rails.application.run_tasks_blocks

def run_tasks_blocks(app) #:nodoc:
  railties.each { |r| r.run_tasks_blocks(app) }
  super
  require "rails/tasks"
  task :environment do
    ActiveSupport.on_load(:before_initialize) { config.eager_load = false }

    require_environment!
  end
end

# super読んでるので親をみる

[4] pry(main)> Rails.application.class.ancestors
=> [RailsSample6::Application,
 Rails::Application,
 Rails::Engine,
 Rails::Railtie,
 Rails::Initializable,
 ActiveSupport::ToJsonWithActiveSupportEncoder,
 Object,
 PP::ObjectMixin,
 JSON::Ext::Generator::GeneratorMethods::Object,
 ActiveSupport::Tryable,
 ActiveSupport::Dependencies::Loadable,
 Kernel,
 BasicObject]

# 関係ありそうなのはRails::Engine, Rails::Railtie

[6] pry(main)> $ Rails::Engine#run_tasks_blocks

def run_tasks_blocks(*) #:nodoc:
  super
  paths["lib/tasks"].existent.sort.each { |ext| load(ext) }
end


# lib/tasksにあるfileをloadしている。
# 自分で定義したものがここで読まれていた。


[7] pry(main)> $ Rails::Railtie#run_tasks_blocks

def run_tasks_blocks(app) #:nodoc:
  extend Rake::DSL
  each_registered_block(:rake_tasks) { |block| instance_exec(app, &block) }
end

[15] pry(main)> $ Rails::Railtie#each_registered_block

def each_registered_block(type, &block)
  klass = self.class
  while klass.respond_to?(type)
    klass.public_send(type).each(&block)
    klass = klass.superclass
  end
end

# public_send :rake_tasks
# を親クラスに向かってしていく.

[16] pry(main)> $ Rails::Application.rake_tasks

def rake_tasks(&blk)
  register_block_for(:rake_tasks, &blk)
end

[17] pry(main)> $ Rails::Application.register_block_for

def register_block_for(type, &blk)
  var_name = "@#{type}"
  blocks = instance_variable_defined?(var_name) ? instance_variable_get(var_name) : instance_variable_set(var_name, [])
  blocks << blk if blk
  blocks
end

# ここまで見て
# Rails::Railtie#each_registered_block
# が、
# Rails::Application, Rails::Engine, Rails::Railtie
# が:rake_tasks用に保持してるProcをexecしていくのがわかった。
# それがなんなのかの深追いはやめて本筋に戻る。

[3] pry(main)> $ Rails.application.run_tasks_blocks

def run_tasks_blocks(app) #:nodoc:
  railties.each { |r| r.run_tasks_blocks(app) }
  super
  require "rails/tasks"
  task :environment do
    ActiveSupport.on_load(:before_initialize) { config.eager_load = false }

    require_environment!
  end
end

# `require 'rails/tasks'` は rails routesなどのコマンドを読み込むもの

[38] pry(main)> $ Rails.application.require_environment!

def require_environment! #:nodoc:
  environment = paths["config/environment"].existent.first
  require environment if environment
end

# これはconfig/environment.rbを読み込むもの
```

```config/environment.rb
# Load the Rails application.
require_relative 'application'

# Initialize the Rails application.
Rails.application.initialize!
```

config/applicationはrakefileで読み込んでいるので
`Rails.application.initialize!`
を呼ぶ

```
[2] pry(main)> $ Rails.application.initialize!

def initialize!(group = :default) #:nodoc:
  raise "Application has been already initialized." if @initialized
  run_initializers(group, self)
  @initialized = true
  self
end

[3] pry(main)> $ Rails.application.run_initializers

def run_initializers(group = :default, *args)
  return if instance_variable_defined?(:@ran)
  initializers.tsort_each do |initializer|
    initializer.run(*args) if initializer.belongs_to?(group)
  end
  @ran = true
end
```

諸々のinitializersが実行される。
多分config/initializers/*
もこれで実行される。

もう疲れたから今日は終わり。

## memo
desc 'hoge'
しないと rake -Tで出てこない