Scala入門記007 sbt + ScalaLogging

Javaの潤沢なライブラリが使えるScalaですが、そのまま使おうとしてもあまりイケてないことが多いです。
Play Frameworkplay.api.Loggerを使っていると、通常はメッセージを渡す代わりに関数を渡せます。
そのためメッセージ文字列の生成を指定したログレベルが有効な時に限定できたりして実にScalaっぽいです。


今回はScalaLoggingというものがあるということなので使ってみました。
Scala入門記の目次はこちらです。


ScalaLogging


Scalaのマクロを使って、logger.isDebugEnabled等の判断をコンパイル時に追加しているらしいです。
PlayのLoggerはLoggerをラップして対応しているところをマクロで対応しているということですね。


sbtの設定

GitHubのドキュメントにはsbtの依存ライブラリに以下を追加するように書かれています。

libraryDependencies += "com.typesafe" %% "scalalogging-slf4j" % "1.0.1"

流し読みしてこれだけ設定すると、Loggerの実装がないという旨の以下のようにメッセージが出ます。

SLF4J: Defaulting to no-operation (NOP) logger implementation


ScalaLoggingはLoggerの実装としてSLF4J かLog4j2かを選択してsbtで設定しなければならないです。


SLF4J

SLF4Jを使うためにまずはこちらのサイトを参考に以下のように設定してみました。

libraryDependencies ++= Seq(
  "com.typesafe" %% "scalalogging-slf4j" % "1.0.1",
  "ch.qos.logback" % "logback-classic" % "1.0.13"
)


この設定をしたうえで入門記006で使ったHelloオブジェクトを以下のように変更しました。

package example

import com.typesafe.scalalogging.slf4j.Logging

object Hello extends Logging {

  def main(args: Array[String]) {
    println(createGreeting(args))
  }

  def createGreeting(args: Array[String]) = {

    logger.info("args size:" + args.length)

    args.headOption match {
      case Some(name) => "Hello " + name + "!"
      case None => "Hello!"
    }
  }

}


これで"sbt run"するとログが表示されるようになりました。


Log4j2

まだbetaですがLog4jの2.0系のライブラリも使えます。
こちらはライブラリへの依存に加え、最低限動かすにも設定ファイル(log4j2.xml)が必要です。

libraryDependencies ++= Seq(
  "com.typesafe" %% "scalalogging-log4j" % "1.0.1",
  "org.apache.logging.log4j" % "log4j-core" % "2.0-beta9"
)


また、src/main/resources/log4j2.xmlは以下のように設定しました。

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
  <appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </appenders>
  <loggers>
    <root level="info">
      <appender-ref ref="Console"/>
    </root>
  </loggers>
</configuration>


ソースコードはpackageの指定のところだけがSLF4Jと異なります。

package example

import com.typesafe.scalalogging.log4j.Logging

object Hello extends Logging {

  def main(args: Array[String]) {
    println(createGreeting(args))
  }

  def createGreeting(args: Array[String]) = {

    logger.info("args size:" + args.length)

    args.headOption match {
      case Some(name) => "Hello " + name + "!"
      case None => "Hello!"
    }
  }

}


これで"sbt run"するSLF4Jと同様にログが表示されるようになりました。



依存ライブラリ

参考までに実際の依存ライブラリをInteliJ IDEAで表示してみました。

追加前

f:id:t_hachinohe:20140121024634p:plain

SLF4J

f:id:t_hachinohe:20140121024659p:plain

Log4j2

f:id:t_hachinohe:20140121025121p:plain


ソースコード

今回の記事で使ったソースコードは以下のGitリポジトリの2つのタグです。

https://github.com/thachi/scala-sample-001

まとめ

どのくらい使われているのかはわかりませんが、今回はScalaLoggingというものを使ってみました。
私はplay.api.Loggerのような対応が方が好みですが、コンパイル時に解決できるこちらの方がエコですよね。


