Skip to content

Commit

Permalink
Ensure stopAtFirstUnrecognized is taken into account from commands (#176
Browse files Browse the repository at this point in the history
)
  • Loading branch information
alexarchambault authored Feb 6, 2020
1 parent 98ea9a2 commit 9fd9a36
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 3 deletions.
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/caseapp/core/app/CaseApp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import caseapp.core.help.{Help, WithHelp}
import caseapp.core.parser.Parser
import caseapp.core.RemainingArgs

abstract class CaseApp[T](implicit val parser: Parser[T], val messages: Help[T]) {
abstract class CaseApp[T](implicit val parser0: Parser[T], val messages: Help[T]) {

def parser: Parser[T] =
if (stopAtFirstUnrecognized)
parser0.stopAtFirstUnrecognized
else
parser0

def run(options: T, remainingArgs: RemainingArgs): Unit

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,7 @@ import dataclass.data
def args: Seq[Arg] =
underlying.args

override def defaultStopAtFirstUnrecognized: Boolean =
underlying.defaultStopAtFirstUnrecognized

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ import dataclass.data
def args: Seq[Arg] =
underlying.args

override def defaultStopAtFirstUnrecognized: Boolean =
underlying.defaultStopAtFirstUnrecognized

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ import dataclass.data
def args: Seq[Arg] =
underlying.args

override def defaultStopAtFirstUnrecognized: Boolean =
underlying.defaultStopAtFirstUnrecognized

}
12 changes: 10 additions & 2 deletions core/shared/src/main/scala/caseapp/core/parser/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ abstract class Parser[T] {
*/
def args: Seq[Arg]

def defaultStopAtFirstUnrecognized: Boolean =
false
def stopAtFirstUnrecognized: Parser[T] =
StopAtFirstUnrecognizedParser(this)

final def parse(args: Seq[String]): Either[Error, (T, Seq[String])] =
detailedParse(args)
Expand All @@ -73,7 +77,7 @@ abstract class Parser[T] {
final def detailedParse(args: Seq[String]): Either[Error, (T, RemainingArgs)] =
detailedParse(
args,
stopAtFirstUnrecognized = false
stopAtFirstUnrecognized = defaultStopAtFirstUnrecognized
)

final def detailedParse(
Expand Down Expand Up @@ -143,7 +147,11 @@ abstract class Parser[T] {
*/
final def withHelp: Parser[WithHelp[T]] = {
implicit val parser: Parser.Aux[T, D] = this
Parser[WithHelp[T]]
val p = Parser[WithHelp[T]]
if (defaultStopAtFirstUnrecognized)
p.stopAtFirstUnrecognized
else
p
}

final def map[U](f: T => U): Parser.Aux[U, D] =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package caseapp.core.parser

import caseapp.core.{Arg, Error}
import dataclass.data

@data class StopAtFirstUnrecognizedParser[T](underlying: Parser[T]) extends Parser[T] {
type D = underlying.D
def init: D = underlying.init
def step(args: List[String], d: D): Either[(Error, List[String]), Option[(D, List[String])]] =
underlying.step(args, d)
def get(d: D): Either[Error, T] =
underlying.get(d)
def args: Seq[Arg] =
underlying.args
override def defaultStopAtFirstUnrecognized: Boolean =
true
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ object ManualCommandNotAdtOptions {
@ProgName("c2")
final case class Command2Opts(b: Boolean)

@ProgName("c3")
final case class Command3Opts(n: Int = 2)

}
14 changes: 14 additions & 0 deletions tests/shared/src/test/scala/caseapp/Tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,20 @@ object Tests extends TestSuite {
h.argsNameOption.exists(_ == "c1-stuff")
}
}

"stop at first unrecognized argument if asked so" - {
* - {
val res = ManualCommandNotAdt.commandParser.parse[Default0](Seq("c3", "-b"))
val expectedRes = Right((Default0(), Nil, Some(Right((Seq("c3"), Inr(Inr(Inl(ManualCommandNotAdtOptions.Command3Opts()))), Seq("-b"))))))
assert(res == expectedRes)
}

* - {
val res = ManualCommandNotAdt.commandParser.parse[Default0](Seq("c3", "-n", "1", "--foo"))
val expectedRes = Right((Default0(), Nil, Some(Right((Seq("c3"), Inr(Inr(Inl(ManualCommandNotAdtOptions.Command3Opts(1)))), Seq("--foo"))))))
assert(res == expectedRes)
}
}
}

"sub commands" - {
Expand Down
9 changes: 9 additions & 0 deletions tests/shared/src/test/scala/caseapp/demo/Demo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,23 @@ object ManualCommandNotAdtStuff {
}
}

case object Command3StopAtUnreco extends CaseApp[ManualCommandNotAdtOptions.Command3Opts] {
override def stopAtFirstUnrecognized = true
def run(options: ManualCommandNotAdtOptions.Command3Opts, args: RemainingArgs): Unit = {

}
}

val parser = CommandParser.nil
.add(Command1)
.add(Command2)
.add(Command3StopAtUnreco)
.reverse

val help = CommandsHelp.nil
.add(Command1)
.add(Command2)
.add(Command3StopAtUnreco)
.reverse

}
Expand Down

0 comments on commit 9fd9a36

Please sign in to comment.