Ruby:如何处理代码“块”(特定于域的语言)

时间:2012-07-10 21:47:47

标签: ruby

基本上,我想象一些看起来像这样的伪代码

build_command_list {
   add_command("cmd 1")
   add_command("cmd 2")
   conditional_branch( some_cond ) {
      add_command("cmd3")
      add_command("cmd4")
   }
   conditional_branch( some_other_cond ) {
      add_command("cmd 5")
   }
}

方法build_command_list将采用一段代码,然后递归地构建一个树结构,其中每个节点都是一个命令,一些解释器将从该根获取该树并执行它,这是第一个命令那段代码(在这种情况下,"cmd 1"

add_commandconditional_branch是确定如何创建节点的其他方法。

conditional branch这样的命令告诉解释器评估一个条件,如果是,它将处理它的命令列表。

我想知道ruby是否有一些东西可以让我像上面的例子一样编写一段代码,然后拿出代码并解析它?

如果没有,也许有人可以建议我以这样的方式编写输入,以便我可以从一组命令构建正确的命令树?

2 个答案:

答案 0 :(得分:2)

您可以编写完全符合此要求的DSL:

class CommandList
  def add_command(str)
    puts "Adding command #{str}"
  end

  def conditional_branch(condition, &block)
    b = ConditionalBranch.new(condition)

    puts "With condition: #{condition} {"
    b.instance_eval(&block)
    puts "}"
  end
end

class ConditionalBranch < CommandList
  def initialize condition
    @condition = condition
  end
end

def build_command_list &block
  c = CommandList.new
  c.instance_eval(&block)
end

DSL使用

build_command_list {
   add_command("cmd 1")
   add_command("cmd 2")
   conditional_branch( "some_cond" ) {
      add_command("cmd3")
      add_command("cmd4")
   }
   conditional_branch( "some_other_cond" ) {
      add_command("cmd 5")
   }
}

输出

Adding command cmd 1
Adding command cmd 2
With condition: some_cond {
Adding command cmd3
Adding command cmd4
}
With condition: some_other_cond {
Adding command cmd 5
}

请注意,这可能不会按照您希望的方式处理条件,它只是一个示例,说明如何使用instance_eval来评估给定对象上下文中的块

答案 1 :(得分:0)

你在这里谈论的是一种DSL(领域特定语言)。

您可以在ruby中实现内部和外部DSL。

对于外部DSL,您需要创建一个解析器。这就是为什么用ruby创建内部DSL通常会更好。

我写了一篇关于可用于实现此目的的基本技术的博客文章:http://blog.nofail.de/2010/02/writing-your-own-dsl-with-ruby/