Skip to content

Instantly share code, notes, and snippets.

@meysampg
Created May 25, 2022 10:42
Show Gist options
  • Save meysampg/73fa44338a2edaf2651e98c8570a6ff6 to your computer and use it in GitHub Desktop.
Save meysampg/73fa44338a2edaf2651e98c8570a6ff6 to your computer and use it in GitHub Desktop.
CLI argument parser for Scala2
package ir.mpgutils.utils
import scala.annotation.tailrec
class UnknownArgumentException(val msg: String) extends Exception(msg)
/**
* Parse CLI arguments to a Map[String, String].
*
* Example:
* given: List("--a", "--b", "--c", "d", "e ", "f", "--j", "--g", "h", "--I")
* output: Map("a" -> "true", "b" -> "true", "c" -> "d,e,f", "g" -> "h", "i" -> "true", "j" -> "true")
*/
object ArgumentParser {
val arguments: Seq[String] = Seq(
)
def apply(arguments: Array[String]): Map[String, String] = apply(arguments.toList)
def apply(arguments: List[String]): Map[String, String] =
try {
getOptionsAcc(Map(), arguments)
} catch {
case e: UnknownArgumentException =>
throw new Exception(e.msg + usage())
}
def usage(): String = "\nUsage: SPARK_SUBMIT SUBMIT-OPTIONS app.jar --key value\n" + arguments.map(k => s"\t--$k").mkString("\n")
@tailrec
private def getOptionsAcc(map: Map[String, String], argv: List[String]): Map[String, String] = argv match {
case Nil => map
case key :: _ if key.startsWith("--") && !arguments.contains(key.toLowerCase.replace("--", "").trim) =>
throw new UnknownArgumentException(s"Argument '`${key}` is unrecognised.")
case key :: value :: tail if key.startsWith("--") && !value.startsWith("--") =>
val pureKey: String = key.replace("--", "").toLowerCase
getOptionsAcc(map ++ Map(kebabToCamel(pureKey) -> value.trim), tail)
case key :: value :: tail if key.startsWith("--") && value.startsWith("--") =>
val pureKey: String = key.replace("--", "").trim.toLowerCase
getOptionsAcc(map ++ Map(kebabToCamel(pureKey) -> "true"), value :: tail)
case value :: tail if value.startsWith("--") =>
val pureKey: String = value.replace("--", "").trim.toLowerCase
getOptionsAcc(map ++ Map(kebabToCamel(pureKey) -> "true"), tail)
case value :: tail if map.nonEmpty =>
getOptionsAcc(map ++ Map(map.last._1 -> s"${map.last._2},${value.trim}"), tail)
}
private def kebabToCamel(s: String): String = {
@tailrec
def kebabToCamelAcc(acc: String, chars: List[Char], headIsUpper: Boolean): String = chars match {
case Nil => acc
case head :: Nil => acc + (if (headIsUpper) head.toUpper else head)
case head :: tail =>
if (tail.head == '-') kebabToCamelAcc(acc + head, tail.tail, headIsUpper = true)
else kebabToCamelAcc(acc + (if (headIsUpper) head.toUpper else head), tail, headIsUpper = false)
}
kebabToCamelAcc("", s.toList, headIsUpper = false)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment