Skip to content

Instantly share code, notes, and snippets.

@etorreborre
Last active March 28, 2016 09:03
Show Gist options
  • Save etorreborre/2ef77cbef35e349d3303 to your computer and use it in GitHub Desktop.
Save etorreborre/2ef77cbef35e349d3303 to your computer and use it in GitHub Desktop.
Pseudo-code for doing DI on a service using an actor with 2 different implementations
trait MyActor
case class InMemoryActor() extends MyActor
case class ProductionActor(connection: DBConnection) extends MyActor
case class MyService(actor: MyActor)
object MyService {
def fromConfig(config: Config): ConfigError Xor MyActor =
??? // read application.conf
}
class MySpec extends Specification with ForEach[MyService] { def is = s2"""
The service should do this $e1
"""
def e1 = { service =>
// replace the actor implementation using the ConfigRewriter
val actor: MyActor = InMemoryActor()
service.replace[MyActor](actor)
// test the service here
ok
}
def foreach[R : AsResult](f: MyService => R) = {
MyService.fromConfig(ConfigFactory.load("application-test.conf")).fold(
e => Failure(ConfigError.render(e)),
s => f(s)
)
}
}
/**
* This is using: https://bitbucket.org/inkytonik/kiama
*/
trait ConfigRewriter {
/**
* Take the first value of a given type (approximated with a ClassTag)
* and replace it everywhere in the graph
*/
def singleton[S : ClassTag, G](graph: G): G =
replaceWithStrategy(singletonStrategy[S], graph)
/**
* Replace all values of type S, with the same value
*/
def replace[S : ClassTag, G](s: S, graph: G): G =
replaceWithStrategy(replaceStrategy[S](s), graph)
/**
* Replace with a given strategy
*/
def replaceWithStrategy[G](strategy: Strategy, graph: G): G =
rewrite(everywheretd(strategy))(graph)
/**
* Replace with a given partial function
*/
def replaceWith[G, T](s: T ==> Option[T], graph: G): G =
replaceWithStrategy(strategy(s), graph)
def singletonStrategy[S : ClassTag]: Strategy = {
var s: Option[S] = None
strategy[Any] {
case v if implicitly[ClassTag[S]].runtimeClass.isInstance(v) =>
s match {
case Some(singleton) => Some(singleton)
case None => s = Some(v.asInstanceOf[S])
Some(v)
}
case other => None
}
}
def replaceStrategy[S : ClassTag](s: S): Strategy =
strategy[Any] {
case v if Reflect.implements(v) => Some(s)
case other => None
}
}
object ConfigRewriter extends ConfigRewriter with ConfigRewriterSyntax
/**
* Syntactic sugar for rewriting nodes in a graph
*
* The methods here allow to chain various replacements:
*
* g.singleton[T].replace[S](s)
*/
trait ConfigRewriterSyntax {
implicit class Rewrite[G](graph: G) {
def singleton[S : ClassTag]: G =
ConfigRewriter.singleton[S, G](graph)
def replace[S : ClassTag](s: S): G =
ConfigRewriter.replace[S, G](s, graph)
def replaceWith[T](s: T ==> Option[T]): G =
ConfigRewriter.replaceWith(s, graph)
}
}
object ConfigRewriterSyntax extends ConfigRewriterSyntax
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment