Skip to content

Commit

Permalink
Scala-js
Browse files Browse the repository at this point in the history
Revert scalameter to 0.19
  • Loading branch information
gekomad committed Nov 17, 2024
1 parent dd4e148 commit 71a04af
Show file tree
Hide file tree
Showing 65 changed files with 7,229 additions and 44 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

Itto-CSV is a pure scala library for working with the CSV format

`libraryDependencies += "com.github.gekomad" %% "itto-csv" % "2.1.0"`
The latest version of the library is available for Scala 2.12, 2.13, 3 and Scala-js.

Scala 2.12 and 2.13
`libraryDependencies += "com.github.gekomad" %% "itto-csv" % "2.1.1"`

Scala 2
-------
View [microsite](https://gekomad.github.io/itto-csv/v1/docs/) for more information.

Expand Down
6 changes: 4 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@

lazy val root = (project in file(".")).aggregate(scala2, scala3)
lazy val `itto-csv` = (project in file(".")).aggregate(scala2, scala3, scala2Js, scala3Js)

lazy val scala2 = project in file("scala2")

lazy val scala3 = project in file("scala3")

lazy val scala2Js = project in file("scala2_js")

lazy val scala3Js = project in file("scala3_js")
2 changes: 2 additions & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.12.2")
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.0")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.2.2")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.17.0")
addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.21.1")
30 changes: 11 additions & 19 deletions scala2/build.sbt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name := "itto-csv"
version := "2.1.0"
version := "2.1.1"
organization := "com.github.gekomad"
//scalaVersion := "2.12.20"
scalaVersion := "2.13.15"
//scalaVersion := "2.12.20"
val fs2Version = "3.11.0"
scalacOptions ++= {
if (scalaVersion.value.startsWith("2.12")) {
Expand Down Expand Up @@ -32,28 +32,20 @@ scalacOptions ++= Seq(
"-Xfatal-warnings"
)

//cats

libraryDependencies += "co.fs2" %% "fs2-core" % fs2Version
libraryDependencies += "co.fs2" %% "fs2-io" % fs2Version
libraryDependencies += "co.fs2" %% "fs2-core" % fs2Version
libraryDependencies += "co.fs2" %% "fs2-io" % fs2Version
libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.12"
libraryDependencies += "com.github.gekomad" %% "scala-regex-collection" % "2.0.1"
libraryDependencies += "com.storm-enroute" %% "scalameter" % "0.19" % Test
libraryDependencies += "org.scalameta" %% "munit" % "1.0.2" % Test
libraryDependencies += "org.apache.commons" % "commons-csv" % "1.12.0" % Test
libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.18.1" % Test

//shapeless
libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.12"

//scala-regex-collection
libraryDependencies += "com.github.gekomad" %% "scala-regex-collection" % "2.0.0"

//test
libraryDependencies += "com.storm-enroute" %% "scalameter" % "0.21" % Test
libraryDependencies += "org.scalameta" %% "munit" % "1.0.2" % Test
libraryDependencies += "org.apache.commons" % "commons-csv" % "1.12.0" % Test
libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.18.1" % Test
testFrameworks += new TestFramework("munit.Framework")
Test / testOptions += Tests.Argument(TestFrameworks.ScalaCheck, "-minSuccessfulTests", "1000")

//sonatype
publishTo := sonatypePublishToBundle.value
logLevel := Level.Debug

pomExtra :=
<licenses>
<license>
Expand Down
18 changes: 9 additions & 9 deletions scala2/src/test/scala/StringToCsvFieldMeter.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import com.github.gekomad.ittocsv.parser.{IttoCSVFormat, StringToCsvField}
import org.apache.commons.csv.CSVFormat
import org.scalacheck.Gen
import org.scalameter.{config, Key, KeyValue, Warmer}
import org.scalameter.{Key, Warmer, config}

class StringToCsvFieldMeter extends munit.FunSuite {

Expand All @@ -10,24 +10,24 @@ class StringToCsvFieldMeter extends munit.FunSuite {
implicit val csvFormat: IttoCSVFormat = IttoCSVFormat.default

val standardConfig = config(
KeyValue((Key.exec.minWarmupRuns, 20)),
KeyValue((Key.exec.maxWarmupRuns, 100000)),
KeyValue((Key.exec.benchRuns, 200)),
KeyValue((Key.verbose, false))
).withWarmer(new Warmer.Default)
Key.exec.minWarmupRuns -> 20,
Key.exec.maxWarmupRuns -> 100000,
Key.exec.benchRuns -> 200,
Key.verbose -> false
) withWarmer new Warmer.Default

val asciiStringGen = Gen.asciiPrintableStr.map(_.mkString.take(20))
val l = Gen.listOfN(100, asciiStringGen).sample.get

val apacheTime = {
implicit val _a = CSVFormat.DEFAULT
standardConfig.measure(l.foreach(ApacheCommonCsvHelper.fildParser))
standardConfig measure l.foreach(ApacheCommonCsvHelper.fildParser)
}

{
val ittoTime = standardConfig.measure(l.foreach(StringToCsvField.stringToCsvField))
val ittoTime = standardConfig measure l.foreach(StringToCsvField.stringToCsvField)
printf(f"** itto-csv time: ${ittoTime.value}%1.2f apache-csv time: ${apacheTime.value}%1.2f**\n")
}
}

}
}
16 changes: 9 additions & 7 deletions scala2/src/test/scala/TokenizeCsvMeter.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import com.github.gekomad.ittocsv.parser.IttoCSVFormat
import org.scalacheck.Gen
import org.scalameter.{Key, KeyValue, Warmer, config}
import org.scalameter.{Key, Warmer, config}


