Consider the following:
There is a textfile with a certain amount of lines, like:
test.txt: a b c d e f g h
(each in there own line)
Then there is the following class used for parsing:
class MyAwesomeParser
{
def parse(fileName: String, readLines: Int): IndexedSeq[String] =
{
val randomAccessFile = new RandomAccessFile(fileName, "r")
val x: IndexedSeq[String] = for
{
x <- 0 until readLines
r = randomAccessFile.readLine()
} yield r
x
}
}
Here come the tests:
class MyAwesomeParserTest extends WordSpec
{
"MyAwesomeParser" when {
"read" should {
"parse only specified number of lines" in {
val parser = new EdgeParser("")
val x = parser.parse("test.txt", 5)
assert(x.size == 5)
}
}
"MyAwesomeParser" when {
"read" should {
"parse only until end of file" in {
val parser = new EdgeParser("")
val x = parser.parse("test.txt", 10)
assert(x.size == 8)
}
}
}
}
Second test is the problematic one. Now of course you say, you're missing a guard here... well, well, if I add
x <- 0 until readLines if randomAccessFile.readLine != null
to the implementation then it skips a few lines, because readLine already consumes the line.
r = randomAccessFile.readLine
x <- 0 until readLines if r != null
will not work sadly, as first one line has to be assignment for comprehension.
Now I wonder, is it even possible with a for comprehension to loop until a given amount of times OR stop before based on that readLine != null
condition?
Is my syntax just broken?
You may encapsulate randomAccessFile.readLine
in an Option
, so that null
will be changed to None
and value
to Some(value)
.
Moreover, Option
can be considered as a collection, so you may put it in the same for comprehension as the IndexedSeq
:
for {
x <- 0 until readLines
r <- Option(randomAccessFile.readLine())
} yield r