ソースコードをテンプレートから自動生成する

はじめに

仕事柄、テキストを編集するツール(スクリプト)を書く機会が多いです。

テンプレートからソースコードを自動生成するツールを書いてみたところ、生産性がかなり上がったので紹介しておきます。(自動生成と言っても雛形だけなので、ロジックは自分で書く必要があります)

コマンドラインで簡単に生成できるのと、テンプレートを自由に設定・追加できるのがポイントです。

使い方

ツールを設置後、以下のコマンドでソースコードが生成されます。さらに、自動で実行可能なパーミッションが設定されます。(cやjavaなどはパーミッションの設定がされません。詳細は「テンプレートの種類」参照)

% gen_source hoge.rb
hoge.rb was generated.
hoge.rb was set as 744
% cat hoge.rb
#!/usr/bin/ruby

# = hoge.rb
#
# Author::    takahiro
# Copyright:: takahiro
# License::   GPL
#

# == Version
#
# * 2011-04-18 1.00 (takahiro)
#

# == Summary
#
# This file is for
#

# == Interface
#
# * input
# **
# * output
# **
#

# == Example
#

# == Description
#
# This file is for
#

#require 'optparse'

#opt = OptionParser.new

#opt.banner  = <<EOF
#Usage : #{$0} [options] [filename]
#
#ex) #{$0} ./hoge.txt
#    cat hoge.txt | #{$0}
#
#this script is...
#
#[options]
#EOF

#begin

#  opt.on( '-a', 'hogehoge' ) { |v| p v }
#  opt.on( '-h', 'show helps and exit' ) { |v|
#    puts opt
#    exit
#  }
#  opt.parse!( ARGV )
#  p ARGV

#rescue OptionParser::ParseError => e

#  puts opt
#  exit

#end

#if ARGV.size == 0 then
#  f = STDIN
#elsif ARGV.size == 1 then
#  f = File.open( ARGV[ 0 ] )
#  IN_FILE = ARGV[ 0 ]
#else
#  puts opt
#  exit
#end

#f.each do |line|
#  puts line
#end

適切な部分をコメントアウトしたり、適切なロジックを追加するだけで、引数で与えられたファイル、もしくは、標準入力から渡された文字列を処理するスクリプトが出来上がります。


第二引数に種類を指定することもできます。以下のコマンドだとfuga.cgiという名前のpythonファイルが生成されます。

% gen_source fuga.cgi py

設置の仕方

mercurialでcloneを生成
% hg clone https://ta-gen-source.googlecode.com/hg/ ta-gen-source

Webブラウザhttp://code.google.com/p/ta-gen-source/source/browse/から取得してもいいです。

取得したらgen_source.shとtemplate.sh, template.rb, template.pyの一行目に書かれているパスを自分の環境に合わせたものに変更してください。

PATHの通っているディレクトリにgen_source.shをリンク

ここではgen_source.shが置いてあるディレクトリを/home/$USER/proj/ta-gen-sourceとし、PATHが通っているディレクトリを/home/$USER/binとします。

% cd /home/$USER/bin
% ln -s /home/$USER/proj/ta-gen-source/gen_source.sh gen_source

これで設置は完了です。

テンプレートの設定

テンプレートの種類

gen_source.shと同じディレクトリにあるtemplate.*の拡張子がコードの種類に対応しています。

例1

% gen_source hoge.rb

の場合はtemplate.rbをテンプレートとしてソースコードを生成します。

例2

% gen_source fuga.cgi py

の場合はtemplate.pyをテンプレートとしてソースコードを生成します。

template.*の先頭にパスが設定されている場合(正確に言うとファイルの先頭行の先頭が「#!」となっている場合)、パーミッションに744が設定されます。

テンプレートの追加

gen_source.shと同じディレクトリにtemplate.*を追加することでテンプレートを新たに追加できます。

テンプレートの削除

gen_source.shと同じディレクトリにあるtemplate.*を削除することでテンプレートの削除ができます。

テンプレートの編集

gen_source.shと同じディレクトリにあるtemplate.*をテキストエディタで編集してください。以下の文字列はgen_source.sh実行時にそれぞれ適切な文字列に変換されます。

  • %%USER%% : ユーザ名(ログインID)
  • %%DATE%% : 日時
  • %%FILE%% : ファイル名
  • %%NAME%% : ファイル名から拡張子を除いたもの


template.*はテキスト処理に適したものになっています。自分に合ったものに書き換えるとぐっと便利になると思います。

rdocやjavadocにフィットしたものにしたり、テストコードを埋め込んでおくのもいいかもしれません。

メリット

  • どのソースコードでもヘッダ情報などに一定の品質が保てる
  • 「ツールを書こう」と思い立ってからツールを実行するまでの時間が短縮できる
  • テンプレートを眺めると、しばらく使っていなかった言語でもある程度思い出すことができる
    • 「思い出す」というコストが減るので、その場その場で適切な言語を選択できる
    • 「思い出す」というコストがあると、使い慣れている言語しか使用しなくなる

注意

gen_source.shの中でreadlinkというコマンドを使用しています。検索したところ、環境によってはこのコマンドが使えないそうです。その場合はreadlinkの代わりにシンボリックリンクのリンク先を取得する方法を考えないといけません。( $( ls -l $0 | cut -d' ' -f10 )でいける? )

終わりに

テキスト処理はどのツールでも似たようなことをやっているので、引数・オプションで様々な条件に適用できるようにしようかと思っていたのですが、コードが複雑・煩雑になってしまいました。

考えを変えて、テンプレートからソースコードを自動生成させる手法に変えたところ、構成がかなりシンプルになりました。


テンプレートからソースコードを自動生成する手法は人にとっては当たり前すぎることかもしれませんが、もし知らなかったのならば試してみる価値はあると思います。