patternMinor
Test runner for Scala problems
Viewed 0 times
scalarunnerfortestproblems
Problem
I'm learning Scala and could use another set of eyes on the code below. I'm creating a test runner for the 99 scala problems set. I figure between actually solving the problems and working through the pains of setting up a new IDE (trying IntelliJ from Eclipse), using new build tools (trying SBT from Maven), new testing tools etc, I'll have the language down pat. The code below is a runner that grabs all the solution files in a given directory and executes them. While the code works, I can't help but feel as though I'm doing this in the 'Java' way and not the 'Scala' way (ie - I'm not being very 'functional' in my implementation). Does anyone who knows Scala pretty well have any comment on what I've written thus far?
runner:
```
import java.io.File
import org.apache.commons.io.FilenameUtils
/**
* boodstraps program
*/
object bootStrap {
def main(args: Array[String]): Unit = {
// go through solution files and execute
for (fName <- getSolutionFiles(new File("./src/main/scala"))) {
val fNameNoExtS = FilenameUtils.removeExtension(fName.getName)
solutionRunner(fNameNoExtS)
}
}
def solutionRunner(name: String): Unit = {
println(name)
val classLoader = this.getClass.getClassLoader
val clazz = classLoader.loadClass(name)
val solutionMethod = clazz.getDeclaredMethod("solution")
solutionMethod.invoke(clazz.newInstance)
}
/**
* trolls through working directory and all sub directories in search of files
* with names starting with "sp_" ('sp' for 'scala problem'). thanks to
* stack overflow for base code: http://stackoverflow.com/questions/2637643/
* how-do-i-list-all-files-in-a-subdirectory-in-scala
*
* @param f - java File object
* @return targetFileList - Array[java.io.File] - list of file objects
* that have names starting with "sp_"
*/
def getSolutionFiles(f: File): Array[File] = {
// create lists of files, directories, and target files
runner:
```
import java.io.File
import org.apache.commons.io.FilenameUtils
/**
* boodstraps program
*/
object bootStrap {
def main(args: Array[String]): Unit = {
// go through solution files and execute
for (fName <- getSolutionFiles(new File("./src/main/scala"))) {
val fNameNoExtS = FilenameUtils.removeExtension(fName.getName)
solutionRunner(fNameNoExtS)
}
}
def solutionRunner(name: String): Unit = {
println(name)
val classLoader = this.getClass.getClassLoader
val clazz = classLoader.loadClass(name)
val solutionMethod = clazz.getDeclaredMethod("solution")
solutionMethod.invoke(clazz.newInstance)
}
/**
* trolls through working directory and all sub directories in search of files
* with names starting with "sp_" ('sp' for 'scala problem'). thanks to
* stack overflow for base code: http://stackoverflow.com/questions/2637643/
* how-do-i-list-all-files-in-a-subdirectory-in-scala
*
* @param f - java File object
* @return targetFileList - Array[java.io.File] - list of file objects
* that have names starting with "sp_"
*/
def getSolutionFiles(f: File): Array[File] = {
// create lists of files, directories, and target files
Solution
Idiomatic Scala Style
-
Class, object, and trait names follow camelCase style with the first letter capitalized. One example where you don't follow this rule is
-
For a few reasons, it is considered bad practice to user underscores in names. Applying the convention from the bullet point above with this we'd make the following transformation to your code:
-
The above rules also extend to types that you define. Consequently I'd change
-
Methods which act as accessors should be declared without parenthesis (unless they have side effects). In particular this applies to your
-
If you ever have any style questions check out this documentation.
Code Suggestions
A modified version of your
Cheers :)
-
Class, object, and trait names follow camelCase style with the first letter capitalized. One example where you don't follow this rule is
abstract class spMeta extends logging.-
For a few reasons, it is considered bad practice to user underscores in names. Applying the convention from the bullet point above with this we'd make the following transformation to your code:
class sp_01 extends spMeta => class Sp01 extends SpMeta.-
The above rules also extend to types that you define. Consequently I'd change
type inputT to type InputT, etc.-
Methods which act as accessors should be declared without parenthesis (unless they have side effects). In particular this applies to your
def getSolution(): SolutionT = ... which should just be plain old parenthesis-less def getSolution: SolutionT = ...-
If you ever have any style questions check out this documentation.
Code Suggestions
A modified version of your
getSolutionFiles method with explanations below.def getSolutionFiles(dir: File): Array[File] = {
val dirContents = dir.listFiles
val targetFiles = dirContents filter(x => x.getName.startsWith("sp_") && !x.isDirectory)
val childDirs = dirContents filter(_.isDirectory)
targetFiles ++ childDirs flatMap(d => getSolutionFiles(d))
}- I renamed the method paramter to
dirfromfile.
- All of the operations in this method are on the container type
Array. So I renamed some of the values to remove any mention ofList.
- Overall I think the renaming of these values make this method much easier to to immediately comprehend.
- Just to show you 'another way' and not because I thought anything was wrong with your original choice, I replaced your use of a regular expression for finding the correct files with
startsWith(...). Note there is also a methodendsWith(...).
- A bug could occur if the name of a file passed your filter predicate but is in fact a directory. I added a condition to to eliminate that possibility.
Cheers :)
Code Snippets
def getSolutionFiles(dir: File): Array[File] = {
val dirContents = dir.listFiles
val targetFiles = dirContents filter(x => x.getName.startsWith("sp_") && !x.isDirectory)
val childDirs = dirContents filter(_.isDirectory)
targetFiles ++ childDirs flatMap(d => getSolutionFiles(d))
}Context
StackExchange Code Review Q#81849, answer score: 2
Revisions (0)
No revisions yet.