清洁解决方案,用于在程序执行过程中放入REPL控制台

lol*_*ski 11 scala sbt scala-2.10

有什么工作解决方案可以放入REPL控制台与Scala 2.10?

这主要用于调试目的 - 我想在执行过程中暂停,并且有一个REPL控制台,我可以在当前执行状态下使用程序中的复杂表达式检查值并测试程序的逻辑.那些使用Ruby编程的人可能知道类似的功能:binding.pry.

AFAIK,Scala 2.9及以下曾经有过,breakIf但它已从更高版本中删除.使用ILoop似乎是新的方式,但由于sbt没有将scala-library添加到类路径而引入了问题.

这样这样的几个解决方案似乎提供了一个很好的解决方法,但我的观点是必须有一个解决方案,我不必花费数小时甚至数天来使REPL工作.

简而言之,涉及更多的样板步骤 - 与此相反,binding.pry这只是一行代码,没有额外的样板.

我不知道在执行程序作为sbt任务时是否存在问题,而不是直接运行程序可执行文件,但出于开发目的,我正在运行并使用sbt任务测试我的程序.

lpi*_*ora 5

您可以轻松地breakIf在代码中重新实现该方法.我认为没有更清洁的方法.

首先,您必须添加一个scala编译器库 build.sbt

libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value
Run Code Online (Sandbox Code Playgroud)

一旦完成,您就可以实施 breakIf

import scala.reflect.ClassTag
import scala.tools.nsc.Settings
import scala.tools.nsc.interpreter.{ILoop, NamedParam}

def breakIf[T](assertion: => Boolean, args: NamedParam*)(implicit tag: ClassTag[T]) = {
    val repl = new ILoop()

    repl.settings = new Settings()
    repl.settings.embeddedDefaults[T]
    repl.settings.Yreplsync.value = true
    repl.in = repl.chooseReader(repl.settings)

    repl.createInterpreter()

    args.foreach(p => repl.bind(p.name, p.tpe, p.value))

    repl.loop()
    repl.closeInterpreter()
  }
Run Code Online (Sandbox Code Playgroud)

我认为这很简单,唯一棘手的部分是你必须正确设置类路径.您需要embeddedDefaults使用项目中的课程进行调用(请参阅我对其他问题的回答).

您可以使用以下新breakIf内容:

val x = 10
breakIf[X](assertion = true, NamedParam("x", "Int", x))
Run Code Online (Sandbox Code Playgroud)

X你的课程在哪里?

我不知道这是否能回答你的问题,因为很难衡量什么是容易的,什么是困难的.

另外,作为旁注 - 如果您想将其用于调试目的,为什么不使用调试器.我猜大多数调试器都可以连接到程序,在断点处停止并在该上下文中计算表达式.

编辑

看起来它不适用于当前版本的Scala 2.10,工作代码似乎是:

import scala.reflect.ClassTag
import scala.tools.nsc.Settings
import scala.tools.nsc.interpreter.{ILoop, NamedParam}

def breakIf[T](assertion: => Boolean, args: NamedParam*)(implicit tag: ClassTag[T]) = {

  val repl = new ILoop() {
    override protected def postInitialization(): Unit = {
      addThunk(args.foreach(p => intp.bind(p)))
      super.postInitialization()
    }
  }

  val settings = new Settings()

  settings.Yreplsync.value = true
  settings.usejavacp.value = true
  settings.embeddedDefaults[T]

  args.foreach(repl.intp.rebind)

  repl.process(settings)

}
Run Code Online (Sandbox Code Playgroud)

和用法就像

  val x = 10
  breakIf[X](assertion = true, NamedParam("x", x))
Run Code Online (Sandbox Code Playgroud)