Commits

apitech committed 82c2de1 Draft

Added companion meth, moved newInstance to public API, restructured test/example with for comprehensions, and moved test source files to root

  • Participants
  • Parent commits 6abbeb6

Comments (0)

Files changed (10)

+/*
+ * Copyright 2013 API Technologies, LLC
+ *
+ * Distributed under the terms of the modified BSD license. See the LICENSE file
+ * for further details.
+ */
+
+class FileTest(val testVal: String) extends FileTestTrait {
+  def test: String = testVal
+}

File MyChildConfig.cfg

+/*
+ * Copyright 2013 API Technologies, LLC
+ *
+ * Distributed under the terms of the modified BSD license. See the LICENSE file
+ * for further details.
+ */
+
+object MyChildConfig extends ChildConfig {
+  val reqString = "MyReqString"
+
+  override val optString = Some("MyOptString")
+}

File MyParentConfig.cfg

+/*
+ * Copyright 2013 API Technologies, LLC
+ *
+ * Distributed under the terms of the modified BSD license. See the LICENSE file
+ * for further details.
+ */
+
+object MyParentConfig extends ParentConfig {
+  val childConfig = MyChildConfig
+}

File src/main/resources/MyChildConfig.cfg

-/*
- * Copyright 2013 API Technologies, LLC
- *
- * Distributed under the terms of the modified BSD license. See the LICENSE file
- * for further details.
- */
-
-object MyChildConfig extends ChildConfig {
-  val reqString = "MyReqString"
-
-  override val optString = Some("MyOptString")
-}

File src/main/resources/MyParentConfig.cfg

-/*
- * Copyright 2013 API Technologies, LLC
- *
- * Distributed under the terms of the modified BSD license. See the LICENSE file
- * for further details.
- */
-
-object MyParentConfig extends ParentConfig {
-  val childConfig = MyChildConfig
-}

File src/main/scala/api/source/example/ConfigFiles.scala

  * for further details.
  */
 
-import api.source.{srcFileToObj, srcFileToClass}
+import api.source.{companion, srcFileToClass}
 import java.io.File
 
 trait ParentConfig {
 }
 
 package api.source.example {
-  // NOTE: This example will only work when extracted (not in a JAR file)
+  // NOTE: Requires 'MyParentConfig' and 'MyChildConfig' in cwd
   object ConfigFiles extends App {
-    val srcDir = System.getProperty("user.dir") +
-      List("", "src", "main", "resources", "").mkString(File.separator)
+    val srcDir = System.getProperty("user.dir") + File.separator
 
-    srcFileToClass[ChildConfig](srcDir + "MyChildConfig.cfg", "MyChildConfig$")
-    srcFileToObj[ParentConfig](srcDir + "MyParentConfig.cfg", "MyParentConfig$") match {
+    val obj = for {
+      _ <- srcFileToClass[ChildConfig](srcDir + "MyChildConfig.cfg").right
+      o <- companion(srcFileToClass[ParentConfig](srcDir + "MyParentConfig.cfg")).right
+    } yield o
+
+    obj match {
       case Left(e)        =>
         throw e
       case Right(config)  =>

File src/main/scala/api/source/package.scala

 import scala.reflect.ClassTag
 import java.util.Date
 import java.io.File
+import java.lang.reflect.Constructor
 import api.source.util._
 
 package object source {
 
   private def tryCreate[T: ClassTag](clsEither: ClsEither[T], args: Seq[Any])
       : ObjEither[T] =
-    try clsEither match {
+    clsEither match {
       case Left(obj)  => Left(obj)
-      case Right(cls) => Right(newInstance(cls, args))
-    } catch {
-      case e: Exception => Left(e)
+      case Right(cls) => newInstance(cls, args)
     }
 
   // *** Main functions ***
                             modDate:  Date = new Date,
                             force:    Boolean = false): ObjEither[T] =
     tryCreate(srcToClass(src, name, outDir, modDate, force), args)
+
+  def companion[T](cls: Class[T]): ObjEither[T] =
+    newInstance(loadClass(companionPath(cls)))
+
+  def companion[T](cls: ClsEither[T]): ObjEither[T] =
+    cls match {
+      case Left(e)    => Left(e)
+      case Right(cl)  => companion(cl)
+    }
+
+  def newInstance[T](cls: Class[T], args: Seq[Any] = Seq.empty): ObjEither[T] = {
+    try {
+      Right(if (cls.getName.endsWith("$"))
+        cls.getField("MODULE$").get(null).asInstanceOf[T]
+      else {
+        val constructors =  cls.getConstructors.toList
+        require(constructors.size == 1,
+          "Constructor not found or ambiguous constructor " +
+            "(only single constructor classes are allowed)")
+        constructors.head.asInstanceOf[Constructor[T]]
+          .newInstance(args.asInstanceOf[Seq[AnyRef]]: _*)
+      })
+    } catch {
+      case e: Exception => Left(e)
+    }
+  }
 }

File src/main/scala/api/source/util/package.scala

 import scala.tools.nsc.Global
 import java.io._
 import java.net.URLClassLoader
-import java.lang.reflect.Constructor
 
 package object util {
   def lastModified(fileName: String): Long = new File(fileName).lastModified
     classLoader.loadClass(file).asInstanceOf[Class[T]]
   }
 
-  def getFullPath(classPath: String): String =
-    Option(getClass.getResource(classPath)) match {
+  def getFullPath(classPath: String, cls: Class[_]): String =
+    Option(cls.getResource(classPath)) match {
       case None      => ""
       case Some(url) => url.getPath
     }
 
-  def pathOfClass(className: String): String = {
+  def pathOfClass(className: String, cls: Class[_] = getClass): String = {
     val resource = className.split('.').mkString("/", "/", ".class")
 
-    getFullPath(resource) match {
+    getFullPath(resource, cls) match {
       case s @ ""   => s
       case path @ _ =>
         val indexOfFile = path.indexOf("file:")
     }
   }
 
-  def newInstance[T](cls: Class[T], args: Seq[Any] = Seq.empty): T = {
-    if (cls.getName.endsWith("$")) cls.getField("MODULE$").get(null).asInstanceOf[T]
-    else {
-      val constructors =  cls.getConstructors.toList
-      require(constructors.size == 1,
-        "Constructor not found or ambiguous constructor " +
-          "(only single constructor classes are allowed)")
-      constructors.head.asInstanceOf[Constructor[T]]
-        .newInstance(args.asInstanceOf[Seq[AnyRef]]: _*)
-    }
+  def companionPath[T](cls: Class[T]): String = {
+    val name = cls.getName
+    pathOfClass(name, cls) + File.separator + name.split('.')(0) + '$'
   }
 
   def compile[T: ClassTag](src: String, outDir: String, name: String, isFile: Boolean = true)

File src/test/resources/api/source/FileTest.scala

-/*
- * Copyright 2013 API Technologies, LLC
- *
- * Distributed under the terms of the modified BSD license. See the LICENSE file
- * for further details.
- */
-
-package api.source
-
-class FileTest(val testVal: String) extends FileTestTrait {
-  def test: String = testVal
-}

File src/test/scala/api/source/CompileTests.scala

  * for further details.
  */
 
-package api.source
-
 import java.io.File
 import org.scalatest.FunSuite
-import util.newInstance
 
 trait FileTestTrait {
   def test: String
   def test: Int
 }
 
-class CompileTests extends FunSuite {
-  private val src = """
-    import api.source.TestTrait
+package api.source {
+  class CompileTests extends FunSuite {
+    private val src = """
+      class Test(val i: Int) extends TestTrait {
+        def test: Int = i
+      }
+    """
 
-    class Test(val i: Int) extends TestTrait {
-      def test: Int = i
+    private val dir = System.getProperty("user.dir") + File.separator
+    private val name = "FileTest"
+
+    test("srcToObj") {
+      val testVal = 42
+
+      srcToObj[TestTrait](src, "Test", Seq(testVal)) match {
+        case Left(e)     => throw e
+        case Right(test) => expectResult(testVal)(test.test)
+      }
     }
-  """
 
-  private val dir = System.getProperty("user.dir") +
-    List("", "src", "test", "resources", "api", "source", "").mkString(File.separator)
-  private val name = "api.source.FileTest"
+    // NOTE: Requires 'FileTest' in cwd
+    test("srcFileToObj") {
+      val testVal = "test"
 
-  test("srcToObj") {
-    val testVal = 42
+      srcFileToObj[FileTestTrait](dir + name, name, Seq(testVal), dir) match {
+        case Left(e)     => throw e
+        case Right(test) => expectResult(testVal)(test.test)
+      }
+    }
 
-    srcToObj[TestTrait](src, "Test", Seq(testVal)) match {
-      case Left(e)     => throw e
-      case Right(test) => expectResult(testVal)(test.test)
+    test("srcToClass + newInstance") {
+      val testVal = 42
+
+      val obj = for {
+        c <- srcToClass[TestTrait](src, "Test").right
+        o <- newInstance(c, Seq(testVal)).right
+      } yield o
+
+      obj match {
+        case Left(e)  => throw e
+        case Right(o) => expectResult(testVal)(o.test)
+      }
     }
-  }
 
-  // NOTE: This test will only work when in extracted form (not in a JAR)
-  test("srcFileToObj") {
-    val testVal = "test"
+    // NOTE: Requires 'FileTest' in cwd
+    test("srcFileToClass + newInstance") {
+      val testVal = "test"
 
-    srcFileToObj[FileTestTrait](dir + "FileTest.scala", name, Seq(testVal), dir) match {
-      case Left(e)     => throw e
-      case Right(test) => expectResult(testVal)(test.test)
-    }
-  }
+      val obj = for {
+        c <- srcFileToClass[FileTestTrait](dir + name, name, dir).right
+        o <- newInstance(c, Seq(testVal)).right
+      } yield o
 
-  test("srcToClass + newInstance") {
-    val testVal = 42
-
-    srcToClass[TestTrait](src, "Test") match {
-      case Left(e)        => throw e
-      case Right(testCls) =>
-        expectResult(testVal)(newInstance(testCls, Seq(testVal)).test)
-    }
-  }
-
-  // NOTE: This test will only work when in extracted form (not in a JAR)
-  test("srcFileToClass + newInstance") {
-    val testVal = "test"
-
-    srcFileToClass[FileTestTrait](dir + "FileTest.scala", name, dir) match {
-      case Left(e)        => throw e
-      case Right(testCls) =>
-        expectResult(testVal)(newInstance(testCls, Seq(testVal)).test)
+      obj match {
+        case Left(e)  => throw e
+        case Right(o) => expectResult(testVal)(o.test)
+      }
     }
   }
 }