Macros/Shapeless 在方法中控制字符串值

Macros/Shapeless to control string value in method

我正在创建一个 DSL,其中用户有给定的时间,他们可以在其中传递包含他们想要的操作的字符串。

所有这些操作都是使用一些正则表达式控制的。 现在使用无形或宏,我想控制用户使用 DSL 组成的内容,如果字符串不符合我们预期的字符串,则代码无法编译。

例如Si

Given("a good action") -> fine
When("wrong string action") -> compilation error 

任何人都可以给我指点一个好的博客或文档来说明如何实现这一点吗?

此致

在 Gabriele 的解决方案之后,我现在面临一个设计问题。这是我的 vaidator class

object DSLValidator {

  import scala.language.experimental.macros

  def Given(message: String): Any = macro checkActionImpl

  def When(message: String): Any = macro checkActionImpl

  def Then(message: String): Any = macro checkActionImpl

  def And(message: String): Any = macro checkActionImpl

  def checkActionImpl(c: blackbox.Context)(message: c.Tree): c.Tree = {
    import c.universe._
    def isValidAction(s: String): Boolean = checkMessage(s)

    message match {
      case _tree@Literal(Constant(s: String)) if isValidAction(s) => _tree
      case _ => c.abort(c.enclosingPosition, "Invalid action for DSL. Check the allowed actions in RegexActions")
    }
  }

  val PARAMS = "(.*)=(.*)"
  val PAYLOAD_VALUE_REGEX = s"^Payload $PARAMS".r

  def checkMessage(action: String): Boolean = {
    action match {
      case PAYLOAD_VALUE_REGEX(c, c1) => true
      case "Make a request to server" => true
      case _ => false
    }
  }
}

如果我用错误的参数从另一个 class 调用 Given/When/Then,编译器会像我们预期的那样报错。

  @Test
  def TestDSL(): Unit = {
    DSLValidator.Given("Make a request to wrong")--> not compiling
    DSLValidator.When("Payload code=works") --> compiling
    println("End")
  }

但现在认为整个想法不仅是检查编译时的值,而且还要执行 Given/When/then

的逻辑

而且我意识到,当我在函数中使用宏时,我们别无他法。

   def Given(message: String): Any =  { 
          macro checkActionImpl
          //My bussiness logic
      }

没有编译,所以我的问题是,我现在可以把业务逻辑放在哪里,宏函数的调用在哪里继续工作。

同时使用静态 class 作为桥接器不起作用并且不会编译,因为字符串消息不适合。

object Macros {

  def Given(message: String) = {
    DSLValidator.Given(message)
    //Logic here
    println("Given")
  }
}

Macros.Given("Make a request to wrong")

有什么想法吗?

此致

我认为 shapeless 在这种情况下无法帮助您,因此宏是可行的方法。

这是您可以从中开始的宏的框架:

import scala.language.experimental.macros
def Given(message: String): /* the return type of Given */ = macro givenImpl

def givenImpl(c: Context)(message: c.Tree): c.Tree = {
  import c.universe._
  def isValid(s: String): Boolean = ??? // your validation logic here

  message match {
    case case t @ Literal(Constant(s: String)) if isValid(s) => t
    case _ => c.abort(c.enclosingPosition, "Invalid message")
  }

}

为了完全理解这一点,我建议您阅读: