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

前端 未结 2 662
伪装坚强ぢ
伪装坚强ぢ 2021-02-14 02:24

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

相关标签:
2条回答
  • 2021-02-14 02:55

    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))
    
    0 讨论(0)
  • 2021-02-14 03:01

    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.

    0 讨论(0)
提交回复
热议问题