From cad152379ef614a6e731ce787298632543713e86 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Wed, 24 Jul 2019 09:40:56 +0100 Subject: [PATCH] Remove Monocle dependency (#121) * Replace Monocle with local SimpleLens implementation * [domain] SimpleLensTest avoid short variables and remove field imports --- CHANGELOG.org | 1 + build.sbt | 7 -- .../kemitix/thorp/core/ConfigOptions.scala | 8 +-- .../net/kemitix/thorp/core/Counters.scala | 15 +++-- .../net/kemitix/thorp/core/SyncLogging.scala | 1 - .../net/kemitix/thorp/domain/Config.scala | 21 +++--- .../net/kemitix/thorp/domain/LocalFile.scala | 7 +- .../net/kemitix/thorp/domain/RemoteKey.scala | 5 +- .../net/kemitix/thorp/domain/SimpleLens.scala | 18 ++++++ .../kemitix/thorp/domain/SimpleLensTest.scala | 64 +++++++++++++++++++ 10 files changed, 113 insertions(+), 34 deletions(-) create mode 100644 domain/src/main/scala/net/kemitix/thorp/domain/SimpleLens.scala create mode 100644 domain/src/test/scala/net/kemitix/thorp/domain/SimpleLensTest.scala diff --git a/CHANGELOG.org b/CHANGELOG.org index 2c30db0..fa0944e 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -16,6 +16,7 @@ The format is based on [[https://keepachangelog.com/en/1.0.0/][Keep a Changelog] ** Changed - Replace cats-effect with zio (#117) + - Replace Monocle with local SimpleLens implementation (#121) ** Dependencies diff --git a/build.sbt b/build.sbt index 9d2281e..bc493c7 100644 --- a/build.sbt +++ b/build.sbt @@ -38,12 +38,6 @@ val testDependencies = Seq( "org.scalamock" %% "scalamock" % "4.3.0" % Test ) ) -val domainDependencies = Seq( - libraryDependencies ++= Seq( - "com.github.julien-truffaut" %% "monocle-core" % "1.6.0", - "com.github.julien-truffaut" %% "monocle-macro" % "1.6.0" - ) -) val commandLineParsing = Seq( libraryDependencies ++= Seq( "com.github.scopt" %% "scopt" % "4.0.0-RC2" @@ -122,6 +116,5 @@ lazy val console = (project in file("console")) lazy val domain = (project in file("domain")) .settings(commonSettings) - .settings(domainDependencies) .settings(assemblyJarName in assembly := "domain.jar") .settings(testDependencies) diff --git a/core/src/main/scala/net/kemitix/thorp/core/ConfigOptions.scala b/core/src/main/scala/net/kemitix/thorp/core/ConfigOptions.scala index 0fdd95f..9f0662b 100644 --- a/core/src/main/scala/net/kemitix/thorp/core/ConfigOptions.scala +++ b/core/src/main/scala/net/kemitix/thorp/core/ConfigOptions.scala @@ -1,7 +1,6 @@ package net.kemitix.thorp.core -import monocle.Lens -import monocle.macros.GenLens +import net.kemitix.thorp.domain.SimpleLens case class ConfigOptions( options: List[ConfigOption] = List() @@ -25,6 +24,7 @@ case class ConfigOptions( } object ConfigOptions { - val options: Lens[ConfigOptions, List[ConfigOption]] = - GenLens[ConfigOptions](_.options) + val options: SimpleLens[ConfigOptions, List[ConfigOption]] = + SimpleLens[ConfigOptions, List[ConfigOption]](_.options, + c => a => c.copy(options = a)) } diff --git a/core/src/main/scala/net/kemitix/thorp/core/Counters.scala b/core/src/main/scala/net/kemitix/thorp/core/Counters.scala index 553b002..9dde311 100644 --- a/core/src/main/scala/net/kemitix/thorp/core/Counters.scala +++ b/core/src/main/scala/net/kemitix/thorp/core/Counters.scala @@ -1,7 +1,6 @@ package net.kemitix.thorp.core -import monocle.Lens -import monocle.macros.GenLens +import net.kemitix.thorp.domain.SimpleLens final case class Counters( uploaded: Int = 0, @@ -11,8 +10,12 @@ final case class Counters( ) object Counters { - val uploaded: Lens[Counters, Int] = GenLens[Counters](_.uploaded) - val deleted: Lens[Counters, Int] = GenLens[Counters](_.deleted) - val copied: Lens[Counters, Int] = GenLens[Counters](_.copied) - val errors: Lens[Counters, Int] = GenLens[Counters](_.errors) + val uploaded: SimpleLens[Counters, Int] = + SimpleLens[Counters, Int](_.uploaded, b => a => b.copy(uploaded = a)) + val deleted: SimpleLens[Counters, Int] = + SimpleLens[Counters, Int](_.deleted, b => a => b.copy(deleted = a)) + val copied: SimpleLens[Counters, Int] = + SimpleLens[Counters, Int](_.copied, b => a => b.copy(copied = a)) + val errors: SimpleLens[Counters, Int] = + SimpleLens[Counters, Int](_.errors, b => a => b.copy(errors = a)) } diff --git a/core/src/main/scala/net/kemitix/thorp/core/SyncLogging.scala b/core/src/main/scala/net/kemitix/thorp/core/SyncLogging.scala index 250d54c..c0ac772 100644 --- a/core/src/main/scala/net/kemitix/thorp/core/SyncLogging.scala +++ b/core/src/main/scala/net/kemitix/thorp/core/SyncLogging.scala @@ -1,7 +1,6 @@ package net.kemitix.thorp.core import net.kemitix.thorp.console._ -//import net.kemitix.thorp.console.MyConsole._ import net.kemitix.thorp.domain.StorageQueueEvent.{ CopyQueueEvent, DeleteQueueEvent, diff --git a/domain/src/main/scala/net/kemitix/thorp/domain/Config.scala b/domain/src/main/scala/net/kemitix/thorp/domain/Config.scala index 6389cbc..5fff0a6 100644 --- a/domain/src/main/scala/net/kemitix/thorp/domain/Config.scala +++ b/domain/src/main/scala/net/kemitix/thorp/domain/Config.scala @@ -1,8 +1,5 @@ package net.kemitix.thorp.domain -import monocle.Lens -import monocle.macros.GenLens - final case class Config( bucket: Bucket = Bucket(""), prefix: RemoteKey = RemoteKey(""), @@ -13,10 +10,16 @@ final case class Config( ) object Config { - val sources: Lens[Config, Sources] = GenLens[Config](_.sources) - val bucket: Lens[Config, Bucket] = GenLens[Config](_.bucket) - val prefix: Lens[Config, RemoteKey] = GenLens[Config](_.prefix) - val filters: Lens[Config, List[Filter]] = GenLens[Config](_.filters) - val debug: Lens[Config, Boolean] = GenLens[Config](_.debug) - val batchMode: Lens[Config, Boolean] = GenLens[Config](_.batchMode) + val sources: SimpleLens[Config, Sources] = + SimpleLens[Config, Sources](_.sources, b => a => b.copy(sources = a)) + val bucket: SimpleLens[Config, Bucket] = + SimpleLens[Config, Bucket](_.bucket, b => a => b.copy(bucket = a)) + val prefix: SimpleLens[Config, RemoteKey] = + SimpleLens[Config, RemoteKey](_.prefix, b => a => b.copy(prefix = a)) + val filters: SimpleLens[Config, List[Filter]] = + SimpleLens[Config, List[Filter]](_.filters, b => a => b.copy(filters = a)) + val debug: SimpleLens[Config, Boolean] = + SimpleLens[Config, Boolean](_.debug, b => a => b.copy(debug = a)) + val batchMode: SimpleLens[Config, Boolean] = + SimpleLens[Config, Boolean](_.batchMode, b => a => b.copy(batchMode = a)) } diff --git a/domain/src/main/scala/net/kemitix/thorp/domain/LocalFile.scala b/domain/src/main/scala/net/kemitix/thorp/domain/LocalFile.scala index 4688e9e..8f91a4b 100644 --- a/domain/src/main/scala/net/kemitix/thorp/domain/LocalFile.scala +++ b/domain/src/main/scala/net/kemitix/thorp/domain/LocalFile.scala @@ -3,9 +3,6 @@ package net.kemitix.thorp.domain import java.io.File import java.nio.file.Path -import monocle.Lens -import monocle.macros.GenLens - final case class LocalFile( file: File, source: File, @@ -41,5 +38,7 @@ object LocalFile { pathToKey(resolvedPath)) } - val remoteKey: Lens[LocalFile, RemoteKey] = GenLens[LocalFile](_.remoteKey) + val remoteKey: SimpleLens[LocalFile, RemoteKey] = + SimpleLens[LocalFile, RemoteKey](_.remoteKey, + b => a => b.copy(remoteKey = a)) } diff --git a/domain/src/main/scala/net/kemitix/thorp/domain/RemoteKey.scala b/domain/src/main/scala/net/kemitix/thorp/domain/RemoteKey.scala index 0c3ed34..2413c63 100644 --- a/domain/src/main/scala/net/kemitix/thorp/domain/RemoteKey.scala +++ b/domain/src/main/scala/net/kemitix/thorp/domain/RemoteKey.scala @@ -3,8 +3,6 @@ package net.kemitix.thorp.domain import java.io.File import java.nio.file.{Path, Paths} -import monocle.macros.GenLens - final case class RemoteKey( key: String ) { @@ -39,5 +37,6 @@ final case class RemoteKey( } object RemoteKey { - val key = GenLens[RemoteKey](_.key) + val key: SimpleLens[RemoteKey, String] = + SimpleLens[RemoteKey, String](_.key, b => a => b.copy(key = a)) } diff --git a/domain/src/main/scala/net/kemitix/thorp/domain/SimpleLens.scala b/domain/src/main/scala/net/kemitix/thorp/domain/SimpleLens.scala new file mode 100644 index 0000000..32ebbca --- /dev/null +++ b/domain/src/main/scala/net/kemitix/thorp/domain/SimpleLens.scala @@ -0,0 +1,18 @@ +package net.kemitix.thorp.domain + +case class SimpleLens[A, B](field: A => B, update: A => B => A) { + + def composeLens[C](other: SimpleLens[B, C]): SimpleLens[A, C] = + SimpleLens[A, C]( + a => other.field(field(a)), + a => c => update(a)(other.update(field(a))(c)) + ) + + def ^|->[C](other: SimpleLens[B, C]): SimpleLens[A, C] = composeLens(other) + + def set(b: B)(a: A): A = update(a)(b) + + def get(a: A): B = field(a) + + def modify(f: B => B)(a: A): A = update(a)(f(field(a))) +} diff --git a/domain/src/test/scala/net/kemitix/thorp/domain/SimpleLensTest.scala b/domain/src/test/scala/net/kemitix/thorp/domain/SimpleLensTest.scala new file mode 100644 index 0000000..6308273 --- /dev/null +++ b/domain/src/test/scala/net/kemitix/thorp/domain/SimpleLensTest.scala @@ -0,0 +1,64 @@ +package net.kemitix.thorp.domain + +import org.scalatest.FreeSpec + +class SimpleLensTest extends FreeSpec { + + "lens" - { + val subject = Subject(0, "s") + "modify" in { + val expected = Subject(1, "s") + val result = Subject.anIntLens.modify(_ + 1)(subject) + assertResult(expected)(result) + } + "get" in { + val expected = "s" + val result = Subject.aStringLens.get(subject) + assertResult(expected)(result) + } + "set" in { + val expected = Subject(0, "k") + val result = Subject.aStringLens.set("k")(subject) + assertResult(expected)(result) + } + } + + "lens composed" - { + val wrapper = Wrapper(1, Subject(2, "x")) + val subjectStringLens = Wrapper.aSubjectLens ^|-> Subject.aStringLens + "modify" in { + val expected = Wrapper(1, Subject(2, "X")) + val result = subjectStringLens.modify(_.toUpperCase)(wrapper) + assertResult(expected)(result) + } + "get" in { + val expected = "x" + val result = subjectStringLens.get(wrapper) + assertResult(expected)(result) + } + "set" in { + val expected = Wrapper(1, Subject(2, "k")) + val result = subjectStringLens.set("k")(wrapper) + assertResult(expected)(result) + } + } + + case class Subject(anInt: Int, aString: String) + object Subject { + val anIntLens: SimpleLens[Subject, Int] = + SimpleLens[Subject, Int](_.anInt, subject => i => subject.copy(anInt = i)) + val aStringLens: SimpleLens[Subject, String] = + SimpleLens[Subject, String](_.aString, + subject => str => subject.copy(aString = str)) + } + case class Wrapper(anInt: Int, aSubject: Subject) + object Wrapper { + val anIntLens: SimpleLens[Wrapper, Int] = + SimpleLens[Wrapper, Int](_.anInt, wrapper => i => wrapper.copy(anInt = i)) + val aSubjectLens: SimpleLens[Wrapper, Subject] = + SimpleLens[Wrapper, Subject]( + _.aSubject, + wrapper => subject => wrapper.copy(aSubject = subject)) + } + +}