search term:

sbt プラグむンをテストする

テストの話をしよう。䞀床プラグむンを曞いおしたうず、どうしおも長期的なものになっおしたう。新しい機胜を加え続けるもしくはバグを盎し続けるためにはテストを曞くのが合理的だ。だけど、ビルドツヌルのプラグむンのテストなんおどうやっお曞けばいいんだろうもちろん飛ぶんだよ。

scripted test framework

sbt は、scripted test framework ずいうものが付いおきお、ビルドの筋曞きをスクリプトに曞くこずができる。これは、もずもず 倉曎の自動怜知や、郚分コンパむルなどの耇雑な状況䞋で sbt 自䜓をテストするために曞かれたものだ:

ここで、仮に B.scala を削陀するが、A.scala には倉曎を加えないものずする。ここで、再コンパむルするず、A から参照される B が存圚しないために、゚ラヌが埗られるはずだ。 [äž­ç•¥ (非垞に耇雑なこずが曞いおある)]

scripted test framework は、sbt が以䞊に曞かれたようなケヌスを的確に凊理しおいるかを確認するために䜿われおいる。

正確には、このフレヌムワヌクは siasia ずしお知られる Artyom Olshevskiy 氏により移怍された scripted-plugin 経由で利甚可胜だが、これは正匏なコヌドベヌスに取り蟌たれおいる。

ステップ 1: snapshot

scripted-plugin はプラグむンをロヌカルに publish するため、たずは version を -SNAPSHOT なものに蚭定しよう。

ステップ 2: scripted-plugin

次に、scripted-plugin をプラグむンのビルドに加える。project/scripted.sbt:

libraryDependencies <+= (sbtVersion) { sv =>
  "org.scala-sbt" % "scripted-plugin" % sv
}

以䞋を scripted.sbt に加える:

ScriptedPlugin.scriptedSettings

scriptedLaunchOpts := { scriptedLaunchOpts.value ++
  Seq("-Xmx1024M", "-XX:MaxPermSize=256M", "-Dplugin.version=" + version.value)
}

scriptedBufferLog := false

ステップ 3: src/sbt-test

src/sbt-test/<テストグルヌプ>/<テスト名> ずいうディレクトリ構造を䜜る。ずりあえず、src/sbt-test/<プラグむン名>/simple から始めるずする。

sff4s: simple future facade for Scala

future の実装には様々なものがあるけど、暙準ラむブラリの䞭に共通の芪 trait があれば、特定のプラットフォヌムスタックにコヌドを䟝存させずにこの抂念を衚珟できるのにず思っおいた。そう思う人が他にもいるかは分からないけど、ラむブラリの䜜者なんかには圹に立぀んじゃないかな。取り敢えずこれが、sff4s を曞いた動機だ。

future っお䜕?

倚分名前ぐらいは聞いたこずあるかもしれないけど、䞀応おさらいしよう。future倀promise ずも呌ばれるは未完の蚈算を衚珟する。

  • future倀は未完の蚈算を衚珟する。

これがよく䜿われる説明だけど、それだけでは分からない。ここで蚀倖に含たれおいるのは、その蚈算は裏で行われおいるずいうこずだ。それは同じコンピュヌタ内の別のスレッドか、別のサヌバの䞭かもしれないし、行列埅ちでただ蚈算は始たっおさえいないかもしれない。ずにかく、蚈算は珟圚の制埡フロヌの倖で行われおいるずいうこずだ。

  • 蚈算はどこか別の所で行われる。

future倀のもう䞀぀の偎面は、そのうちに蚈算結果を埗られるずいうこずだ。Scala の堎合は def apply() を呌び出すなどの明瀺的なステップを芁する。蚈算が未完の堎合は、ブロック(block)する。぀たり、蚈算結果が埗られるたで埅たされるもしくはタむムアりトする。

  • future倀から蚈算結果を埗るこずができる。

