(minor) Version updates, ScalaDoc, bug fixes. (#6)
All checks were successful
/ Build and Release Library (push) Successful in 1m59s

Reviewed-on: #6
This commit is contained in:
Pat Garrity 2025-03-23 20:02:08 +00:00
parent 32a69d734b
commit 2982d729bf
7 changed files with 323 additions and 35 deletions

View file

@ -1,4 +1,4 @@
val scala3: String = "3.4.2"
val scala3: String = "3.6.4"
ThisBuild / scalaVersion := scala3
ThisBuild / versionScheme := Some("semver-spec")
@ -22,7 +22,7 @@ val sharedSettings = Seq(
lazy val testSettings = Seq(
libraryDependencies ++= Seq(
"org.scalameta" %% "munit" % "1.0.0" % Test
"org.scalameta" %% "munit" % "1.1.0" % Test
)
)
@ -39,6 +39,6 @@ lazy val core = project
.settings(name := s"${gsProjectName.value}-core-v${semVerMajor.value}")
.settings(
libraryDependencies ++= Seq(
"gs" %% "gs-uuid-v0" % "0.3.0"
"gs" %% "gs-uuid-v0" % "0.4.0"
)
)

View file

@ -7,11 +7,23 @@ trait Generated[A]:
object Generated:
/** Summon an instance of the [[Generated]] type class.
*
* @param G
* The type class instance.
* @return
* The summoned instance of [[Generated]].
*/
def apply[A](
using
G: Generated[A]
): Generated[A] = G
/** Implementation of [[Generated]] based on an instance of [[Gen]].
*
* @param gen
* The underlying [[Gen]] used to produce values.
*/
final class FromGenerator[A](gen: Gen[A]) extends Generated[A]:
override def generate(): A = gen.gen()

View file

@ -145,11 +145,11 @@ object Gen:
end option
/** Generator for a list of some [[Size]] based on a generator for the list
* elements.
/** Generator for a list of some [[gs.datagen.v0.generators.Size]] based on a
* generator for the list elements.
*
* @param size
* The [[Size]] of the list.
* The [[gs.datagen.v0.generators.Size]] of the list.
* @param gen
* The generator for the list elements.
*/
@ -158,12 +158,12 @@ object Gen:
gen: Gen[A]
): Gen[List[A]] = new GenList[A](size, gen)
/** Generator for a set of some [[Size]] based on a generator for the set
* elements.
/** Generator for a set of some [[gs.datagen.v0.generators.Size]] based on a
* generator for the set elements.
*
* @param size
* The goal [[Size]] of the set. If duplicate elements are generated, the
* size will be less then specified.
* The goal [[gs.datagen.v0.generators.Size]] of the set. If duplicate
* elements are generated, the size will be less then specified.
* @param gen
* The generator for the list elements.
*/
@ -234,7 +234,7 @@ object Gen:
* values.
*
* @param size
* The [[Size]] of the generated map.
* The [[gs.datagen.v0.generators.Size]] of the generated map.
* @param keyGen
* The generator for keys.
* @param valueGen
@ -255,7 +255,7 @@ object Gen:
* keys to values.
*
* @param size
* The [[Size]] of the generated map.
* The [[gs.datagen.v0.generators.Size]] of the generated map.
* @param keyValueGen
* The generator for key/value pairs.
*/
@ -274,8 +274,9 @@ object Gen:
*/
object string:
/** Generator for a string of the specified [[Size]], where the characters
* are restricted by the given alphabet.
/** Generator for a string of the specified
* [[gs.datagen.v0.generators.Size]], where the characters are restricted
* by the given alphabet.
*
* @param size
* The size constraints for the generated string.
@ -291,8 +292,9 @@ object Gen:
size = size
)
/** Generator for a string of the specified [[Size]], where the characters
* are restricted to ASCII lowercase letters.
/** Generator for a string of the specified
* [[gs.datagen.v0.generators.Size]], where the characters are restricted
* to ASCII lowercase letters.
*
* @param size
* The size constraints for the generated string.
@ -305,8 +307,9 @@ object Gen:
size = size
)
/** Generator for a string of the specified [[Size]], where the characters
* are restricted to ASCII uppercase letters.
/** Generator for a string of the specified
* [[gs.datagen.v0.generators.Size]], where the characters are restricted
* to ASCII uppercase letters.
*
* @param size
* The size constraints for the generated string.
@ -319,8 +322,9 @@ object Gen:
size = size
)
/** Generator for a string of the specified [[Size]], where the characters
* are restricted to ASCII letters.
/** Generator for a string of the specified
* [[gs.datagen.v0.generators.Size]], where the characters are restricted
* to ASCII letters.
*
* @param size
* The size constraints for the generated string.
@ -333,8 +337,9 @@ object Gen:
size = size
)
/** Generator for a string of the specified [[Size]], where the characters
* are restricted to ASCII letters and numbers.
/** Generator for a string of the specified
* [[gs.datagen.v0.generators.Size]], where the characters are restricted
* to ASCII letters and numbers.
*
* @param size
* The size constraints for the generated string.
@ -347,8 +352,9 @@ object Gen:
size = size
)
/** Generator for a string of the specified [[Size]], where the characters
* are restricted to lowercase ASCII letters and numbers.
/** Generator for a string of the specified
* [[gs.datagen.v0.generators.Size]], where the characters are restricted
* to lowercase ASCII letters and numbers.
*
* @param size
* The size constraints for the generated string.
@ -361,8 +367,9 @@ object Gen:
size = size
)
/** Generator for a string of the specified [[Size]], where the characters
* are restricted to uppercase ASCII letters and numbers.
/** Generator for a string of the specified
* [[gs.datagen.v0.generators.Size]], where the characters are restricted
* to uppercase ASCII letters and numbers.
*
* @param size
* The size constraints for the generated string.
@ -377,7 +384,7 @@ object Gen:
end string
/** Generators for integers.
/** Generators for integers (32-bit integers).
*/
object integer:
@ -411,7 +418,7 @@ object Gen:
end integer
/** Generators for longs.
/** Generators for longs (64-bit integers).
*/
object long:
@ -453,7 +460,7 @@ object Gen:
*
* ## Example
*
* The following generator produces a date before today where:
* The following generator produces a date before the given date where:
*
* - The day component is subtracted by 0 to 10.
* - The month component is subtracted by 1 to 11.
@ -494,6 +501,37 @@ object Gen:
years = years
)
/** Generate a date before the current date.
*
* ## Example
*
* The following generator produces a date before **today** where:
*
* - The day component is subtracted by 0 to 10.
* - The month component is subtracted by 1 to 11.
* - The year component is subtracted by 0 to 30.
*
* The produced date will be, at most, 30 years, 11 months and 10 days
* prior to the selected pivot. It will be at least 1 month prior to the
* selected pivot.
*
* {{{
* Gen.date.beforeToday(
* days = MinMax.nonNegative(0, 10),
* months = MinMax.nonNegative(1, 11),
* years = MinMax.nonNegative(0, 30)
* )
* }}}
*
* @param date
* The maximum date.
* @param days
* The range of days prior to today.
* @param months
* The range of months prior to today.
* @param years
* The range of years prior to today.
*/
def beforeToday(
days: MinMax.NonNegative,
months: MinMax.NonNegative = MinMax.Zero,
@ -507,6 +545,38 @@ object Gen:
years = years
)
/** Generate a date after the given date.
*
* ## Example
*
* The following generator produces a date after the given date where:
*
* - The day component is added by 0 to 10.
* - The month component is added by 1 to 11.
* - The year component is added by 0 to 30.
*
* The produced date will be, at most, 30 years, 11 months and 10 days
* after the selected pivot. It will be at least 1 month after the selected
* pivot.
*
* {{{
* Gen.date.after(
* date = LocalDate.now(),
* days = MinMax.nonNegative(0, 10),
* months = MinMax.nonNegative(1, 11),
* years = MinMax.nonNegative(0, 30)
* )
* }}}
*
* @param date
* The maximum date.
* @param days
* The range of days after the given date.
* @param months
* The range of months after the given date.
* @param years
* The range of years after the given date.
*/
def after(
date: LocalDate,
days: MinMax.NonNegative,
@ -520,6 +590,38 @@ object Gen:
years = years
)
/** Generate a date after the current date.
*
* ## Example
*
* The following generator produces a date after the **current** date
* where:
*
* - The day component is added by 0 to 10.
* - The month component is added by 1 to 11.
* - The year component is added by 0 to 30.
*
* The produced date will be, at most, 30 years, 11 months and 10 days
* after the selected pivot. It will be at least 1 month after the selected
* pivot.
*
* {{{
* Gen.date.afterToday(
* days = MinMax.nonNegative(0, 10),
* months = MinMax.nonNegative(1, 11),
* years = MinMax.nonNegative(0, 30)
* )
* }}}
*
* @param date
* The maximum date.
* @param days
* The range of days after today.
* @param months
* The range of months after today.
* @param years
* The range of years after today.
*/
def afterToday(
days: MinMax.NonNegative,
months: MinMax.NonNegative = MinMax.Zero,
@ -533,26 +635,89 @@ object Gen:
years = years
)
/** Generate a date around (centered upon) the given date.
*
* ## Example
*
* The following generator produces a date around the given date where:
*
* - The day component is added or subtracted by 0 to 10.
* - The month component is added or subtracted by 1 to 11.
* - The year component is added or subtracted by 0 to 30.
*
* The produced date will be, at most, 30 years, 11 months and 10 days
* before or after the selected pivot. It will be at least 1 month before
* or after the selected pivot.
*
* {{{
* Gen.date.around(
* date = LocalDate.now(),
* days = MinMax.nonNegative(0, 10),
* months = MinMax.nonNegative(1, 11),
* years = MinMax.nonNegative(0, 30)
* )
* }}}
*
* @param date
* The maximum date.
* @param days
* The range of days before or after the given date.
* @param months
* The range of months before or after the given date.
* @param years
* The range of years before or after the given date.
*/
def around(
date: LocalDate,
days: MinMax,
months: MinMax = MinMax.Zero,
years: MinMax = MinMax.Zero
): Gen[LocalDate] =
new GenLocalDate.After(
new GenLocalDate.Around(
pivot = date,
days = days,
months = months,
years = years
)
/** Generate a date around (centered upon) today.
*
* ## Example
*
* The following generator produces a date around today where:
*
* - The day component is added or subtracted by 0 to 10.
* - The month component is added or subtracted by 1 to 11.
* - The year component is added or subtracted by 0 to 30.
*
* The produced date will be, at most, 30 years, 11 months and 10 days
* before or after today. It will be at least 1 month before or after
* today.
*
* {{{
* Gen.date.around(
* days = MinMax.nonNegative(0, 10),
* months = MinMax.nonNegative(1, 11),
* years = MinMax.nonNegative(0, 30)
* )
* }}}
*
* @param date
* The maximum date.
* @param days
* The range of days before or after today.
* @param months
* The range of months before or after today.
* @param years
* The range of years before or after today.
*/
def aroundToday(
days: MinMax,
months: MinMax = MinMax.Zero,
years: MinMax = MinMax.Zero,
clock: Clock = DefaultClock
): Gen[LocalDate] =
new GenLocalDate.After(
new GenLocalDate.Around(
pivot = LocalDate.now(clock),
days = days,
months = months,

View file

@ -2,11 +2,28 @@ package gs.datagen.v0.generators
import gs.datagen.v0.Gen
import java.time.LocalDate
import java.util.Random
/** Base for generators that produce `java.time.LocalDate` values.
*/
trait GenLocalDate extends Gen[LocalDate]
/** Provids implementations for [[GenLocalDate]].
*/
object GenLocalDate:
/** Implementation of [[GenLocalDate]] that selects random dates before some
* given date.
*
* @param pivot
* The pivot date before which random values are selected.
* @param days
* The day bound.
* @param months
* The month bound.
* @param years
* The year bound.
*/
final class Before(
val pivot: LocalDate,
val days: MinMax,
@ -14,6 +31,8 @@ object GenLocalDate:
val years: MinMax
) extends GenLocalDate:
/** @inheritDocs
*/
override def generate(input: Any): LocalDate =
val rng = Gen.rng()
pivot
@ -21,6 +40,18 @@ object GenLocalDate:
.minusMonths(months.select(rng).toInt)
.minusYears(years.select(rng).toInt)
/** Implementation of [[GenLocalDate]] that selects random dates after some
* given date.
*
* @param pivot
* The pivot date after which random values are selected.
* @param days
* The day bound.
* @param months
* The month bound.
* @param years
* The year bound.
*/
final class After(
val pivot: LocalDate,
val days: MinMax,
@ -28,6 +59,8 @@ object GenLocalDate:
val years: MinMax
) extends GenLocalDate:
/** @inheritDocs
*/
override def generate(input: Any): LocalDate =
val rng = Gen.rng()
pivot
@ -35,4 +68,82 @@ object GenLocalDate:
.plusMonths(months.select(rng).toInt)
.plusYears(years.select(rng).toInt)
/** Implementation of [[GenLocalDate]] that selects random dates centered on
* some given date.
*
* @param pivot
* The pivot date around which random values are selected.
* @param days
* The day bound.
* @param months
* The month bound.
* @param years
* The year bound.
*/
final class Around(
val pivot: LocalDate,
val days: MinMax,
val months: MinMax,
val years: MinMax
) extends GenLocalDate:
/** @inheritDocs
*/
override def generate(input: Any): LocalDate =
val rng = Gen.rng()
pivot
.plusOrMinusDays(rng, days)
.plusOrMinusMonths(rng, months)
.plusOrMinusYears(rng, years)
extension (base: LocalDate)
/** Select a bounded random number of days before or after the base date.
*
* @param rng
* The random generator.
* @param range
* The bounded range.
* @return
* The new date.
*/
def plusOrMinusDays(
rng: Random,
range: MinMax
): LocalDate =
if rng.nextBoolean() then base.plusDays(range.select(rng).toInt)
else base.minusDays(range.select(rng).toInt)
/** Select a bounded random number of months before or after the base date.
*
* @param rng
* The random generator.
* @param range
* The bounded range.
* @return
* The new date.
*/
def plusOrMinusMonths(
rng: Random,
range: MinMax
): LocalDate =
if rng.nextBoolean() then base.plusMonths(range.select(rng).toInt)
else base.minusMonths(range.select(rng).toInt)
/** Select a bounded random number of years before or after the base date.
*
* @param rng
* The random generator.
* @param range
* The bounded range.
* @return
* The new date.
*/
def plusOrMinusYears(
rng: Random,
range: MinMax
): LocalDate =
if rng.nextBoolean() then base.plusYears(range.select(rng).toInt)
else base.minusYears(range.select(rng).toInt)
end GenLocalDate

View file

@ -4,7 +4,7 @@ import gs.datagen.v0.Gen
import gs.uuid.v0.UUID
final class GenUUID extends Gen[UUID]:
given UUID.Generator = UUID.Generator.version4()
given UUID.Generator = UUID.Generator.version4
override def generate(input: Any): UUID =
UUID.generate()

View file

@ -1 +1 @@
sbt.version=1.10.1
sbt.version=1.10.11

View file

@ -28,6 +28,6 @@ externalResolvers := Seq(
"Garrity Software Releases" at "https://maven.garrity.co/gs"
)
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.12")
addSbtPlugin("gs" % "sbt-garrity-software" % "0.3.0")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.3.1")
addSbtPlugin("gs" % "sbt-garrity-software" % "0.5.0")
addSbtPlugin("gs" % "sbt-gs-semver" % "0.3.0")