Skip to content

Commit 0c6bbe2

Browse files
committed
Replace Monix with ZIO, ScalaTest with zio-test (#6)
* Replace Monix with ZIO, ScalaTest with zio-test - Replace monix-eval/monix-execution with zio 2.1.25 - Replace cats.effect.Resource with ZIO.acquireRelease + Scope - Replace monix Atomic with java.util.concurrent.atomic.AtomicReference - Replace Task(...) with ZIO.attempt(...) - Replace Task.parSequenceUnordered with ZIO.collectAllParDiscard - Replace .runSyncUnsafe() with Unsafe.unsafe { Runtime.default.unsafe.run(...) } - Replace ScalaTest/ScalaCheck with zio-test - Rewrite tests using ZIOSpecDefault and assertTrue * Format build.sbt
1 parent 41ae7ad commit 0c6bbe2

3 files changed

Lines changed: 146 additions & 160 deletions

File tree

build.sbt

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,11 @@ addCommandAlias("rctc", "reload; ctc")
3030

3131
// ### Dependencies ###
3232

33+
val zioVersion = "2.1.25"
34+
3335
lazy val testKitLibs = Seq(
34-
"org.scalacheck" %% "scalacheck" % "1.19.0",
35-
"org.scalactic" %% "scalactic" % "3.2.20",
36-
"org.scalatest" %% "scalatest" % "3.2.20",
36+
"dev.zio" %% "zio-test" % zioVersion,
37+
"dev.zio" %% "zio-test-sbt" % zioVersion,
3738
).map(_ % Test)
3839

3940
lazy val poi =
@@ -45,15 +46,6 @@ lazy val poi =
4546
)
4647
)("4.1.0")
4748

48-
lazy val monix =
49-
(
50-
(version: String) =>
51-
Seq(
52-
"io.monix" %% "monix-execution" % version,
53-
"io.monix" %% "monix-eval" % version,
54-
)
55-
)("3.4.1")
56-
5749
// ### Modules ###
5850

5951
lazy val root =
@@ -69,7 +61,9 @@ lazy val core =
6961
.settings(stdSettings *)
7062
.settings(
7163
libraryDependencies ++= Seq(
64+
"dev.zio" %% "zio" % zioVersion,
7265
"io.github.kantan-scala" %% "kantan.csv" % "0.11.0",
7366
"com.github.pathikrit" %% "better-files" % "3.9.2",
74-
) ++ monix ++ poi ++ testKitLibs
67+
) ++ poi ++ testKitLibs,
68+
testFrameworks += new TestFramework("zio.test.sbt.ZTestFramework"),
7569
)

core/src/main/scala/com/colisweb/jruby/concurrent/constant/memory/excel/ConcurrentConstantMemoryExcel.scala

Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
package com.colisweb.jruby.concurrent.constant.memory.excel
22

3-
import cats.effect.Resource
43
import com.colisweb.jruby.concurrent.constant.memory.excel.utils.KantanExtension
54
import kantan.csv.{CellDecoder, CellEncoder}
6-
import monix.eval.Task
7-
import monix.execution.Scheduler
8-
import monix.execution.atomic.Atomic
95
import org.apache.poi.ss.usermodel.*
106
import org.apache.poi.ss.util.WorkbookUtil
117
import org.apache.poi.xssf.streaming.SXSSFWorkbook
8+
import zio.*
129