最初に future倀が宣蚀された時には蚈算結果は有るかもしれないし、ただ無いかもしれない。うたくいけば、ある時点で結果が到着し、オブゞェクトの内郚構造が倉曎される。これを、future倀を「解決」(resolve)したずいう。勝手に状態が倉わるものずいうのはプログラミングではあたり芋かけないので、少し䞍気味ではある。

  • 蚈算結果を解決するための裏口がある。

これたでで、最も単玔な圢の future倀を蚘述した。実際に圹に立぀には他の機胜も必芁だけど、これでも䜿えないこずはない。ちょっず䜿甚䟋をみおみよう:

val factory = sff4s.impl.ActorsFuture
val f = factory future {
  Thread.sleep(1000)
  1
}
f() // => これは 1秒間ブロックした埌で 1 を返す

现かい事は気にしないで、最埌の䞀行の振る舞いだけ芋おほしい。このように、蚈算結果を取埗するこずを、匷芁(forcing)するずもいう。最小限の API は以䞋のようになる。

Future v0.1

abstract class Future[+A] {
  /** 蚈算結果を匷芁しお無期限にブロックする */
  def apply(): A
}

Scala から䜿甚可胜な future倀の実装にはいく぀かあるけど、どれも䞀から曞かれおる。䞊のような共通な芪クラスがあれば、特定のラむブラリに䟝存しないコヌドを曞くこずができる。

ただ来ない?

Future v0.1 に察しお唯䞀できる事が蚈算結果が戻っおくるたでブロックしおしたうので、あたりにも䞍䟿だ。埅぀こずしかできないから future を䜿わないほうがいい。そのため、党おの future倀が提䟛するもう䞀぀の機胜ずしお、蚈算結果の甚意ができたかを確かめるノンブロッキング(non-blocking)な方法がある。これは実装によっお isDone、isSet、isDefined、isCompleted などず呌ばれおいるが、党お同じ意味だ。今のずころ、僕の奜みずしおは def isDefined: Boolean がいいず思う。future を抂念的に Option の倉数ずしお考えるこずができるからだ。

モナドはメタファヌではない

Scala界の関数型プログラミング䞀掟を代衚する論客の䞀人、@djspiewak が 2010幎に曞いた “Monads Are Not Metaphors” を翻蚳したした。翻蚳の公開は本人より蚱諟枈みです。翻蚳の間違い等があれば遠慮なくご指摘ください。

2010幎12月27日 Daniel Spiewak 著 2011幎5月29日 e.e d3si9n èš³

僕は今、玄束を砎るずころだ。およそ䞉幎前、僕は絶察にモナドの蚘事だけは曞かないず自分に玄束した。既にモナドに関する蚘事は有り䜙っおいる。蚘事の数が倚すぎおその倚さだけで倚くの人は混乱しおいる。しかも党員がモナドに察しお異なる扱い方をしおいるため、モナドの抂念を初めお孊がうずする者は、ブリトヌ、宇宙服、象、砂挠のベドりィン (蚳泚: アラブ系遊牧民) の共通項を探す努力をするハメになっおいる。

僕は、この混乱した喩え話のサヌカスにわざわざもう䞀぀远加するようなこずはしない。たず、どの喩え話も完党には正確では無い。どの喩えも党䜓像を䌝えきれおいないし、いく぀かは重芁な点に関しお露骚に誀解を招くような内容になっおいる。メキシコ料理や宇宙そらに思いをはせるこずでは、絶察にモナドを理解するこずはできない。モナドを理解する唯䞀の芋方は、それをありのたたの姿、぀たり数孊的抂念ずしお芋るこずだ。

実戊での Scala: Cake パタヌンを甚いた Dependency Injection (DI)

Akka の䜜者ずしお益々泚目を集めおいる Jonas Bonér が 2008幎に曞いた “Real-World Scala: Dependency Injection (DI)” を翻蚳したした。翻蚳の公開は本人より蚱諟枈みです。翻蚳の間違い等があれば遠慮なくご指摘ください。

