Clean solution for dropping into REPL console in the middle of program execution

情到浓时终转凉″ 提交于 2019-12-04 17:47:22

问题


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

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 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.

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.

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.

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.


回答1:


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

First you have to add a scala compiler library to your build.sbt

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

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()
  }

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).

You can use the new breakIf as follows:

val x = 10
breakIf[X](assertion = true, NamedParam("x", "Int", 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.

Edit

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)

}

and usage is like

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



回答2:


I was looking at this recently and found Ammonite to be a sufficient solution for my needs.

  1. Add Ammonite to your library dependencies: libraryDependencies += "com.lihaoyi" % "ammonite" % "1.6.0" cross CrossVersion.full
  2. Invoke Ammonite where you want to drop to the REPL shell: ammonite.Main().run()

Note that you have to pass any variables you want bound inside of run, e.g. run("var1" -> var1). Have a look at their example - Instantiating Ammonite.



来源:https://stackoverflow.com/questions/24674288/clean-solution-for-dropping-into-repl-console-in-the-middle-of-program-execution

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!