Danger のプラグインの構造
プルリクエストに関する定形作業を自動化するツール Danger のプラグインを書く機会があったので、プラグインの構造について簡単にメモ。v5.13.0 を参照している。
プラグインクラスの概要
プラグインは Danger モジュールの直下に Danger::Plugin を継承して定義する。クラス名は慣習として DangerfileFooBar となる。
module Danger class DangerfileFooBar < Plugin def greet(msg) # used in Dangerfile ...
Plugin.inherited によって、このクラス自身がプラグインの1つとして登録される。
あとはプラグインが提供したい機能を public メソッドとして定義すればいい。
Dangerfile の実行環境
Dangerfile のコードは Danger::Dangerfile インスタンスの instance_eval として実行される。
- https://github.com/danger/danger/blob/v5.13.0/lib/danger/danger_core/dangerfile.rb#L197-L206
- https://github.com/danger/danger/blob/v5.13.0/lib/danger/danger_core/dangerfile.rb#L296-L298
各プラグインのインスタンスは初期化時に Dangerfile インスタンスの read only なインスタンス変数として登録される。この時、各プラグインクラスの特異メソッド instance_name がインスタンス変数名として使われる。(後述)
Plugin から継承する重要なメソッド
Plugin#initialize
上述の Danger::Dangerfile を受け取ってインスタンス変数 @dangerfile にセットする。
インスタンス作成は Danger 内部で行われるため、プラグイン作成者はこの挙動を変えてはいけない。オーバーライドする場合も引数は変えずに必ず super を呼び出すこと。
def initialize(dangerfile) super # Your code end
Plugin.instance_name
Dangerfile 内でプラグインを参照するための名前を宣言するメソッド。当然だが毎回同じ値を返すこと。
デフォルトではクラス名から Dangerfile を取り除き、スネークケースにした文字列を返すようになっている。例えば DangerfileFooBar.instance_name は "foo_bar" を返すので、Dangerfile 内で foo_bar.greet("hello") のように書ける。
Plugin#method_missing
method_missing では initialize で保存した @dangerfile にフォールバックする。
これはとても重要で、これのおかげであるプラグインから他のプラグイン(例: github)を参照することができる。
とりあえずここまで調べて気が済んだので一旦ここまで。また何かあったら書き足すかも。
Dangerfile 内の danger や github も実態がプラグインなので、勉強しやすくていい。