2008幎10月6日 Jonas Bonér 著 2011幎4月22日 eed3si9n èš³

さお、実戊での Scala シリヌズ第二匟の今回は、Scala を甚いた Depenency Injection (DI) の実装をみおいきたい。Scala は、備わっおいる蚀語機構だけを甚いおも䜕通りかの DI を実珟できる非垞に豊かでディヌプな蚀語だが、必芁に応じお既存の Java DI フレヌムワヌクを䜿うこずもできる。

Triental では、䞀぀の戊略に萜ち着くたで䞉぀の異なる方法を詊した。以䞋のように話を進めおいく。たず、珟行の DI の実珟方法を詳しく説明した埌で、詊した他の方法も簡単にカバヌする。

Cake パタヌンを甚いる

私たちが甚いおいる珟行の戊略は、いわゆる Cake パタヌンに基づいおいる。このパタヌンは、Martin Odersky の論文 Scalable Component Abstractions においお、Ordersky ず圌のチヌムが Scala のコンパむラを構成した方法ずしお最初に発衚された。このパタヌンがどのようにしお DI を実珟するのかずいうこずを日本語で説明する事を詊みるよりも、私たちの実際に䜿っおいるコヌドに倧たかに基づいた愚盎なサンプルコヌドをみおみよう。

泚意: 順を远っお、最終バヌゞョンに向けおリファクタリングしながら説明しおいくので、最終バヌゞョンを読んで理解するたでは、「ダメじゃん!」ず叫ぶのは埅っおほしいもちろん、読了埌にどうしおもず蚀うなら批刀、賞賛、意芋、アむディアなどを送っおもいい。たた、このサンプルコヌドは、このようなサンプルの䟋にもれず、非垞に耇雑な方法で取るに足りない事を行っおいるようにみえるが、我慢しお倧芏暡システムでの実際のサヌビスを想像しお、どのように応甚できるかを想像しお欲しい。

たずは、UserRepository (DAO、Data Access Object) を実装しよう。

// 実際の氞続化は䜕もしおいなくお、画面にナヌザを衚瀺するだけのダミヌ。 
class UserRepository {  
  def authenticate(user: User): User = {   
    println("authenticating user: " + user)  
    user  
   }  
  def create(user: User) = println("creating user: " + user)  
  def delete(user: User) = println("deleting user: " + user)  
}

trait むンタヌフェむスずその実装に分けお実装するこずもできたが、話を簡単にするために、敢えおここではそうしなかった。

Scala ず Json で tweed を織る

次々ずダバいコヌドを玡ぎ出し NY Scala シヌンの䞭心的存圚であり続ける @n8han が二幎前に曞いた “Weaving tweed with Scala and Json” を翻蚳したした。翻蚳の公開は本人より蚱諟枈みです。翻蚳の間違い等があれば遠慮なくご指摘ください。

2009幎5月27日 n8han 著 2011幎1月2日 eed3si9n èš³

抜出子は、Programming in Scala の 24章にのみ蚘述されおいる Scala の秘密機胜で、この春の倧ヒットだ。今たでは皆 case Some(thing) => kerpow(thing) で満足だったのが、今では抜出子を曞けなければ #scala freenode にも入れおもらえない。ズルをすれば Scala チャンネルの硬掟な垞連たちは君のコンピュヌタをハックしお驚くほど銬鹿げたドヌルハりスを連続再生しおただし混济シャワヌシヌンを陀く、番組の「アクティブ」のように意味のあるタむピングを諊めなければいけない。

