Skip to content

Commit

Permalink
Create extension methods for onSubtype/on.../eachItem/each... in DSL
Browse files Browse the repository at this point in the history
  • Loading branch information
MateuszKubuszok committed Apr 8, 2024
1 parent 8a94eaa commit 9b9b749
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ object fixtures {
}

object nonFunhappy {
def validateA(a: Int): Int = throw new Exception("a not nice")
def validateA(a: Int): Int = sys.error("a not nice")
def validateB(b: Double): Double = b
def validateC(c: String): String = throw new Exception("c not pretty")
def validateD(d: Option[String]): Option[String] = throw new Exception("I don't like this d")
def validateC(c: String): String = sys.error("c not pretty")
def validateD(d: Option[String]): Option[String] = sys.error("I don't like this d")
}

object happy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ package object dsl {
implicit def TryPartialTransformerOps[A](`try`: Try[A]): syntax.TryPartialTransformerOps[A] =
syntax.TryPartialTransformerOps(`try`)

implicit def TransformationPathOps[A](a: A): syntax.TransformationPathOps[A] =
syntax.TransformationPathOps(a)

Check warning on line 38 in chimney/src/main/scala-2/io/scalaland/chimney/dsl/package.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/dsl/package.scala#L38

Added line #L38 was not covered by tests

// Extension methods in dsl.* summon TypeClass.AutoDerived while extension methods in syntax.* summon TypeClass.
// This help us preserve legacy behavior in dsl code while keeping stricter separation in auto/syntax imports.

Expand Down
28 changes: 28 additions & 0 deletions chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package io.scalaland.chimney

import io.scalaland.chimney.internal.runtime.{IsCollection, IsEither, IsMap, IsOption}

import scala.annotation.unused
import scala.util.Try

/** Imports only extension methods for summoning and using Transformer, PartialTransformer or Patcher
Expand Down Expand Up @@ -177,4 +180,29 @@ package object syntax {
def toPartialResult: partial.Result[A] =
partial.Result.fromTry(`try`)
}

// TODO: docs
implicit final class TransformationPathOps[A](@unused private val a: A) extends AnyVal {

def onSubtype[B <: A]: B =
sys.error(".onSubtype should be only called within Chimney DSL")

Check warning on line 188 in chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala#L188

Added line #L188 was not covered by tests

def onSome[B](implicit @unused ev: IsOption.Of[A, B]): B =
sys.error(".onSome should be only called within Chimney DSL")

Check warning on line 191 in chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala#L191

Added line #L191 was not covered by tests

def onLeft[L, R](implicit @unused ev: IsEither.Of[A, L, R]): L =
sys.error(".onLeft should be only called within Chimney DSL")

Check warning on line 194 in chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala#L194

Added line #L194 was not covered by tests

def onRight[L, R](implicit @unused ev: IsEither.Of[A, L, R]): R =
sys.error(".onRight should be only called within Chimney DSL")

Check warning on line 197 in chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala#L197

Added line #L197 was not covered by tests

def eachItem[B](implicit @unused ev: IsCollection.Of[A, B]): B =
sys.error(".eachItem should be only called within Chimney DSL")

Check warning on line 200 in chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala#L200

Added line #L200 was not covered by tests

def eachMapKey[K, V](implicit @unused ev: IsMap.Of[K, V, A]): K =
sys.error(".eachMapKey should be only called within Chimney DSL")

Check warning on line 203 in chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala#L203

Added line #L203 was not covered by tests

def eachMapValue[K, V](implicit @unused ev: IsMap.Of[K, V, A]): V =
sys.error(".eachMapValue should be only called within Chimney DSL")

Check warning on line 206 in chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/syntax/package.scala#L206

Added line #L206 was not covered by tests
}
}
12 changes: 11 additions & 1 deletion chimney/src/main/scala-3/io/scalaland/chimney/dsl/dsl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,17 @@ import io.scalaland.chimney.internal.compiletime.derivation.transformer.Transfor
import io.scalaland.chimney.internal.compiletime.derivation.patcher.PatcherMacros

export io.scalaland.chimney.inlined.{into, intoPartial, using}
export io.scalaland.chimney.syntax.{toPartialResult, toPartialResultOrString}
export io.scalaland.chimney.syntax.{
eachItem,
eachMapKey,
eachMapValue,
onLeft,
onRight,
onSome,
onSubtype,

Check warning on line 15 in chimney/src/main/scala-3/io/scalaland/chimney/dsl/dsl.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-3/io/scalaland/chimney/dsl/dsl.scala#L8-L15

Added lines #L8 - L15 were not covered by tests
toPartialResult,
toPartialResultOrString
}

// Extension methods in dsl.* summon TypeClass.AutoDerived while extension methods in syntax.* summon TypeClass.
// This help us preserve legacy behavior in dsl code while keeping stricter separation in auto/syntax imports.
Expand Down
26 changes: 26 additions & 0 deletions chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package io.scalaland.chimney.syntax

import io.scalaland.chimney.{partial, PartialTransformer, Patcher, Transformer}
import io.scalaland.chimney.internal.runtime.{IsCollection, IsEither, IsMap, IsOption}

import scala.annotation.unused
import scala.util.Try

// Extension methods in dsl.* summon TypeClass.AutoDerived while extension methods in syntax.* summon TypeClass.
Expand Down Expand Up @@ -172,3 +174,27 @@ extension [T](`try`: Try[T]) {
transparent inline def toPartialResult: partial.Result[T] =
partial.Result.fromTry(`try`)
}

extension [A](@unused a: A) {

def onSubtype[B <: A]: B =
sys.error(".onSubtype should be only called within Chimney DSL")

Check warning on line 181 in chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala#L180-L181

Added lines #L180 - L181 were not covered by tests

def onSome[B](implicit @unused ev: IsOption.Of[A, B]): B =
sys.error(".onSome should be only called within Chimney DSL")

Check warning on line 184 in chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala#L183-L184

Added lines #L183 - L184 were not covered by tests

def onLeft[L, R](implicit @unused ev: IsEither.Of[A, L, R]): L =
sys.error(".onLeft should be only called within Chimney DSL")

Check warning on line 187 in chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala#L186-L187

Added lines #L186 - L187 were not covered by tests

def onRight[L, R](implicit @unused ev: IsEither.Of[A, L, R]): R =
sys.error(".onRight should be only called within Chimney DSL")

Check warning on line 190 in chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala#L189-L190

Added lines #L189 - L190 were not covered by tests

def eachItem[B](implicit @unused ev: IsCollection.Of[A, B]): B =
sys.error(".eachItem should be only called within Chimney DSL")

Check warning on line 193 in chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala#L192-L193

Added lines #L192 - L193 were not covered by tests

def eachMapKey[K, V](implicit @unused ev: IsMap.Of[K, V, A]): K =
sys.error(".eachMapKey should be only called within Chimney DSL")

Check warning on line 196 in chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala#L195-L196

Added lines #L195 - L196 were not covered by tests

def eachMapValue[K, V](implicit @unused ev: IsMap.Of[K, V, A]): V =
sys.error(".eachMapValue should be only called within Chimney DSL")

Check warning on line 199 in chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-3/io/scalaland/chimney/syntax/syntax.scala#L198-L199

Added lines #L198 - L199 were not covered by tests
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ private[compiletime] trait Configurations { this: Derivation =>
case _ => false
}

override def toString: String = s".whenSubtype[${Type.prettyPrint(tpe.Underlying)}]"
override def toString: String = s".onSubtype[${Type.prettyPrint(tpe.Underlying)}]"
}
case object EachItem extends Segment {
override def toString: String = ".eachItem"

Check warning on line 156 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala#L156

Added line #L156 was not covered by tests
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.scalaland.chimney.internal.runtime

import scala.annotation.unused

sealed trait IsCollection[C] {
type Item
}
object IsCollection {
type Of[C, A] = IsCollection[C] { type Item = A }

private object Impl extends IsCollection[Nothing]

// build-in Chimney support for collections assumes that they are BOTH Iterable and have a Factory
implicit def scalaCollectionIsCollection[A, C <: Iterable[A]](implicit

Check warning on line 14 in chimney/src/main/scala/io/scalaland/chimney/internal/runtime/IsCollection.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/runtime/IsCollection.scala#L14

Added line #L14 was not covered by tests
@unused ev: scala.collection.compat.Factory[A, C]
): IsCollection.Of[C, A] = Impl.asInstanceOf[IsCollection.Of[C, A]]

Check warning on line 16 in chimney/src/main/scala/io/scalaland/chimney/internal/runtime/IsCollection.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/runtime/IsCollection.scala#L16

Added line #L16 was not covered by tests
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.scalaland.chimney.internal.runtime

sealed trait IsEither[E] {
type Left
type Right
}
object IsEither {

type Of[E, L, R] = IsEither[E] { type Left = L; type Right = R }

private object Impl extends IsEither[Nothing]

implicit def eitherOsEither[L, R, E <: Left[L, R]]: IsEither.Of[E, L, R] = Impl.asInstanceOf[IsEither.Of[E, L, R]]
}

Check warning on line 14 in chimney/src/main/scala/io/scalaland/chimney/internal/runtime/IsEither.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/runtime/IsEither.scala#L13-L14

Added lines #L13 - L14 were not covered by tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.scalaland.chimney.internal.runtime
import scala.annotation.unused

sealed trait IsMap[M] {
type Key
type Value
}
object IsMap {
type Of[M, K, V] = IsMap[M] { type Key = K; type Value = V }

private object Impl extends IsMap[Nothing]

// build-in Chimney support for maps assumes that they are BOTH Map and have a Factory
implicit def scalaMapIsMap[K, V, M <: Map[K, V]](implicit
@unused ev: scala.collection.compat.Factory[(K, V), M]
): IsMap.Of[K, V, M] = Impl.asInstanceOf[IsMap.Of[K, V, M]]

Check warning on line 16 in chimney/src/main/scala/io/scalaland/chimney/internal/runtime/IsMap.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/runtime/IsMap.scala#L16

Added line #L16 was not covered by tests
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.scalaland.chimney.internal.runtime

sealed trait IsOption[O] {
type Value
}
object IsOption {

type Of[O, A] = IsOption[O] { type Value = A }

private object Impl extends IsOption[Nothing]

implicit def optionIsOption[A, O <: Option[A]]: IsOption.Of[O, A] = Impl.asInstanceOf[IsOption.Of[O, A]]

Check warning on line 12 in chimney/src/main/scala/io/scalaland/chimney/internal/runtime/IsOption.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/runtime/IsOption.scala#L12

Added line #L12 was not covered by tests
}
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ class PartialTransformerProductSpec extends ChimneySpec {

val result7 = Person("John", 10, 140)
.intoPartial[User]
.withFieldComputed(_.age, _ => throw new Exception("error happened"))
.withFieldComputed(_.age, _ => sys.error("error happened"))
.transform
result7.asOption ==> None
result7.asEither.isLeft ==> true
Expand Down

0 comments on commit 9b9b749

Please sign in to comment.