在程序执行过程中进入 REPL 控制台的干净解决方案 [英] Clean solution for dropping into REPL console in the middle of program execution

查看:36
本文介绍了在程序执行过程中进入 REPL 控制台的干净解决方案的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于 Scala 2.10,是否有任何可行的解决方案可以进入 REPL 控制台?

Is there any working solution for dropping into REPL console with for Scala 2.10?

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

This is mainly for debugging purpose - I want to pause in the middle of execution, and have a REPL console where I can inspect values and test the program's logic using complex expressions within my program at the current state of execution. Those who have programmed in Ruby might know similar function: the binding.pry.

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

AFAIK, Scala 2.9 and under used to have breakIf but it has been removed from the later versions. Using ILoop seems to be the new way but introduced issues due to sbt not adding scala-library to the classpath.

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

Several solutions such as this and this seem to offer a good workaround but my point is there must be a solution where I don't have to spend hours or even days just to make the REPL working.

简而言之,涉及更多样板步骤 - 这与 binding.pry 形成对比,后者只是一行代码,没有额外的样板.

In short, there's a lot more boilerplate steps involved - this is in contrast with binding.pry which is just a line of code with no additional boilerplate.

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

I am not aware if there's an issue introduced in executing the program as an sbt task as opposed to if running the program executable directly, but for development purpose I am currently running and testing my program using sbt task.

推荐答案

您可以轻松地在代码中重新实现 breakIf 方法.我认为没有更简洁的方法可以做到这一点.

You could easily reimplement the breakIf method in your code. I don't think there is much cleaner way of doing that.

首先你必须在你的 build.sbt

libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value

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

Once that's done you can implement 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()
  }

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

I think it's pretty straight forward, the only tricky part is that you have to set-up the classpath properly. You need to call embeddedDefaults with a class from your project (see my answer to another question).

您可以使用新的 breakIf 如下:

You can use the new breakIf as follows:

val x = 10
breakIf[X](assertion = true, NamedParam("x", "Int", x))

其中 X 只是你的一些类.

Where X is just some of your classes.

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

I don't know if this answers your question, because it's hard to measure what is easy and what is hard.

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

Additionally just as a side note - if you want to use it for debugging purposes, why not use a debugger. I guess most of the debuggers can connect to a program, stop at a breakpoint and evaluate expressions in that context.

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

Seems like it doesn't work on current release of Scala 2.10, the working code seems to be:

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)

}

和用法就像

  val x = 10
  breakIf[X](assertion = true, NamedParam("x", x))

这篇关于在程序执行过程中进入 REPL 控制台的干净解决方案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