蚳泚。以䞋 Draco より抜粋 ロッサム・コヌポレヌションは人間の人栌、経隓をすべお消し、新しい人栌を怍え付ける技術を開発した。圌らはこの技術を甚いお、戊闘甚の人圢アクティブを生み出した。 人圢たちはドヌルハりスずいう斜蚭で生掻しおいる。誰かの人栌を移怍され、任務に挑む。 アクティブの䞀人、゚コヌは蚘憶のリラむト䞭に゚ラヌが起こり、完党には蚘憶が消されおいなかった。

この抜出子はちょっずチクっずしたすからね

呜からがら逃げ出した僕は抜出子をありずあらゆる状況に適甚するよう努めた。䟋えば、JavaScript むンタプリタが理解できるお排萜な文字列、Json オブゞェクトだ。抜出子を䜿えば case 構文でこのように凊理するこずができる:

import dispatch.json.Js
val echo = Js("""{"acting": "無衚情で前を芋おいる"}""")
object Echo extends Js { val acting = 'acting ? str }
echo match {
  case Echo.acting(hmm) => hmm
  case _ => "pshaw"
}

res0: String = staring blankly ahead

Symbol 'acting に察しお ? を呌び出すこずで抜出子が䜜成される。Symbol には ? メ゜ッドはないが暗黙の倉換でそれをも぀オブゞェクトに倉換されおいる。Echo はい぀も挔技しおるずいうこずが分かっおいるので、この抜出子を䜿っお盎接代入するこずもできる:

IntelliJ IDEA のための Twilight

Scala をやりながら他の IDE も詊したしたが、結局 TextMate に戻っおいたす。 今回巷で話題の IntelliJ IDEA に䟿乗するにあたっお、Twilight theme を䜜りたした。

screenshot

型クラスによる XML デヌタバむンディング

結局の所scalaxb のナヌザぱンティティ・オブゞェクトが衚珟する珟実の問題に興味があるのであっおそれがどう XML に氞続化されるかずいったこずではないだからい぀かデヌタバむンディングの実装をシングルトン/コンパニオン・オブゞェクトから远い出さなければいけないこずは分かっおいた぀い最近たでデヌタバむンディングの実装は以䞋のように生成されおいた:

object Address extends rt.ElemNameParser[Address] {
  val targetNamespace = "http://www.example.com/IPO"

  def parser(node: scala.xml.Node): Parser[Address] =
    ...

  def toXML(__obj: Address, __namespace: String, __elementLabel: String, __scope: scala.xml.NamespaceBinding): scala.xml.NodeSeq =
    ...
}

぀たりscalaxb は Address そのものずは関係の無い XML デヌタバむンディングのために䞀等地をハむゞャックしおしたったのだ

adapter

たず最初に以䞋のような adapter オブゞェクトに远い出すこずを考えた:

object DefaultXMLAdapter {
  object AddressAdapter extends rt.ElemNameParser[Address] {
    val targetNamespace = "http://www.example.com/IPO"

    def parser(node: scala.xml.Node): Parser[Address] =
      ...

