2011年6月1日水曜日

ScalaのOptionやListのfilterとwithFilterの違い

Option,Listには
filter
withFilter
の2種類のメソッドが存在します。
どちらも引数は
T => Boolean

でFilterの処理を行いますが、ほかのmapや多段のfilterを組み合わせる場合違いが出てきます。

以下が実際の実行結果の違いです。
どちらも、偶数だけを取り出して、2倍をしたリストを取得しています。


val l = List(1,2,3,4)

l.withFilter( i => {
println("fitler " + i)
i % 2 == 0
}).map( i => {
println("map " + i)
i * 2
})


l.filter( i => {
println("fitler " + i)
i % 2 == 0
}).map( i => {
println("map " + i)
i * 2
})



実行結果は以下のようになります。


//withFilter -> map
fitler 1
fitler 2
map 2
fitler 3
fitler 4
map 4
fitler 5

//filter -> map
fitler 1
fitler 2
fitler 3
fitler 4
fitler 5
map 2
map 4



filterを使用した場合、途中でfilterされたListが生成されてしまいますが、
withFilterを使用した場合、中間状態のListは生成されません。
もし、filterやmapを何段も使用する場合はwithFilterを使ったほうがパフォーマンスが高くなります。

2011年5月26日木曜日

Lift Mapper How To

Lift Mapperでテーブル設計をする際の最小限の知識のまとめ
詳しいことはここを見てください。
主にMySQLを使用しているため、DBの用語等はMySQLのものとなります。

よく使われるフィールド

object DefaultFieldModel extends DefaultFieldModel with LongKeyedMetaMapper[DefaultFieldModel]

class DefaultFieldModel extends LongKeyedMapper[DefaultFieldModel]{
  def getSingleton = DefaultFieldModel 

  object idField extends MappedLongIndex(this) 

  object intField extends MappedInt(this)
  object longField extends MappedLong(this)
  object varcharField extends MappedString(this,100)// VARCHAR(100)
  object textField extends MappedText(this) // TEXT
  object dateField extends MappedDate(this) // DATE
  object dateTimeField extends MappedDateTime(this) // DATETIME

}

//usage

val newObject = DefaultFieldModel.createInstance
newObject.idField(1)
newObject.textField("hoge")
...
newObject.save()


val read = DefaultFieldModel.findByKey(1L).open_!
println("ID:" + read.idField.is)




AUTO INCREMENTなIDの設定 + CRUD画面の簡単生成

object AutoIncrement extends AutoIncrement with LongKeyedMetaMapper[AutoIncrement] with CRUDify[Long,AutoIncrement]{
  /*
  def menus : List[Menu]
  がCRUDifyにより追加されます
  これをSiteMenuMapに追加しておくことでCRUD画面が作成されます。
  */

}

class AutoIncrement extends LongKeyedMapper[AutoIncrement] widh IdPK{

  def getSingleton = AutoIncrement

  /**
   IdPKにて
   object id extends MappedLongIndex(this)
   のフィールドが作成されます。
  */

}



インデックス、複合インデックスの設定のやりかた

object IndexSample extends IndexSample with LongKeyedMetaMapper[IndexSample]{

  //複合インデックス設定
  override def dbIndexes = {
    List(
      new Index(unionIndex1 , unionIndex2 , unionIndex3),
      new Index(unionIndex3 , unionIndex2)
    )
  }

}

class IndexSample extends LongKeyedMapper[IndexSample] widh IdPK{

  def getSingleton = AutoIncrement

  //フィールドのインデックス設定
  object indexForSingleField extends MappedInt(this){
    override def dbIndexed_? = true
  }
  object unionIndex1 extends MappedInt(this)
  object unionIndex2 extends MappedInt(this)
  object unionIndex3 extends MappedInt(this)

}



OneToOne , OneToMany


object MailBox ...

class MailBox extends LongKeyedMapper[MailBox] with IdPK with OneToMany[Long, MailBox]{
  
