From 6e8255f8530e2815ddb260ec182bd05ed48a8890 Mon Sep 17 00:00:00 2001 From: Robey Pointer Date: Thu, 31 Mar 2011 18:20:34 -0700 Subject: [PATCH 1/2] use paren convention --- util-core/src/main/scala/com/twitter/conversions/string.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util-core/src/main/scala/com/twitter/conversions/string.scala b/util-core/src/main/scala/com/twitter/conversions/string.scala index 49a620a0bf..444526786c 100644 --- a/util-core/src/main/scala/com/twitter/conversions/string.scala +++ b/util-core/src/main/scala/com/twitter/conversions/string.scala @@ -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) { From 4a38622f8491fa11207b056eaf84a3ba3d210000 Mon Sep 17 00:00:00 2001 From: Robey Pointer Date: Thu, 31 Mar 2011 18:49:34 -0700 Subject: [PATCH 2/2] allow in-place eval of the type scrooge would like to do.s --- .../main/scala/com/twitter/util/Eval.scala | 43 +++++++++++++------ .../com/twitter/util/EvaluatorSpec.scala | 8 +++- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/util-eval/src/main/scala/com/twitter/util/Eval.scala b/util-eval/src/main/scala/com/twitter/util/Eval.scala index cc9a3ff40f..278933cf83 100644 --- a/util-eval/src/main/scala/com/twitter/util/Eval.scala +++ b/util-eval/src/main/scala/com/twitter/util/Eval.scala @@ -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] } @@ -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) @@ -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 + } } } } diff --git a/util-eval/src/test/scala/com/twitter/util/EvaluatorSpec.scala b/util-eval/src/test/scala/com/twitter/util/EvaluatorSpec.scala index 356ef80e53..f4c2ae7284 100644 --- a/util-eval/src/test/scala/com/twitter/util/EvaluatorSpec.scala +++ b/util-eval/src/test/scala/com/twitter/util/EvaluatorSpec.scala @@ -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 } @@ -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 + } } }