Упрощение/СУШКА оператора case в Scala для шаблонов Twirl

Итак, я использую шаблоны play Twirl (не в игре; независимый проект), и у меня есть несколько шаблонов, которые генерируют некоторые DDL базы данных. Следующие работы:

if(config.params.showDDL.isSupplied) {
    print( BigSenseServer.config.options("dbms") match {
      case "mysql" => txt.mysql(
        BigSenseServer.config.options("dbDatabase"),
        InetAddress.getLocalHost().getCanonicalHostName,
        BigSenseServer.config.options("dboUser"),
        BigSenseServer.config.options("dboPass"),
        BigSenseServer.config.options("dbUser"),
        BigSenseServer.config.options("dbPass")
      )
      case "pgsql" => txt.pgsql(
        BigSenseServer.config.options("dbDatabase"),
        InetAddress.getLocalHost().getCanonicalHostName,
        BigSenseServer.config.options("dboUser"),
        BigSenseServer.config.options("dboPass"),
        BigSenseServer.config.options("dbUser"),
        BigSenseServer.config.options("dbPass")
      )
      case "mssql" => txt.mssql$.MODULE$(
        BigSenseServer.config.options("dbDatabase"),
        InetAddress.getLocalHost().getCanonicalHostName,
        BigSenseServer.config.options("dboUser"),
        BigSenseServer.config.options("dboPass"),
        BigSenseServer.config.options("dbUser"),
        BigSenseServer.config.options("dbPass")
      )
    })

    System.exit(0)
}

Но у меня много повторяющихся заявлений. Если я попытаюсь присвоить регистр переменной и использовать трюк $.MODULE$, я получу сообщение об ошибке, говорящее, что моя переменная не принимает параметры:

val b = BigSenseServer.config.options("dbms") match {
      case "mysql" => txt.mysql$.MODULE$
      case "pgsql" => txt.pgsql$.MODULE$
      case "mssql" => txt.mssql$.MODULE$
}
b("string1","string2","string3","string4","string5","string6")

и ошибка:

BigSense/src/main/scala/io/bigsense/server/BigSenseServer.scala:32: play.twirl.api.BaseScalaTemplate[T,F] с play.twirl.api.Template6[A,B,C,D,E ,F,Result] не принимает параметров

Как лучше всего упростить этот код Scala?

EDIT: Окончательное решение, используя комбинацию ответов ниже

В приведенных ниже ответах предлагается создать фабричные классы, но я действительно хочу этого избежать, поскольку у меня уже есть сгенерированный Twirl объект шаблона. Частично примененные функции помогли мне лучше понять, как этого добиться. Оказывается, все, что мне нужно было сделать, это выбрать apply методов и выполнить их эта-расширение; при необходимости в сочетании с частичным применением функций. Отлично работает следующее:

  if(config.params.showDDL.isSupplied) {

    print((config.options("dbms") match {
      case "pgsql" => 
        txt.pgsql.apply _
      case "mssql" => 
        txt.mssql.apply _
      case "mysql" => 
        txt.mysql.apply(InetAddress.getLocalHost().getCanonicalHostName,
                        _:String, _:String, _:String,_:String, _:String)
    })(
        config.options("dbDatabase"),
        config.options("dboUser"),
        config.options("dboPass"),
        config.options("dbUser"),
        config.options("dbPass")
    ))

    System.exit(0)
  }

person djsumdog    schedule 26.02.2015    source источник


Ответы (2)


Вы можете попробовать использовать эта-расширение и частично примененные функции.

Дана фабрика с некоторыми методами:

class Factory {
  def mysql(i: Int, s: String) = s"x: $i/$s"
  def pgsql(i: Int, s: String) = s"y: $i/$s"
  def mssql(i: Int, j: Int, s: String) = s"z: $i/$j/$s"
}

Вы можете абстрагироваться от таких методов:

val factory = new Factory()

// Arguments required by all factory methods
val i = 5
val s = "Hello"

Seq("mysql", "pgsql", "mssql").foreach {
  name =>

    val f = name match {
      case "mysql" =>
        // Eta-expand: Convert method into function
        factory.mysql _

      case "pgsql" =>
        factory.pgsql _

      case "mssql" =>
        // Argument for only one factory method
        val j = 10
        // Eta-expand, then apply function partially
        factory.mssql(_ :Int, j, _: String)
    }

    // Fill in common arguments into the new function
    val result = f(i, s)
    println(name + " -> " + result)
}

Как видите, в случае с «mssql» аргументы могут даже различаться; однако общие аргументы нужно передать только один раз. Цикл foreach предназначен только для проверки каждого случая, код в теле показывает, как частично применить функцию.

person Beryllium    schedule 26.02.2015
comment
Я хотел избежать фабрики для существующих объектов, но ваш ответ помог мне понять, чего я хотел достичь. Проверьте редактирование моего исходного поста. - person djsumdog; 27.02.2015
comment
Пожалуйста. Фабричный класс в моем ответе - просто иметь компилируемый фрагмент (игра не требуется). В любом случае ваше окончательное решение реализует именно то, что я хотел бы показать - частичное применение соответствующих методов :-) - person Beryllium; 27.02.2015

Вы можете попытаться сделать это, используя tuple() для создания кортежной версии функции.

object X {
  def a(x : Int, y : Int, z : Int) = "A" + x + y + z
  def b(x : Int, y : Int, z : Int) = "B" + x + y + z
  def c(x : Int, y : Int, z : Int) = "C" + x + y + z
}

val selectedFunc = X.a _

selectedFunc.tupled((1, 2, 3)) //returns A123

В частности, вы должны хранить свои параметры в кортеже:

val params = (BigSenseServer.config.options("dbDatabase"), 
              InetAddress.getLocalHost().getCanonicalHostName) //etc.

а затем в вашем заявлении о совпадении:

case "mysql" => (txt.mysql _).tupled(params)
person Piotr Rudnicki    schedule 26.02.2015