# File-to-fully qualified class name function

My instincts are telling me a seasoned Scala programmer will find my code less than optimal. As will no doubt be obvious, I'm a Java guy who has just started in with Scala. Is there a more 'functional' way to accomplish this that I'm missing?

/**
* takes a file object and returns a string representing the fully qualified
* class name represented by that file.
*
* @param file
* @return string representation of the fully qualified class name
*/
def makeFqClassName(file: File): String = {
// pull out the file name - we'll use this for our class name
val fNameNoExtS = FilenameUtils.removeExtension(file.getName)

// extract only the path
val fPathOnlyS =
file.getPath.substring(0, file.getPath.lastIndexOf(File.separator))

// create a list of the path name, minus the delimiter
val fPathDelimList: List[String] = fPathOnlyS.split("/").toList

// truncate the list to include on the class name info
val fqNameList: List[String] =
fPathDelimList.drop(fPathDelimList.lastIndexOf("solutions"))

// convert the list to a string representation of a class name and return
// to caller
fqNameList.mkString(".") + "." + fNameNoExtS
}


Expected input: .java file object where the file name and the class name enclosed in the file are the same.

Sp01.scala

Expected output: fully qualified class name:

solutions.working_with_lists.Sp01

Note that if we were working with one of the problems from another group, the class name would be something like:

solutions.arithmetic.Sp31

The reason for all this is that I'm new to Scala and working my way through the 99 Scala problems set. This method is part of a test runner that trolls through the project files, picks up solution files, then uses reflection to instantiate an instance of the solution class and executes its solver method. This way I can organize the project files in a way that makes sense - in a way that matches the manner in which the problem set is structured - as well as work on whatever problem I want to work on while simultaneously giving me the freedom to reorganize the package structure w/o having to refactor the runner code.

• What exactly are you trying to accomplish, and why is "solutions" a special case? – 200_success Feb 25 '15 at 21:59
• @200_success I'm working my way through the 99 scala problems - this is part of the test runner (see preview.tinyurl.com/kyqc55h for the full code). the top-level package name is 'solutions', which is why that's special. because I'm coding and running the tests as I go, the test runner traverses the project directories and searches for files that conform to a spec, creates an instance of the class embodied in the file, and executes the solution/test code. this utility allows me to take a file path/file name and turn it into a fully qualified class name to use in the reflection code. – David Holiday Feb 25 '15 at 22:19
• Could you include an input and expected output? – t. fochtman Feb 27 '15 at 3:53
• requested info is contained in the update. also - know that this is part of a test runner that I've written as part of my endeavor to solve the entire 99 scala problems set. – David Holiday Feb 27 '15 at 17:31

My current assumption is that the string returned by file.getPath is going to look something like ..\solutions\some-parent-dir\some-scala-file.scala

If this is the case then you can try the following function:

def makeFqClassName(file: File): String = {
val fileName :: _ = file.getName.split('.').toList
val upDir :: upUpDir :: _ = file.getParent.split(File.separator(0)).toList.reverse
s"$upUpDir.$upDir.\$fileName"
}


I've introduced a smidgen of strange syntax just to show you a possibility. As a way of explaining what is going on, consider that the following are functionally equivalent:

  val foo :: _ = List(0, 1, 2, 3)
val goo = List(0, 1, 2, 3).head


From the POV of operations performed they're unequivalent. foo is defined from the result of a pattern match that discards the tail of the list. goo as you know is the result of the invocation of the head method. (I suppose it could be the case that the compiler is smart enough to translate a pattern match on a list that only takes the head of the list into an invocation of the head method, but lets just ignore that for now :^) And a final example:

val a :: b :: c :: d :: ez = ('a' to 'z').toList


Here a , b , c , and d are assigned the expected character values and ez is a list consisting of the characters e through z.