実装の選択についてはサクッと試すにはSLF4Jの実装が楽そうです。
Log4j2は使ったことがなかったので今後は使ってみたいと思っています。


Scala入門記の目次はこちらです。


Scala入門記006 sbt + ScalaTest

プログラムを書いて何かしらのシステム開発するにはテストは必須だと思います。
プログラミング中に書くUnitTestの環境は現代の開発には欠かせないものでしょう。

今回はsbtによるScalaTtestとEclipse, IntelliJ IDEAでのテストスタイルについてまとめてみました。
Scala入門記の目次はこちらです。


テスト対象

テスト対象にするため、Scala入門記002 初めてのScalaプログラムで書いたHelloオブジェクトに挨拶文を作るためのメソッドを作りました。
1つ目の引数が存在する場合はその引数に応じて「Hello ほげほげ!」という挨拶文を生成します。
引数がない場合は「Hello!」という挨拶文を生成します。

object Hello {

  def main(args: Array[String]) {
    println(createGreeting(args))
  }

  def createGreeting(args: Array[String]) = {
    args.headOption match {
      case Some(name) => "Hello " + name + "!"
      case None => "Hello!"
    }
  }

}


これは、

sbt run

を実行すると

Hello!

を出力します。


また、引数を付けて

sbt "run Takashi"

を実行すると

Hello Takashi!

を出力します。


sbtの設定

ScalaTestを実行するにはScalaTestのライブラリに依存する必要があります。

build.sbt

libraryDependencies += "org.scalatest" % "scalatest_2.10" % "2.0" % "test"

を追記するとScalaTestがtest実行時のみ使えるようになります。


テストを書くときは

sbt ~test

とすると自動実行されて便利です。


テストコード

ScalaTestは色々なスタイルでテストコードを記述できるようです。
詳細はSelecting testing stylesを見ると紹介されています。

FlatSpec

まずはScalaSpecの公式サイトに習ってHelloSpecを作りました。

import org.scalatest._

class HelloSpec extends FlatSpec with Matchers {

  "Hello" should "create a simple greeting" in {
    val greeting = Hello.createGreeting(Array())
    greeting should be("Hello!")
  }

  it should "create a greeting with name" in {
    val greeting = Hello.createGreeting(Array("Takashi"))
    greeting should be("Hello Takashi!")
  }

}

FunSuite

import org.scalatest.FunSuite

class HelloSuite extends FunSuite {

  test("引数を指定しない場合に\"Hello!\"が取得できる") {
    val actual = Hello.createGreeting(Array())
    assert(actual == "Hello!")
  }

  test("引数に\"Takashi\"を指定した場合に\"Hello Takashi!\"が取得できる") {
    val actual = Hello.createGreeting(Array("Takashi"))
    assert(actual == "Hello Takashi!")
  }

}

今回は日本語も使ってみました。
macのターミナルでは正常に日本語が表示できました。

JUnit

build.sbt

libraryDependencies += "junit" % "junit" % "4.11" % "test"

を追加するとJUnitの形式も使えます。

import org.junit.Test
import org.scalatest.Assertions

class HelloTest extends Assertions {

  @Test def createGreetingWithEmptyArgs {
    val greeting = Hello.createGreeting(Array())
    assert(greeting == "Hello!")
  }

  @Test def createGreetingWithArgs {
    val greeting = Hello.createGreeting(Array("Takashi"))
    assert(greeting == "Hello Takashi!")
  }

}

残念なことにこのJUnitテストは

sbt test

では無視されてしまいます。

私は2番めのFunSuiteが好み&日本語もありかな、と思いました。


IDEでテスト

開発しながらテストするにはやっぱりIDEでテストしたいです。
今回はEclipseIntelliJ IDEAの両方でScalaTestの使い心地を試してみました。

Eclipseでテスト

EclipseにScalaTestのプラグインが入っているとEclipse内でテストができます。
ただし、現時点では緑のバーは見れなかったので残念でした。