class TokenizeCsvMeter extends munit.FunSuite {

Expand All @@ -9,11 +10,12 @@ class TokenizeCsvMeter extends munit.FunSuite {
implicit val csvFormat: IttoCSVFormat = IttoCSVFormat.default
import com.github.gekomad.ittocsv.util.StringUtils._
val standardConfig = config(
KeyValue((Key.exec.minWarmupRuns, 20)),
KeyValue((Key.exec.maxWarmupRuns, 100000)),
KeyValue((Key.exec.benchRuns, 200)),
KeyValue((Key.verbose, false))
).withWarmer(new Warmer.Default)
Key.exec.minWarmupRuns -> 20,
Key.exec.maxWarmupRuns -> 100000,
Key.exec.benchRuns -> 1000,
Key.verbose -> false
) withWarmer new Warmer.Default

val asciiStringGen = Gen.asciiPrintableStr.map(_.mkString.take(40))
val l = Gen.listOfN(1000, asciiStringGen).sample.get

Expand All @@ -24,4 +26,4 @@ class TokenizeCsvMeter extends munit.FunSuite {
}
printf(f"** tokenizeCsvMeter time: ${time.value}%1.2f **\n")
}
}
}
59 changes: 59 additions & 0 deletions scala2_js/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name := "itto-csv"
publishTo := sonatypePublishTo.value

import org.scalajs.linker.interface.{ESVersion, ModuleSplitStyle}

lazy val scala2Js = project
.in(file("."))
.enablePlugins(ScalaJSPlugin)
.settings(
version := "2.1.1",
scalaVersion := "2.13.15",
//scalaVersion := "2.12.20",
organization := "com.github.gekomad",
scalaJSUseMainModuleInitializer := false,
scalaJSLinkerConfig ~= (_.withESFeatures(_.withESVersion(ESVersion.ES2018))),
scalaJSLinkerConfig ~= {
_.withModuleKind(ModuleKind.ESModule)
.withModuleSplitStyle(ModuleSplitStyle.SmallModulesFor(List("scala2Js")))
},

scalacOptions ++= {
if (scalaVersion.value.startsWith("2.12")) {
Seq("-Ypartial-unification", "-Xfatal-warnings")
} else {
Seq("-Xfatal-warnings")
}
},
libraryDependencies += "co.fs2" %%% "fs2-core" % "3.11.0",
libraryDependencies += "co.fs2" %%% "fs2-io" % "3.11.0",
libraryDependencies += "com.chuusai" %%% "shapeless" % "2.3.12",
libraryDependencies += "com.github.gekomad" %%% "scala-regex-collection" % "2.0.1",
libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.8.0",
libraryDependencies += "org.scalameta" %%% "munit" % "1.0.2" % Test,
libraryDependencies += "org.scalacheck" %%% "scalacheck" % "1.18.1" % Test
)