    def toXML(__obj: Address, __namespace: String, __elementLabel: String, __scope: scala.xml.NamespaceBinding): scala.xml.NodeSeq =
      ...
  }
}

この方法にはいく぀かの問題があるたずscalaxb のランタむムである DataRecord が今たではコンパニオン・オブゞェクトの暗黙性を䜿っおたどっおいた toXML にたどり着けないずいうこずだコンパニオン・オブゞェクトの興味深い䞀面ずしお「コンパむラは暗黙 (implicit) の定矩を倉換元の型ず倉換先の型のコンパニオン・オブゞェクトにも探しにいく」(Programming in Scala, p. 441) ずいうものがある

第二の問題はアむデンティティヌ問題だナヌザのコヌドの邪魔にならないようにしようずしおいるのにAddress オブゞェクトのためには DefeaultXMLAdapter.AddressAdapterItem のためには DefeaultXMLAdapter.ItemAdapterなどず かえっお目に障るものを導入しおしたったナヌザが知っおいる必芁があるのは Address が XML に倉換できるずいう事実だけあっおそれがどう行われおいるかずいうのは䜙蚈な詳现でしかない

第䞉の問題ずしお拡匵性の問題がある䟋えばAddress を定矩する ipo.xsd ずAddress を䜿う purchaseReport芁玠を定矩する report.xsd の二぀のスキヌマがあるずする問題はreport.DefaultXMLAdapter.PurchaseReportAdapter は ipo.DefaultXMLAdapter.AddressAdapter を参照するためipo.DefaultXMLAdapter を拡匵しおカスタムのデヌタバむンディングをするこずができないずいうこずだ

sjson: Scala の型クラスによる JSON シリアラむれヌション

Debasish Ghosh さん (@debasishg) の “sjson: Now offers Type Class based JSON Serialization in Scala” を翻蚳したした 元蚘事はこちら: http://debasishg.blogspot.com/2010/07/sjson-now-offers-type-class-based-json.html (翻蚳の公開は本人より蚱諟枈みです) 翻蚳の間違い等があれば遠慮なくご指摘ください

長い間 sjson のシリアラむれヌション API はリフレクションに䟝存するものだったこの方法の長所ずしおは瞁の䞋ではリフレクションによる実装が頑匵っおいおも API は䜿いやすくするこずができたずいうこずだ

しかしJSON 構造ず Scala のオブゞェクトでは型情報の豊かさに倧きな違いがあるこずを忘れおはいけないScala から JSON にいくずきに䜕らかの圢で型情報をシリアラむれヌションプロトコルの䞀郚ずしお保存しないかぎり可逆倉換させるのは堎合によっおはずおもトリッキヌで難しいこずになる特に JVM では type erasure のせいで JSON構造にシリアル化した Scala オブゞェクトの䞭には元に戻すのがほが䞍可胜なものもあるだろう

ver 0.7 より sjson は元のものに加えリフレクションを䜿わない JSON シリアラむれヌションプロトコルを甚意したこれはナヌザが任意のオブゞェクトから JSON ぞシリアル化する自分のプロトコルを芏定できるようになったリフレクションによる JSON シリアラむれヌションではアノテヌションで行っおいたものをカスタムプロトコルを自分で実装するこずで実珟するこずができる

sjons の型クラスによるシリアラむれヌションは David MacIver による玠晎らしい sbinary (珟圚は Mark Harrah によりメンテされいる) にむンスパむアされおおり同じプロトコルを䜿いたた実装レベルでも色々ず盗たせおもらった

型クラスの基瀎的抂念ぞの入門Scala での実装そしお型クラスを䜿ったシリアラむれヌションプロトコルが Scala でどう蚭蚈できるかに぀いおは数週間前に曞いた以䞋の blog 蚘事を参照しおほしい:

組み蟌み型の JSON シリアラむれヌション

これは sjson でデフォルトのシリアラむれヌションプロトコルを䜿った REPL セッションの䞀䟋だ…

Scala Implicits: 型クラス、襲来

Debasish Ghosh さん (@debasishg) の “Scala Implicits : Type Classes Here I Come” を翻蚳したした 元蚘事はこちら: http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html (翻蚳の公開は本人より蚱諟枈みです) 翻蚳の間違い等があれば遠慮なくご指摘ください

先日 Twitter 䞊で Daniel ず Scala での型クラスに぀いお論議しおいるず突然このトピックに関する曞きかけだった蚘事を発芋したこれを読んでもあなたは特に目新しい事を発芋するわけではないが型クラスに基づいた思考はあなたの蚭蚈の幅に䟡倀を䞎えるこずができるず思うこの蚘事を曞き始めたのはしばらく前に蚭蚈の盎亀性に぀いおの蚘事 (原文)を公開したずきのこずだ

たずは GoF の Adapter パタヌンから始めよう委譲型の Adapter はよく勧められる合成(composition)ずいうテクニック甚いお抜象䜓(abstraction)1どうしをバむンドする

蚭蚈の盎亀性のずきず同じ䟋を䜿うず

case class Address(no: Int, street: String, city: String, 
  state: String, zip: String)

これを LabelMaker ずいうむンタヌフェむスに適合させたいずする぀たり我々は Address オブゞェクトを LabelMaker ずしお䜿いたい

trait LabelMaker[T] {
  def toLabel(value: T): String
}

むンタヌフェむス倉換を行うアダプタヌは…

// Adapter クラス
case class AddressLabelMaker extends LabelMaker[Address] {
  def toLabel(address: Address) = {
    import address._
    "%d %s, %s, %s - %s".format(no, street, city, state, zip)
  }
}

// この Adapter は Address オブゞェクトに LabelMaker のむンタヌフェむスを提䟛する
AddressLabelMaker().toLabel(Address(100, "Monroe Street", "Denver", "CO", "80231"))

さお䞊の蚭蚈で我々が副次的に導入しおしたった耇雑さはなんだろう

Scala 型クラスぞのリファクタリング

Debasish Ghosh さん (@debasishg) の “Refactoring into Scala Type Classes” を翻蚳したした 元蚘事はこちら: http://debasishg.blogspot.com/2010/07/refactoring-into-scala-type-classes.html (翻蚳の公開は本人より蚱諟枈みです) 翻蚳の間違い等があれば遠慮なくご指摘ください

二週間ほど前に Scala の暗黙の(implicit)パラメヌタを甚いた型クラスの実装に぀いお曞いた型クラスはある抜象䜓(abstraction)に぀いおの盎亀した関心事を抜象䜓そのものに盎接組み蟌むこずなくモデル化するこずができるこれでコアな抜象䜓から䜙蚈なものを取り去っお別々の独立したクラス構造に倉えおいくこずができる最近 Akka actor のシリアラむれヌションをリファクタリングしお型クラスの恩恵に関する実地的な知芋を埗るこずができたのでここに報告したい

最初は継承ず trait でうたくいくず思った…

… しかしそれは長続きしなかったJonas Boner ず筆者の間で actor のシリアラむれヌションに関しお面癜い論議があり以䞋のような蚭蚈が生たれた …

trait SerializableActor extends Actor 
trait StatelessSerializableActor extends SerializableActor

trait StatefulSerializerSerializableActor extends SerializableActor {
  val serializer: Serializer
  //..
}

trait StatefulWrappedSerializableActor extends SerializableActor {
  def toBinary: Array[Byte]
  def fromBinary(bytes: Array[Byte])
}

// .. 以䞋続く

このような trait はシリアラむれヌションずいう関心事をコアな actor の実装ず結合(couple)させすぎおしたう様々なシリアラむズ可胜な actor があるため良いクラス名が足りなくなっおきおいたGoF本が教えおくれる知恵の䞀぀にむンタヌフェむスを甚いたクラスの呜名に困るずしたら間違ったこずをやっおいるずいうものがある関心事をより意味のある方法で分割する別のやり方を探ろう

型クラスだ

コアの actor 抜象䜓からシリアラむれヌションに関するコヌドを抜き出し別の型クラスにした

/**
 * Actor 盎列化のための型クラス定矩
 */
trait FromBinary[T <: Actor] {
  def fromBinary(bytes: Array[Byte], act: T): T
}

trait ToBinary[T <: Actor] {
  def toBinary(t: T): Array[Byte]
}

// クラむアントはそれぞれの Actor のための Format[] を実装する必芁がある
trait Format[T <: Actor] extends FromBinary[T] with ToBinary[T]

actor をシリアラむズ可胜にするためにクラむアントが実装する必芁がある FromBinary[T <: Actor] ず ToBinary[T <: Actor] ずいう二぀の型クラスを定矩したこれをさらに Format[T <: Actor] ずいう二぀を合わせた trait に組み合わせた