SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

Judeのクラス図からActiveScaffoldのコードを自動生成する

Jude/LuRuJu/JRuby/ERBを用いたActiveScaffoldのソース自動生成プログラム

Judeのモデルとジェネレータのモデルの違い

 JudeのAPIリファレンスには次のようなモデル構造が記載されています。

JUDE APIのクラス図
JUDE APIのクラス図
JUDEプロジェクト上で作成されたクラス図
JUDEプロジェクト上で作成されたクラス図
上記のクラス図のモデル要素をAPIから操作したときのオブジェクト図
上記のクラス図のモデル要素をAPIから操作したときのオブジェクト図

 JudeのAPIリファレンスに存在するモデル構造は、抽象的になっているので汎用性が高くシンプルです。UMLツールのモデルとしては抽象化されていてよい構造です。一方ジェネレータにこの構造を持ち込むと、汎用的になりすぎます。特定用途のものを汎用的/抽象的に作りすぎると、ロジックが肥大化する傾向があります。

 例えば、JudeAPIの場合、クラスの属性も、関連との接続もすべてAttributeで表します。本質を考えるとそのとおりなので、UMLのモデリングツールのモデルとして適しています。しかし、このジェネレータの場合、属性と関連とを明確に区別できたほうが何かと便利なので、抽象化されていた「関連」と「属性」を明確に分けたクラスづくりにすることにします。

 さらに、テーブルの構造と、モデルの構造は違うので、テーブル用の属性というクラスを作成しています。テーブルの場合は、関連も外部キーで表現されるので、これで表現できるはずです(多対多の関連テーブルを除く)。

ジェネレータのモデル構造
ジェネレータのモデル構造

 後は、GRASPパターンなども参考にしながら、あるデータのある場所(クラス)にそのデータに関するロジックをカプセル化していけばモデルの完成です。

 このように作りたいものの本質を考えて、それに合わせたモデルを考えることで、柔軟でメンテナンスがしやすいアプリケーションができあがります。

 モデル以外の部分では、テーブル用の属性を表すTableAttributetype_conver_hashというHashに、クラスの型とテープルの型の変換テーブルをハードコードしています。外出ししていないのは、自分用のアプリケーションだからです。

 またnamealias_nameはそれぞれ名前(通常、日本語)と、別名(英語)を指しています。別名がない場合は、別名に名前が使われます。

 他のポイントとして、関連を表す「Relation」があります。関連は、ロール名と相手方のクラスの情報を含んでいます。relation_nameはあればロール名、なければ相手方のクラス名です。relation_symbol_nameはActiveRecordの関連の名前です。例えば、

belongs_to :company

 など関連の指定をすると思いますが、:companyに相当するものです。関連の多重度によっては複数系になります。

has_and_belongs_to :bands

 このように「関連」に関するロジックやデータは、「Relation」にカプセル化した設計になっています。

 今から実施したい業務に合わせたモデルにデータを流し込めば、後はオブジェクトの世界でプログラムができるようになります。

アプリケーションの起点

 ソースの中でアプリケーションが動作する起点は以下のパートです。

scaffold_generator.rb
clean_up_build_dir
active_records_factory.each{|active_record|
  active_record.generate_source
}
add_sequence_for_migration_file

 active_records_factoryメソッドの中で、コマンドライン引数で渡されたJudeファイルのクラスを抽出し、ActiveRecordクラスのオブジェクトとして返却してくれます。

def active_records_factory
   active_records = []
   project = Luruju::JudeApiLoader.load ARGV[0]
   project.classes.each{|clazz|
       active_records << ActiveRecord.new(clazz)
   }
   active_records
end

 返却されたActiveRecordオブジェクトのすべてに対してgenerate_sourceメッセージを送信すると、ActiveRecordオブジェクトの方で各種ソースファイルや、マイグレーションファイルが作成されます。

 add_sequence_for_migration_fileは、作成されたマイグレーションファイルの先頭に連番を付与するものです。Railsのマイグレーションファイルは重複していない連番が先頭についている必要があります。

 active_record_factoryメソッドがLuRuJuを使ってクラス情報を習得しています。ActiveRecordのコンストラクタから、ソースを読み込んでいくと、Judeファイルからモデルの作成の過程が理解でき、また、ActiveRecordのgenerate_sourceメソッドからソースを追うと、Rubyオブジェクト化されたActiveRecordオブジェクトから、ERBを使ってソースを生成する過程を学習することができます。

 ぜひソースコードを読み込んでみてください。

最後に

 本記事では、Jude、LuRuJu、JRuby、ERBを用いたActiveScaffoldのソース、およびマイグレーション生成プログラムの使い方とアーキテクチャを説明しました。

 本記事のソースコードは実際に使用することもできますが、あくまで筆者が趣味程度に作ったものであり、プロダクションレベルの品質で作成していません。

 ただ、本記事で伝えたかったことは、Rubyを初めとする上記のツールを組み合わせることで、クラス図からWebアプリケーションを作成するジェネレータが意外と簡単に作れることと、皆さんにも自分が得するジェネレータをJudeやLuRuJu、Rubyを使って気楽に作ってみようかなと思っていただきたかったということです。

 出典は忘れてしまいましたが、単純作業で12時間かかる仕事があり、その仕事は1回しか必要ありません。一方、その仕事をこなすためのスクリプトを作成すると11時間かかるとします。

 優れたプログラマは後者を選択します。なぜなら「楽しい」からです。このプログラムも「月刊DBマガジン 2008/02月号」(翔泳社)のコラム執筆の際に作ったものです。あくまでテストも十分行っていないサンプルレベルで、プロダクションレベルではありませんが、例えばRailsのプロジェクトにできたソースをコピーするとか、Railsのプロジェクトも自動的にセットアップするとかも意外に簡単にできるはずです。

 皆さんも気軽に自分が得するツールをRubyやJudeで作ってみませんか?

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
特集記事連載記事一覧

もっと読む

この記事の著者

牛尾 剛(ウシオ ツヨシ)

株式会社豆蔵 BS事業部 エンタープライズチーム。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/1929 2007/12/25 00:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー