Scalacticを使ってみるその1 ～Equivalence[T]特質、Normalization[A]特質～

# 準備

ScalaTestのjarを読み込みます（ScalacticはScalaTestに同梱されています）。

```scala
scala> :require scalatest_2.11-2.2.4.jar
Added 'c:\work\scalatest_2.11-2.2.4.jar' to classpath.
```

# Equivalence[T]特質

ScalacticのEquivalence[T]特質にはareEquivalent関数が宣言されています。

```scala
abstract def areEquivalent(a: T, b: T): Boolean
```

areEquivalent関数には引数として与えられた2つのT型の実体が等しいかどうかを判定する処理を実装します。

Equivalence[String]特質を拡張した匿名クラスを定義し、実体化してみます。同値の定義として「冒頭の文字が同一である」を採用してみます。

```
scala> import org.scalactic.Equivalence
import org.scalactic.Equivalence

scala> val equiv = new Equivalence[String] {
     | def areEquivalent(a: String, b: String) = if (a.length() == 0 || b.length() == 0) a == b else  a(0) == b(0)
     | }
equiv: org.scalactic.Equivalence[String] = $anon$1@73cf7656
```

使用例。

```scala
scala> equiv.areEquivalent("", "")
res0: Boolean = true

scala> equiv.areEquivalent("a", "")
res1: Boolean = false

scala> equiv.areEquivalent("", "b")
res2: Boolean = false

scala> equiv.areEquivalent("a", "b")
res3: Boolean = false

scala> equiv.areEquivalent("test", "test")
res4: Boolean = true

scala> equiv.areEquivalent("test", "testosterone")
res5: Boolean = true
```

# Normalization[A]特質

ScalacticのNormalization[A]特質にはnormalized関数が宣言されています。

```scala
abstract def normalized(a: A): A
```

normalized関数には引数として与えられたA型の実体を正規化する処理を実装します。

Normalization[String]特質を拡張した匿名クラスを定義し、実体化してみます。正規化として長い文字列を省略する処理を実装してみます。

```scala
scala> import org.scalactic.Normalization
import org.scalactic.Normalization

scala> val truncated = new Normalization[String] {
     | def normalized(s: String) = if (s.length() > 3) s.take(3) + "..." else s
     | }
truncated: org.scalactic.Normalization[String] = $anon$1@4a3404a8
```
使用例。

```scala
scala> truncated.normalized("")
res6: String = ""

scala> truncated.normalized("t")
res7: String = t

scala> truncated.normalized("te")
res8: String = te

scala> truncated.normalized("tes")
res9: String = tes

scala> truncated.normalized("test")
res10: String = tes...
```

もう1つ、Normalization[String]特質を拡張した匿名クラスを定義し、実体化してみます。正規化として文字列の冒頭を大文字にする処理を実装してみます。

```scala
scala> val capitalized = new Normalization[String] {
     | def normalized(s: String) = s.capitalize
     | }
capitalized: org.scalactic.Normalization[String] = $anon$1@4e78ee73
```

使用例。

```scala
scala> capitalized.normalized("")
res11: String = ""

scala> capitalized.normalized("t")
res12: String = T

scala> capitalized.normalized("te")
res13: String = Te

scala> capitalized.normalized("tes")
res14: String = Tes

scala> capitalized.normalized("test")
res15: String = Test
```

and関数で2つのNormalization[A]特質を合成できます。

```scala
final def and(other: Normalization[A]): Normalization[A]
```

```scala
scala> val composed = truncated.and(capitalized)
composed: org.scalactic.Normalization[String] = org.scalactic.Normalization$$anon$2@738b3454

scala> composed.normalized("test")
res16: String = Tes...
```

toEquivalence関数で正規化してから等しいかどうかを判定するNormalizingEquivalence[A]特質を作成できます。

```scala
final def toEquivalence(implicit equivalence: Equivalence[A]): NormalizingEquivalence[A]
```

```scala
scala> val normalizedEquiv = composed.toEquivalence(equiv)
normalizedEquiv: org.scalactic.NormalizingEquivalence[String] = org.scalactic.Normalization$$anon$1@73e539ef

scala> normalizedEquiv.areEquivalent("test", "gest")
res17: Boolean = false

scala> normalizedEquiv.areEquivalent("test", "test")
res18: Boolean = true

scala> normalizedEquiv.areEquivalent("test", "Test")
res19: Boolean = true

scala> normalizedEquiv.areEquivalent("test", "Testosterone")
res20: Boolean = true
```