この記事は「Qiita Advent Calendar 2019 DSLで自作ビルドツールを作ろう」の2日目の記事です。
2日目 ターゲットを作ろう
Makefileで何が必要かということを考えてみると、まずはビルド対象のターゲットが必要です。Makefileだと、以下のようなやつです。
targets: target1 target2 echo Hello World
ターゲットを定義して、そのターゲット依存する別のターゲット、そして実行コマンドを記述するわけです。これらの情報を定義するために、DSLで以下のように記述するようにしたいです。
- 目標とするDSLの構造
make_target :first do # ":first" ターゲットの定義 depends [:second, :third] # 依存関係として:second, :thirdとして登録する executes "echo Hello World" # 実行コマンド end
ターゲットを定義するために、make_target
メソッドを定義しました。make_target
の中では、以下の2つのメソッドを記述できます。
depends
: 該当するターゲットに依存するターゲットを登録します。executes
: 実行するコマンドを指定します。
このメソッドを定義するために、以下のようにTargets
クラスを定義します。
class Target # コンストラクタ def initialize(name) @name = name end # dependsメソッド。依存関係を定義する。 def depends(targets) @depends = targets end # executesメソッド。実行コマンドを定義する。 def executes(commands) @commands = commands end # デバッグ用のコマンド。メンバ変数の中身を表示する。 def show puts "Target Name = #{@name}, Depends = #{@depends}, Commands = #{@commands}" end end
Targets
クラスを定義しました。depends
メソッド、executes
メソッドは見た通りです。デバッグ用のshow
メソッドと、コンストラクタとしてinitialize
を定義しました。
では、このTargetクラスをインスタンス化するためにmake_target
メソッドを定義します。
def make_target (name, &block) target = Target.new(name) target.instance_eval(&block) target.show end
make_target
クラスでは、ターゲットの名前とブロックを受け取り、Target
クラスをインスタンス化します。
そして、インスタンス化したtarget
に対してinstance_eval
を適用し、ブロックの内部のメソッドを適用します。最後に、ここではデバッグのためにshow
メソッドを実行します。
これに対してテストを実行します。上記のテストを実行してみます。
make_target :first do depends [:second, :third] executes "echo Hello World" end
ruby -Isrc/ tests/exec_test.rb
Target Name = first, Depends = [:second, :third], Commands = echo Hello World
正しく表示されていることが確認できました。