使用ScalaCheck生成案例类时,如何避免样板?

时间:2014-11-20 21:03:56

标签: scala scalacheck

我曾经使用类似下面的习惯用ScalaCheck生成案例类:

GenSomething.map2(GenSomethingElse)(MyClass(_, _))

我们最近将ScalaCheck升级到1.11,删除了mapN方法。我真的希望能够避免为每个字段为生成器分配中间名称,mapN方法提供了最简单的方法。现在,最好的语法是:

for {
  something <- GenSomething
  somethingElse <- GenSomethingElse
} yield MyClass(
  something = something,
  somethingElse = somethingElse)

这不是那么糟糕(对于结构会有少量的构造函数参数),但我真的很想说明这里没有什么特别的东西,我只是为每个参数指定生成器而不是代码的读者必须通读才能确认。

简而言之,我想要一些类似于应用语法的东西。不幸的是,它不是使用scalaz,无形或宏的选项。我意识到最后一句话几乎让我的问题“如何在不能访问让我做X的事情的情况下做X”,但我希望有人能有个好主意。

1 个答案:

答案 0 :(得分:0)

由于您明确排除了旨在防止样板的库,因此您必须使用某些样板文件。

您可以使用与Gen.resultOf类似的方法为每个arity定义gen组合器。实际上,您可以使用Gen.resultOf,因为与resultOf的唯一区别在于您希望显式提供Gen而不是隐式提供的Arbitrary

object GenCombiner {

  def zipMap[A, R](a: Gen[A])(f: A ⇒ R): Gen[R] =
    Gen.resultOf(f)(Arbitrary(a))

  def zipMap[A, B, R](a: Gen[A], b: Gen[B])(f: (A, B) ⇒ R): Gen[R] =
    Gen.resultOf(f)(Arbitrary(a), Arbitrary(b))

  def zipMap[A, B, C, R](a: Gen[A], b: Gen[B], c: Gen[C])(f: (A, B, C) ⇒ R): Gen[R] =
    Gen.resultOf(f)(Arbitrary(a), Arbitrary(b), Arbitrary(c))

  // other arities
}

object GenCombinerTest {
  import GenCombiner._

  case class Foo(alpha: String, num: String)

  val fooGen: Gen[Foo] = zipMap(Gen.alphaStr, Gen.numStr)(Foo)
}