如何使用 Scalatest 在 Scala 中开发编译器插件
实际上,我正在根据 http://www.scala- 上的文章为 Scala 开发一个编译器插件lang.org/node/140。
这是插件的代码:
package localhost
import scala.tools.nsc
import nsc.Global
import nsc.Phase
import nsc.plugins.Plugin
import nsc.plugins.PluginComponent
class DivByZero(val global: Global) extends Plugin {
import global._
val name = "divbyzero"
val description = "checks for division by zero"
val components = List[PluginComponent](Component)
private object Component extends PluginComponent {
val global: DivByZero.this.global.type = DivByZero.this.global
val runsAfter = "refchecks"
// Using the Scala Compiler 2.8.x the runsAfter should be written as below
// val runsAfter = List[String]("refchecks");
val phaseName = DivByZero.this.name
def newPhase(_prev: Phase) = new DivByZeroPhase(_prev)
class DivByZeroPhase(prev: Phase) extends StdPhase(prev) {
override def name = DivByZero.this.name
def apply(unit: CompilationUnit) {
for ( tree @ Apply(Select(rcvr, nme.DIV), List(Literal(Constant(0)))) <- unit.body;
if rcvr.tpe <:< definitions.IntClass.tpe)
{
unit.error(tree.pos, "definitely division by zero")
}
}
}
}
}
我正在做那里提到的事情,并编写了一些 makefile 来编译所有内容,然后创建一个 jar 文件。然后我使用以下命令加载带有测试文件的插件 jar 文件:
scalac -Xplugin:myplugin.jar test.scala
并查看输出是什么。我不喜欢这种方式,因为我从 ruby 知道如何做 tdd 和 bdd。我安装了 Scalatest http://www.scalatest.org/。是否可以以某种方式测试 jar 文件或 divbyzero 类?我知道该插件在使用文件执行时将首先加载。我脑子里很乱,不知道是否可以在不创建 jar 文件的情况下直接测试插件类(或者甚至可以测试 jar 文件的某些函数和类)?
如果没有人可以帮助我,我可以像过去的美好时光一样继续发展
感谢您的时间和帮助 马蒂亚斯
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以使用如下代码以编程方式调用 Scala 编译器和插件:
请注意,此代码要求
scala-compiler.jar
和scala-library.jar
打开执行代码时的类路径。如果您在 SBT 之类的内部运行测试,不幸的是情况并非如此。为了让东西在 SBT 中运行,你必须做一些跳跃:
如果你在其他构建环境中运行,你可能会发现 scala-library.jar 已经在类路径上,或者如果你真的很幸运,那么你需要的一切都在标准 Java 类路径上,在这种情况下,你可以将上面的内容替换为:
你可以使用
System.getProperty("java.class" 打印出 Java 类路径的值.path")
并且您当然可以从上面的代码中打印出entries
来查看正在加载测试代码的类加载器所使用的类路径。You can invoke the Scala compiler, plus plugins, programmatically with code like the following:
Note that this code requires that
scala-compiler.jar
andscala-library.jar
be on the classpath when executing the code. If you are running your tests from within something like SBT, this will unfortunately not be the case.To get things running from within SBT, you have to do some hoop jumping:
If you are running from within some other build environment, you might find that
scala-library.jar
is already on the classpath, or if you're really lucky, then everything you need is on the standard Java classpath, in which case you can replace the above with:You can print out the value of the Java classpath with
System.getProperty("java.class.path")
and you can of course print outentries
from the above code to see the classpath used by the class loader that is loading your test code.我想补充一下 samskivert 的答案。重写computeInternalPhases会强制将插件的阶段注入到整个phaseSet中,但是编译器不会将它们视为插件的一部分。例如,如果您想使用以下方式将选项传递给插件
"-P:divbyzero:someoption"
:settings.pluginOptions.appendToValue("divbyzero:someoption")
您将收到以下编译错误:
error: bad option: -P:divbyzero:someoption
这是因为编译器不知道有关名为
divbyzero
的插件的任何信息。添加插件的更合适的方法是重写 loadRoughPluginsList 方法并在其中添加插件,而不是手动将插件的每个阶段注入编译phaseSet:
I'd like to add to samskivert's answer. Overriding
computeInternalPhases
forces to inject the phases of the plugin into the whole phaseSet, however, the compiler doesn't treat them as part of the plugin. So for instance, if you want to pass an option to your plugin"-P:divbyzero:someoption"
using:settings.pluginOptions.appendToValue("divbyzero:someoption")
you will get the following compilation error:
error: bad option: -P:divbyzero:someoption
and that is because compiler doesn't know anything about a plugin named
divbyzero
.The more appropriate way of adding plugin would be to override
loadRoughPluginsList
method and add plugins there, rather than manually inject every phase of the plugin into compilation phaseSet:我认为您正在研究模拟对象(我喜欢 EasyMock,但还有很多其他对象)和一些重构。
当您参考您的 makefile 时,我的印象是您正在使用良好的旧 make。如果是这样,我可以建议您看看SBT、Gradle,或者,当您来自 Ruby 世界时,BuildR。它们都内置了对各种 Scala 测试框架的支持。
I think you're looking at mock objects (I like EasyMock, but there are many others) and some refactoring.
When you refer to your makefile, I get the impression you're using good old make. If so, might I suggest you look at something like SBT, Gradle, or, as you're coming from the Ruby world, BuildR. All of them have built in support for various scala test frameworks.