f:id:t_hachinohe:20140116112305p:plain

IntelliJ IDEAでテスト

IntelliJ IDEAにScalaプラグインが入っているとIntelliJ IDEA内でテストができます。
こちらはEclipseと違い緑になってくれます。
やる気が出ますね!

f:id:t_hachinohe:20140116122115p:plain



まとめ

sbtでテストし続ける場合はIDE用とターミナル用に画面が2つ欲しくなりますね。
IDEでテストするにはIntelliJ IDEAを使うほうがモチベーションがあがりそうです。


Scala入門記の目次はこちらです。


今回の環境

Scala入門記005 sbt + IntelliJ IDEA CE

Scalaすごく良いです。caseクラスがステキです。
最近はやっとJavaで考えてScalaを書く時期は終わりました。
逆にJavaを書いている時に「Scalaだったら。。。」って考えてしまいます。


今回はIntelliJ IDEA CEでScalaを開発してみます。
Scala入門記の目次はこちらです。


IDEの準備

Eclipseからユーザが移りつつあると言われているJavaIDEですがもちろんScalaも開発できます。
JetBrainsのサイトからダウンロードできます。

環境としては無料で使えるIntelliJ IDEA CE 13に以下の3つのプラグインを入れてみました。

f:id:t_hachinohe:20140116114002p:plain


sbtの設定

Eclipseのサイト同様にsbt-ideaというプラグインでsbtプロジェクトをIntelliJ IDEAに対応させることができます。

ドキュメントの通り

addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.5.2")

をplugin.sbtに追加します。

私はEclipseの際と同様に

~/.sbt/0.13/plugins/plugins.sbt

で設定しました。


IntelliJ IDEAのプロジェクトにするにはsbtプロジェクトで

sbt "gen-idea"

とします。


これでIntelliJ IDEAの「Open Project」からそのまま開けます。

f:id:t_hachinohe:20140117121911p:plain


gen-ideaはデフォルトでソースやドキュメントがダウンロードされます。
不要な場合は

sbt "gen-idea no-classifiers"

とする必要があるようです。


まとめ

今はもっぱらEclipseで開発していますが、IntelliJ IDEAも使ってみようと思っています。


Scala入門記 目次

Scala入門記004 sbt + Eclipse

現時点でのIDEの選択肢はEclipseIntelliJ IDEAの2択のようです。
今回はsbtプロジェクトをEclipseに対応させていきます。
Scala入門記の目次はこちらです。


ScalaプロジェクトをEclipseで使う際はEclipse + Scala IDEという構成が今の最良の環境でしょう。
この記事を書いた時点での最新環境として、「Eclipseは4.3 SR1」 + 「Scala IDE 3.0.2」を用意しました。
公式サイトはScala IDE for Eclipseです。
Eclipse Marketplaceからインストールできました。


プロジェクトの設定

Eclipse対応のプロジェクトにするにはsbteclipseというプラグインを使う必要があります。
これはproject/plugins.sbtに以下の記述をすると使えるようになります。

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

これで、

sbt eclipse

とすると、Eclipseに対応した.projectと.classpathが生成されます。
これでEclipseから「Existing Projects into Workspace」でワークスペースにインポートすることができます。

f:id:t_hachinohe:20140117122128p:plain


また、

sbt "eclipse with-source=true"

を実行するとソースがダウンロードされます。


私はよく以下の様な間違いをします。

sbt eclipse with-source=true
sbt "eclipse with-sources=true"
sbt "eclipse -with-source=true"

これらはエラーになります。
mavenとごちゃごちゃになってます(^_^;)


グローバルな設定

このsbteclipseの設定ですが、複数の人で共同開発する際にはリポジトリにコミットしたくないかもしれません。
そんな場合は

~/.sbt/0.13/plugins/plugins.sbt

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


を書くと、どのsbtプロジェクトでもsbteclipseプラグインを使うことができるようになります。

