概要

Scalaのプロジェクト管理は普通は sbt を使うところだけど、最近はTypesafe Activatorという便利な代物が出ていて、sbt よりもインストール手順とかが少しだけ楽なので、こっちを使ってプロジェクトの作成やら管理やらをするのが良いのではないかと思ってみた。

今回は試しにこの子を使ってEclipseでScalaの開発をできる環境を整えてみる。尚、いつも通りLinuxで動作を確認している。Windowsの場合は知らない。

@CretedDate 2013/11/16
@Versions Typesafe activator-1.0.8
@Versions Scala2.10.3

Scala IDE for Eclipseのダウンロード

とりあえずScala IDE for Eclipseをダウンロードしておく。

http://scala-ide.org/

昔はプラグイン単体で配布されていたのだけど、最近はバンドルされたEclipseごとダウンロードできる。Javaが入ってれば叩くだけで実行可。世の中便利になったものだ。

Typesafe Activatorのダウンロード

下記のページからTypesafe Activatorを落としてくる。

http://typesafe.com/activator

自分が落とした時はファイルサイズは238MBあった。けっこう大きい。

Typesafe Activatorを使うと、コマンドラインからScalaやらPlayやらAkkaやらの雛形プロジェクトを生成することができる。また、シェルを介して自動でsbtを落としてきて自動で実行してくれるので、この子を落としてJDKさえ入っていれば、あとは何の用意もなしにScalaの開発に入れる。とても便利。

一応、ブラウザからプロジェクトを云々できるIDE的な機能も入っているけど(というか方向性的にはそっちがメインだと思うけど)、前に使おうとしたら開始3分で落ちたので見なかったフリをしてコマンドラインのみで使っている。今後、徐々に使える代物になっていくかもしれない。Scalaは開発にマシンパワーを食うので、良いマシンにIDEを載せておいてスペックの低いリモートマシンで開発できたら素敵だろうな。

Scalaのアプリを生成してみる

試しにコマンドラインからScalaの基本的なプロジェクトを生成してみる。

ダウンロードした Typesafe Activator を解凍して、中に入っている activator という名前のシェルに引数 new を付けて叩く。これでコマンドラインから新規のScalaプロジェクトを生成できる。

$ unzip typesafe-activator-1.*.*.zip 
$ cd activator-1.*.*.zip 

$ ./activator new

「アプリの名前なんにする?」と聞かれるので、適当な名前を入力する。

Enter an application name
> scala_proj

次に「利用するテンプレートはどれにする? tab押すとリストが出るよ」と言われる。tabキーを押すと何やらたくさんテンプレート名が表示される。たとえば「hello-play-scala」ならPlayの単純なアプリが、「test-patterns-scala」ならScalaTestやSpecs2を使ったテストコード入りのサンプルアプリが出力される。

今回は単純なScalaアプリの「hello-scala」を利用する。

Enter a template name, or hit tab to see a list of possible templates
> hello-scala

これで直下に指定したアプリ名と同名のディレクトリが生成される。

生成されたプロジェクトの構成

下記のような構成になっている。

$ tree scala_proj/

scala_proj/
├── LICENSE
├── activator
├── activator-launch-1.0.8.jar
├── activator.bat
├── build.sbt
├── project
│   └── build.properties
└── src
    ├── main
    │   └── scala
    │       └── Hello.scala
    └── test
        └── scala
            └── HelloSpec.scala

src/main/scalasrc/main/test がいるような一般的なフォルダ構成になっている。test側に入っているHelloSpec.scalaは、ScalaTestを利用したコードが書かれている。ScalaTestへの依存はあらかじめbuild.sbtに記述されている。

アプリを動かしてみる

Scalaのコンパイラとかsbtの導入のような前準備は、activatorさんが良きに計らってくれる。activator run と命令すると、sbtが用意されて、依存ライブラリの解決が行われて、src/main/scala に配置された Hello.scala が実行される。

$ ./activator run

activator test でテストの実行もできる。

$ ./activator test

実行処理自体は sbt が行なっている。引数とかも一緒なので、これまでsbtで開発してきた人なら特に困ることはないはず。

クラス名を指定して実行してみる

指定したクラスを実行したい場合は、 activator runMain を実行する。

試しに適当な実行クラスを作成してみる。下記はコマンドライン引数を受け取って出力するだけの機能。

package foo

