Command Line Interface Scala - scala

So I'm trying to build a command line interface for my scala project,
however, there are many examples online, but not much explanation to how they work etc, i really don't need anything complex.
All i need to be able to do in the command is to allow an input of a file path to the file and an input for the output directory.
Can any help me out and give me an example tell me how it works etc?

For something simple, pattern matching can be sufficient.
def main(args: Array[String]): Unit = args.toList match {
case in :: out :: _ => println(s"OK: $in -> $out")
case _ => println(s"Invalid arguments: $args")
}

I once did something similar (read arguments from CLI - https://github.com/pedrorijo91/euromillions-generator)
I used Argot: https://github.com/bmc/argot
but it seems it's deprecated and they recommend to use Scopt: https://github.com/scopt/scopt

object Main extends App {
args.toList match {
case in :: out :: _ => println(s"OK: $in -> $out")
case _ => println(s"Invalid arguments: $args")
}
}

Related

Scala 3 Using - problems when reading from file

In a Scala 3 project, I have a method which returns a Try from a given String
def translate(text: String) : Try[Thing] = ...
and a method which is supposed to read the contents of a file and pass it on to the first method. Here, I want to use Using because as far as I understand, this is the functional way to handle file I/O, and it returns a Try which I need anyway, and it makes sure the used resource is closed:
def translateFromFile(filepath: String) : Try[Thing] =
Using(Source.fromFile(filepath).getLines.mkString) match
case Success(s) => translate(s)
case Failure(e) => Failure(e)
However, the compiler says
given instance of type scala.util.Using.Releasable[String] was found for parameter evidence$1 of method apply in object Using
Honestly, I don't understand this error message, and I couldn't find any help online. Can someone help? What's the correct way to do this? Thanks!
The error means that you're trying to substitute into Using(...) not something that can be closed but a String.
It should be
def translateFromFile(filepath: String) : Try[Thing] =
Using(Source.fromFile(filepath)) { s =>
translate(s.getLines.mkString) match {
case Success(s) => ???
case Failure(e) => ???
}
}
or just
def translateFromFile(filepath: String) : Try[Thing] =
Using(Source.fromFile(filepath)) { s =>
translate(s.getLines.mkString)
}.flatten
Using(...){s => ...} returns Try and your translate returns Try, so it's Try[Try[...]], that's why .flatten.
There is nothing specific to Scala 3.

Combine multiple extractor objects to use in one match statement

Is it possible to run multiple extractors in one match statement?
object CoolStuff {
def unapply(thing: Thing): Option[SomeInfo] = ...
}
object NeatStuff {
def unapply(thing: Thing): Option[OtherInfo] = ...
}
// is there some syntax similar to this?
thing match {
case t # CoolStuff(someInfo) # NeatStuff(otherInfo) => process(someInfo, otherInfo)
case _ => // neither Cool nor Neat
}
The intent here being that there are two extractors, and I don't have to do something like this:
object CoolNeatStuff {
def unapply(thing: Thing): Option[(SomeInfo, OtherInfo)] = thing match {
case CoolStuff(someInfo) => thing match {
case NeatStuff(otherInfo) => Some(someInfo -> otherInfo)
case _ => None // Cool, but not Neat
case _ => None// neither Cool nor Neat
}
}
Can try
object ~ {
def unapply[T](that: T): Option[(T,T)] = Some(that -> that)
}
def too(t: Thing) = t match {
case CoolStuff(a) ~ NeatStuff(b) => ???
}
I've come up with a very similar solution, but I was a bit too slow, so I didn't post it as an answer. However, since #userunknown asks to explain how it works, I'll dump my similar code here anyway, and add a few comments. Maybe someone finds it a valuable addition to cchantep's minimalistic solution (it looks... calligraphic? for some reason, in a good sense).
So, here is my similar, aesthetically less pleasing proposal:
object && {
def unapply[A](a: A) = Some((a, a))
}
// added some definitions to make your question-code work
type Thing = String
type SomeInfo = String
type OtherInfo = String
object CoolStuff {
def unapply(thing: Thing): Option[SomeInfo] = Some(thing.toLowerCase)
}
object NeatStuff {
def unapply(thing: Thing): Option[OtherInfo] = Some(thing.toUpperCase)
}
def process(a: SomeInfo, b: OtherInfo) = s"[$a, $b]"
val res = "helloworld" match {
case CoolStuff(someInfo) && NeatStuff(otherInfo) =>
process(someInfo, otherInfo)
case _ =>
}
println(res)
This prints
[helloworld, HELLOWORLD]
The idea is that identifiers (in particular, && and ~ in cchantep's code) can be used as infix operators in patterns. Therefore, the match-case
case CoolStuff(someInfo) && NeatStuff(otherInfo) =>
will be desugared into
case &&(CoolStuff(someInfo), NeatStuff(otherInfo)) =>
and then the unapply method method of && will be invoked which simply duplicates its input.
In my code, the duplication is achieved by a straightforward Some((a, a)). In cchantep's code, it is done with fewer parentheses: Some(t -> t). The arrow -> comes from ArrowAssoc, which in turn is provided as an implicit conversion in Predef. This is just a quick way to create pairs, usually used in maps:
Map("hello" -> 42, "world" -> 58)
Another remark: notice that && can be used multiple times:
case Foo(a) && Bar(b) && Baz(c) => ...
So... I don't know whether it's an answer or an extended comment to cchantep's answer, but maybe someone finds it useful.
For those who might miss the details on how this magic actually works, just want to expand the answer by #cchantep anf #Andrey Tyukin (comment section does not allow me to do that).
Running scalac with -Xprint:parser option will give something along those lines (scalac 2.11.12)
def too(t: String) = t match {
case $tilde(CoolStuff((a # _)), NeatStuff((b # _))) => $qmark$qmark$qmark
}
This basically shows you the initial steps compiler does while parsing source into AST.
Important Note here is that the rules why compiler makes this transformation are described in Infix Operation Patterns and Extractor Patterns. In particular, this allows you to use any object as long as it has unapply method, like for example CoolStuff(a) AndAlso NeatStuff(b). In previous answers && and ~ were picked up as also possible but not the only available valid identifiers.
If running scalac with option -Xprint:patmat which is a special phase for translating pattern matching one can see something similar to this
def too(t: String): Nothing = {
case <synthetic> val x1: String = t;
case9(){
<synthetic> val o13: Option[(String, String)] = main.this.~.unapply[String](x1);
if (o13.isEmpty.unary_!)
{
<synthetic> val p3: String = o13.get._1;
<synthetic> val p4: String = o13.get._2;
{
<synthetic> val o12: Option[String] = main.this.CoolStuff.unapply(p3);
if (o12.isEmpty.unary_!)
{
<synthetic> val o11: Option[String] = main.this.NeatStuff.unapply(p4);
if (o11.isEmpty.unary_!)
matchEnd8(scala.this.Predef.???)
Here ~.unapply will be called on input parameter t which will produce Some((t,t)). The tuple values will be extracted into variables p3 and p4. Then, CoolStuff.unapply(p3) will be called and if the result is not None NeatStuff.unapply(p4) will be called and also checked if it is not empty. If both are not empty then according to Variable Patterns a and b will be bound to returned results inside corresponding Some.

Pattern matching using current object

I'm trying to match an Option, and test to see if it's a Some containing the object making the call. So the code I want to write looks like this:
methodReturningOption() match {
case Some(this) => doSomething()
case _ => doSomethingElse()
}
but that fails to compile, with the error
'.' expected but ')' found
I also tried using Some(`this`) which gives the error
not found: value this
I can make it work if I add a variable which refers to this
val This = this
methodReturningOption() match {
case Some(This) => doSomething()
case _ => doSomethingElse()
}
but that looks ugly and seems like an unpleasant workaround. Is there an easier way to pattern match with this as an argument?
I suppose you could try this:
methodReturningOption() match {
case Some(x) if x == this => doSomething()
case _ => doSomethingElse()
}
It looks like this is considered a special keyword and can't be used in that context.
Jack Leow's solution is probably the best - I'd recommend going with that since it's much more explicit. However as an alternative you can also create a variable point to 'this' using the following syntax. (Note the self => on the first line)
class Person { self =>
def bla() = methodReturningOption() match {
case Some(`self`) => ???
case _ => ???
}
}
This doesn't really answer the question, it's just a potential alternative syntax that may be useful to you.

Chaining validation in Scala

I have a Scala case class containing command-line configuration information:
case class Config(emailAddress: Option[String],
firstName: Option[String]
lastName: Option[String]
password: Option[String])
I am writing a validation function that checks that each of the values is a Some:
def validateConfig(config: Config): Try[Config] = {
if (config.emailAddress.isEmpty) {
Failure(new IllegalArgumentException("Email Address")
} else if (config.firstName.isEmpty) {
Failure(new IllegalArgumentException("First Name")
} else if (config.lastName.isEmpty) {
Failure(new IllegalArgumentException("Last Name")
} else if (config.password.isEmpty) {
Failure(new IllegalArgumentException("Password")
} else {
Success(config)
}
}
but if I understand monads from Haskell, it seems that I should be able to chain the validations together (pseudo syntax):
def validateConfig(config: Config): Try[Config] = {
config.emailAddress.map(Success(config)).
getOrElse(Failure(new IllegalArgumentException("Email Address")) >>
config.firstName.map(Success(config)).
getOrElse(Failure(new IllegalArgumentException("First Name")) >>
config.lastName.map(Success(config)).
getOrElse(Failure(new IllegalArgumentException("Last Name")) >>
config.password.map(Success(config)).
getOrElse(Failure(new IllegalArgumentException("Password"))
}
If any of the config.XXX expressions returns Failure, the whole thing (validateConfig) should fail, otherwise Success(config) should be returned.
Is there some way to do this with Try, or maybe some other class?
It's pretty straightforward to convert each Option to an instance of the right projection of Either:
def validateConfig(config: Config): Either[String, Config] = for {
_ <- config.emailAddress.toRight("Email Address").right
_ <- config.firstName.toRight("First Name").right
_ <- config.lastName.toRight("Last Name").right
_ <- config.password.toRight("Password").right
} yield config
Either isn't a monad in the standard library's terms, but its right projection is, and will provide the behavior you want in the case of failure.
If you'd prefer to end up with a Try, you could just convert the resulting Either:
import scala.util._
val validate: Config => Try[Config] = (validateConfig _) andThen (
_.fold(msg => Failure(new IllegalArgumentException(msg)), Success(_))
)
I wish that the standard library provided a nicer way to make this conversion, but it doesn't.
It's a case class, so why aren't you doing this with pattern matching?
def validateConfig(config: Config): Try[Config] = config match {
case Config(None, _, _, _) => Failure(new IllegalArgumentException("Email Address")
case Config(_, None, _, _) => Failure(new IllegalArgumentException("First Name")
case Config(_, _, None, _) => Failure(new IllegalArgumentException("Last Name")
case Config(_, _, _, None) => Failure(new IllegalArgumentException("Password")
case _ => Success(config)
}
In your simple example, my priority would be to forget monads and chaining, just get rid of that nasty if...else smell.
However, while a case class works perfectly well for a short list, for a large number of configuration options, this becomes tedious and the risk of error increases. In this case, I would consider something like this:
Add a method that returns a key->value map of the configuration options, using the option names as the keys.
Have the Validate method check if any value in the map is None
If no such value, return success.
If at least one value matches, return that value name with the error.
So assuming that somewhere is defined
type OptionMap = scala.collection.immutable.Map[String, Option[Any]]
and the Config class has a method like this:
def optionMap: OptionMap = ...
then I would write Config.validate like this:
def validate: Either[List[String], OptionMap] = {
val badOptions = optionMap collect { case (s, None) => s }
if (badOptions.size > 0)
Left(badOptions)
else
Right(optionMap)
}
So now Config.validate returns either a Left containing the name of all the bad options or a Right containing the full map of options and their values. Frankly, it probably doesn't matter what you put in the Right.
Now, anything that wants to validate a Config just calls Config.validate and examines the result. If it's a Left, it can throw an IllegalArgumentException containing one or more of the names of bad options. If it's a Right, it can do whatever it wanted to do, knowing the Config is valid.
So we could rewrite your validateConfig function as
def validateConfig(config: Config): Try[Config] = config.validate match {
case Left(l) => Failure(new IllegalArgumentException(l.toString))
case _ => Success(config)
}
Can you see how much more functional and OO this is getting?
No imperative chain of if...else
The Config object validates itself
The consequences of a Config object being invalid are left to the larger program.
I think a real example would be more complex yet, though. You are validating options by saying "Does it contain Option[String] or None?" but not checking the validity of the string itself. Really, I think your Config class should contain a map of options where the name maps to the value and to an anonymous function that validates the string. I could describe how to extend the above logic to work with that model, but I think I'll leave that as an exercise for you. I will give you a hint: you might want to return not just the list of failed options, but also the reason for failure in each case.
Oh, by the way... I hope none of the above implies that I think you should actually store the options and their values as an optionMap inside the object. I think it's useful to be able to retrieve them like that, but I wouldn't ever encourage such exposure of the actual internal representation ;)
Here's a solution that I came up with after some searching and scaladocs reading:
def validateConfig(config: Config): Try[Config] = {
for {
_ <- Try(config.emailAddress.
getOrElse(throw new IllegalArgumentException("Email address missing")))
_ <- Try(config.firstName.
getOrElse(throw new IllegalArgumentException("First name missing")))
_ <- Try(config.lastName.
getOrElse(throw new IllegalArgumentException("Last name missing")))
_ <- Try(config.password.
getOrElse(throw new IllegalArgumentException("Password missing")))
} yield config
}
Similar to Travis Brown's answer.

Idiomatic way to find a matching line in Scala

I have an Iterable[String] representing the lines in a file and I'd like to find the first line in that sequence that matches a regular expression and return a numerical value extracted by the regex. The file is big enough that it wouldn't make sense to load the whole thing into memory and then call toString() or something, so I'll need to go through it a line at a time.
Here's what I have (it works):
val RateRegex : Regex = ".....".r
def getRate(source : Source) : Option[Double] = {
import java.lang.Double._
for(line <- source.getLines() ) {
line match {
case RateRegex(rawRate) => return Some(parseDouble(rawRate))
case None => ()
}
}
return None
}
This seems ugly to me. It feels very imperative and case None => () might as well be replaced with a comment that says "you're doing it wrong."
I think I want something like def findFirstWhereNonNone(p : Function[A,Option[B]]) => Option[B] where the collection's elements are of type A.
Are there built-in methods that would let me do this in a more functional way? Should I just write that method?
P.S. While I'm at it, is there an alternative to using java.lang.Double.parseDouble? Scala's Double class doesn't expose it.
P.P.S I've seen a lot of posts on SO suggesting that the Source API shouldn't be used in production, but they're all from 2008 and 2009. Is that still the case? If so, what should I use for IO?
Update
I now have:
import util.matching.Regex.Groups
for{line <- source.getLines()
Groups(rawRate) <- RateRegex.findFirstMatchIn(line)} {
return Some(parseDouble(rawRate))
}
return None
which feels a lot better to me.
EDIT: This third alternative ia quite neat:
source
.getLines()
.collectFirst{ case RateRegex(x) => x.toDouble}
Not sure if it's more functional, but you can use the behaviour of foreach/for-comprehensions on Options
def getRate(source : Source) : Option[Double] = {
for {line <- source.getLines()
rawRate <- RateRegex.findFirstIn(line)}
return Some(rawRate toDouble)
return None
}
This works too (quite similar to EasyAngel's answer):
source
.getLines()
.map{RateRegex.findFirstMatchIn(_)}
.filter{_.isDefined}
.map{_.get.group(0).toDouble}
.head
.toList
.headOption
The last three are a little ugly. The take(1) is to ensure we only evaluate up to the first match. The toList is to force the evaluation, and the headOption to extract the first value as Some() or None if there is none. Is there a more idiomatic way of doing this?
Here is one of the possible solutions:
def getRates(source : Source) = source.getLines.map {
case RateRegex(rate) => Some(rate toDouble)
case _ => None
} filter (_ isDefined) toList
Please note, that this function now returns now List[Option[Double]] of all found rates. It's also important, that Iterator remains lazy until I call toList
Update
As was asked in comments, here is solution, that returns only first occurrence:
def getRate(source : Source): Option[Double] = source.getLines.map {
case RateRegex(rate) => Some(rate toDouble)
case _ => None
} find (_ isDefined) getOrElse None