Swift gybの環境構築
Swift gybの環境構築
ふとSwiftのgybが気になったので環境構築を試して見ました
gybとは
Swift言語開発の副産物のメタプログラミングツールgybがとても良い
— おもちメタル (@omochimetaru) 2017年6月30日
gybは「Generate Your Boilerplate」の略称みたいです(gyb --help
より)
具体的に何かと言うと、Swiftの公式リポジトリの中でSwiftコードの自動生成に使われているPython製のテンプレートエンジンになります
gybを導入する
というわけで、こちらを参考に環境構築して見ました
まずgyb自体はapple/swiftの/utils/
の中にそのまま入っています
Qiitaの紹介記事ままですがcurlでgybファイルを取得していきます
mkdir gyb curl "https://raw.githubusercontent.com/apple/swift/master/utils/gyb.py" -o "gyb/gyb.py" curl "https://raw.githubusercontent.com/apple/swift/master/utils/gyb" -o "gyb/gyb" chmod +x gyb/gyb
上記のshellをそのまま実行すればgybを動かすのに必要なファイルが揃います
実際に動くかどうか確認します
$ cd gyb $ ./gyb --help
これでhelpの一覧が出れば成功です
usage: gyb [-h] [-D NAME=VALUE] [-o TARGET] [--test] [--verbose-test] [--dump] [--line-directive LINE_DIRECTIVE] [file] Generate Your Boilerplate! positional arguments: file Path to GYB template file (defaults to stdin) optional arguments: -h, --help show this help message and exit -D NAME=VALUE Bindings to be set in the template's execution context -o TARGET Output file (defaults to stdout) --test Run a self-test --verbose-test Run a verbose self-test --dump Dump the parsed template to stdout --line-directive LINE_DIRECTIVE Line directive prefix; empty => no line markers A GYB template consists of the following elements: - Literal text which is inserted directly into the output - %% or $$ in literal text, which insert literal '%' and '$' symbols respectively. - Substitutions of the form ${<python-expression>}. The Python expression is converted to a string and the result is inserted into the output. - Python code delimited by %{...}%. Typically used to inject definitions (functions, classes, variable bindings) into the evaluation context of the template. Common indentation is stripped, so you can add as much indentation to the beginning of this code as you like - Lines beginning with optional whitespace followed by a single '%' and Python code. %-lines allow you to nest other constructs inside them. To close a level of nesting, use the "%end" construct. - Lines beginning with optional whitespace and followed by a single '%' and the token "end", which close open constructs in %-lines. Example template: - Hello - %{ x = 42 def succ(a): return a+1 }% I can assure you that ${x} < ${succ(x)} % if int(y) > 7: % for i in range(3): y is greater than seven! % end % else: y is less than or equal to seven % end - The End. - When run with "gyb -Dy=9", the output is - Hello - I can assure you that 42 < 43 y is greater than seven! y is greater than seven! y is greater than seven! - The End. -
gybの使い方
ヘルプ
$ ./gyb --help
もしくは
$ ./gyb -h
テンプレートをコンソール上に出力
下記コマンドからgyb形式のテンプレートを元に出力を行えます
注意点として--line-directive=
のオプションを追加しない場合は// ###sourceLocation
というgyb側がSwiftコンパイラの為に出力するコメントも一緒に出力されてしまうので見た目的にも追加した方が良いです
$ ./gyb {gyb_file} --line-directive=
Int/UIntの全てのビットの型に対して最大値を返す関数を追加
テンプレートがこちら
template.swift.gyb
%{ intTypes = [8,16,32,64] }% % for intType in intTypes: % for sign in ['','U']: /// Extension that adds a few additional functionalities to ${sign}Int${intType} extension ${sign}Int${intType} { /// Returns a ${sign}Int${intType} with all ones %if sign == '': public static var allOnes:Int${intType} { return Int${intType}(bitPattern: UInt${intType}.max) } %else: public static var allOnes:UInt${intType} { return UInt${intType}.max } %end } %end %end
出力してみます、下記コマンドを叩いて見ます
$ ./gyb template.swift.gyb --line-directive=
これでInt / UIntの8から64ビットの型に対してextensionするコードが生成されてるのが確認できれば成功です
/// Extension that adds a few additional functionalities to Int8 extension Int8 { /// Returns a Int8 with all ones public static var allOnes:Int8 { return Int8(bitPattern: UInt8.max) } } /// Extension that adds a few additional functionalities to UInt8 extension UInt8 { /// Returns a UInt8 with all ones public static var allOnes:UInt8 { return UInt8.max } } /// Extension that adds a few additional functionalities to Int16 extension Int16 { /// Returns a Int16 with all ones public static var allOnes:Int16 { return Int16(bitPattern: UInt16.max) } } /// Extension that adds a few additional functionalities to UInt16 extension UInt16 { /// Returns a UInt16 with all ones public static var allOnes:UInt16 { return UInt16.max } } /// Extension that adds a few additional functionalities to Int32 extension Int32 { /// Returns a Int32 with all ones public static var allOnes:Int32 { return Int32(bitPattern: UInt32.max) } } /// Extension that adds a few additional functionalities to UInt32 extension UInt32 { /// Returns a UInt32 with all ones public static var allOnes:UInt32 { return UInt32.max } } /// Extension that adds a few additional functionalities to Int64 extension Int64 { /// Returns a Int64 with all ones public static var allOnes:Int64 { return Int64(bitPattern: UInt64.max) } } /// Extension that adds a few additional functionalities to UInt64 extension UInt64 { /// Returns a UInt64 with all ones public static var allOnes:UInt64 { return UInt64.max } }
あと例えばファイル内のgybファイルを一気に出力するような場合はomochiさんがこういうスクリプトを書いてくれてたりするので参考にすると良いかもしれません
終わりに
こんな感じで書くことが決まってるのに型の都合で書かないといけないコードだったりが、gybを使うことで人間が手を動かす量が減るのは最高ですね
まだ使い始めたばっかりなのでなんともですけど、swagger.ymlからAPI定義を元にgyb経由して自動でモデル定義吐けたりとかが理想です、どんどん楽していきたい…(切実)