Created
September 3, 2015 17:02
-
-
Save sortega/122e7a332c10aa632a1b to your computer and use it in GitHub Desktop.
Line count kata
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package lines | |
import java.io.File | |
import scala.annotation.tailrec | |
object LineCount { | |
def of(file: File): Int = { | |
val source = scala.io.Source.fromFile(file) | |
try of(source.toStream) | |
finally source.close() | |
} | |
def of(string: String): Int = of(string.toStream) | |
def of(input: Stream[Char]): Int = countLines(input, nonEmptyLines = 0) | |
@tailrec | |
private def countLines( | |
input: Stream[Char], | |
nonEmptyLines: Int, | |
currentLineIsEmpty: Boolean = true): Int = { | |
def newNonEmptyLines: Int = nonEmptyLines + (if (currentLineIsEmpty) 0 else 1) | |
input match { | |
case Stream.Empty => newNonEmptyLines | |
case '\n' #:: remaining => countLines(remaining, newNonEmptyLines) | |
case whitespace #:: remaining if Character.isWhitespace(whitespace) => | |
countLines(remaining, nonEmptyLines, currentLineIsEmpty) | |
case '"' #:: remaining => | |
countLines(remaining.dropWhile(_ != '"').tail, nonEmptyLines, currentLineIsEmpty = false) | |
case '/' #:: '/' #:: remaining => | |
countLines(remaining.dropWhile(_ != '\n'), nonEmptyLines, currentLineIsEmpty) | |
case '/' #:: '*' #:: remaining => | |
val commentSize = remaining.sliding(2).takeWhile(_ != "*/".toStream).size + 2 | |
val (comment, afterComment) = remaining.splitAt(commentSize) | |
countLines( | |
input = afterComment, | |
nonEmptyLines = if (comment.contains('\n')) newNonEmptyLines else nonEmptyLines | |
) | |
case nonWhitespace #:: remaining => | |
countLines(remaining, nonEmptyLines, currentLineIsEmpty = false) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package lines | |
import org.scalatest.{FlatSpec, ShouldMatchers} | |
class LineCountTest extends FlatSpec with ShouldMatchers { | |
"Line count" should "have 0 lines for empty files" in { | |
LineCount.of("") shouldBe 0 | |
} | |
it should "have 0 lines for lines with just whitespace" in { | |
LineCount.of(" \n\t\n\n") shouldBe 0 | |
} | |
it should "count lines with text" in { | |
LineCount.of( | |
"""def fun(arg1, arg2): foo | |
| | |
|def bar: 3 | |
""".stripMargin) shouldBe 2 | |
} | |
it should "discard line comments" in { | |
LineCount.of( | |
"""// This file contains 3 lines of code | |
|public interface Dave { | |
| int countLines(File inFile); // not the real signature! | |
|} | |
| | |
""".stripMargin) shouldBe 3 | |
} | |
it should "discard block comments" in { | |
LineCount.of( | |
"""// This file contains 3 lines of code | |
|public interface Dave { | |
| /** | |
| * count the number of lines in a file | |
| */ | |
| int countLines(File inFile); // not the real signature! | |
|} | |
| | |
""".stripMargin) shouldBe 3 | |
} | |
it should "discard bizarre comments" in { | |
LineCount.of( | |
"""/***** | |
| * This is a test program with 5 lines of code | |
| * \/* no nesting allowed! | |
| //*****//***/// Slightly pathological comment ending... | |
| | |
|public class Hello { | |
| public static final void main(String [] args) { // gotta love Java | |
| // Say hello | |
| System./*wait*/out./*for*/println/*it*/("Hello/*"); | |
| } | |
| | |
|} | |
| | |
""".stripMargin) shouldBe 5 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment