Skip to content

Instantly share code, notes, and snippets.

@fanf
Created July 18, 2013 16:06
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save fanf/6030588 to your computer and use it in GitHub Desktop.
Save fanf/6030588 to your computer and use it in GitHub Desktop.
Simple, Static Scala dependency injection with Shapeless
package test_shapeless
object DI {
import shapeless._
trait Injecter[L <: HList, A] {
def apply(l: L) : A
}
trait InjecterAux[L <: HList, A] {
def apply(l: L) : A
}
object Injecter {
implicit def injecter[L <: HList, A0](implicit injecter: InjecterAux[L, A0]) = new Injecter[L,A0] {
def apply(l:L) : A0 = injecter(l)
}
}
object InjecterAux {
implicit def foo[L <: HList, A, Out0 <: HList]
(implicit subtypeUnifier: SubtypeUnifierAux[L, A, Out0], filter: FilterAux[Out0, A, A :: HNil]) =
new InjecterAux[L,A] {
def apply(l:L) : A = filter(subtypeUnifier(l)).head
}
}
implicit class Injector[L <: HList](l:L) {
def inject[A](implicit injecter: Injecter[L,A]) : A = injecter(l)
}
}
object DependencyInjectionTest extends App {
import shapeless._
trait ServiceOneImpl { def hello : String }
class ServiceOneImpl_0 extends ServiceOneImpl { val hello = "impl_0" }
trait ServiceMultiImpl { def hello: String }
class ServiceMultiImpl_1 extends ServiceMultiImpl { val hello = "impl_1"}
class ServiceMultiImpl_2 extends ServiceMultiImpl { val hello = "impl_2"}
trait Marker
val register =
(new ServiceOneImpl_0) ::
(new ServiceMultiImpl_1) ::
(new ServiceMultiImpl_2 with Marker) ::
HNil
implicit class Uniqueable[L <: HList](l: L) {
def unique[A](implicit filter: FilterAux[L, A, A :: HNil]) = {
filter(l).head
}
}
//implementation work
val s1 = register.unique[ServiceOneImpl_0]
println(s1.hello) //impl_0
val s2 = register.unifySubtypes[ServiceOneImpl].unique[ServiceOneImpl]
println(s2.hello) //impl_0
val s3 = register.unifySubtypes[ServiceMultiImpl with Marker].unique[ServiceMultiImpl with Marker]
println(s3.hello) //impl_2
import DI._
val s4 = register.inject[ServiceOneImpl_0]
println(s4.hello) //impl_0
val s5 = register.inject[ServiceOneImpl]
println(s5.hello) //impl_0
val s6 = register.inject[ServiceMultiImpl with Marker]
println(s6.hello) //impl_2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment