• This repository has been archived on 13/Feb/2024
  • Stars
    star
    252
  • Rank 161,312 (Top 4 %)
  • Language
    Scala
  • License
    Apache License 2.0
  • Created almost 4 years ago
  • Updated 10 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Construct ZLayers automagically (w/ helpful compile-time errors)

🪄 zio-magic

Release Artifacts Snapshot Artifacts

ANNOUNCEMENT: This library is officially included as a first-class feature of ZIO 2.0 😊

Construct ZLayers automagically, with friendly compile-time hints!

// build.sbt
libraryDependencies += "io.github.kitlangton" %% "zio-magic" % "0.3.12"

What's all this then?

// Given a dependency graph (Cake needs Chocolate & Flour, which in turn need Spoon)*
//
//          Cake
//          /   \
//   Chocolate   Flour
//       |         |
//     Spoon     Spoon
//
// *Not an actual recipe.
import zio._
import zio.magic._

def run(args: List[String]): URIO[ZEnv, ExitCode] = {
  
  // An effect requiring Cake and Console. Yum!
  val program: URIO[Console with Cake, Unit] =
    Cake.isDelicious.flatMap { bool => console.putStrLn(s"Cake is delicious: $bool") }

  // The old way
  val manually: ULayer[Cake with Console] =
    ((Spoon.live >>> Flour.live) ++ (Spoon.live >>> Chocolate.live)) >>> Cake.live ++ Console.live

  // The magical way (The order doesn't matter)
  val magically: UIO[Unit] =
    program.inject(
      Cake.live,
      Flour.live,
      Chocolate.live,
      Spoon.live,
      Console.live
    )

  magically.exitCode
}

And if you leave something off, a compile time clue!

val magically: UIO[Unit] =
  program.inject(
    Cake.live,
    //Flour.live, <-- Oops
    Chocolate.live,
    Spoon.live,
    Console.live
  )
   ZLayer Wiring Error

>  provide zio.magic.Example.Flour.Service
>      for Cake.live

Versus leaving out a dependency when manually constructing your layer...

 val manually: ULayer[Cake with Console] =
   (Flour.live ++ (Spoon.live >>> Chocolate.live)) >>> Cake.live ++ Console.live
 // ^ A Spoon is missing here! 
type mismatch;
 found   : zio.ZLayer[zio.magic.Example.Spoon.Spoon with Any,Nothing,zio.magic.Example.Cake.Cake with zio.console.Console]
    (which expands to)  zio.ZLayer[zio.Has[zio.magic.Example.Spoon.Service] with Any,Nothing,zio.Has[zio.magic.Example.Cake.Service] with zio.Has[zio.console.Console.Service]]
 required: zio.ULayer[zio.magic.Example.Cake.Cake with zio.console.Console]
    (which expands to)  zio.ZLayer[Any,Nothing,zio.Has[zio.magic.Example.Cake.Service] with zio.Has[zio.console.Console.Service]]
      ((Flour.live) ++ (Spoon.live >>> Chocolate.live)) >>> Cake.live ++ Console.live

Also

You can also directly construct a ZLayer (However you must annotate the call to ZLayer.wire[LikeThis], because macros).

val layer = ZLayer.wire[Flour with Console](Console.live, Flour.live, Spoon.live)

To construct URLayer[In, Out] use ZLayer.wireSome[In, Out] this way:

val layer = ZLayer.wireSome[CommonEnv, Flour with Console](Console.live, Flour.live, Spoon.live)

Alternatively you can provide environment partially with injectSome[Rest](l1, l2, l3) - similarly to .provideSomeLayer.

There's also .injectCustom for which behaves similarly to .provideCustomLayer, only it also provides ZEnv.any to all transitive dependencies.

val program: URIO[Console with Car, Unit] = ???

val carLayer: URLayer[Blocking with Wheels, Car] = ???
val wheelLayer: ULayer[Wheels] = ???

// The ZEnv you use later will provide both Blocking to carLayer and Console to the program
val provided: URIO[ZEnv, Unit] = 
  program.injectCustom(carLayer, wheelLayer)

Specs

inject, injectCustom, injectSome, injectShared, injectCustomShared and injectSomeShared all work for zio-test's Spec.

Debug!

Try ZLayer.wireDebug[Cake] or ZLayer.wireSomeDebug[Blocking with Console, Cake] to print out a pretty tree! Ooh la la!

ZLayer Wiring Graph
===================

 â—‰ Cake.live
 ├─◑ Flour.live
 │ ├─◑ Spoon.live
 │ │ ╰─◑ Blocking.live
 │ ╰─◑ Console.live
 ╰─◑ Berries.live
   ╰─◑ Spoon.live
     ╰─◑ Blocking.live

