Skip to content

Commit

Permalink
Examples of Meta plug-ins (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
serras authored Dec 11, 2021
2 parents b5a4210 + 9537bf8 commit 23325be
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 22 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Build Artifacts

on: pull_request

env:
JAVA_OPTS: -Xms512m -Xmx1024m
GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.configureondemand=true -Dorg.gradle.jvmargs=-Xmx3g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8"

jobs:
build_artifacts:

runs-on: ubuntu-latest
timeout-minutes: 30

steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0

- uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: '11'

- name: Build and test with Gradle
run: ./gradlew build

- name: Bundle build report
if: failure()
run: find . -type d -name 'reports' | zip -@ -r build-reports.zip

- name: Upload build report
if: failure()
uses: actions/upload-artifact@master
with:
name: error-report
path: build-reports.zip

- name: Bundle analysis report
run: mkdir sarif && find . -name '*.sarif' | xargs -I{} cp "{}" ./sarif/

- name: Upload analysis report
uses: github/codeql-action/upload-sarif@v1
with:
# Path to SARIF file relative to the root of the repository
sarif_file: sarif
8 changes: 4 additions & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ val arrow_meta_version: String by project

plugins {
application
id("com.google.devtools.ksp") version "1.6.0-1.0.1"
kotlin("jvm") version "1.6.0"
}

Expand All @@ -16,26 +17,25 @@ application {
}

repositories {
// mavenLocal()
mavenLocal()
mavenCentral()
maven(url = "https://oss.sonatype.org/content/repositories/snapshots/")
}

buildscript {
repositories {
// mavenLocal()
mavenLocal()
maven(url = "https://oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
classpath("io.arrow-kt.optics:io.arrow-kt.optics.gradle.plugin:2.0-SNAPSHOT")
classpath("io.arrow-kt.analysis.kotlin:io.arrow-kt.analysis.kotlin.gradle.plugin:2.0-SNAPSHOT")
}
}

apply(plugin = "io.arrow-kt.optics")
apply(plugin = "io.arrow-kt.analysis.kotlin")

dependencies {
ksp("io.arrow-kt:arrow-optics-ksp:2.0-SNAPSHOT")
implementation("io.arrow-kt:arrow-core:$arrow_version")
implementation("io.arrow-kt:arrow-fx-coroutines:$arrow_version")
implementation("io.arrow-kt:arrow-optics:$arrow_version")
Expand Down
22 changes: 12 additions & 10 deletions src/main/kotlin/io/arrow/example/Application.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class ExampleApp(
call.respondText("Hello World!")
}
get("/process") {
when (val result = either<BadRequest, List<Entry>> {
val result = either<BadRequest, List<Entry>> {
val order = Either.catch { call.receive<Order>() }
.mapLeft { badRequest(it.message ?: "Received an invalid order") }
.bind()
Expand All @@ -61,17 +61,19 @@ class ExampleApp(
}.mapLeft { availability ->
badRequest("Following productIds weren't available: ${availability.joinToString { it.productId }}")
}.bind()
}) {
}
when (result) {
is Either.Left<BadRequest> ->
call.respond(result.value)
is Either.Right<List<Entry>> -> when (billing.processBilling(mapOf())) {
BillingResponse.OK ->
call.respondText("ok")
BillingResponse.USER_ERROR ->
call.respondText(status = HttpStatusCode.BadRequest) { "not enough items" }
BillingResponse.SYSTEM_ERROR ->
call.respondText(status = HttpStatusCode.InternalServerError) { "server error" }
}
is Either.Right<List<Entry>> ->
when (billing.processBilling(result.value.associate(Entry::asPair))) {
BillingResponse.OK ->
call.respondText("ok")
BillingResponse.USER_ERROR ->
call.respond(badRequest("not enough items"))
BillingResponse.SYSTEM_ERROR ->
call.respondText(status = HttpStatusCode.InternalServerError) { "server error" }
}
}
}
}
Expand Down
28 changes: 28 additions & 0 deletions src/main/kotlin/io/arrow/example/MetaExamples.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@file:Suppress("unused")
package io.arrow.example

import arrow.optics.Every

// WRONG
// fun Order.containsSingleProductWrong() =
// entries.all { entry -> entry.id == entries[0].id }

// RIGHT
fun Order.containsSingleProductRight() =
if (entries.isEmpty()) false
else entries.all { entry -> entry.id == entries[0].id }

fun Order.addOneFreeNoOptics(): Order =
Order(entries.map { it.copy(amount = it.amount + 1) })

fun Order.addOneFreeOptics(): Order {
// an optic focuses on a set of elements
// in this case we focus:
// 1. on the 'entries' field
// 2. on each element on the list
// 3. on the 'amount' field
// RESULT: we focus on each 'amount' field in each 'Entry'
val optic = Order.entries compose Every.list() compose Entry.amount
// now we can perform a single modification step
return optic.modify(this) { it + 1 }
}
12 changes: 8 additions & 4 deletions src/main/kotlin/io/arrow/example/Model.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ package io.arrow.example
import arrow.optics.optics

@optics
data class Order(val entries: List<Entry>) {
companion object { }
data class Entry(val id: String, val amount: Int) {
companion object // required by @optics

val asPair: Pair<String, Int>
get() = Pair(id, amount)
}

@optics
data class Entry(val id: String, val amount: Int) {
companion object { }
data class Order(val entries: List<Entry>) {
companion object // required by @optics
}

fun Order.flatten(): Order = Order(
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/io/arrow/example/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import arrow.fx.coroutines.parTraverseValidated
import arrow.typeclasses.Semigroup
import kotlinx.coroutines.CoroutineScope

public fun <A, E> A.ensure(predicate: (A) -> Boolean, problem: () -> E): ValidatedNel<E, A> =
fun <A, E> A.ensure(predicate: (A) -> Boolean, problem: () -> E): ValidatedNel<E, A> =
if (predicate(this)) this.validNel() else problem().invalidNel()

public suspend fun <E, A, B> Iterable<A>.parTraverseValidated(
suspend fun <E, A, B> Iterable<A>.parTraverseValidated(
f: suspend CoroutineScope.(A) -> ValidatedNel<E, B>
): ValidatedNel<E, List<B>> =
this.parTraverseValidated(Semigroup.nonEmptyList(), f)
4 changes: 2 additions & 2 deletions src/test/kotlin/io/arrow/example/ApplicationTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ class ApplicationTest {
Order(emptyList())
) {
assertEquals(HttpStatusCode.BadRequest, response.status())
assertEquals("""["EMPTY_ORDER"]""", response.content)
assertEquals("EMPTY_ORDER", response.content)
}

@Test
fun `wrong id gives error`() = testProcess(
Order(listOf(Entry("NOT-AN-ID", 2)))
) {
assertEquals(HttpStatusCode.BadRequest, response.status())
assertEquals("""["INCORRECT_ID"]""", response.content)
assertEquals("INCORRECT_ID", response.content)
}

@Test
Expand Down

0 comments on commit 23325be

Please sign in to comment.