1310
import java.io.{File, FileOutputStream}
1411
import java.nio.file.{Files, Path}
1512
import java.util.UUID
13+
import java.util.concurrent.atomic.AtomicReference
1614
import scala.annotation.switch
1715
import scala.collection.immutable.SortedSet
1816
import scala.collection.mutable.ListBuffer
@@ -68,46 +66,47 @@ object ConcurrentConstantMemoryExcel {
6866

6967
private[excel] type Row = Array[Cell]
7068

71-
private given Codec = Codec.UTF8
72-
private given Scheduler = Scheduler.computation(name = "ConcurrentConstantMemoryExcel-computation")
69+
private given Codec = Codec.UTF8
7370

7471
final val blankCell: Cell = Cell.BlankCell
7572

7673
final def stringCell(value: String): Cell = Cell.StringCell(value)
7774

7875
final def numericCell(value: Double): Cell = Cell.NumericCell(value)
7976

80-
final def newWorkbookState(sheetName: String, headerValues: Array[String]): Atomic[ConcurrentConstantMemoryState] =
81-
Atomic(
77+
final def newWorkbookState(
78+
sheetName: String,
79+
headerValues: Array[String],
80+
): AtomicReference[ConcurrentConstantMemoryState] =
81+
AtomicReference(
8282
ConcurrentConstantMemoryState(
8383
sheetName = WorkbookUtil.createSafeSheetName(sheetName),
8484
headerData = headerValues,
8585
tmpDirectory = Files.createTempDirectory(UUID.randomUUID().toString).toFile,
8686
tasks = List.empty,
87-
pages = SortedSet.empty
87+
pages = SortedSet.empty,
8888
)
8989
)
9090

9191
final def addRows(
92-
atomicCms: Atomic[ConcurrentConstantMemoryState],
92+
atomicCms: AtomicReference[ConcurrentConstantMemoryState],
9393
computeRows: => Array[Row],
94-
pageIndex: Int
94+
pageIndex: Int,
9595
): Unit = {
9696
import KantanExtension.arrayEncoder
9797

9898
val tmpCsvFile = java.io.File.createTempFile(UUID.randomUUID().toString, ".csv", atomicCms.get().tmpDirectory)
9999
val newPage = Page(pageIndex, tmpCsvFile.toPath)
100-
val task = Task(tmpCsvFile.writeCsv[Row](computeRows, rfc))
100+
val task = ZIO.attempt(tmpCsvFile.writeCsv[Row](computeRows, rfc))
101101

102-
atomicCms.transform { cms =>
103-
cms.copy(pages = cms.pages + newPage, tasks = cms.tasks :+ task)
104-
}
102+
atomicCms.updateAndGet(cms => cms.copy(pages = cms.pages + newPage, tasks = cms.tasks :+ task))
103+
()
105104
}
106105

107-
final def writeFile(atomicCms: Atomic[ConcurrentConstantMemoryState], fileName: String): Unit = {
106+
final def writeFile(atomicCms: AtomicReference[ConcurrentConstantMemoryState], fileName: String): Unit = {
108107
val cms = atomicCms.get()
109108

110-
def computeWorkbookData(wb: SXSSFWorkbook): Task[Unit] = Task {
109+
def computeWorkbookData(wb: SXSSFWorkbook): Task[Unit] = ZIO.attempt {
111110
val sheet = wb.createSheet(cms.sheetName)
112111
sheet.setDefaultColumnWidth(24)
113112

@@ -147,37 +146,29 @@ object ConcurrentConstantMemoryExcel {
147146
}
148147

149148
// TODO: Expose the `swallowIOExceptions` parameter in the `writeFile` function ?
150-
def clean(swallowIOExceptions: Boolean = false): Task[Unit] = Task {
149+
def clean(swallowIOExceptions: Boolean = false): Task[Unit] = ZIO.attempt {
151150
import better.files.* // better-files `delete()` method also works on directories, unlike the Java one.
152151
cms.tmpDirectory.toScala.delete(swallowIOExceptions)
153152
()
154153
}
155154

156-
// Used as a Resource to ease the clean of the temporary CSVs created during the tasks calcultation.
157-
val computeIntermediateTmpCsvFiles: Resource[Task, Unit] =
158-
Resource.make(Task.parSequenceUnordered(cms.tasks).flatMap(_ => Task.unit))(_ => clean())
159-
160-
val workbookResource: Resource[Task, SXSSFWorkbook] =
161-
Resource.make {
162-
// We'll manually manage the `flush` to the hard drive.
163-
Task(new SXSSFWorkbook(-1))
164-
}((wb: SXSSFWorkbook) =>
165-
Task {
166-
wb.dispose() // dispose of temporary files backing this workbook on disk. Necessary because not done in the `close()`. See: https://stackoverflow.com/a/50363245
167-
wb.close()
168-
}
169-
)
170-
171-
val fileOutputStreamResource: Resource[Task, FileOutputStream] =
172-
Resource.make(Task(new FileOutputStream(fileName)))(out => Task(out.close()))
173-
174-
computeIntermediateTmpCsvFiles
175-
.use { _ =>
176-
workbookResource.use { wb =>
177-
computeWorkbookData(wb).flatMap(_ => fileOutputStreamResource.use(out => Task(wb.write(out))))
178-
}
179-
}
180-
.runSyncUnsafe()
155+
val program: ZIO[Scope, Throwable, Unit] =
156+
for {
157+
_ <- ZIO.acquireRelease(ZIO.collectAllParDiscard(cms.tasks))(_ => clean().orDie)
158+
wb <- ZIO.acquireRelease(ZIO.attempt(new SXSSFWorkbook(-1)))(wb =>
159+
ZIO.succeed {
160+
wb.dispose() // dispose of temporary files backing this workbook on disk. Necessary because not done in the `close()`. See: https://stackoverflow.com/a/50363245
161+
wb.close()
162+
}
163+
)
164+
_ <- computeWorkbookData(wb)
165+
out <- ZIO.acquireRelease(ZIO.attempt(new FileOutputStream(fileName)))(out => ZIO.succeed(out.close()))
166+
_ <- ZIO.attempt(wb.write(out))
167+
} yield ()
168+
169+
Unsafe.unsafe { implicit unsafe =>
170+
Runtime.default.unsafe.run(ZIO.scoped(program)).getOrThrowFiberFailure()
171+
}
181172
}
182173

183174
}

0 commit comments

Comments
 (0)