object Foo extends App {
  println("foo : " + args(0)
}

下記のようなコマンドで実行する。

$ ./activator 'runMain foo.Foo bar'

これで引数も渡して実行できた。

Eclipseプロジェクトに変換する

Eclipseで使いたいので、sbtにEclipseプラグインを追加する。プラグインの追加は project/plugins.sbt に記述する。

$ vi project/plugins.sbt

下記の行を記述。バージョンは適宜最新を調べて変更する。

addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.4.0")

記述したら activator eclipse を実行する。

$ ./activator eclipse

あとはEclipse上から作成したプロジェクトをimportすれば、Eclipse上で開発が可能になる。依存ライブラリ周りをいじった場合は、再度 activator eclipse して、EclipseのプロジェクトをF5で更新すれば依存関係も更新される。

デフォルトの設定だとEclipseに src/main/resourcessrc/test/resources がいない。build.sbt に下記の行を追加すると、resouces ディレクトリがEclipseのソースフォルダに追加される。

EclipseKeys.createSrc := EclipseCreateSrc.Default + EclipseCreateSrc.Resource

依存するライブラリを追加してみる

単純にローカルに置いてあるjarファイルを追加したい時は、プロジェクトの直下に lib ディレクトリを作り、その中にjarファイルを放り込めば、勝手に解決してくれる。

Mavenのように依存ライブラリを設定する場合は、 build.sbt に指定を追加する。今回利用しているテンプレートには、最初から下記のような ScalaTest の依存を解決する記述が入ってる。

libraryDependencies += "org.scalatest" %% "scalatest" % "1.9.1" % "test"

試しに個人的に愛用しているSolrjを dependency に追加してみる。scalatestの記述の下に1行空けてこんなのを書く。

libraryDependencies += "org.apache.solr" % "solr-solrj" % "4.5.1"

ScalaTestの時と記述がちょっと違う。Scala系のライブラリはScalaのバージョンも必要だったり、テスト系のライブラリはテストの時以外依存性に入らないように明記しておく必要があったりとか、その辺の違いのせい。

自分はたいていMaven Repository: Search/Browser/Explorerで検索して、見つかった記述をコピペしてる。

Eclipseを利用している場合は、追加後に ./activator eclipse すると、Referenced Libraries の中に追加したライブラリが入っている。

依存するライブラリが個別のレポジトリを利用している場合は、対象のレポジトリを build.sbt に追記する。下記はClouderaのレポジトリを追加した例。

resolvers += "cloudera" at "https://repository.cloudera.com/artifactory/cloudera-repos/"

assemblyプラグインで実行可能なjarファイルを作る

作成したプロジェクトを実行可能なjarファイルにしてポンと叩きたい時は assemblyプラグインを使うと便利。まずは project/plugins.sbt に下記のような記述を追加。

resolvers += "sbt-assembly-resolver-0" at "http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases"

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.10.1")

resolversにプラグインを置いてるサイトを記述して、addSbtPlugin で assemblyプラグインを指定してる。バージョンは変わるかもしれないので公式サイトを見て都度確認。

次に build.sbt の1番上に下記の行を追加。

import AssemblyKeys._

assemblySettings

これで準備完了。下記のコマンドを実行すると、jarファイルが生成される。どこにjarファイルが出力されたかは、出力されるメッセージの一番下に表示される。

$ ./activator assembly

出来上がった子を実行してみる。

$ java -cp target/scala-2.10/hello_scala-assembly-1.0.jar  foo.Foo 引数

Mainクラスを明示してないので、java -jarだと動かない。Mainクラスを指定したい時は、build.sbt に下記の行を足す。

mainClass in assembly := Some("foo.Foo")

あと、assembly する時もテストが走ってしまうのだけど、毎回走られると微妙なので止めたい人は build.sbt に下記のような記述を入れる。

test in assembly := {}

たまに依存性がライブラリ同士でぶつかってしまって、下記のようなエラーになることがある。

java.lang.RuntimeException: deduplicate: different file contents found in the following

そんな時は AssemblyStrategy を設定してあげるとうまく行く。下記はとりあえず MergeStrategy.first に設定しておいて、MANIFEST.MF が被ったら discard しておけ的な記述。これでだいたい通る。どっちの依存を取るか厳密に決めたい時は、case を足して個別に決める。

mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) =>
  {
    case "META-INF/MANIFEST.MF" => MergeStrategy.discard
    case x => MergeStrategy.first
  }
}