Let me know if you can think of any helpful variants, and I'll give 'em a whirl!

More Repositories

1

neotype

A friendly newtype library for Scala 3
Scala
158
star
2

scala-update

Update your Scala dependencies interactively
Scala
132
star
3

parallel-for

Automatically parallelize your for-comprehensions at compile time.
Scala
131
star
4

zio-app

Quickly create and develop full-stack Scala apps with ZIO and Laminar.
Scala
124
star
5

OmenTextField

A better TextField for SwiftUI. A growing, multiline, auto-focusable TextField supporting bindable focus.
Swift
118
star
6

animus

An FRP animation library for Laminar
Scala
95
star
7

quotidian

A menagerie of macro utilities and extensions for Scala 3
Scala
92
star
8

zio-catechism

Animated ZIO documentation and visualizations
Scala
58
star
9

zio-tui

Scala
55
star
10

zio-slides

An interactive, websocket-backed slide presentation app.
Scala
48
star
11

given

A tool for interactively updating your Scala dependencies.
Rust
43
star
12

formula

Form Combinator Library for decimating frontend boilerplate.
Scala
37
star
13

conclave

An elegant and perfect meetup application
Scala
25
star
14

zio-api

An API DSL for constructing servers, clients, and documentation.
Scala
24
star
15

zio-start

A wizard for generating new ZIO applications.
Scala
20
star
16

migraine

A minimalist DB migration manager.
Scala
18
star
17

stubby

A simple stubbing library for ZIO tests.
Scala
17
star
18

idiomatic-zio-app-architecture

This repo contains the code for a series of Zymposium videos on ZIO App Architecture and ZLayers
Scala
14
star
19

zio-from-scatch

Rebuilding ZIO from scratch for fun and (educational) profit
Scala
12
star
20

automaton

RPC + GPT
Scala
9
star
21

Spandex

A Snippet App for macOS
Swift
8
star
22

java-to-scala

This repository contains the exercises and examples for the "Java to Scala" course.
Scala
6
star
23

scala-macro-fun

FuN ScAlA MaCrOs!
Scala
5
star
24

scala-school-site

5
star
25

scala-3-compile-time-business

scala-3-compile-time-business
Scala
5
star
26

Swipe-Actions-from-Scratch

Code for the Swipe Actions from Scratch video series
Swift
5
star
27

eulerplate

A tool for generating Haskell boilerplate for solving Hacker Rank challenges.
Haskell
5
star
28

terminus

A TUI library for Rust.
Rust
4
star
29

boilerplate

A DSL for boilerplate generation (A counter-hex against the evil number 22)
Scala
4
star
30

compile-time-time

A repository for the Compile-Time Time videos
Scala
4
star
31

jmh-benchmark-action

A GitHub CI Action for automating the comparison of JMH benchmarking results.
Scala
4
star
32

Spring-Animation-From-Scratch

Code for the Spring Animation From Scratch Videos
Swift
4
star
33

kitcoin

An animated bitcoin-esque (blockchain/consensus) network simulator
PureScript
3
star
34

Swift-Observation-From-Scratch

Reimplementing Swift's Observation functionality
Swift
3
star
35

raft-skeleton

raft
Scala
3
star
36

computer-time

Scala
3
star
37

type-inference

type-inference
Scala
2
star
38

OSSRH-62496

What a repo!
2
star
39

zio-hackathon

Scala
2
star
40

quill-examples-zymposium

Scala
2
star
41

zio-trials

Interactive ZIO exercises
Scala
2
star
42

zio-play-example

Scala
2
star
43

hack-hackery

hacking on HACK ASM
Assembly
2
star
44

declarative-vs-executable

Scala
2
star
45

snaked

A multiplayer, socket-based, command-line snake game.
Haskell
2
star
46

local-deps-example

A sane local dependency workflow for Scala and sbt
Scala
2
star
47

OmenGridAnimation

Swift
1
star
48

Swift-Deck

A very WIP SwiftUI Slide Deck DSL
Swift
1
star
49

au_pair

Ruby
1
star
50

job_hunger_ember

JavaScript
1
star
51

okasaki

Scala Explorations based upon Chris Okasaki's Purely Functional Data Structures
Scala
1
star
52

scala-symposia

Executable Scala lessons
Scala
1
star
53

Rosalind-Problems

Ruby
1
star
54

attr_asker

Ruby
1
star
55

AtomSetup

JavaScript
1
star
56

fixins

A salubrious assortment of Scalafix rules
Scala
1
star