为什么测试范围设置不能保持正确的值?

时间:2014-06-04 23:08:38

标签: scala sbt

范围在sbt中很重要。我完全没问题。但是也有委托规则允许您构建设置的分层结构。我想用它来为更具体的规则带来额外的设置。

import sbt._
import Keys._

object TestBuild extends Build {
  val sourceExample = settingKey[Seq[String]]("example source for setting dependency")
  val targetExample = settingKey[Seq[String]]("example of a dependent setting")

  override lazy val settings = super.settings ++ Seq (
    sourceExample := Seq("base"),
    targetExample := "extended" +: sourceExample.value,
    sourceExample in Test += "testing"
  )
}

该示例为我提供了意外的输出:

> show compile:sourceExample
[info] List(base)
> show test:sourceExample
[info] List(base, testing)
> show compile:targetExample
[info] List(extended, base)
> show test:targetExample
[info] List(extended, base)

我希望test:targetExampleList(extended, base, testing)而不是List(extended, base)。一旦我得到结果,我立即弄清楚为什么它如图所示。 test:targetExample *:targetExample代表libraryDependencies in Test计算的值,但不是在嵌套范围内计算它的规则。

这种行为给我编写自己的插件带来了两个困难。作为插件开发人员,我有额外的工作要在每个范围内定义相同的规则。我必须记住内部任务的范围定义,才能正确地将其用作用户。

如何克服这种不便?我想在 call-by-name 语义中引入设置,而不是按值调用。什么技巧可能适用于它?

P.S。使用% test时,trait A { lazy val x : Int = 5 } trait B extends A { lazy val y : Int = x * 2} trait C extends A { override lazy val x : Int = 3 } 看起来更简洁。


我应该清楚地表明,我完全理解sbt正如文档中描述的那样导出值。它起着创作者的作用。

但我为什么要服从规则呢?我看到他们完全违反直觉。 Sbt引入了实际工作的继承语义,与过去定义的方式不同。当你写

(new B with C).y

你希望name->value是6,而不是10.知道它实际上是10允许你正确使用这种继承,但是你希望找到更常规的方法来实现继承。您甚至可以根据{{1}}字典编写自己的实现。并且您可以根据编程的第十条规则继续进行。

所以我正在寻找一种能够根据常见语言带来继承语义的黑客。作为一个起点,我建议编写command来扫描所有设置,并明确地将它们从父母推送到孩子。并且每次sbt运行时自动调用此命令。

但对我来说这似乎太脏了,所以如果有更多优雅的方式来实现类似的语义,我很好奇。

2 个答案:

答案 0 :(得分:0)

"错误" 值的原因是targetExample取决于sourceExample范围内的Compile,如下所示:

targetExample := "extended" +: sourceExample.value

如果它使用sourceExample范围内的Test值,请使用in Test明确表达您的意愿,如下所示:

targetExample := "extended" +: (sourceExample in Test).value

使用inspect了解依赖关系链。

顺便说一句,我强烈建议使用build.sbt文件进行这样一个简单的构建定义。

答案 1 :(得分:0)

您可以使用默认设置,并按Plugins Best Practices - Playing nice with configurations中所述的不同配置重复使用。我相信,这应该给你一个类似于你正在寻找的语义。

您可以定义基本设置并在不同配置中重复使用。

import sbt._
import Keys._

object TestBuild extends Build {

  val sourceExample = settingKey[Seq[String]]("example source for setting dependency")
  val targetExample = settingKey[Seq[String]]("example of a dependent setting")

  override lazy val settings = super.settings ++ 
    inConfig(Compile)(basePluginSettings) ++
    inConfig(Test)(basePluginSettings ++ Seq(
      sourceExample += "testing" // we are already "in Test" here
    ))

  lazy val basePluginSettings: Seq[Setting[_]] = Seq (
    sourceExample := Seq("base"),
    targetExample := "extended" +: sourceExample.value
  )

} 

PS。既然你正在谈论编写你的插件,你可能还想看看编写sbt插件的新方法,即AutoPlugin,因为旧的机制现在是deprecated