  def getSingleton = MailBox

  //one to many
  object mails extends MappedOneToMany(Mail , Mail.mailBox, OrderBy(Mail.id, Ascending))
  
}

object Mail ...

class Mail extends LongKeyedMapper[MailBox] with IdPK{
  
  def getSingleton = Mail
  //one to one(many to one)
  object mailBox extends MappedLongForeignKey(this,MailBox)

}




ManyToMany

object User ...

class User extends LongKeyedMapper[User] with IdPK with ManyToMany{

  def getSingleton = User
  
  //many to many
  object mails extends MappedManyToMany(Mail , Mail.mailBox, OrderBy(Mail.id, Ascending))
  
}
object Role...

class Role extends LongKeyedMapper[Role] with IdPK{

  def getSingleton = Role 
}

object UesrHasRole ...

class UesrHasRole extends Mapper[UserHasRole]{
  
  def getSingleton = UserHasRole
  
  object user extends LongMappedMapper(this,User)
  object role extends LongMappedMapper(this,Role)

}

2011年4月20日水曜日

Scala specsの実行順序



import org.junit.runner.RunWith
import org.specs.Specification
import org.specs.runner.{JUnit, JUnitSuiteRunner}

@RunWith(classOf[JUnitSuiteRunner])
class ExecuteOrderTest extends Specification with JUnit{

doBeforeSpec{
println("Do once before all specs")
}
doAfterSpec{
println("Do once after all specs")
}
"First" should {
doFirst{
println("Do once before all test in First")
}
doBefore{
println("Do before every test in First")
}
"hello" in {

println("Hello world")
}
"good by" in {
println("Good by world")
}
doAfter{
println("Do after every test in First")
}
doLast{
println("Do once after all test in First ")
}
}
"Second" should {
doFirst{
println("Do once before all test in Second")
}
doBefore{
println("Do before every test in Second")
}
"hello2" in {
println("Hello world2")
}
"good by2" in {
println("Good by world2")
}
doAfter{
println("Do after every test in Second")
}
doLast{
println("Do once after all test in Second ")
}
}


}


実行結果

Do once before all specs

Do once before all test in First
Do before every test in First
Hello world
Do after every test in First
Do before every test in First
Good by world
Do after every test in First
Do once after all test in First

Do once before all test in Second
Do before every test in Second
Hello world2
Do after every test in Second
Do before every test in Second
Good by world2
Do after every test in Second
Do once after all test in Second

Do once after all specs

2011年1月11日火曜日

Scalaで親クラスのオーバーロードコンストラクタを使用する

結論:Scalaで継承を行った際に、親クラスのオーバーロードされたコンストラクタを使用する方法は、ありません

どんなコードを書きたいかを、Javaで書くと


class A{
public A(){}
public A(int v){}
}
class B extends A{
public B() {super();}
public B(int v){super(v);}
}


になりますが、これをScalaで書こうとした場合、scalaではPrimaryConstructorを除くコンストラクターを呼び出せないため、単純に上記のようなコードを移植することは出来ません。

一応解決策を3つほど紹介

諦める



こんなコードは書かないようにしましょう。

デフォルト値を代入



デフォルト値がわかる場合は、デフォルト値を入れてやる

class A(){
def this( v: Int) = this()
}

class B(v : Int) extends A(v){
def this() = this(0)
}


複数のクラス作成




class A(){
def this( v: Int) = this()
}

class B1(v : Int) extends A(v)

class B2 extends A

2010年5月26日水曜日

携帯、特にAUとかでFlashのLoadVariables使うときの注意

携帯のFlash Liteの実装適当すぎ
マジしねばいいのに

クロスドメインでLoadVariablesするときの注意

crossdomain.xmlの注意点



サーバーのルートに置きましょう
その時、返すContent-Typeは、
http://www.adobe.com/jp/devnet/articles/crossdomain_policy_file_spec.html#introduction
の推奨する
Content-Type: text/x-cross-domain-policy
には絶対にしてはいけません。
これにしてしまうと、AUが認識しません。
text/xmlやapplication/xmlなどにしておきましょう。

