diff options
-rw-r--r-- | libraries/eval/Eval.scala | 22 | ||||
-rw-r--r-- | libraries/eval/test/EvalTest.scala | 8 | ||||
-rw-r--r-- | libraries/eval/test/resources/IncludeInclude.scala | 7 |
3 files changed, 33 insertions, 4 deletions
diff --git a/libraries/eval/Eval.scala b/libraries/eval/Eval.scala index 8f05ed1..a952b52 100644 --- a/libraries/eval/Eval.scala +++ b/libraries/eval/Eval.scala @@ -100,6 +100,10 @@ class Eval(target: Option[File]) { new ClassScopedResolver(getClass), new FilesystemResolver(new File(".")), new FilesystemResolver(new File("." + File.separator + "config")) + ) ++ ( + Option(System.getProperty("com.twitter.util.Eval.includePath")) map { path => + new FilesystemResolver(new File(path)) + } ) ) ) @@ -112,7 +116,7 @@ class Eval(target: Option[File]) { * to the text. * Last modified is computed here because we support includes */ - def sourceForString(code: String) = { + def sourceForString(code: String): LastMod = { preprocessors.foldLeft(LastMod(0L, code)) { (acc, p) => val processed = p(acc.code) LastMod(acc.timestamp max processed.timestamp, processed.code) @@ -300,7 +304,6 @@ class Eval(target: Option[File]) { private[this] def file(path: String): File = new File(root.getAbsolutePath + File.separator + path) - def resolvable(path: String): Boolean = file(path).exists @@ -344,7 +347,9 @@ class Eval(target: Option[File]) { * Note that it is *not* recursive. Included files cannot have includes */ class IncludePreprocessor(resolvers: Seq[Resolver]) extends Preprocessor { - def apply(code: String): LastMod = { + def maximumRecursionDepth = 100 + def apply(code: String): LastMod = apply(code, maximumRecursionDepth) + def apply(code: String, maxDepth: Int): LastMod = { var lastMod = 0L val lines = code.lines map { line: String => val tokens = line.trim.split(' ') @@ -355,7 +360,16 @@ class Eval(target: Option[File]) { } match { case Some(r: Resolver) => { lastMod = lastMod max r.lastModified(path) - StreamIO.buffer(r.get(path)).toString + // recursively process includes + if (maxDepth == 0) { + throw new IllegalStateException("Exceeded maximum recusion depth") + } else { + apply(StreamIO.buffer(r.get(path)).toString, maxDepth - 1) match { + case LastMod(timestamp, code) => + lastMod = lastMod max timestamp + code + } + } } case _ => throw new IllegalStateException("No resolver could find '%s'".format(path)) diff --git a/libraries/eval/test/EvalTest.scala b/libraries/eval/test/EvalTest.scala index 2fa7d44..40d15a7 100644 --- a/libraries/eval/test/EvalTest.scala +++ b/libraries/eval/test/EvalTest.scala @@ -85,6 +85,14 @@ object EvalSpec extends Specification { derived.toString mustEqual "hello, joe" } + "recursive #include" in { + val derived = Eval[() => String]( + TempFile.fromResourcePath("/Base.scala"), + TempFile.fromResourcePath("/IncludeInclude.scala")) + derived() mustEqual "hello" + derived.toString mustEqual "hello, joe; hello, joe" + } + "toSource returns post-processed code" in { val derived = Eval.toSource(TempFile.fromResourcePath("/DerivedWithInclude.scala")) derived must include("hello, joe") diff --git a/libraries/eval/test/resources/IncludeInclude.scala b/libraries/eval/test/resources/IncludeInclude.scala new file mode 100644 index 0000000..cc1f966 --- /dev/null +++ b/libraries/eval/test/resources/IncludeInclude.scala @@ -0,0 +1,7 @@ +val b1 = +#include DerivedWithInclude.scala +val b2 = +#include DerivedWithInclude.scala +new Base { + override def toString = b1 + "; " + b2 +} |