Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ object string {
*/
def regexSub(re: Regex)(replace: (Regex.MatchData => String)): String = {
var offset = 0
var out = new StringBuilder
val out = new StringBuilder()

for (m <- re.findAllIn(wrapped).matchData) {
if (m.start > offset) {
Expand Down
43 changes: 30 additions & 13 deletions util-eval/src/main/scala/com/twitter/util/Eval.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ object Eval {
/**
* Eval[Int]("1 + 1") // => 2
*/
def apply[T](code: String): T = {
def apply[T](code: String, resetState: Boolean = true): T = {
val id = uniqueId(code)
val className = "Evaluator__" + id
val cls = compiler(wrapCodeInClass(className, code), className, id)
val cls = compiler(wrapCodeInClass(className, code), className, id, resetState)
cls.getConstructor().newInstance().asInstanceOf[() => Any].apply().asInstanceOf[T]
}

Expand All @@ -76,6 +76,21 @@ object Eval {
apply(scala.io.Source.fromInputStream(stream).mkString)
}

/**
* Compile an entire source file into the virtual classloader.
*/
def compile(code: String) {
Eval.compiler(code)
}

/**
* Like `Eval()`, but doesn't reset the virtual classloader before evaluating. So if you've
* loaded classes with `compile`, they can be referenced/imported in code run by `inPlace`.
*/
def inPlace[T](code: String) = {
apply[T](code, false)
}

private def uniqueId(code: String): String = {
val digest = MessageDigest.getInstance("SHA-1").digest(code.getBytes())
val sha = new BigInteger(1, digest).toString(16)
Expand Down Expand Up @@ -204,18 +219,20 @@ object Eval {
}

/**
* Reset the compiler, compile a new class, load it, and return it. Thread-safe.
* Compile a new class, load it, and return it. Thread-safe.
*/
def apply(code: String, className: String, id: String): Class[_] = synchronized {
cache.get(id) match {
case Some(cls) =>
cls
case None =>
reset()
apply(code)
val cls = classLoader.loadClass(className)
cache(id) = cls
cls
def apply(code: String, className: String, id: String, resetState: Boolean = true): Class[_] = {
synchronized {
cache.get(id) match {
case Some(cls) =>
cls
case None =>
if (resetState) reset()
apply(code)
val cls = classLoader.loadClass(className)
cache(id) = cls
cls
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ object EvaluatorSpec extends Specification {
new File("util-eval/src/test/resources", path)
}

"Evaluator" should {
"Eval" should {
"apply('expression')" in {
Eval[Int]("1 + 1") mustEqual 2
}
Expand All @@ -25,5 +25,11 @@ object EvaluatorSpec extends Specification {
"apply(InputStream)" in {
Eval[Int](getClass.getResourceAsStream("/OnePlusOne.scala")) mustEqual 2
}

"inPlace('expression')" in {
Eval.compile("object Doubler { def apply(n: Int) = n * 2 }")
Eval.inPlace[Int]("Doubler(2)") mustEqual 4
Eval.inPlace[Int]("Doubler(14)") mustEqual 28
}
}
}