Skip to content

Commit

Permalink
Merge pull request #435 from alexarchambault/fix-full-help
Browse files Browse the repository at this point in the history
Ensure WithFullHelp args have a non-empty origin field
  • Loading branch information
alexarchambault authored Nov 10, 2022
2 parents 5a653bd + 22123fd commit f587a8e
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 28 deletions.
7 changes: 5 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,11 @@ lazy val tests = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.settings(
shared,
caseAppPrefix,
publish / skip := true,
libraryDependencies += Deps.utest.value % Test,
publish / skip := true,
libraryDependencies ++= Seq(
Deps.pprint.value % Test,
Deps.utest.value % Test
),
testFrameworks += new TestFramework("utest.runner.Framework")
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,63 @@
package caseapp.core.help

import caseapp.core.parser.Parser
import caseapp.{ExtraName, HelpMessage}
import caseapp.{ExtraName, Group, HelpMessage, Parser}
import caseapp.core.parser.{Argument, NilParser, StandardArgument}
import caseapp.core.{Arg, Error}
import caseapp.core.parser.RecursiveConsParser
import caseapp.core.util.Formatter

import shapeless.{HNil, :: => :*:}

abstract class WithFullHelpCompanion {

implicit def parser[T, D](implicit underlying: Parser.Aux[T, D]): Parser[WithFullHelp[T]] =
Parser.nil
.addAll[WithHelp[T]].apply
.add[Boolean](
"helpFull",
default = Some(false),
extraNames = Seq(ExtraName("fullHelp")),
helpMessage = Some(HelpMessage("Print help message, including hidden options, and exit"))
)
.as[WithFullHelp[T]]
implicit def parser[T, D](implicit
underlying: Parser.Aux[T, D]
): Parser.Aux[
WithFullHelp[T],
(Option[Boolean] :*: Option[Boolean] :*: D :*: HNil) :*: Option[Boolean] :*: HNil
] = {

val baseHelpArgument = StandardArgument[Boolean](
Arg("helpFull")
.withExtraNames(Seq(
ExtraName("fullHelp"),
ExtraName("-help-full"),
ExtraName("-full-help")
))
.withGroup(Some(Group("Help")))
.withOrigin(Some("WithFullHelp"))
.withHelpMessage(Some(
HelpMessage("Print help message, including hidden options, and exit")
))
.withIsFlag(true)
).withDefault(() => Some(false))

// accept "-help" too (single dash)
val helpArgument: Argument[Boolean] =
new Argument[Boolean] {
def arg = baseHelpArgument.arg
def withDefaultOrigin(origin: String) =
this
def init = baseHelpArgument.init
def step(
args: List[String],
index: Int,
d: Option[Boolean],
nameFormatter: Formatter[ExtraName]
): Either[(Error, List[String]), Option[(Option[Boolean], List[String])]] =
args match {
case ("-help-full" | "-full-help") :: rem => Right(Some((Some(true), rem)))
case _ => baseHelpArgument.step(args, index, d, nameFormatter)
}
def get(d: Option[Boolean], nameFormatter: Formatter[ExtraName]) =
baseHelpArgument.get(d, nameFormatter)
}

val withHelpParser = WithHelp.parser[T, D](underlying)

val p = RecursiveConsParser(withHelpParser, helpArgument :: NilParser)

p.to[WithFullHelp[T]]
}

}
Original file line number Diff line number Diff line change
@@ -1,19 +1,59 @@
package caseapp.core.help

import caseapp.core.parser.Parser
import caseapp.{ExtraName, HelpMessage}
import caseapp.{ExtraName, Group, HelpMessage, Parser}
import caseapp.core.Scala3Helpers.*
import caseapp.core.parser.{Argument, NilParser, StandardArgument}
import caseapp.core.{Arg, Error}
import caseapp.core.parser.RecursiveConsParser
import caseapp.core.util.Formatter

abstract class WithFullHelpCompanion {

implicit def parser[T: Parser]: Parser[WithFullHelp[T]] =
Parser.nil
.addAll[WithHelp[T]](using WithHelp.parser[T])
.add[Boolean](
"helpFull",
default = Some(false),
extraNames = Seq(ExtraName("fullHelp")),
helpMessage = Some(HelpMessage("Print help message, including hidden options, and exit"))
)
.as[WithFullHelp[T]]
implicit def parser[T](implicit
underlying: Parser[T]
): Parser[WithFullHelp[T]] = {

val baseHelpArgument = StandardArgument[Boolean](
Arg("helpFull")
.withExtraNames(Seq(
ExtraName("fullHelp"),
ExtraName("-help-full"),
ExtraName("-full-help")
))
.withGroup(Some(Group("Help")))
.withOrigin(Some("WithFullHelp"))
.withHelpMessage(Some(
HelpMessage("Print help message, including hidden options, and exit")
))
.withIsFlag(true)
).withDefault(() => Some(false))

// accept "-help" too (single dash)
val helpArgument: Argument[Boolean] =
new Argument[Boolean] {
def arg = baseHelpArgument.arg
def withDefaultOrigin(origin: String) =
this
def init = baseHelpArgument.init
def step(
args: List[String],
index: Int,
d: Option[Boolean],
nameFormatter: Formatter[ExtraName]
): Either[(Error, List[String]), Option[(Option[Boolean], List[String])]] =
args match {
case ("-help-full" | "-full-help") :: rem => Right(Some((Some(true), rem)))
case _ => baseHelpArgument.step(args, index, d, nameFormatter)
}
def get(d: Option[Boolean], nameFormatter: Formatter[ExtraName]) =
baseHelpArgument.get(d, nameFormatter)
}

val withHelpParser = WithHelp.parser[T](underlying)

val p = RecursiveConsParser(withHelpParser, helpArgument :: NilParser)

p.to[WithFullHelp[T]]
}

}
1 change: 1 addition & 0 deletions project/Deps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ object Deps {
def catsEffect3 = setting("org.typelevel" %%% "cats-effect" % "3.3.14")
def dataClass = "io.github.alexarchambault" %% "data-class" % "0.2.6"
def macroParadise = "org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.patch
def pprint = setting("com.lihaoyi" %%% "pprint" % "0.8.0")
def scalaCompiler = setting("org.scala-lang" % "scala-compiler" % scalaVersion.value)
def scalaReflect = setting("org.scala-lang" % "scala-reflect" % scalaVersion.value)
def shapeless = setting("com.chuusai" %%% "shapeless" % "2.3.10")
Expand Down
3 changes: 1 addition & 2 deletions project/Mima.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@ import scala.sys.process._
object Mima {

def binaryCompatibilityVersions: Set[String] =
Seq("git", "tag", "--merged", "HEAD^", "--contains", "cacc9a0340fde584a10a814037db6a8947881931")
Seq("git", "tag", "--merged", "HEAD^", "--contains", "5a653bdd41972587bd3fb3d9751c0e0cf11c1e74")
.!!
.linesIterator
.map(_.trim)
.filter(_.startsWith("v"))
.map(_.stripPrefix("v"))
.filter(_ != "2.1.0-M19")
.toSet

def settings = Def.settings(
Expand Down
18 changes: 18 additions & 0 deletions tests/shared/src/test/scala/caseapp/ParserTests.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package caseapp

import caseapp.core.{Arg, Error, Indexed}
import caseapp.core.help.{WithFullHelp, WithHelp}
import caseapp.core.parser.{Argument, NilParser, StandardArgument}
import caseapp.core.parser.ParserOps
import caseapp.core.util.Formatter
Expand Down Expand Up @@ -87,6 +88,23 @@ object ParserTests extends TestSuite {
assert(numFooArg.origin == Some("FewArgs"))
}

test("WithHelp args have an origin") {
case class Dummy()
val parser: Parser[WithHelp[Dummy]] = WithHelp.parser
val args = parser.args
assert(args.nonEmpty)
assert(args.forall(_.origin.contains("WithHelp")))
}

test("WithFullHelp args have an origin") {
case class Dummy()
val parser: Parser[WithFullHelp[Dummy]] = WithFullHelp.parser
val args = parser.args
assert(args.exists(_.origin.contains("WithHelp")))
assert(args.exists(_.origin.contains("WithFullHelp")))
assert(args.forall(_.origin.exists(o => o == "WithHelp" || o == "WithFullHelp")))
}

test("Custom Argument type") {
case class Helper(n: Int, values: List[String])

Expand Down

0 comments on commit f587a8e

Please sign in to comment.