Skip to main content
Version: ZIO 1.x

How to use ZIO Macros?

Scrapping the boilerplate with macros

Many libraries come together with usage best practices and repeatable code, ZIO is no different. Fortunately ZIO provides macros to perform these repetitive tasks for you. At the moment these are only available for Scala versions 2.x, however their equivalents for Dotty are on our roadmap.

Prerequisites

To enable macro expansion you need to setup your project:

  • for Scala >= 2.13 add compiler option
scalacOptions += "-Ymacro-annotations"
  • for Scala < 2.13 add macro paradise compiler plugin
compilerPlugin(("org.scalamacros" % "paradise"  % "2.1.1") cross CrossVersion.full)

Capability accessors

Installation

libraryDependencies += "dev.zio" %% "zio-macros" % "<zio-version>"

Description

The @accessible macro generates capability accessors into annotated module object.

import zio.{ Has, ZIO }
import zio.macros.accessible

@accessible
object AccountObserver {
trait Service {
def processEvent(event: AccountEvent): UIO[Unit]
}

// below will be autogenerated
def processEvent(event: AccountEvent) =
ZIO.accessM[Has[AccountObserver.Service]](_.get[Service].processEvent(event))
}

For normal values, a ZIO with Nothing on error channel is generated. If the code is throwing exceptions see @throwing below.

import zio.{ Has, ZIO }
import zio.macros.accessible

@accessible
object Module {
trait Service {
def pureMethod(v: Something): SomethingElse
}

// below will be autogenerated
def pureMethod(v: Something): ZIO[Service, Nothing, SomethingElse] =
ZIO.access[Has[Module.Service]](_.get[Service].pureMethod(v))
}

The @throwing annotation will mark impure methods. Using this annotation will request ZIO to push the error on the error channel.

import zio.{ Has, ZIO }
import zio.macros.accessible

@accessible
object Module {
trait Service {
@throwing
def impureMethod(v: Something): SomethingElse
}

// below will be autogenerated
def impureMethod(v: Something): ZIO[Service, Throwable, SomethingElse] =
ZIO.accessM[Has[Module.Service]](s => ZIO(s.get[Service].impureMethod(v)))
}

Note: the macro can only be applied to objects which contain a trait called Service.

Capability tags

Installation

libraryDependencies += "dev.zio" %% "zio-test" % "<zio-version>"

Description

The @mockable[A] generates capability tags and mock layer into annotated object.

import zio.test.mock.mockable

@mockable[AccountObserver.Service]
object AccountObserverMock

Will result in:

import zio.{ Has, UIO, URLayer, ZLayer }
import zio.test.mock.{ Mock, Proxy }

object AccountObserverMock extends Mock[Has[AccountObserver.Service]] {

object ProcessEvent extends Effect[AccountEvent, Nothing, Unit]
object RunCommand extends Effect[Unit, Nothing, Unit]

val compose: URLayer[Has[Proxy], AccountObserver] =
ZLayer.fromServiceM { proxy =>
withRuntime.map { rts =>
new AccountObserver.Service {
def processEvent(event: AccountEvent) = proxy(ProcessEvent, event)
def runCommand: UIO[Unit] = proxy(RunCommand)
}
}
}
}