2012年9月11日火曜日

scala-sbt.g8

Scala界ではプロジェクトの雛形生成器?としてgiter8が有名で、Typesafe Stack 2.0でも使われています。

Installing the Typesafe Stack 2.0.2にはscalaプロジェクトの雛形も多数用意されていますが、プレインなsbtプロジェクトとしてはscala-sbtが用意されています。

以下のようにするとsbtプロジェクトの雛形を簡単に構築できます。

$ g8 typesafehub/scala-sbt

オレ様scala-sbt

実際に自分プロジェクトで使うとプレインバニラな雛形は物足りなくなるので、各所でオレ様scala-sbtが多数作られていると思います。

ボクも自分用に作ってみたので紹介します。自分用にカスタマイズしたポイントは以下になります。(注意:個人向けなので、普通に使って便利なのかは保証の限りではありません。(笑))

プラグインの設定

sbtプラグインとして以下のものの設定を行いました。

  • ensime
  • eclipse plugin
  • conscript
  • onejar
プログラムの雛形

生成するプログラムの雛形として以下の機能を盛り込みました。ちょっとした開発ツールを作る時の土台にすることを想定しています。

  • scalaz
  • scalax.io
  • オプションのハンドリング
  • コマンドの切り分け
  • エラー処理
  • Scalatest

mainのソースコードは以下のようになります。

package com.example.command

import scala.util.control.Exception.{catching, allCatch}
import scalaz.{Resource => _, _}, Scalaz._
import scalax.io._
import scalax.file._

class Command(val args: Array[String]) {
  var verbose: Boolean = false
  var directory: Option[String] = None

  def run() {
    catching(classOf[java.io.IOException]).withApply {
      e => _error(e.getMessage)
    } apply {
      _run()
    }
  }

  private def _run() {
    _parse_options(args.toList) match {
      case "ls" :: Nil => _ls()
      case "cat" :: file :: Nil => _cat(file)
      case _ => _usage
    }
  }

  private def _error(msg: String) {
    Console.err.println(msg)
  }

  private def _parse_options(args: List[String]): List[String] = {
    _parse_options(args, Nil)
  }

  private def _parse_options(in: List[String], out: List[String]): List[String] = {
    in match {
      case Nil => out
      case "-verbose" :: rest => {
        verbose = true
        _parse_options(rest, out)
      }
      case "-dir" :: arg :: rest => {
        directory = arg.some
        _parse_options(rest, out)
      }
      case arg :: rest => _parse_options(rest, out :+ arg)
    }
  }

  private def _usage {
    println("usage: sample command args")
  }

  private def _ls() {
    for (path <- Path(directory | ".").children("[^.]*", nil)) {
      println(path.name)
    }
  }

  private def _cat(file: String) {
    println(Resource.fromFile(file).string)
  }
}

Scalatestによるテストケースは以下のようになります。

package com.example.command

import org.scalatest.WordSpec
import org.scalatest.matchers.ShouldMatchers
import org.scalatest.junit.JUnitRunner
import org.junit.runner.RunWith

@RunWith(classOf[JUnitRunner])
class CommandSpec extends WordSpec with ShouldMatchers {
  "Command" should {
    "execute" that {
      "empty arguments" in {
        val app = new Command(Array())
        app.run()
      }
      "one argument" in {
        val app = new Command(Array("ls"))
        app.run()
      }
    }
  }
}

使い方

giter8

giter8のインストール方法はトップページにありますが、ここには載っていないMacPortsでもインストールできます。ボクはMacPortsでインストールしました。

$ sudo port install giter8
scala-sbtの雛形生成

オレ様版scala-sbtの雛形生成は以下になります。

$ g8 asami/scala-sbt

以下のようにパラメタを聞いてくるので入力すると雛形が生成されます。

organization [com.example]: 

package [com.example.command]: 

name [command]: 

scala_version [2.9.2]: 

version [0.1-SNAPSHOT]: 
コンパイル&テスト

雛形が生成されるので、コンパイル&テストしてみます。

$ cd command
$ sbt test

最後に以下のようなメッセージが出て正常終了するはずです。

[info] CommandSpec:
[info] Command 
[info]   should execute that 
[info]   - empty arguments
[info]   - one argument
[info] Passed: : Total 2, Failed 0, Errors 0, Passed 2, Skipped 0
[success] Total time: 13 s ...
ensime

ensimeの環境設定は以下になります。

$ sbt "ensime generate"
eclipse

Eclipseの環境設定は以下になります。

$ sbt eclipse

これで開発はEmacs&ensime、デバッグはEclipseの最強の組合せでScalaプログラミングできる環境を簡単に整えることができます!(笑)

0 件のコメント:

コメントを投稿