//sonatype
publishTo := sonatypePublishToBundle.value

pomExtra :=
<licenses>
<license>
<name>Apache 2</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>gekomad</id>
<name>Giuseppe Cannella</name>
<url>https://github.com/gekomad</url>
</developer>
</developers>
<scm>
<url>https://github.com/gekomad/itto-csv</url>
<connection>scm:git:https://github.com/gekomad/itto-csv</connection>
</scm>
<url>https://github.com/gekomad/itto-csv</url>
1 change: 1 addition & 0 deletions scala2_js/project/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sbt.version=1.10.5
3 changes: 3 additions & 0 deletions scala2_js/project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.5")
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.17.0")
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.github.gekomad.ittocsv.core

import java.util.UUID
import com.github.gekomad.ittocsv.util.TryTo.tryToEither

/** Converts a string to type
*
* @author
* Giuseppe Cannella
* @since 0.0.1
* @see
* See test code for more information
* @see
* See [[https://github.com/gekomad/itto-csv/blob/master/README.md]] for more information.
*/
object Conversions {

trait ConvertTo[A] {
def to(a: String): Either[ParseFailure, A]
}

implicit val toInts: ConvertTo[Int] = (a: String) => tryToEither(a.toInt)(ParseFailure(s"$a is not Int"))

implicit val toDoubles: ConvertTo[Double] = (a: String) => tryToEither(a.toDouble)(ParseFailure(s"$a is not Double"))

implicit val toBytes: ConvertTo[Byte] = (a: String) => tryToEither(a.toByte)(ParseFailure(s"$a is not Byte"))

implicit val toShorts: ConvertTo[Short] = (a: String) => tryToEither(a.toShort)(ParseFailure(s"$a is not Short"))

implicit val toFloats: ConvertTo[Float] = (a: String) => tryToEither(a.toFloat)(ParseFailure(s"$a is not Float"))

implicit val toLongs: ConvertTo[Long] = (a: String) => tryToEither(a.toLong)(ParseFailure(s"$a is not Long"))

implicit val toChars: ConvertTo[Char] = (a: String) =>
tryToEither(if (a.length == 1) a(0) else throw new Exception)(ParseFailure(s"$a is not Char"))

implicit val toBooleans: ConvertTo[Boolean] = (a: String) =>
tryToEither(a.toBoolean)(ParseFailure(s"$a is not Boolean"))

implicit val toUUIDS: ConvertTo[UUID] = (a: String) =>
tryToEither(UUID.fromString(a))(ParseFailure(s"$a is not UUID"))

import java.time._
import java.time.format.DateTimeFormatter._

implicit def fromGenericOption[A](implicit
f: String => Either[ParseFailure, A]
): String => Either[ParseFailure, Option[A]] =
s => if (s == "") Right(None) else f(s).map(Some(_))

implicit val fromStringToLocalDateTime: String => Either[ParseFailure, LocalDateTime] = { s =>
tryToEither(LocalDateTime.parse(s, ISO_LOCAL_DATE_TIME))(ParseFailure(s"Not a LocalDataTime $s"))
}

implicit val fromStringToLocalDate: String => Either[ParseFailure, LocalDate] = { s =>
tryToEither(LocalDate.parse(s, ISO_LOCAL_DATE))(ParseFailure(s"Not a LocalDate $s"))
}

implicit val fromStringToLocalTime: String => Either[ParseFailure, LocalTime] =
(s: String) => tryToEither(LocalTime.parse(s, ISO_LOCAL_TIME))(ParseFailure(s"Not a LocalTime $s"))

implicit val fromStringToOffsetDateTime: String => Either[ParseFailure, OffsetDateTime] =
(s: String) => tryToEither(OffsetDateTime.parse(s, ISO_OFFSET_DATE_TIME))(ParseFailure(s"Not a OffsetDateTime $s"))

implicit val fromStringToOffsetTime: String => Either[ParseFailure, OffsetTime] =
(s: String) => tryToEither(OffsetTime.parse(s, ISO_OFFSET_TIME))(ParseFailure(s"Not a OffsetTime $s"))

implicit val fromStringToZonedDateTime: String => Either[ParseFailure, ZonedDateTime] =
(s: String) => tryToEither(ZonedDateTime.parse(s, ISO_ZONED_DATE_TIME))(ParseFailure(s"Not a ZonedDateTime $s"))

implicit val fromStringInstant: String => Either[ParseFailure, Instant] =
(s: String) => tryToEither(Instant.parse(s))(ParseFailure(s"Not a Instant $s"))

def convert[A](s: String)(implicit f: ConvertTo[A]): Either[ParseFailure, A] = f.to(s)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.github.gekomad.ittocsv.core

import cats.{Applicative, Id}
import cats.data.{Validated, ValidatedNel}
import com.github.gekomad.ittocsv.core.Conversions.ConvertTo
import com.github.gekomad.ittocsv.core.Types.Validate
import com.github.gekomad.ittocsv.parser.IttoCSVFormat
import com.github.gekomad.ittocsv.util.TryTo._
import com.github.gekomad.ittocsv.core.Conversions.convert
trait Convert[V] {
def parse(input: String): ValidatedNel[ParseFailure, V]
}
import scala.language.higherKinds
object Convert {
import cats.implicits._

def to[V](input: String)(implicit C: Convert[V]): ValidatedNel[ParseFailure, V] = C.parse(input)

def instance[V](body: String => ValidatedNel[ParseFailure, V]): Convert[V] = (input: String) => body(input)

def f[A: ConvertTo, F[_]: Applicative](implicit csvFormat: IttoCSVFormat): Convert[F[List[A]]] =
Convert.instance(
_.split(csvFormat.delimeter.toString, -1).toList
.map(s => tryToValidate(convert[A](s).getOrElse(throw new Exception))(ParseFailure(s"Bad type on $s")))
.sequence
.map(Applicative[F].pure(_))
)

implicit def optionLists[A: ConvertTo](implicit csvFormat: IttoCSVFormat): Convert[Option[List[A]]] = f[A, Option]

implicit def lists[A: ConvertTo](implicit csvFormat: IttoCSVFormat): Convert[List[A]] = f[A, Id]

implicit def genericValidator[A](implicit csvFormat: IttoCSVFormat, validator: Validate[A]): Convert[A] =
Convert.instance(validator.validate(_).toValidatedNel)

implicit def generic[A](implicit f: String => Either[ParseFailure, A]): Convert[A] =
Convert.instance(f(_).toValidatedNel)

implicit val optionBoolean: Convert[Option[Boolean]] = Convert.instance {
case "" => Validated.valid(None)
case s => tryToValidate(Some(s.toBoolean))(ParseFailure(s"Not a Boolean for input string: $s"))
}

implicit val optionShort: Convert[Option[Short]] = Convert.instance {
case "" => Validated.valid(None)
case s => tryToValidate(Some(s.toShort))(ParseFailure(s"Not a Short for input string: $s"))
}

implicit val optionByte: Convert[Option[Byte]] = Convert.instance {
case "" => Validated.valid(None)
case s => tryToValidate(Some(s.toByte))(ParseFailure(s"Not a Byte for input string: $s"))
}

implicit val optionChar: Convert[Option[Char]] = Convert.instance {
case "" => Validated.valid(None)
case s =>
tryToValidate(if (s.length == 1) Some(s(0)) else throw new Exception)(
ParseFailure(s"Not a Char for input string: $s")
)
}

implicit val optionString: Convert[Option[String]] = Convert.instance {
case "" => Validated.valid(None)
case s => Validated.valid(Some(s))
}

implicit val optionDouble: Convert[Option[Double]] = Convert.instance {
case "" => Validated.valid(None)
case s => tryToValidate(Some(s.toDouble))(ParseFailure(s"Not a Double for input string: $s"))
}

implicit val optionInt: Convert[Option[Int]] = Convert.instance {
case "" => Validated.valid(None)
case s => tryToValidate(Some(s.toInt))(ParseFailure(s"Not a Int for input string: $s"))
}

implicit def gen[A](implicit conv: ConvertTo[A]): Convert[A] = Convert.instance(conv.to(_).toValidatedNel)

implicit val strings: Convert[String] = Convert.instance(_.validNel)
}
Loading

0 comments on commit 71a04af

Please sign in to comment.