All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.andrewmccall.faker.module.ScalaModule.scala Maven / Gradle / Ivy

The newest version!
package com.andrewmccall.faker.module

import com.andrewmccall.faker.{Config, Data, Entry, Faker, Namespace, StringEntry}
import org.apache.logging.log4j.scala.Logging
import org.reflections.scanners.MethodAnnotationsScanner
import org.reflections.util.{ClasspathHelper, ConfigurationBuilder}

import scala.reflect.runtime.universe._

class ScalaModule(clazz: Class[_], faker: Faker, config: Config) extends Logging {

  private val rm = scala.reflect.runtime.currentMirror
  private val t = rm.classSymbol(this.clazz).toType
  private val a = typeOf[faker]
  private val instance = clazz.getConstructor(classOf[Faker], classOf[Config]).newInstance(faker, config)

  def getName: String = {
    this.clazz.getSimpleName.toLowerCase
  }

  def getKeys: Iterable[String] = {
    t.members.filter(_.isMethod).filter(_.annotations.map(_.tree.tpe).contains(a)).map(snakify)
  }

  def contains(method: String): Boolean = {
    val ms = t.member(TermName(method))
    ms.annotations.foreach(i => logger.info(s"Annotations: $i ${i.getClass}"))
    ms != NoSymbol && ms.annotations.map(_.tree.tpe).contains(a)
  }

  def apply(method: String, args: Map[String, Any]): Any = {
    val ms = t.member(TermName(method)).asMethod
    ms.annotations.foreach(i => logger.info(s"Annotations: $i type- ${i.tpe} ${i.getClass}"))

    if (ms != NoSymbol && ms.annotations.map(_.tree.tpe).contains(a)) {

      // construct the args.
      val fullArgs = getDefaultArguments(ms) ++ args
      val argList = ms.paramLists.head.map(_.asTerm).zipWithIndex.map({case (p, i) => fullArgs.get(p.name.toString)})
      rm.reflect(instance).reflectMethod(ms).apply(argList)
    }
  }

  def getDefaultArguments(method: String): Map[String, Any] = {
    val ms = t.member(TermName(method)).asMethod
    getDefaultArguments(ms)
  }

  def getDefaultArguments(ms: MethodSymbol): Map[String, Any] = {

    logger.trace(s"Getting default arguments for Method ${ms.name}")

    val args = ms.paramLists.head.map(_.asTerm).filter(_.isParamWithDefault).zipWithIndex.map({ case (p, i) => {

      logger.trace(s"Finding paramenter ${p} for index ${i}")
      val term = TermName(s"${ms.name.toString}$$default$$${i + 1}")
      logger.trace(s"Method name will be: ${term.toString}")
      val method = t.member(term).asMethod
      logger.trace(s"Got method ${method}")
      (p.name.toString, rm.reflect(instance).reflectMethod(method).apply())
    }
    }).toMap

    logger.debug(s"${ms.name} has arguments ${args}")
    args
  }

  private def snakify(symbol: Symbol): String = {
    ScalaModule.snakify(symbol.fullName)
  }

}

object ScalaModule extends Logging {

  def loadModules(faker: Faker, config: Config): Data = {

    logger.info("Loading Modules.")

    import org.reflections.Reflections
    val reflections = new Reflections(
      new ConfigurationBuilder()
        .setUrls(ClasspathHelper.forPackage("com.andrewmccall.faker.module"))
        .setScanners(new MethodAnnotationsScanner())
    )

    val modules = reflections.getMethodsAnnotatedWith(classOf[com.andrewmccall.faker.module.faker])

    import scala.collection.JavaConverters._

    for (elem <- modules.asScala.toSeq) {
      logger.trace(s"Found $elem ${elem.getDeclaringClass}")
    }


    new ModuleData(modules.asScala.map(_.getDeclaringClass).toSeq.distinct.map(c => {
        logger.debug(s"Creating new ${c.getName} as ${c.getSimpleName}")
        val mod = new ScalaModule(c, faker, config)
        mod.getName -> mod
    }).toMap)
  }

  /**
    * Turn a string of format "FooBar" or "fooBar" into snake case "foo_bar"
    *
    * @return the snake cased string
    */
  private[module] def snakify(name: String) = name.replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2").replaceAll("([a-z\\d])([A-Z])", "$1_$2").toLowerCase

  private class ModuleData(modules: Map[String, ScalaModule]) extends Data {


    private def parseKey(key: String): (String, String) = {
      val parts = "\\.".r.split(key).takeRight(2)
      if (parts.length == 2) (parts(0).toLowerCase, parts(1).toLowerCase)
      else ("","")
    }

    override def fetch(key: String, locale: Option[String] = None, defaultLocale: String = Faker.defaultLocale): Option[Entry] = {
      val parsedKey = parseKey(key)
      Some(StringEntry(modules(parsedKey._1).apply(parsedKey._2, Map.empty).toString))
    }
    override def contains(key: String, locale: Option[String] = None, defaultLocale: String = Faker.defaultLocale): Boolean = {
      val parsedKey = parseKey(key)
      modules.contains(parsedKey._1) && modules(parsedKey._1).contains(parsedKey._2)
    }

    /**
      * Fetches any sub-keys for a key in this data.
      *
      * @param key
      * @return
      */
    override def getKeys(): Iterable[String] = modules.keys
  }



}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy