package listPreparation
object Item {
var errors = false
def apply(line: String) = {
val parts = line.split(" *\\|\\| *")
parts match {
case Array(a, b, c, d, e, f) =>
new Item(a, b, c.toInt, d.toInt, e.toInt, f.toInt)
case Array(a, b) =>
new Item(a, b)
case _ =>
errors = true
new Item("// " + line, "?", 0, 0, 0, 0)
}
}
}
case class Item(val stimulus: String, var response: String,
timesCorrect: Int, timesIncorrect: Int,
interval: Int, date: Int) {
/** Constructor for virgin items. */
def this(stimulus: String, response: String) {
this(stimulus, response, 0, 0, 0, 0)
}
def equalStimulus(that: Item) = this.stimulus == that.stimulus
def equalResponse(that: Item) = this.response == that.response
override def toString =
stimulus + " || " + response +
(if (timesCorrect != 0 || timesIncorrect != 0)
" || " + timesCorrect + " || " + timesIncorrect +
" || " + interval + " || " + date
else "")
}
|
3. This defines a singleton object of class Item. Variable definitions (line 4) and function definitions (line 6) in this object are like static definitions in Java.
6. apply constructs and returns a new Item from the given line.
8. The parts array is tested to see whether it has 6 elements (line 9), 2 elements (line 11), or something else (line 13).
20-23. The case class is both a definition of class Item and a constructor for it. It provides getter methods for val parameters and getter and setter methods for var parameters.
25. this defines an auxiliary constructor.
29. Testing string equality with == just works.
34. The last value computed in a function is the value that it returns.
35. if...else is an expression as well as a statement. |
package listPreparation
import java.io.File
object ListPreparer {
def main(args: Array[String]): Unit = {
val itemList1 = readItemList(None)
val itemList2 = readItemList(None)
val itemList3 = combineItemLists(itemList1, itemList2)
writeItemList(itemList3)
}
/** Choose a file and read it in as a list of lines. */
def readFileAsListOfLines(): List[String] = {
import scala.swing.FileChooser, java.io.File
val chooser = new FileChooser
val response = chooser.showOpenDialog(null)
if (response == FileChooser.Result.Approve) {
readFileAsListOfLines(chooser.selectedFile)
}
else readFileAsListOfLines()
}
/** Read in the named file as a list of lines. */
def readFileAsListOfLines(fileName: String): List[String] = {
val file = new File(fileName)
readFileAsListOfLines(file)
}
/* Read in the File as a list of lines. */
def readFileAsListOfLines(file: File): List[String] = {
import scala.io.Source, scala.io.Source._
val stream = Source.fromFile(file)
val lines = stream.getLines.toList
stream.close
lines
}
/** Given a File, file name, or None, read in a list of Items. */
def readItemList(source: Any): List[Item] = {
val lines = source match {
case fileName: String => readFileAsListOfLines(fileName)
case file: File => readFileAsListOfLines(file)
case _ => readFileAsListOfLines()
}
for (line <- lines) yield Item(line)
}
/** Choose a file and save the given item list on it. */
def writeItemList(list: List[Item]) {
import scala.swing.FileChooser, java.io.File, java.io.PrintWriter
val chooser = new FileChooser
val response = chooser.showSaveDialog(null)
if (response == FileChooser.Result.Approve) {
val stream = new PrintWriter(chooser.selectedFile)
for (item <- list) stream.println(item)
stream.close
}
}
/** Find stimulus stimulus in item list. */
def findStimulus(goal: Item, list: List[Item]): Option[Item] = {
for (item <- list if item.equalStimulus(goal)) return Some(item)
return None
}
/** Start with list1 and add items from list2. If the stimulus from
* list2 is the same as from list1, but the response differs, ask
* the user to choose between them. A response other than 1 or 2
* is taken to be a new definition. */
def combineItemLists(list1: List[Item], list2: List[Item]): List[Item] = {
var list3 = for (item <- list1) yield item
for (item2 <- list2) {
findStimulus(item2, list1) match {
case Some(item1) =>
if (! item2.equalResponse(item1)) {
println("1 " + item1.stimulus + " || " + item1.response)
println("2 " + item2.stimulus + " || " + item2.response)
readLine("Which? ").trim match {
case "1" => // Don't change item
case "2" => item1.response = item2.response
case newDef => item1.response = newDef
}
}
case None => list3 ++= List(item2)
}
}
list3
}
}
|
5. We only need one ListPreparer object, so we don't need to define a separate class.
15, 26, 32. Overloaded methods. Not all are in current use, but they are being kept for reasons of flexibility. The return type is specified after the colon (:).
16, 33, 52. import statements can be local.
42. An appropriate case is chosen based on the type of the parameter source.
47. Converts a list of lines into a list of Items.
65. Where a Java method might return an object or null, Scala prefers to return a Some(object) or None.
83. In this case, the variable newDef is set to the value read in by readLine.
86. item2 is appended to list3. |