毎回エディタからファイル作成したり、名前空間指定したりするのが面倒なので、コードを生成できるようにした。
コードの生成というか、ファイル生成に近いです。
使い方
名前空間とディレクトリのペアに対応させるジェネレータをマッピングする設定ファイルを書いて、 オートロードで読み込めるようにするだけで、あとはコマンド実行するだけでクラスファイルを出力してくれる。
設定ファイルを用意する
<?hh //strict namespace MyPackage\Generators; use HHPack\Codegen\Cli\{ GeneratorProvider }; use HHPack\Codegen\HackUnit\{ TestClassGenerator }; use HHPack\Codegen\Project\{ PackageClassGenerator }; use function HHPack\Codegen\Cli\{ namespace_of, library, library_test }; final class Generators implements GeneratorProvider { // Your package namespace const string PACKAGE_NAMESPACE = 'MyPackage'; const string PACKAGE_TEST_NAMESPACE = 'MyPackage\Test'; public function generators(): Iterator<Pair<GenerateType, ClassFileGenerator>> { // Link package namespace to generator yield library( namespace_of(static::PACKAGE_NAMESPACE, 'src') ->map(PackageClassGenerator::class)); // Link package test namespace to generator yield library_test( namespace_of(static::PACKAGE_TEST_NAMESPACE, 'test') ->map(TestClassGenerator::class)); } }
hh_autoload.jsonに設定を追加
次にhh_autoload.jsonのdevRootsにパスを設定します。
下記の設定だと、configディレクトリが読みこみ対象になります。
{ "roots": "src", "devRoots": "config" }
hhvm_autoloadが必要なので、インストールしてください。
これだけでコードが生成できるようになります。
コードの生成
パッケージのクラスを生成する
生成するタイプとクラス名を指定すると、設定ファイルで指定したディレクトリにファイルを生成できます。
ファイルにはあらかじめ名前空間が設定されるので、指定する手間が省けます。
クラスファイル
libを指定すると、クラスファイルを生成します。
vendor/bin/codegen lib Foo\LibClass
テストクラスファイル
testを指定すると、テスト用のクラスファイルを生成します。
vendor/bin/codegen test Foo\LibClassTest
独自ジェネレータ
ClassFileGeneratableインターフェースを実装すれば独自のジェネレータを定義できます。
下記は、プレーンなクラスファイルを生成するジェネレータです。
どういうファイルが生成可能かはhack-codegenを参考にしてください。
shapeを定義したり、trait定義できたり、結構いろんなものが生成できます。
<?hh //strict namespace MyPackage\Generators; use HHPack\Codegen\{GenerateClass, ClassFileGeneratable}; use Facebook\HackCodegen\{ICodegenFactory, CodegenFile, CodegenClass}; final class CustomGenerator implements ClassFileGeneratable { public function __construct(private ICodegenFactory $cg) {} public static function from(ICodegenFactory $factory): this { return new self($factory); } public function generate(GenerateClass $class): CodegenFile { // ファイルを生成するコードを書く return $this->cg ->codegenFile($class->fileName()) ->setIsStrict(true) ->setNamespace($class->belongsNamespace()); } private function classOf(string $className): CodegenClass { return $this->cg->codegenClass($className)->setIsFinal(true); } }