speek
という gem をリリースしてみたという記事です。
users.schema
のようなテーブル定義からモデルファイルの型定義を出力します。
ターミナルでの入力例はこんな感じです。
% gem install speek
Fetching speek-0.1.1.gem
Successfully installed speek-0.1.1
Parsing documentation for speek-0.1.1
Installing ri documentation for speek-0.1.1
Done installing documentation for speek after 0 seconds
1 gem installed
% cat example/schema/users.schema
create_table "users", id: :bigint, unsigned: true, force: :cascade, options: "ENGINE=InnoDB" do |t|
t.string "name", null: false
t.text "desc", null: true
t.datetime "deleted_at"
t.integer "weight", null: false, default: 0, unsigned: true
t.boolean "is_banned", null: false, default: false
t.timestamps
end
% speek -i example/schema/users.schema -s rbs
class User
attr_accessor id: Integer
attr_accessor name: String
attr_accessor desc: (String | nil)
attr_accessor deleted_at: (Time | nil)
attr_accessor weight: Integer
attr_accessor is_banned: Boolean
attr_accessor created_at: Time
attr_accessor updated_at: Time
end
単純に AST を操作してなんかやるというのをやってみたかったから、gemをリリースしてみたかったから。というのが個人的な動機ですが…
Ruby には型がないから書きたくないという人がいると聞きますが、近年は rbs という仕組みがあり、 steep という gem や IDE などでいくらか型の恩恵に授かる機会が増えました。
一方で rbs ファイルをアプリケーションのコードとは別に作成し、管理するのは気が滅入る作業です。 動いているシステムの歴史がながければ長いほど、この手間は大きいです。 なんとか既存の資産を活かして rbs を生成したいという気持ちがありました。
自分の所属しているチームでは Rails を使っていて、 ridgepole という gem を使いテーブル定義(schema)を管理しています。 そしてこの schema に対応するモデルが存在していますが、型定義はなかったりします。 そこで、 schema の抽象構文木を利用することでモデルに対応する型定義を出力する gem を作ってみたという感じです
speek
では3つのオプションを指定することが出来ます
-i:input_file_path
: 入力とする schemafile のパスを指定するオプション-o:output_file_path
: 出力先のファイルパスを指定するオプション。指定がなければ標準出力される-s:schema_type
: 出力する型定義の種類
やや命名でミスった感じがあるので直したいとは思っているのですが、いまはこんな感じです。
-s:schema_type
では rbs の他に GraphQL の型も生成できるようにしています。
先程の出力する型を GraphQL 風にしてみると
% speek -i example/schema/users.schema -s gql
type User {
id: Int!
name: String!
desc: String
deletedAt: String
weight: Int!
isBanned: Boolean!
createdAt: String!
updatedAt: String!
}
のようになり、API モードで作成した graphql-rails を使っているようなプロジェクトでも使えるのではないでしょうか。
個人的に開発しているプロダクトで色々使っていき、便利にしていこうと思っています
GraphQL の Custom Scalars に対応したり protobuf の出力もしたいなぁなどと思っています