Say I have a value which is Some("aaabbbccc"), I want to test if the value inside the Some contain some other string.
I tried:
val myvalue = Some("aaabbbccc")
myvalue must beSome(contain("bbb"))
It can't compile, but I can't find out a working one.
How to write such an assertion?
You may run into such cases
None must be none
Some("foo") must beSome(contain("f"))
These two statements won't compile.
Compiler will complains
method apply in trait MatchResult cannot be accessed in org.specs2.matcher.MatchResult[Option[T]]
[error] None must be none
[error]
^
Just put a ; at the end of the first statement and everything will be fine
You could try using a custom matcher like the following, taken straight out of the documentation: http://www.scalatest.org/user_guide/matchers_quick_reference
val beOdd =
Matcher { (left: Int) =>
MatchResult(
left % 2 == 1,
left + " was not odd",
left + " was odd"
)
}
3 should beOdd
That said.. perhaps there is a nice scala way of expressing what you're after.
I just saw the string include matcher, but how it could work with an Option[String]..?
string should include ("seven")
Ok.. got it:
option.value should be < 7
Which in your case would be:
myvalue should be ('defined)
myvalue.value should include ("bbb")
scala> val myvalue = Some("aaabbbccc")
myvalue: Some[String] = Some(aaabbbccc)
scala> myvalue exists (_.contains("bbb"))
res0: Boolean = true
scala> myvalue exists (_.contains("abc"))
res1: Boolean = false
You can adapt this easily to specs2:
(myvalue exists (_.contains("bbb"))) must beTrue
The real choice is in how you want the test to react in case myValue happens to be None. If you want it to fail on None, use the above. If you want it to succeed, use this instead:
(myValue forall (_.contains("bbb"))) must beTrue
In both cases, it will do the test you want on Some.
Related
my Task is to read registrations from a file given like:
Keri,345246,2
Ingar,488058,2
Almeta,422016,1
and insert them into a list(Tuple of (String, Int, Int).
So far I wrote this:
The problem is that I don‘t understand why I can't try to cast value2 and value3 to Int even tho they should be Strings because they come from an Array of Strings. Could someone tell me, what my mistake is, I am relatively new to Scala
What is the point of using Scala if you are going to write Java code?
This is how you would properly read a file as a List of case classes.
import scala.io.Source
import scala.util.Using
// Use proper names for the fields.
final case class Registration(field1: String, field2: Int, field3: Int)
// You may change the error handling logic.
def readRegistrationsFromFile(fileName: String): List[Registration] =
Using(Source.fromFile(fileName)) { source =>
source.getLines().map(line => line.split(',').toList).flatMap {
case field1Raw :: field2Raw :: field3Raw :: Nil =>
for {
field2 <- field2Raw.toIntOption
field3 <- field3Raw.toIntOption
} yield Registration(field1 = field1Raw.trim, field2, field3)
case _ =>
None
}.toList
}.getOrElse(default = List.empty)
(feel free to ask any question you may have about this code)
In Scala, in order to convert a String to an Int you need explicit casting.
This can be achieved like this if you are sure the string can be parsed into a integer:
val values = values(1).toInt
If you cannot trust the input (and you probably should not), you can use .toIntOption which will give you a Option[Int] defined if the value was converted successfully or undefined if the string did not represent an integer.
The previous answers are correct. I would add a few more points.
saveContent is declared as a val. This is means it cannot be changed (assigned another value). You can use the Scala REPL (command-line) tool to check:
scala> val saveContent = Nil
val v: collection.immutable.Nil.type = List()
scala> saveContent = 3
^
error: reassignment to val
Instead, you could use a var, although it would be more idiomatic to have an overall pattern like the one provided by Luis Miguel's answer - with pattern-matching and a for-comprehension.
You can use the Scala REPL to check the types of the variables, too. Splitting a String will always lead to more Strings, not Ints, etc.
> val values = "a,2,3".split(",")
val values: Array[String] = Array(a, 2, 3)
> values(2)
val res3: String = 3
This is why a cast like Gael's is necessary.
Array-type access is done with parentheses and not square brackets, in Scala. See above, and http://scalatutorials.com/tour/interactive_tour_of_scala_lists for more details.
I am attempting to create a property-based test in a Scala Test FlatSpec that uses the ScalaCheck :| operator to give failure messages for different parts of the ending boolean expression.
However, I am running into an issue where the && operator does not short circuit. In this case the earlier part of the expression checks to see if the next part of the expression can be run, otherwise that later section would throw an exception.
Here is an example of what the issue looks like. If decoded is None, then the expression should short circuit on the && so that decoded.get is not run, as it would throw an exception.
val value: Array[Int] = Array.fill(2)(0)
val encoded = encode(value)
val decoded: Option[Array[Int]] = decode(value)
decoded.isDefined :| "decoded None" &&
value.sameElements(decoded.get)
When I write the boolean without using the :| operator to give a failure message, the test fails on the decoded.isDefined without throwing an exception.
val value: Array[Int] = Array.fill(2)(0)
val encoded = encode(value)
val decoded: Option[Array[Int]] = decode(value)
decoded.isDefined &&
value.sameElements(decoded.get)
However, when I include a failure message with :|, it fails with a NoSuchElementException on the value.sameElements(decoded.get) line and does not display the failure message for decoded.isDefined even though it would evaluate to false.
The imports and test class declaration I am using are the following:
import org.scalacheck.Prop._
import org.scalatest.prop.Checkers
import org.scalatest.{FlatSpec, Matchers}
class ByteRWTests extends FlatSpec with Matchers with Checkers {
I am writing property checks in the following manner:
it should "be equal" in {
check(
forAll { (int: Int) =>
int == int
}
)
}
Is there any way to get the short circuiting for && to work with expressions using :|, or is there a workaround for this issue?
Why you see the difference
The issue is that while the && for booleans is short-circuiting, the && method on Prop isn't, and whether or not you use a label determines where the implicit conversion from boolean to Prop happens. For example:
import org.scalacheck.Prop, Prop._
val value: Array[Int] = Array.fill(2)(0)
val decoded: Option[Array[Int]] = None
val p1: Prop = decoded.isDefined && value.sameElements(decoded.get)
val p2: Prop = decoded.isDefined :| "decoded None" && value.sameElements(decoded.get)
Here the p1 definition desugars to this:
Prop.propBoolean(decoded.isDefined && value.sameElements(decoded.get))
While p2 gives you this:
(Prop.propBoolean(decoded.isDefined) :| "decoded None").&&(
Prop.propBoolean(value.sameElements(decoded.get))
)
(For what it's worth this is another example of why I don't like fancy implicit-conversion-based DSLs.)
Workaround
Unfortunately it's just not possible to get the && method on Prop to do what you want here, but you can define your own version of conjunction that does:
def propAnd(p1: => Prop, p2: => Prop) = p1.flatMap { r =>
if (r.success) Prop.secure(p2) else Prop(_ => r)
}
And then:
scala> propAnd(decoded.isDefined :| "decoded None" , value.sameElements(decoded.get))
res1: org.scalacheck.Prop = Prop
scala> .check
! Falsified after 0 passed tests.
> Labels of failing property:
decoded None
This method actually exists in ScalaCheck, but it's not part of the public API. A comment on the implementation does note that it "(Should maybe be in Prop module)", so if you find you're doing this kind of thing a lot, you might try opening a pull request to move the method from Commands to Prop and make it public.
In the specific case you've given here, though, I'd probably suggest using something like exists on the Option instead of checking whether it's defined and then using get.
When working in Scala, I often want to parse a field of type [A] and convert it to a Option[A], with a single case (for example, "NA" or "") being converted to None, and the other cases being wrapped in some.
Right now, I'm using the following matching syntax.
match {
case "" => None
case s: String => Some(s)
}
// converts an empty String to None, and otherwise wraps it in a Some.
Is there any more concise / idiomatic way to write this?
There are a more concise ways. One of:
Option(x).filter(_ != "")
Option(x).filterNot(_ == "")
will do the trick, though it's a bit less efficient since it creates an Option and then may throw it away.
If you do this a lot, you probably want to create an extension method (or just a method, if you don't mind having the method name first):
implicit class ToOptionWithDefault[A](private val underlying: A) extends AnyVal {
def optNot(not: A) = if (underlying == not) None else Some(underlying)
}
Now you can
scala> 47.toString optNot ""
res1: Option[String] = Some(47)
(And, of course, you can always create a method whose body is your match solution, or an equivalent one with if, so you can reuse it for that particular case.)
I'd probably use filterNot here:
scala> Option("hey").filterNot(_ == "NA")
res0: Option[String] = Some(hey)
scala> Option("NA").filterNot(_ == "NA")
res1: Option[String] = None
It requires you to think of Option as a collection with one or zero elements, but if you get into that habit it's reasonably clear.
A simple and intuitive approach includes this expression,
if (s.isEmpty) None else Some(s)
This assumes s labels the value to be otherwise matched (thanks to #RexKerr for the note).
I've searched for a half-hour, and still cannot figure it out.
In SIP: Modularizing Language Features there are a number of features which will require explicit "enabling" in Scala 2.10 (import language.feature).
Amongst them there is postfixOps, to which I just cannot find a reference anywhere. What exactly does this feature allow?
It allows you to use operator syntax in postfix position. For example
List(1,2,3) tail
rather than
List(1,2,3).tail
In this harmless example it is not a problem, but it can lead to ambiguities. This will not compile:
val appender:List[Int] => List[Int] = List(1,2,3) ::: //add ; here
List(3,4,5).foreach {println}
And the error message is not very helpful:
value ::: is not a member of Unit
It tries to call the ::: method on the result of the foreach call, which is of type Unit. This is likely not what the programmer intended. To get the correct result, you need to insert a semicolon after the first line.
The simplest answer ever:
Dropping dot from methods without parameters is DEPRECATED!
List(1,2,3) reverse //is bad style and will lead to unpredicted behaviour
List(1,2,3) map(_*2) reverse //bad too, because reverse can take first method call from the next line (details below)
OK to drop dot in methods that take one parameter of higher order function like map, filter, count and be safe!
Also, purely functional methods like zip.
List(1,2,3) map(_*2) filter(_>2)
(List(1,2,3) map(_*2)).reverse //safe and good
List(1,3,5) zip List(2,4,6)
Long answer WHY
case class MyBool(x: Boolean) {
def !!! = MyBool(!x) //postfix
def or(other: MyBool): MyBool = if(x) other else this //infix
def justMethod0() = this //method with empty parameters
def justMethod2(a: MyBool, b: MyBool) = this //method with two or more
override def toString = if(x) "true" else "false"
}
1) Postfix operator - is actually a method call with no parameters (a!==a.!) and without brackets. (considered not safe and deprecated)
val b1 = MyBool(false) !!!
List(1,2,3) head
2) Postfix operator is method, that should end the line, or else it will be treated as infix.
val b1 = MyBool(true) no! no! //ERROR
//is actually parsed like
val b2 = MyBool(true).no!(no!) //(no!) is unknown identifier
//as bad as
Vector(1,2,3) toList map(_*2) //ERROR
3) Infix operator is method with one parameter, that can be called without dot and parentheses. Only for purely functional methods
val c1 = MyBool(true) or b1 or MyBool(true)
val c2 = MyBool(true).or(b1).or(MyBool(true))
c1 == c2
4) Method with one or more parameters will chain without dot if you call it with parameters. def a(), def a(x), def a(x,y)
But you should do this only for methods that use higher order function as parameter!
val d1 = MyBool(true) justMethod2(b1, c1) or b1 justMethod0() justMethod2(c1, b1)
//yes, it works, but it may be confusing idea
val d2 = MyBool(true).justMethod2(b1,c1).or(b1).justMethod0().justMethod2(c1, b1)
d1 == d2
//looks familiar? This is where it should be used:
List(1,2,3) filter(_>1) map(_*2)
Sample warnings:
warning: there were 1 deprecation warning(s); re-run with -deprecation
for details warning: postfix operator tail should be enabled by making
the implicit value scala.language.postfixOps visible. This can be
achieved by adding the import clause 'import
scala.language.postfixOps' or by setting the compiler option
-language:postfixOps. See the Scala docs for value scala.language.postfixOps for a discussion why the feature should be
explicitly enabled.
It refers to the ability to call a nullary (with no arg list or empty arg list) method as a postfix operator:
By example:
case class MyBool(value: Boolean) {
def negated = new MyBool(!value)
}
val b1 = MyBool( true )
val b2 = b1 negated // Same as b1.negated
See: http://www.scala-lang.org/node/118
I meet some scala code with "?" but do not know what it mean in scala, could anyone explain it to me ? Thanks.
And here's one example
def getJobId(conf: Configuration): String =
?(conf.get("scoobi.jobid")).getOrElse(sys.error("Scoobi job id not set."))
For me it looks like the apply method of Option. Is there somewhere the following import statement in the code:
import Option.{apply => ?}
This means apply is imported as ?. From the doc of Option.apply:
An Option factory which creates Some(x) if the argument is not null,
and None if it is null.
The whole statement means then:
if conf.get("scoobi.jobid") is not equal null, assign this string,
otherwise assign the string sys.error("Scoobi job id not set.")
returns
It's just a legal character, just like "abcd..."
scala> def ?(i: Int) = i > 2
$qmark: (i: Int)Boolean
scala> val a_? = ?(3)
a_?: Boolean = true
UPD: See Valid identifier characters in Scala , Scala method and values names
UPD2: In the example "?" could be function, method of this or just some object with apply method. It probably returns Option[String].