Steepコードリーディング(2日目)

# Steepコードリーディング(2日目)

前回の続き、`Steep::Drivers::Check#run`の`load_config`を追っていく。

## `Steep::Drivers::Utils::DriverHelper`

https://github.com/soutaro/steep/blob/290ab9a3d023f1ed8011fb720c420c611e5473b9/lib/steep/drivers/utils/driver_helper.rb

### `Steep::Drivers::Utils::DriverHelper#load_config`

プロジェクト内のSteepfileを使って`Project`インスタンスを返している。`Project`インスタンスには`Project::Target`の配列を持つ`Project#targets`があり、これをeachして[gem_rbs_collection](https://github.com/ruby/gem_rbs_collection)の`rbs_collection.lock.yaml`ファイルのチェックを行っている

```rb
def load_config(path: steepfile || Pathname("Steepfile"))
  if path.file?
    steep_file_path = path.absolute? ? path : Pathname.pwd + path
    Project.new(steepfile_path: steep_file_path).tap do |project|
      Project::DSL.parse(project, path.read, filename: path.to_s)
    end
  else
    Steep.ui_logger.error { "Cannot find a configuration at #{path}: `steep init` to scaffold. Using current directory..." }
    Project.new(steepfile_path: nil, base_dir: Pathname.pwd).tap do |project|
      Project::DSL.eval(project) do
        target :'.' do
          check '.'
          signature '.'
        end
      end
    end
  end.tap do |project|
    project.targets.each do |target|
      case result = target.options.load_collection_lock
      when nil, RBS::Collection::Config::Lockfile
        # ok
      when Pathname
        # File is missing
        if result == target.options.collection_config_path
          # Config file is missing
          Steep.ui_logger.error { "rbs-collection configuration is missing: `#{result}`" }
        else
          # Lockfile is missing
          Steep.ui_logger.error { "Run `rbs collection install` to generate missing lockfile: `#{result}`" }
        end
      when YAML::SyntaxError
        # File is broken
        Steep.ui_logger.error { "rbs-collection setup is broken:\nsyntax error #{result.inspect}" }
      when RBS::Collection::Config::CollectionNotAvailable
        unless disable_install_collection
          install_collection(target, target.options.collection_config_path || raise)
        else
          Steep.ui_logger.error { "Run `rbs collection install` to set up RBS files for gems" }
        end
      end
    end
  end
end
```

## `Steep::Project`

https://github.com/soutaro/steep/blob/290ab9a3d023f1ed8011fb720c420c611e5473b9/lib/steep/project.rb

## `Project::DSL`

https://github.com/soutaro/steep/blob/290ab9a3d023f1ed8011fb720c420c611e5473b9/lib/steep/project/dsl.rb

### `Project::DSL#.parse`

プロジェクト内のSteepfileのコードをinstance_evalで実行し、`Project`のオプションを設定する。

```rb
def self.parse(project, code, filename: "Steepfile")
  Steep.logger.tagged filename do
    dsl = self.new(project: project)
    dsl.instance_eval(code, filename)
    project.global_options = dsl.to_library_options
  end
end
```

Steepfileには`target :app do ... end`のように記述するが、それが`Project::DSL#target`を呼び出すスクリプトとなる。

### `Project::DSL#target`

`Project::Target`を作成し、`Project#targets`に追加する。

```rb
def target(name, &block)
  dsl = TargetDSL.new(name, project: project)

  Steep.logger.tagged "target=#{name}" do
    dsl.instance_eval(&block) if block
  end

  target = Project::Target.new(
    name: dsl.name,
    source_pattern: dsl.source_pattern,
    signature_pattern: dsl.signature_pattern,
    options: dsl.library_configured? ? dsl.to_library_options : nil,
    code_diagnostics_config: dsl.code_diagnostics_config,
    project: project,
    unreferenced: dsl.unreferenced
  )

  dsl.groups.each do
    group = Group.new(target, _1.name, _1.source_pattern, _1.signature_pattern, _1.code_diagnostics_config || target.code_diagnostics_config)
    target.groups << group
  end

  project.targets << target
end
```

SteepfileのDSLを追加したり変更したいときは、この辺りのメソッドを追加したり変更すると良さそう。

次回は `Steep::Drivers::Check#run` の `Server::WorkerProcess.start_typecheck_workers` を追っていく。