浅海 智晴(あさみ ともはる)
 最近はすっかりScalaプログラマ。代表作はXML SmartDoc(XML文書処理システム),Relaxer(XML/Javaスキーマコンパイラ)。現在はScala DSLモデルコンパイラSimpleModelerを開発中。近著は「上流工程UMLモデリング」(日経BP),「マインドマップではじめるモデリング講座」(翔泳社)。モデル駆動開発×クラウド・コンピューティングの研究プロジェクトedge2.cc(Edge to Cloud Computing)を中心に活動中。
本記事の目次
  1 はじめに
2 例題 2.1 コンパイル 2.2 アプリケーション
3 DSLの説明 3.1 クラス宣言 3.2 基本情報 3.3 申請情報 3.3.1 字句上の工夫 3.3.2 by-nameパラメタ 3.3.3 施設と設備 3.3.4 同時使用
4 JSON,XMLとの比較 4.1 JSON 4.2 XML
5 メインルーチン
6 DSLの基底クラス 6.1 インスタンス変数 6.2 implicit conversion 6.3 メソッド
7 Candidate 7.1 流れるようなインタフェース
8 Enumeration
9 HTML生成器 9.1 XMLリテラル 9.2 時間
10 HTML
11 まとめ

1 はじめに

 本記事では,Scalaをホスト言語としたDSLの定義と,このDSLを処理するプログラムの作成方法について,例題を用いて説明しています。前回は「5章 メインルーチン」まで掲載しました。今回は「6章 DSLの基底クラス」から最後までです。

6 DSLの基底クラス

 リスト5の施設利用申請書は文字通り,施設利用申請書の基底クラスです。施設利用申請書はこの施設利用申請書をextendsします。施設利用申請書のようなDSLの基底クラスは,ScalaでDSLを構築するうえで非常に重要なクラスです。

 施設利用申請書のサブクラスが実際の申請書データとなります。この申請書データのインスタンスが生成される時に,コンストラクタが実行されインスタンス変数の設定とメソッドの呼び出しが行われます。その結果,アプリケーションが必要とするデータ構造が構築されます。

リスト5●施設利用申請書.scala
package app

import scala.collection.mutable.ArrayBuffer
import scala.xml.Node
import java.util.Date
import java.text.SimpleDateFormat
import 施設区分._
import 設備区分._

class 施設利用申請書 {
  var 会員番号: String = ""
  var 名前: String = ""
  val reasons = new ArrayBuffer[Node]
  val candidates = new RootCandidate()
  private var current: Candidate = null

  def 理由(reason: Node) {
    reasons += reason
  }

  def 申請(candidate: => Unit) {
    current = candidates
    candidate
    current = null
  }

  def 同時利用(candidate: => Unit): SetCandidate = {
    val child = current.addSet()
    current = child
    candidate
    current = child.parent
    child
  }

def 同時利用(date: String, startTime: String, endTime: String)(candidate: => \
    Unit): SetCandidate = {
val child = current.addSet(to_date(date), to_time(startTime), \
    to_time(endTime))
    current = child
    candidate
    current = child.parent
    child
  }

  def 施設(facility: 施設区分): FacilityCandidate = {
    val child = current.addFacility(facility)
    child
  }

def 施設(date: String, startTime: String, endTime: String, facility: 施設区分): \
    FacilityCandidate = {
val child = current.addFacility(to_date(date), to_time(startTime), \
    to_time(endTime), facility)
    child
  }

  def 設備(equipment: 設備区分): EquipmentCandidate = {
    val child = current.addEquipment(equipment)
    child
  }

def 設備(date: String, startTime: String, endTime: String, equipment: 設備区分): \
    EquipmentCandidate = {
val child = current.addEquipment(to_date(date), to_time(startTime), \
    to_time(endTime), equipment)
    child
  }

  private def to_date(string: String): Date = {
    val df = new SimpleDateFormat("yyyyMMdd")
    df.parse(string)
  }

  private def to_time(string: String): Date = {
    val df = new SimpleDateFormat("HHmm")
    df.parse(string)
  }

  implicit def intToString(value: Int): String = value.toString
  implicit def stringToNode(value: String): Node = <div>{value}</div>
}

 以下では,施設利用申請書の構造についてポイントを説明します。