From 634705ca145774551af463e94f229beecd9fd3fd Mon Sep 17 00:00:00 2001 From: Chris Birchall Date: Tue, 10 Feb 2015 10:36:50 +0000 Subject: [PATCH] Add annotation to exclude params from memoize cache keys --- .../scala/scalacache/memoization/Macros.scala | 8 +++++++- .../scalacache/memoization/annotations.scala | 6 ++++++ .../CacheKeyExcludingConstructorParamsSpec.scala | 6 ++++++ .../CacheKeyIncludingConstructorParamsSpec.scala | 15 +++++++++++++++ .../memoization/CacheKeySpecCommon.scala | 11 +++++++++++ 5 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 core/src/main/scala/scalacache/memoization/annotations.scala diff --git a/core/src/main/scala/scalacache/memoization/Macros.scala b/core/src/main/scala/scalacache/memoization/Macros.scala index 2a5f320b..381ec74b 100644 --- a/core/src/main/scala/scalacache/memoization/Macros.scala +++ b/core/src/main/scala/scalacache/memoization/Macros.scala @@ -124,7 +124,13 @@ object Macros { private def paramListsToTree(c: blackbox.Context)(symbolss: List[List[c.Symbol]]): c.Tree = { import c.universe._ - val identss: List[List[Ident]] = symbolss.map(ss => ss.map(s => Ident(s.name))) + val cacheKeyExcludeType = c.typeOf[cacheKeyExclude] + def shouldExclude(s: c.Symbol) = { + s.annotations.exists(a => a.tree.tpe == cacheKeyExcludeType) + } + val identss: List[List[Ident]] = symbolss.map(ss => ss.collect { + case s if !shouldExclude(s) => Ident(s.name) + }) listToTree(c)(identss.map(is => listToTree(c)(is))) } diff --git a/core/src/main/scala/scalacache/memoization/annotations.scala b/core/src/main/scala/scalacache/memoization/annotations.scala new file mode 100644 index 00000000..9da69a7c --- /dev/null +++ b/core/src/main/scala/scalacache/memoization/annotations.scala @@ -0,0 +1,6 @@ +package scalacache.memoization + +import scala.annotation.StaticAnnotation + +final class cacheKeyExclude extends StaticAnnotation + diff --git a/core/src/test/scala/scalacache/memoization/CacheKeyExcludingConstructorParamsSpec.scala b/core/src/test/scala/scalacache/memoization/CacheKeyExcludingConstructorParamsSpec.scala index 3e7c3718..d46cb1ad 100644 --- a/core/src/test/scala/scalacache/memoization/CacheKeyExcludingConstructorParamsSpec.scala +++ b/core/src/test/scala/scalacache/memoization/CacheKeyExcludingConstructorParamsSpec.scala @@ -50,6 +50,12 @@ class CacheKeyExcludingConstructorParamsSpec extends FlatSpec with CacheKeySpecC } } + it should "exclude values of arguments annotated with @cacheKeyExclude" in { + checkCacheKey("scalacache.memoization.CacheKeySpecCommon.withExcludedParams(1, 3)()") { + withExcludedParams(1, "2", "3")(4) + } + } + it should "work for a method inside a class" in { checkCacheKey("scalacache.memoization.AClass.insideClass(1)") { new AClass().insideClass(1) diff --git a/core/src/test/scala/scalacache/memoization/CacheKeyIncludingConstructorParamsSpec.scala b/core/src/test/scala/scalacache/memoization/CacheKeyIncludingConstructorParamsSpec.scala index fc744bfe..a8d735cf 100644 --- a/core/src/test/scala/scalacache/memoization/CacheKeyIncludingConstructorParamsSpec.scala +++ b/core/src/test/scala/scalacache/memoization/CacheKeyIncludingConstructorParamsSpec.scala @@ -19,6 +19,15 @@ class CacheKeyIncludingConstructorParamsSpec extends FlatSpec with CacheKeySpecC } } + it should "exclude values of constructor params annotated with @cacheKeyExclude" in { + val instance = new ClassWithExcludedConstructorParam(50, 10) + instance.scalaCache = scalaCache + + checkCacheKey("scalacache.memoization.ClassWithExcludedConstructorParam(50).foo(42)") { + instance.foo(42) + } + } + it should "include values of all arguments for all argument lists" in { checkCacheKey("scalacache.memoization.CacheKeySpecCommon.multipleArgLists(1, 2)(3, 4)") { multipleArgLists(1, "2")("3", 4) @@ -43,6 +52,12 @@ class CacheKeyIncludingConstructorParamsSpec extends FlatSpec with CacheKeySpecC } } + it should "exclude values of arguments annotated with @cacheKeyExclude" in { + checkCacheKey("scalacache.memoization.CacheKeySpecCommon.withExcludedParams(1, 3)()") { + withExcludedParams(1, "2", "3")(4) + } + } + it should "work for a method inside a class" in { // The class's implicit param (the ScalaCache) should be included in the cache key) checkCacheKey(s"scalacache.memoization.AClass()(${scalaCache.toString}).insideClass(1)") { diff --git a/core/src/test/scala/scalacache/memoization/CacheKeySpecCommon.scala b/core/src/test/scala/scalacache/memoization/CacheKeySpecCommon.scala index 14c7ac9f..0266e394 100644 --- a/core/src/test/scala/scalacache/memoization/CacheKeySpecCommon.scala +++ b/core/src/test/scala/scalacache/memoization/CacheKeySpecCommon.scala @@ -41,6 +41,10 @@ trait CacheKeySpecCommon extends Suite with Matchers with ScalaFutures with Befo 123 } + def withExcludedParams(a: Int, @cacheKeyExclude b: String, c: String)(@cacheKeyExclude d: Int): Int = memoize { + 123 + } + } class AClass(implicit val scalaCache: ScalaCache) { @@ -83,3 +87,10 @@ class ClassWithConstructorParams(b: Int) { a + b } } + +class ClassWithExcludedConstructorParam(b: Int, @cacheKeyExclude c: Int) { + implicit var scalaCache: ScalaCache = null + def foo(a: Int): Int = memoize { + a + b + c + } +}