type holyshared = Engineer<mixed>

技術的なことなど色々

Hack用のコードジェネレータの新しいバージョンをリリース

Hack用のコードジェネレータの新しいバージョンをリリースしました。
前のバージョンでは、デフォルトのジェネレータしか使用できなかったのを独自のジェネレータを使用できるようにしました。

サンプルのプロジェクト下記に用意してあります。
https://github.com/holyshared/hhpack-codegen-example

利用する為の設定

composer.json

hhpack/codegenを開発用のパッケージに追加します。

"require-dev": {
  "hhpack/codegen": "^0.2.0"
},

hh_autoload.json

ジェネレータの設定が読み込めるように、devRootsにパスを追加します。
パスが間違っていると、設定が読み込めないので注意してください。

{
  "roots": "src",
  "devRoots": "/path/to/" // 設定ファイルがあるパス
}

ジェネレータの設定ファイルを追加する

名前空間に対して、対応するジェネレータをマッピングするのは変わっていないです。
今回のバージョンではジェネレータに対して、名前と説明をメタ情報と持たせることができます。
このメタ情報は、コマンドラインからジェネレータを指定するのに使用します。

下記の例ではジェネレータにそれぞれ、package:class、package:testclassという名前をつけています。

<?hh //strict

namespace HHPack\Example\Generators;

use HHPack\Codegen\Cli\{ DefinedGenerator };
use HHPack\Codegen\Contract\{ GeneratorProvider };
use HHPack\Codegen\HackUnit\{ TestClassGenerator };
use HHPack\Codegen\Project\{ PackageClassGenerator };
use function HHPack\Codegen\Cli\{ namespace_of, define_generator };

final class Generators implements GeneratorProvider {
  public function generators(): Iterator<DefinedGenerator> {
    // Link package namespace to generator
    yield define_generator('package:class', 'generate class file for package')
      ->mapTo(
        namespace_of('HHPack\Example', 'src')->
          map(PackageClassGenerator::class)
      );

    // Link package test namespace to generator
    yield define_generator('package:testclass', 'generate test class file for package')
      ->mapTo(
        namespace_of'HHPack\Example\Test' 'test')->
          map(TestClassGenerator::class)
      );
  }
}

コードの生成

コードを生成するにはコマンドラインからジェネレーターを指定します。
利用できるジェネレータは、ヘルプで確認できます。

vendor/bin/codegen -h

Usage: codegen [OPTIONS] [GEN] [NAME]

Arguments:
   GEN: generator name (ex. lib, test)
    package:class       generate class file for package
    package:testclass   generate test class file for package

  NAME: generate class name (ex. Foo\Bar)

Options:
  -h, --help     Display help message
  -v, --version  Display version

今回の例だと、package:class、package:testclassを利用できます。

vendor/bin/codegen package:class [CLASS_NAME]
vendor/bin/codegen package:testclass [CLASS_NAME]

例えば下記の例だと、src/FooBarのクラスファイルを生成します。

vendor/bin/codegen package:class Foo\\Bar

独自ジェネレータ

独自のジェネレータを使用したい場合は、インタフェースのHHPack\Codegen\Contract\ClassFileGeneratableを実装すればいいです。
詳しくはデフォルトで組み込まれているソースを参考にしてください。

use HHPack\Codegen\{GenerateClassFile};
use HHPack\Codegen\Contract\{ClassFileGeneratable};
use Facebook\HackCodegen\{ICodegenFactory, CodegenFile, CodegenClass};

final class MyGenerator implements ClassFileGeneratable {
  public static function from(ICodegenFactory $factory): this {
    return new self($factory);
  }

  public function generate(GenerateClassFile $target): CodegenFile {
  }
}