Skip to content

Commit

Permalink
Added the ability to bind values to the REPL
Browse files Browse the repository at this point in the history
  • Loading branch information
John Johnson II committed May 28, 2022
1 parent a644f95 commit ced0627
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 11 deletions.
36 changes: 34 additions & 2 deletions src/main/scala/com/potenciasoftware/rebel/BaseRepl.scala
@@ -1,8 +1,12 @@
package com.potenciasoftware.rebel

import scala.reflect.ClassTag
import scala.reflect.runtime.universe.TypeTag
import scala.tools.nsc.Settings
import scala.tools.nsc.interpreter.Repl
import scala.tools.nsc.interpreter.shell.ILoop
import scala.tools.nsc.interpreter.shell.ShellConfig
import scala.tools.nsc.typechecker.TypeStrings

import BaseRepl._

Expand Down Expand Up @@ -36,13 +40,26 @@ class BaseRepl {
/** Override to provide banner text to display at startup. */
protected val banner: String = WelcomePlaceholder

protected def config: ShellConfig = ShellConfig(settings)
/**
* Override to provide bound values.
* These will be available from within the REPL.
*/
protected def boundValues: Seq[Parameter] = Seq()

private lazy val repl: ILoop = new ILoop(ShellConfig(settings)) {

protected def repl: ILoop = new ILoop(config) {
val _banner = Option(banner).getOrElse(WelcomePlaceholder)
override def welcome: String = {
_banner.replaceAll(WelcomePlaceholder, super.welcome)
}

override def createInterpreter(interpreterSettings: Settings): Unit = {
super.createInterpreter(interpreterSettings)
intp.beQuietDuring {
for (param <- boundValues)
param.bindTo(intp)
}
}
}

def run(): Unit = {
Expand All @@ -52,4 +69,19 @@ class BaseRepl {

object BaseRepl {
private val WelcomePlaceholder = "%%%%welcome%%%%"

class Parameter private (
name: String,
`type`: String,
value: Any,
modifiers: List[String]
) {
private[BaseRepl] def bindTo(intp: Repl): Unit =
intp.bind(name, `type`, value, modifiers)
}

object Parameter {
def apply[A: TypeTag: ClassTag](name: String, value: A, modifiers: String*) =
new Parameter(name, TypeStrings.fromTag[A], value, modifiers.toList)
}
}
30 changes: 22 additions & 8 deletions src/test/scala/com/potenciasoftware/rebel/BaseReplTest.scala
Expand Up @@ -7,23 +7,24 @@ import scala.tools.nsc.Settings
import scala.tools.nsc.interpreter.shell.ILoop
import scala.tools.nsc.interpreter.shell.ShellConfig

import TestUtils._
import BaseRepl.Parameter
import BaseReplTest._
import TestUtils._

class BaseReplTest extends AnyFlatSpec with Matchers {

def basic() = new TestRepl()

"BaseRepl" should "behave like the normal ILoop" in {
replTest[BaseReplTest]("basic", Seq("42 + 42"))
replTest[BaseReplTest]("basic", "42 + 42")
.out.asBlock shouldBe """
|scala> val res0: Int = 84
|
|scala> """.stripMargin
}

it should "have the default compiler options" in {
replTest[BaseReplTest]("basic", Seq("def test(): Int = 1", "test")).out(3) shouldBe
replTest[BaseReplTest]("basic", "def test(): Int = 1", "test").out(3) shouldBe
"scala> warning: 1 deprecation (since 2.13.3); for details, " +
"enable `:setting -deprecation` or `:replay -deprecation`"
}
Expand All @@ -37,7 +38,7 @@ class BaseReplTest extends AnyFlatSpec with Matchers {
}

it should "set custom compiler options" in {
replTest[BaseReplTest]("customCompilerOptions", Seq("def test(): Int = 1", "test"))
replTest[BaseReplTest]("customCompilerOptions", "def test(): Int = 1", "test")
.out.drop(2).take(3).asBlock shouldBe
"""
|scala> val res0: Int = 1
Expand All @@ -47,18 +48,31 @@ class BaseReplTest extends AnyFlatSpec with Matchers {
def defaultBanner() = new BaseRepl()

it should "display the standard ILoop banner by default" in {
replTest[BaseReplTest]("defaultBanner", Seq())
replTest[BaseReplTest]("defaultBanner")
.out.takeWhile(_ != "scala> ").asBlock shouldBe
s"${new ILoop(ShellConfig(new Settings)).welcome}\n"
}

def customBanner() = new BaseRepl() {
override protected val banner: String = "Custom Banner"
}

it should "display a custom banner" in {
replTest[BaseReplTest]("customBanner", Seq())
replTest[BaseReplTest]("customBanner")
.out.takeWhile(_ != "scala> ").asBlock shouldBe "Custom Banner\n"
}

def customBanner() = new BaseRepl() {
override protected val banner: String = "Custom Banner"
def boundAnswer() = new TestRepl {

private val Answer: Int = 42

override protected def boundValues: Seq[Parameter] =
Seq(Parameter("Answer", Answer))
}

it should "bind custom variables" in {
replTest[BaseReplTest]("boundAnswer", "println(Answer)")
.out(1) shouldBe "scala> println(Answer)42"
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/test/scala/com/potenciasoftware/rebel/TestUtils.scala
Expand Up @@ -83,7 +83,7 @@ object TestUtils {
* (Note: including a [[":q"]] line at the end of the input
* is not necessary.)
*/
def replTest[C: ClassTag](methodName: String, inputLines: Iterable[String]): RunResults = {
def replTest[C: ClassTag](methodName: String, inputLines: String*): RunResults = {
import scala.sys.process._

val in = new InputLinesStream(inputLines ++ Seq(":q"))
Expand Down

0 comments on commit ced0627

Please sign in to comment.