From 791ec04c27bc7311aa17f8324bd40ac0ef9f4079 Mon Sep 17 00:00:00 2001 From: Andrzej Ressel Date: Tue, 13 Aug 2024 00:15:56 +0200 Subject: [PATCH] Add support for java.time.Duration --- docs/args.md | 4 ++++ docs/options.md | 4 ++++ .../src/test/scala/zio/cli/PrimTypeSpec.scala | 2 ++ .../shared/src/main/scala/zio/cli/Args.scala | 18 ++++++++++++++++++ .../src/main/scala/zio/cli/Options.scala | 7 +++++++ .../src/main/scala/zio/cli/PrimType.scala | 18 ++++++++++++++++++ .../cli/completion/PrimTypeCompletion.scala | 2 ++ 7 files changed, 55 insertions(+) diff --git a/docs/args.md b/docs/args.md index 4c248ab3..c957fa8a 100644 --- a/docs/args.md +++ b/docs/args.md @@ -74,6 +74,10 @@ Args.integer(name) ### Date/Time Args The following methods produce `Args` whose type parameter is a Date/Time type of the `java.time` library. +- Produces `Args[java.time.Duration]`. The input must be a time-based amount of time in the ISO-8601 format, such as 'P1DT2H3M'. +```scala mdoc:silent +Args.duration(name) +``` - Produces `Args[java.time.Instant]`. The input must be an instant in time in UTC format, such as 2007-12-03T10:15:30.00Z. ```scala mdoc:silent Args.instant(name) diff --git a/docs/options.md b/docs/options.md index 05e08850..2b519da5 100644 --- a/docs/options.md +++ b/docs/options.md @@ -85,6 +85,10 @@ Options.integer(name) ### Date/Time Options The following methods produce `Options` whose type parameter is a Date/Time type of the `java.time` library. +- Produces `Options[java.time.Duration]`. The input must be a time-based amount of time in the ISO-8601 format, such as 'P1DT2H3M'. +```scala mdoc:silent +Options.duration(name) +``` - Produces `Options[java.time.Instant]`. The input must be an instant in time in UTC format, such as 2007-12-03T10:15:30.00Z. ```scala mdoc:silent Options.instant(name) diff --git a/zio-cli/jvm/src/test/scala/zio/cli/PrimTypeSpec.scala b/zio-cli/jvm/src/test/scala/zio/cli/PrimTypeSpec.scala index c874c1b6..33944853 100644 --- a/zio-cli/jvm/src/test/scala/zio/cli/PrimTypeSpec.scala +++ b/zio-cli/jvm/src/test/scala/zio/cli/PrimTypeSpec.scala @@ -125,6 +125,7 @@ object PrimTypeSpec extends ZIOSpecDefault { Gen.bigDecimal(BigDecimal("1.41421356237309504880168"), BigDecimal("50.4")), "BigDecimal" ), + simplePrimTypeSuite(PrimType.Duration, anyDuration, "Duration"), simplePrimTypeSuite(PrimType.Integer, anyBigInt, "Integer"), simplePrimTypeSuite(PrimType.Instant, Gen.instant, "Instant"), simplePrimTypeSuite(PrimType.LocalDateTime, anyLocalDateTime, "LocalDateTime"), @@ -180,6 +181,7 @@ object PrimTypeSpec extends ZIOSpecDefault { val anyBigInt: Gen[Any, BigInt] = Gen.long(0, Long.MaxValue).map(BigInt(_)) val anyBoolean: Gen[Any, Boolean] = Gen.fromIterable(List(true, false)) + val anyDuration = Gen.finiteDuration val anyInstant = Gen.instant.map(_.atZone(ZoneOffset.UTC)) val anyPeriod = for { first <- Gen.localDateTime.map(_.toLocalDate) diff --git a/zio-cli/shared/src/main/scala/zio/cli/Args.scala b/zio-cli/shared/src/main/scala/zio/cli/Args.scala index 3faadbfe..c904a9c6 100644 --- a/zio-cli/shared/src/main/scala/zio/cli/Args.scala +++ b/zio-cli/shared/src/main/scala/zio/cli/Args.scala @@ -4,6 +4,7 @@ import zio._ import zio.cli.HelpDoc.{Span, p} import java.time.{ + Duration => JDuration, Instant => JInstant, LocalDate => JLocalDate, LocalDateTime => JLocalDateTime, @@ -325,6 +326,23 @@ object Args extends ArgsPlatformSpecific { val decimal: Args[BigDecimal] = Single(None, PrimType.Decimal) + /** + * Creates a duration argument with a custom argument name + * + * @param name + * Argument name + * @return + * Duration argument + */ + def duration(name: String): Args[JDuration] = + Single(Some(name), PrimType.Duration) + + /** + * Creates a duration argument with 'duration' as argument name + */ + val duration: Args[JDuration] = + Single(None, PrimType.Duration) + /** * Creates an integer argument with a custom argument name * diff --git a/zio-cli/shared/src/main/scala/zio/cli/Options.scala b/zio-cli/shared/src/main/scala/zio/cli/Options.scala index 9d024e52..a62e972a 100644 --- a/zio-cli/shared/src/main/scala/zio/cli/Options.scala +++ b/zio-cli/shared/src/main/scala/zio/cli/Options.scala @@ -6,6 +6,7 @@ import zio.{IO, UIO, ZIO, Zippable} import zio.cli.oauth2._ import java.time.{ + Duration => JDuration, Instant => JInstant, LocalDate => JLocalDate, LocalDateTime => JLocalDateTime, @@ -811,6 +812,12 @@ object Options extends OptionsPlatformSpecific { def decimal(name: String): Options[BigDecimal] = Single(name, Vector.empty, PrimType.Decimal) + /** + * Creates a parameter excepting a date-based amount of time in the ISO-8601 format, such as 'P1DT2H3M'. + */ + def duration(name: String): Options[JDuration] = + Single(name, Vector.empty, PrimType.Duration) + /** * Creates a parameter expecting an integer. */ diff --git a/zio-cli/shared/src/main/scala/zio/cli/PrimType.scala b/zio-cli/shared/src/main/scala/zio/cli/PrimType.scala index 7d0edcba..2e372f81 100644 --- a/zio-cli/shared/src/main/scala/zio/cli/PrimType.scala +++ b/zio-cli/shared/src/main/scala/zio/cli/PrimType.scala @@ -5,6 +5,7 @@ import zio.cli.HelpDoc.Span.text import zio.cli.files.FileSystem import java.time.{ + Duration => JDuration, Instant => JInstant, LocalDate => JLocalDate, LocalDateTime => JLocalDateTime, @@ -205,6 +206,23 @@ object PrimType extends PathPlatformSpecific { lazy val FalseValues: Set[String] = Set("false", "0", "n", "no", "off") } + /** + * Type representing a time-based amount of time in the ISO-8601 format, such as 'P1DT2H3M'. + */ + case object Duration extends PrimType[JDuration] { self => + lazy val isBool: Boolean = false + + lazy val typeName: String = "duration" + + lazy val choices: Option[String] = None + + def validate(value: Option[String], conf: CliConfig): IO[String, JDuration] = + attempt(value, JDuration.parse, self.typeName) + + lazy val helpDoc: HelpDoc.Span = + text("A time-based amount of time in the ISO-8601 format, such as 'P1DT2H3M'.") + } + /** * Type representing parameter for instant in time in UTC format, such as 2007-12-03T10:15:30.00Z. */ diff --git a/zio-cli/shared/src/main/scala/zio/cli/completion/PrimTypeCompletion.scala b/zio-cli/shared/src/main/scala/zio/cli/completion/PrimTypeCompletion.scala index 1bc0ff96..a3920744 100644 --- a/zio-cli/shared/src/main/scala/zio/cli/completion/PrimTypeCompletion.scala +++ b/zio-cli/shared/src/main/scala/zio/cli/completion/PrimTypeCompletion.scala @@ -14,6 +14,8 @@ object PrimTypeCompletion { ZIO.succeed(Set("true", "false").filter(_.startsWith(prefix))).map(appendSpaces) case PrimType.Decimal => ZIO.succeed(Set.empty) + case PrimType.Duration => + ZIO.succeed(Set.empty) case PrimType.Enumeration(cases @ _*) => ZIO .succeed(cases.collect {