Scala2.10の新機能を勉強する その2 ImplicitClass
前回のつづきで、
今日はScala2.10のImplicitClassをやってみたいと思います。
ImplicitClassって?
簡単に言うと、ImplicitConversionを楽に書ける機能、
と理解して良いんでしょうかね?
SIP-13 - Implicit classes - Scala Documentation
つまり
- 変換する型の定義
- 変換するメソッドの定義
が一発で書ける。
とりあえず、書いてみます。
ImplicitClassを書いてみる
こんな感じで書いてみました。
「HalfInt」はclassの定義とimplicit defの定義が必要ですが、
「DoubleInt」はimplicit classの定義だけで済んでいます。
これは確かに完結で良い。
ただ、これ、同じようにコンパイルされるんだろうか?
という事で、jadってみます。
package implicitclass; import scala.Function0; import scala.Predef$; import scala.runtime.*; // Referenced classes of package implicitclass: // ImplicitClass_01$ public final class ImplicitClass_01 { public static class HalfInt { public int half() { return i / 2; } private final int i; public HalfInt(int i) { this.i = i; super(); } } public static class DoubleInt { public int _mthdouble() { return i * 2; } private final int i; public DoubleInt(int i) { this.i = i; super(); } } public static class delayedInit.body extends AbstractFunction0 { public final Object apply() { Predef$.MODULE$.println(BoxesRunTime.boxToInteger($outer.DoubleInt(1)._mthdouble())); Predef$.MODULE$.println(BoxesRunTime.boxToInteger($outer.toHalfInt(1).half())); return BoxedUnit.UNIT; } private final ImplicitClass_01$ $outer; public delayedInit.body(ImplicitClass_01$ $outer) { if($outer == null) { throw new NullPointerException(); } else { this.$outer = $outer; super(); return; } } } public static void main(String args1[]) { ImplicitClass_01$.MODULE$.main(args1); } public static void delayedInit(Function0 function0) { ImplicitClass_01$.MODULE$.delayedInit(function0); } public static String[] args() { return ImplicitClass_01$.MODULE$.args(); } public static void scala$App$_setter_$executionStart_$eq(long l) { ImplicitClass_01$.MODULE$.scala$App$_setter_$executionStart_$eq(l); } public static long executionStart() { return ImplicitClass_01$.MODULE$.executionStart(); } public static HalfInt toHalfInt(int i) { return ImplicitClass_01$.MODULE$.toHalfInt(i); } public static DoubleInt DoubleInt(int i) { return ImplicitClass_01$.MODULE$.DoubleInt(i); } }
ほぼ同じようにコンパイルされてるっぽい(?)
ImplicitClassを切り出してみる
次にImplicitClassを切り出してみます。
コメントにも書いてありますが、
implicit classをトップレベルで書けないようです。
以下のようなエラーになりました。
[error] /Users/xxxx/workspace/scala-samples/scala-2.10-sample/src/main/scala/implicitclass/ImplicitClass_02.scala:10: `implicit' modifier cannot be used for top-level objects [error] implicit class TripleInt(i: Int) { [error] ^ [error] one error found [error] (compile:compile) Compilation failed
importに関しては、implicit defで定義する時も同じような使いかたをするだろうし、
あまり変わらないかな??
今日は、ここまでにします。
次回はValueClassに挑戦。
(内容薄いですが、メモなので、、、、(逃
Scala2.10の新機能を勉強する その1 StringInterpolation
久々のブログですが、
今更ながらScala2.10の新機能をちゃんと勉強しておこうと思います。
※終わったらRuby2.0やろうと思ってますが、、、
今回のテーマ
StringInterpolation
です。
StringInterpolationって?
Rubyの式展開のように、文字列リテラル内に、式を書く事ができる機能です。
Interpolationって、どういう意味だろうか、、、
初めて聞いたので、意味がわからず、、調べてみました。
alc
http://eow.alc.co.jp/search?q=interpolation&ref=sa
→〔他のものに〕挿入すること、差し挟むこと
なるほど、文字列になんか差し込むので、StringInterpolation、なんですね。
とりあえず言葉の意味は理解できました。
式を埋め込んでみる
まずは、単純に変数の値を埋め込んでみます。
これで、
Hello hoge!
となります。
Rubyの記法に比べると{}が無くて、#が$になった感じですね。
では、次に、計算式やらメソッド呼び出しやらを埋め込んでみます。
ここでは{}が必要な場面が登場しました。
変数もしくは引数なしのメソッド呼び出しは{}は不要ですが、
それ以外は必要になるようです。
※当然といえば当然ではある、、、。
フォーマットを指定して埋め込む
次はフォーマットを指定して値を埋め込んでみたいと思います。
ここで最後の行はエラーになりました。
コメントにも書きましたが、
piはDouble型になるので、Intを期待するフォーマット「%d」は使えません。
※コンパイル時にエラーになります
[error] /xxxx/workspace/scala-samples/scala-2.10-sample/src/main/scala/interpolation/StringInterpolation_03.scala:10: type mismatch; [error] found : Double [error] required: Int [error] println(f"$hoge is $pi%2.4d") // これはpiがDoubleなので、エラーになる [error] ^ [error] one error found [error] (compile:compile) Compilation failed
仕組みを知る
このStringInterpolationの仕組みはStringContextのメソッド飛び出しで実現されているようです。
試してみます。
こんな感じ。
hoge"...."
これは
StringContext(....).hoge(....)
に展開されるようなので、
ImplicitConversionと組み合わせれば、他にも便利なリテラルが実現できそうです。
他の機能を勉強してからやってみたいと思います。
Scala勉強日誌 - Akka その1
Scala勉強日誌 - Actor - 成らぬは人の為さぬなりけり
大分前にActorの勉強して、続きでAkkaの勉強しようと思ってて、完全に忘れていたので、
再開したいと思います。
(仕事で必要になって、勉強したので、メモしているだけ、、、)
今日のテーマは、、、
- SBTプロジェクトを作る
- AkkaのActorを書いてみる
- ActorからActorを呼び出して、結果を受け取ってみる
- Routerを使ってみる。
yagince/akka_practice · GitHub
例によって、環境は、、、
- OS:MacOSX10.8
- Scala : 2.10.0
- sbt :0.12.2
- Akka : 2.1.0
SBTプロジェクトを作る
まずは、プロジェクトを作ります。
今回は、全部ビルド定義ファイルは全部Scalaで書きたかったので、
こんな感じで作成
project/Build.scala
import sbt._ import Keys._ object BuildSettings { val buildOrganization = "yagince" val buildVersion = "0.0.1" val buildScalaVersion = "2.10.0" val buildSettings = Defaults.defaultSettings ++ Seq ( organization := buildOrganization, version := buildVersion, scalaVersion := buildScalaVersion ) } object Resolvers { val typeSafe = "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/" val otherResolvers = Seq(typeSafe) } object Dependencies { val akkaCore = "com.typesafe.akka" %% "akka-actor" % "2.1.0" } object AkkaPracticeBuild extends Build { import Resolvers._ import Dependencies._ import BuildSettings._ val dependencies = Seq ( akkaCore ) val project = Project ( "akka-practice", file("."), settings = buildSettings ++ Seq ( resolvers := otherResolvers, libraryDependencies ++= dependencies ) ) }
project/build.properties
sbt.version=0.12.2
AkkaのActorを書いてみる
では、早速書いてみます。
src/main/scala/akka/sample/AkkaExample01.scala
package akka.sample import actor.PrintActor import akka.actor.{Props, ActorSystem} object AkkaExample01 extends App { val system = ActorSystem("sample") val actor = system.actorOf(Props[PrintActor], "hoge") actor ! "HelloWorld!" system.shutdown }
package akka.sample import actor.PrintActor import akka.actor.{Props, ActorSystem} object AkkaExample01 extends App { val system = ActorSystem("sample") val actor = system.actorOf(Props[PrintActor], "hoge") actor ! "HelloWorld!" system.shutdown }
src/main/scala/akka/sample/actor/PrintActor.scala
package akka.sample.actor import akka.actor.Actor class PrintActor extends Actor { def receive = { case x => println(x) } }
実行結果
> run-main akka.sample.AkkaExample01 [info] Running akka.sample.AkkaExample01 HelloWorld! [success] Total time: 0 s, completed 2013/02/13 22:16:22
単純に渡したオブジェクトを出力するだけのアクターです。
これだけ見ても、scala標準Actorより記述量が少ないですね。
そして、シンプル!
素晴らしい。
ActorからActorを呼んで結果を受け取ってみる
Scala標準Actorの同期メソッドみたいのあるのかな??
無さそう???と思っていたら、
こんな風にするのが普通なのかな???
というわけで書いてみます。
package akka.sample import akka.actor.{ActorSystem, Actor, Props} import akka.routing.RoundRobinRouter object AkkaExample02 extends App { val system = ActorSystem("sample") val actor = system.actorOf(Props[Master]) actor ! 100 Thread.sleep(500) system.shutdown } class Master extends Actor { val actor = context.actorOf(Props[DoubleActor]) def receive = { case i:Int => actor ! i case Doubled(x) => println("received : %d".format(x)) } } class DoubleActor extends Actor { def receive = { case i:Int => sender ! Doubled(i*2) } } case class Doubled(i:Int)
senderへ結果を返して、呼び出し側のreceiveへメッセージパッシングする感じですかね?
確かに、これはシンプルで綺麗だ。
よくよく考えると、同期メソッドって必要ないんじゃなかろうか、、、
Routerを使ってみる
AkkaにはRouterという機能があるようです。
Actorのインスタンスを管理して、
Routerにメッセージ送信すると、
Actorへよしなにバランシングしながらメッセージを横流ししてくれるような感じでしょうか?
書いてみます。
package akka.sample import actor.{Doubled, DoubleActor} import akka.actor.{ActorSystem, Actor, Props} import akka.routing.RoundRobinRouter object AkkaExample02 extends App { val system = ActorSystem("sample") val actor = system.actorOf(Props[Master]) (0 to 10).foreach(actor ! _) Thread.sleep(100) system.shutdown } class Master extends Actor { val router = context.actorOf(Props[DoubleActor].withRouter(RoundRobinRouter(2))) def receive = { case i:Int => router ! i case Doubled(x) => println("received : %d".format(x)) } }
> run-main akka.sample.AkkaExample02 [info] Running akka.sample.AkkaExample02 received : 0 received : 2 received : 6 received : 10 received : 4 received : 14 received : 8 received : 18 received : 12 received : 16 received : 20 [success] Total time: 0 s, completed 2013/02/13 22:27:41
一個前の例のMasterクラスを書き換えて、
DoubleActorをRouterで管理するようにしてみました。
Routerの種類は
- akka.routing.RoundRobinRouter
- akka.routing.RandomRouter
- akka.routing.SmallestMailboxRouter
- akka.routing.BroadcastRouter
- akka.routing.ScatterGatherFirstCompletedRouter
- akka.routing.ConsistentHashingRouter
Routing (Scala) — Akka Documentation
これだけあるようです。
それぞれの違いは、また次回ということで、、、
さて、今日はここまでにします。
CoffeeScriptを書いてみる その2
前回は、
関数定義、文字列内変数展開をやってみました。
さて、今回のテーマは、、、
- 可変長引数
- レンジ
- 比較演算子
- 条件付き代入
- 無名関数
をやってみたいと思います。
可変長引数
関数の引数に「...」をつけると可変長引数になります。
hoge = (ary...) -> console.log ary hoge 1,2,3,4,5
実行結果
[ 1, 2, 3, 4, 5 ]
ちゃんと配列で取得できているようですね。
レンジ
配列をレンジ(範囲)で作成することができます。
書き方はRubyとほぼ同じでした。
range = [1..10] console.log range
実行結果
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
逆順にすることもできます。
reverse_range = [10..0] console.log reverse_range
実行結果
[ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ]
「..」を「...」にすると、右端を含めないレンジになります。
※昇順でも降順でも同じ
reverse_range_2 = [10...0] console.log reverse_range_2
実行結果
[ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ]
比較演算子
等価比較
CoffeeSriptでは「==」を使うと「===」にコンパイルされます。
なので、==で型も含めた比較になります。
※CoffeeScriptにはJavaScriptでいう==に相当する比較演算子は無いそうです。
console.log 1 == "1"
実行結果
false
では、同じ事をJavaScriptでやってみます。
今回はNode.jsを使ってやってみます。
$ node > 1 == "1" true > 1 === "1" false
「1=="1"」はJavaScriptではtureになりますね。
「==」以外にも「is」という演算子が用意されています。
coffee> 1 is "1" false
※ファイルに書くのがめんどくさくなってきたので、辞めました。。。
「is」は「===」にコンパイルされるようです。
他にも自然言語でかける演算子がいくつか用意されています。
coffee> 1 is "1" false coffee> 1 isnt "1" true coffee> not true false coffee> not 1 false coffee> not undefined true coffee> not null true coffee> true and false false coffee> yes true coffee> no false coffee> false or true true
こういうのはコードが非常にリーダブルになるので好き。
存在確認をする演算子もあります。
coffee> hoge? false
RubyのActiveSupportのObject#tryのような使い方もできます。
coffee> hoge?.foo undefined coffee> hoge = {foo: "foo"} { foo: 'foo' } coffee> hoge?.foo 'foo'
条件付き代入
nullもしくは、undefinedの場合のみ代入する。
foo = null foo ?= "foo" console.log foo
実行結果
foo
※これはREPLからやると、エラーになる、、、
ちなみに、「?=」で代入する場合、変数「foo」は定義されている必要があります。
fooが未定義の場合
Error: In foo.coffee, the variable "foo" can't be assigned with ?= because it has not been defined.
と怒られました。
falseの時のみ代入する
bar = false bar ||= "bar" console.log bar
実行結果
bar
ちなみに、これもbarが定義されていないと怒られます。
これは、Rubyと同じで、条件的にfalseと判定できればなんでもいけるのか??
というわけで試してみます。
a = false a ||= "Yes" console.log a b = 0 b ||= "Yes" console.log b c = null c ||= "Yes" console.log c d = undefined d ||= "Yes" console.log d e = "" e ||= "Yes" console.log e
実行結果
Yes Yes Yes Yes Yes
なるほど。
変数が定義されてさえいれば、あとはRubyと同じようなノリなのかな。
変数が定義されていない場合に代入する、というのは、こんな感じで書くんでしょうか?
coffee> hoge = hoge ? "hoge" 'hoge'
無名関数
最後に、無名関数を関数の引数に渡す場合の書き方です。
基本的には、関数定義時となんらかわりありません。
setTimeout -> console.log "Hoge" , 1000
実行結果
$ coffee nameless.coffee Hoge
一秒待って、Hogeと表示されます。
ちなみに、当たり前な事ではありますが、こう書くと、意図しない動きになります。。。
setTimeout -> console.log "Hoge" , 1000
実行結果
$ coffee nameless.coffee Hoge 1000
setTImeoutに対して、
console.log("hoge",1000)
を呼び出す関数を渡した事になるので、当たり前ではありますが、
最初ちょっと???になりました。
(インデントに慣れていないので、、、)
今日はここまで。
次は配列の操作とかクラス定義とかやろうと思ってます。
CoffeeScriptを書いてみる その1
前回、CoffeeScriptの環境を作ったので、
早速書き始めてみようと思います。
今回のテーマ
- 関数定義
- 文字列内変数展開
関数定義
CoffeeScriptでの関数定義はこんな感じになるようです。
helloworld.coffee
helloworld = -> console.log "hello world"
呼び出してみます。
helloworld()
実行
$ coffee helloworld.coffee hello world
引数がある関数を定義してみます。
square.coffee
square = (x) -> x * x console.log square(10)
実行
$ coffee square.coffee 100
関数呼び出す時に、引数は括弧なしでも呼び出せるっぽい??
ちょっと試してみます。
hoge.coffee
hoge = (x,y) -> x + y console.log hoge 1, 2
実行
$ coffee hoge.coffee 3
括弧なしでも呼び出せるっぽい、ですね。
もう一発試してみます。
hoge2.coffee
hoge = (x,y) -> x + y hoge2 = (x,y,z) -> x + y + z console.log hoge 1, hoge2 2, 3, 4
実行
$ coffee hoge2.coffee 10
おぉ、できた、なるほど。
では、引数なしの場合も括弧は省略できるんでしょうか?
CoffeeScriptはRuby+Pythonライクらしいので、
Rubyライクであればできるだろうし、Pythonライクであれば関数オブジェクトが返ってくるのかな?
やってみます。
function.coffee
f = -> "called" console.log f
実行
$ coffee function.coffee [Function]
なるほど、関数オブジェクトが返ってくるっぽい。
以下のように変更して実行してみます。
f = -> "called" console.log f console.log f() console.log f.call()
実行
$ coffee function.coffee [Function] called called
こうなるんですね、なるほど。
では、このcoffeeファイルをJavaScriptにコンパイルしてみましょう。
$ coffee -c function.coffee
コンパイルするときは、「-c」をつけて実行します。
結果
// Generated by CoffeeScript 1.4.0 (function() { var f; f = function() { return "called"; }; console.log(f); console.log(f()); console.log(f.call()); }).call(this);
大体予想どおりではありました。
ちなみに、
var f; f = function() { return "called"; };
これは、
var f = function() { return "called"; }
こうならないのは何故なんでしょう?
前者のほうが効率が良いんでしょうか?
JavaScriptの言語仕様に詳しくないので、理由はわかりませんでした。。。
文字列内変数展開
CoffeeScriptはRubyのように文字列リテラル内で変数展開ができるようです。
試してみます。
string_interpolation.coffee
i = 1 console.log "hoge #{i} foo"
実行
$ coffee string_interpolation.coffee hoge 1 foo
構文はRubyまんまですね。
では、Rubyみたいに式展開はできるのでしょうか?
i = 1 console.log "hoge #{i + 100} foo"
実行
$ coffee string_interpolation.coffee hoge 101 foo
おぉー、できるんですね。なるほど。
関数呼び出しもできるのかな?
f = -> "aaaaaaaaa" console.log "hoge #{f()} foo"
実行
$ coffee string_interpolation.coffee hoge aaaaaaaaa foo
まぁあたりまえか。できますよね。
では、こいつもコンパイルしてみましょう。
i = 1 console.log "hoge #{i} foo" console.log "hoge #{i + 100} foo" f = -> "aaaaaaaaa" console.log "hoge #{f()} foo"
string_interpolation.js
// Generated by CoffeeScript 1.4.0 (function() { var f, i; i = 1; console.log("hoge " + i + " foo"); console.log("hoge " + (i + 100) + " foo"); f = function() { return "aaaaaaaaa"; }; console.log("hoge " + (f()) + " foo"); }).call(this);
なるほど、文字列連結になるんですね。
というわけで、今日はここまで。
(もうちょっと仕様を深く知りたいなぁ)
HomebrewでNode.js入れて、npmでCoffeeScriptを入れる
CoffeeScriptを勉強する為に環境を構築したので、メモ。
環境
- OS : MacOSX 10.8.2
- Node.js : 0.8.16
- npm : 1.1.71
- CoffeeScript : 1.4.0
- Homebrew : 0.9.3
インストール手順
- HomebrewでNode.jsをインストール
- npmをインストール
- CoffeeScriptをインストール
brewから直接CoffeeScriptをインストールできるみたいですが、
npmの管理下に置かれないみたいなので、
別々にインストールすることにしました。
HomebrewでNode.jsをインストール
brew install node
npmをインストール
ここでちょっとはまる。。。orz
curl http://npmjs.org/install.sh | sudo sh
これでインストールできます、という記事をちらほら見てやってみると、
sh: line 1: syntax error near unexpected token `newline' sh: line 1: `<html>Moved: <a href="https://npmjs.org/install.sh">https://npmjs.org/install.sh</a>'
というエラーでインストールに失敗します。
メッセージを見ると、どうやら「https」に移動されたようです。
httpsに直して、実行して無事インストールできました。
(これに気づくのに1時間程、、、)
curl https://npmjs.org/install.sh | sudo sh
CoffeeScriptをインストール
sudo npm install -g coffee-script
今回は-gをつけて、グローバルにインストールしました。
(つけないとローカルインストールになるので、node_modulesにインストールされるようです)
早速書いて実行してみる
helloworld.coffee
helloworld = -> console.log "hello world" helloworld()
実行
coffee helloworld.coffee
hello world
実行できたようです。
次回はEmacs24のpackageを使ってcoffee-modeを入れてみようかな、、、
Play2.0でsbtの独自タスクを定義する
sbtの独自タスク追加方法は、ググればちらほら出てくるのですが、
Playを使ったsbtの独自タスクの定義方法がよくわからず、
ちょっと苦労したので、メモします。
(苦労した、という程の事でもないのですが。。。)
今日の流れ
- sbtでの独自タスク定義方法
- playでの独自タスク定義方法
sbtで独自タスク
sbtで環境依存ファイルを変更するためのカスタムタスクを書いてみたよ - ブログなんだよもん
(こちらを参考にさせて頂きました)
まず、sbtオンリーの場合は、上記サイトにあるように、
こんな感じで書きます。
project/Build.scala
import sbt._ object ProjectBuild extends Build { val hogeKey = TaskKey[Unit]("hoge", "hoge task") val hoge = hogeKey := { println("hoge") } lazy val root = Project( id = "my task", base = file("."), settings = Defaults.defaultSettings ++ Seq(hoge) ) }
- TestKeyでkeyと説明を定義
- :=メソッドを使ってタスクを定義
- Projectのsettingsへ追加
という流れになります。
実行してみます。
% sbt hoge [info] Loading global plugins from /Users/xxx/.sbt/plugins [info] Loading project definition from /Users/xxx/workspace/scala/scala_practice/project [info] Set current project to my task (in build file:/Users/xxx/workspace/scala/scala_practice/) hoge [success] Total time: 0 s, completed 2012/12/03 22:26:54
ちゃんとhogeと出力されました。
Playプロジェクトでsbt独自タスクを定義する
PlayのBuild.scalaはこんな感じです。
project/Build.scala
import sbt._ import Keys._ import PlayProject._ object ApplicationBuild extends Build { val appName = "hoge" val appVersion = "1.0" val appDependencies = Seq( "org.squeryl" %% "squeryl" % "0.9.5" withSources(), "mysql" % "mysql-connector-java" % "5.1.18" ) lazy val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings( resolvers += "t2v.jp repo" at "http://www.t2v.jp/maven-repo/" ) }
PlayではProjectがPlayProjectになっています。
PlayProjectのapplyメソッドを見てみると。
package sbt object PlayProject extends java.lang.Object with sbt.Plugin with sbt.PlayExceptions with sbt.PlayKeys with sbt.PlayReloader with sbt.PlayCommands with sbt.PlaySettings with scala.ScalaObject { def apply(name : scala.Predef.String, applicationVersion : scala.Predef.String = { /* compiled code */ }, dependencies : scala.Seq[sbt.ModuleID] = { /* compiled code */ }, path : sbt.File = { /* compiled code */ }, mainLang : scala.Predef.String = { /* compiled code */ }, settings : => scala.Seq[sbt.Setting[_]] = { /* compiled code */ }) : sbt.Project = { /* compiled code */ } }
「settings」というパラメータがある!
というわけで、以下のようにしてみました。
import sbt._ import Keys._ import PlayProject._ object ApplicationBuild extends Build { val appName = "ripple" val appVersion = "1.0" val appDependencies = Seq( "org.squeryl" %% "squeryl" % "0.9.5" withSources(), "mysql" % "mysql-connector-java" % "5.1.18", "jp.t2v" % "play20.auth_2.9.1" % "0.3" withSources() ) lazy val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA, settings = Seq(Tasks.hogeTask)).settings( resolvers += "t2v.jp repo" at "http://www.t2v.jp/maven-repo/" ) object Tasks { val hogeTaskKey = TaskKey[Unit]("hoge", "test task") lazy val hogeTask = hogeTaskKey := { println("hoge") } } }
で、playコマンド実行。
エラー、、、
... [error] References to undefined settings: ...
うーむ。
エラーメッセージからなにがいけなかったのか、よくわかりません。
と、いうわけで、型をちゃんと調べることにしました。
[追記]
ここの原因は、id:xuweiさんからご指摘頂き、
Defaults.defaultSettings ++ Seq(Tasks.hogeTask)
Defaults.defaultSettingsを忘れている事だと分かりました。
そもそも:=の型は??
def :=(value : => S) : sbt.Project.Setting[sbt.Task[S]] = { /* compiled code */ }
PlayProjectのsettingsの型は?
settings : => scala.Seq[sbt.Setting[_]]
なるほど、そもそも型が違うようです。
[訂正]id:xuweiさんからのご指摘により、同じ型である事がわかりました。
しかし、よくよく見ると、
Projectにはsettingsというメソッドが用意されている。
Project#settingsの型は?
def settings(ss : sbt.Project.Setting[_]*) : sbt.Project = { /* compiled code */ }
「sbt.Project.Setting」これだ!
というわけで、結論、以下のようにして解決しました。
import sbt._ import Keys._ import PlayProject._ object ApplicationBuild extends Build { val appName = "hoge" val appVersion = "1.0" val appDependencies = Seq( "org.squeryl" %% "squeryl" % "0.9.5" withSources(), "mysql" % "mysql-connector-java" % "5.1.18", "jp.t2v" % "play20.auth_2.9.1" % "0.3" withSources() ) lazy val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings( resolvers += "t2v.jp repo" at "http://www.t2v.jp/maven-repo/", Tasks.hogeTask ) object Tasks { val hogeTaskKey = TaskKey[Unit]("hoge", "test task") lazy val hogeTask = hogeTaskKey := { println("hoge") } } }
実行してみます。
% play [info] Loading global plugins from /Users/xxx/.sbt/plugins [info] Loading project definition from /Users/xxx/workspace/ripple/project [info] Set current project to ripple (in build file:/Users/xxx/workspace/ripple/) _ _ _ __ | | __ _ _ _| | | '_ \| |/ _' | || |_| | __/|_|\____|\__ (_) |_| |__/ play! 2.0.4, http://www.playframework.org > Type "help play" or "license" for more information. > Type "exit" or use Ctrl+D to leave this console. [hoge] $ hoge hoge [success] Total time: 0 s, completed 2012/12/03 23:02:27
ちゃんと表示されました。
うーん、勉強不足だ、、、すっごい遠回りした。。orz
[追記]
一応、自分のメモとして、訂正前の状態も書き残しましたが、
ちゃんと調べずに、誤った事を記載してしまい申し訳ありませんでした。
今後も、じゃんじゃんご指摘頂けると助かります。