loadvariablesへの応答を返すときの注意点



応答を返すときのContent-Typeは
http://livedocs.adobe.com/flash/9.0_jp/main/wwhelp/wwhimpl/js/html/wwhelp.htm?href=Part15_FL1_ASLR_1.html
の推奨する
Content-Type: application/x-www-form-urlencoded
には絶対にしてはいけません。
AUが認識しません。
text/plainにしておきましょう。

loadvariables実行時の注意



loadvariablesの第3引数に"GET"の指定は必要なければやめましょう
これをつけてしまうとリクエストのGETパラメーターに、第2引数で与えているフレームの変数全てがつけられてしまいます。しかも、AUだと第一引数にすでにGETパラメータが入っていても?でパラメータをくっつけるのでおかしなことになりかねません

@Flash

kudo = "wahoo"
misuzu = "gaogao"
loadvariables("loadvariables.txt?cache=2",_root,"GET")

とした場合

@AU
loadvariables.text?cache=2?kudo=wahoo&misuzu=gaogao

とかになるので場合によってはおかしなことになります。

2010年5月12日水曜日

JavaのString.formatいろいろ

String.formatによる書式指定覚書

基本

String.format("本日は%sなり%s","晴天","!");
//本日は晴天なり!



進数を変える
//16進数
String.format("%x",12);
//c
String.format("%X",12);
//C

//8進数
String.format("%o",12);
//14


桁区切りにカンマ
String.format("%,d",10000);
//return 10,000


桁数を合わせて、足りない桁は0詰め
String.format("%04d",1);
//0001
String.format("%04d",23);
//0023


小数を指定の小数点以下の桁まで表示する
String.format("%.2f",0.1);
String.format("%.2f",0.0002);
String.format("%.2f",100.0);
//0.10
//0.00
//100.00


インデックスを明示
String.format("%2$s %1$s %2$s","1番","2番");
//2番 1番 2番

2010年4月8日木曜日

LiftでUTF-8以外のレスポンスを返す

現在のLiftは、テンプレートのレスポンスを強制的にUTF-8で返してしまうので、
Shift-jis等の他の文字エンコーディングでレスポンスを返したい場合の方法を紹介

とりあえず、今回はLiftRules.responseTransformersを使用して、NodeResponseの文字エンコーディングを変更する方法紹介します。

1. Responseの定義

import net.liftweb.http.{LiftResponse,InMemoryResponse}
import _root_.scala.xml._
import net.liftweb.util.AltXML

case class MyXHtmlResponse(out : Node,encoding : String) extends LiftResponse{

def xmlDeclare = "\n"

var headers :List[(String,String)] = List()

var code = 200


def toResponse = {

val sb = new StringBuilder(64000)

sb.append(xmlDeclare)

AltXML.toXML(out, _root_.scala.xml.TopScope,
sb, false, false, false)

sb.append(" \n ")
val ret = sb.toString

val h : List[(String,String)] =

("Content-type","application/xhtml+xml;charset=" + encoding) :: headers.filter {
h => h._1.toLowerCase != "content-type"
}

InMemoryResponse(ret.getBytes(encoding), h, List(), code)
}


}



XmlNodeResponseなどは、現在の時点では文字エンコーディングがUTF-8直書きとなっているので、独自に文字コードを変えられるResponseを作成。(なお、ガラケー向けに作る途中のものなので、Cookieなどは無視してます。)

2. Responseの変換メソッドを定義

def convertResponse(response : LiftResponse) : LiftResponse = {
response match {
//
case r : NodeResponse => {
MyXHtmlResponse(r.out,"shift-jis")
}
case _ => response
}

NodeResponseの時のみ変換を行う。

3. 変換メソッドを登録

//Boot時に行う
LiftRules.responseTransformers.append(convertResponse)



Return none utf-8 response with lift framework.