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
も実態がプラグインなので、勉強しやすくていい。