私はグローバルに設定することにしました。


git

sbteclipseを使うとEclipse用のファイルが出来ますが、これは.gitignoreにしておくのが良いでしょう。

除外するのは以下の2つですね。

.project
.classpath

これは.gitignoreに書いても良いですが、こちらもグローバルな.gitignoreにしても良いかもしれません。

~/.gitignore_global


に追加するとすべてのgitリポジトリで有効になります。
この設定は人それぞれの好みかと思います。


まとめ

EclipseScalaをやるときはMarketplaceからScala IDEをインストールするだけで簡単に統合開発環境が用意できます。
私としてはリファクタリング機能は開発には必須なのでEclipseで開発できるのはとても心強いです。


Scala入門記の目次はこちらです。

Scala入門記003 初めてのsbt

実は最近Scala結構やってます。
個人的にもScalaを積極的に使っていくので疑問点を潰していく上でも入門記を続けようと思います。
Scala入門記の目次はこちらです。


前回も紹介しましたが、Scalaでビルドする際はsbtが標準的なツールです。
これをmavenと同等以上に使えるようになりたいところです。

まずは使いはじめるためには公式ドキュメントの和訳「始める sbt - ようこそ」を適宜読んでいくのが良さそうです。


準備

今日は軽く最初から試してみました。
まずは適当なフォルダにビルドの定義build.sbtを作ります。

name := "scala-ample-001"

version := "1.0"

scalaVersion := "2.10.3"

プロジェクト名とそのバージョン、使うscalaのバージョンを指定しただけです。

そしてソースコードを用意します。
ファイルはsrc/main/scala/Hello.scalaにしました。

object Hello {
  def main(args: Array[String]) {
    println("Hello!")
  }
}

実行

実行は前回と同じで以下のコマンドで「Hello!」が表示されます。

sbt run

パッケージング

jarを作るにはpackageです。

sbt package

これで./target/scala-2.10/scala-ample-001_2.10-1.0.jarができます。

scala ./target/scala-2.10/scala-ample-001_2.10-1.0.jar

で生成したjarのHello#mainが実行されます。
ちゃんとjarファイルにはマニフェストファイルが入っています。

sbt clean

でtargetフォルダがなくなります。
project/targetはなくならないようです。


実験

scalaVersion := "2.10.3"

scalaVersion := "2.10.2"

に変えてもrunできました。

scalaVersion := "2.10"

に変えるとエラーになりました。

scalaVersion := "2.10.5"

に変えるてもエラーになりました。

ログを見ていると、コンパイラをダウンロードしてコンパイルしてくれてるようでした。
なので端末に入っていないscalaのバージョンを指定してもビルドできるので便利そうです。
ちなみに2.10.5はリリースされていないのでエラーになったのですね。

最後にscalaVersionを消してしまった場合もコンパイルでき、この際はおそらくシステムのデフォルトが使われるのでしょう。


git

今回のソースをgit管理をする際は.gitignoreは以下としました。

target

今回のサンプルからGitHub管理していきます。
https://github.com/thachi/scala-sample-001


まとめ

build.sbtに名前とバージョンを書くだけでpackageを作ることができます。
非常に簡単で便利です。


Scala入門記の目次はこちらです。

CocoaPods

私が普段使っているXcodeプロジェクトの依存ライブラリの管理ツールの紹介です。

まず、サイトはこちら→ http://cocoapods.org/
簡単なのでこれを見ればいいけれどザクッと紹介します。

Podfileを見つけた場合

Podfileがあるプロジェクトを見たら、xcodeprojは開かずに

pod install

するとxxxx.xcworkspaceができるのでそれを開きます。

podなんて使えない場合

もしpodが入っていなければCocoaPodsを入れる。
※gem(=RubyGems)はmacに最初から入っていた気がします

sudo gem install cocoapods

まとめ

これだけでXcodeのライブラリ管理は幸せになることまちがいなしです。