【问题标题】:What separates a Ruby DSL from an ordinary APIRuby DSL 与普通 API 的区别
【发布时间】:2009-10-12 23:45:49
【问题描述】:

Ruby DSL 有哪些定义性特征将其与常规 API 区分开来?

【问题讨论】:

标签: ruby design-patterns dsl


【解决方案1】:

当您使用 API 时,您会以命令式的方式实例化对象并调用方法。另一方面,一个好的 DSL 应该是声明性的,代表问题域中的规则和关系,而不是要执行的指令。此外,理想情况下,非程序员的人应该可以阅读和修改 DSL(API 不是这种情况)。

另外请记住内部和外部 DSL 的区别。

  • 内部领域特定语言嵌入在编程语言(例如 Ruby)中。它很容易实现,但 DSL 的结构取决于它所嵌入的母语。
  • 外部领域特定语言是一种独立的语言,设计时考虑了特定领域。它在语法方面为您提供了更大的灵活性,但您必须实现代码来解释它。它也更安全,因为编辑域规则的人无法使用母语的所有功能。

【讨论】:

  • +1 用于区分内部和外部 DSL。
  • 感谢您的赏金,现在我可以感觉像 Boba Fett 了:P
【解决方案2】:

DSL(领域特定语言)是一个被过度炒作的术语。如果您只是使用一种语言的子集(例如 Ruby),那么它与原始语言有何不同?答案是,不是。

但是,如果您对源文本进行一些预处理以引入核心语言中没有的新语法或新语义,那么您确实拥有一种新语言,它可能是特定于领域的。

【讨论】:

  • 因此,如果我重写 << 运算符以执行与 Ruby 中普通对象通常会执行的操作不同的操作,那是“新语法”吗?或者,如果它以前从未在任何语言中出现过,它是否只是一种新语法?
  • 嗯,我不认为语法必须完全新颖才能满足新 DSL 的要求。我不得不承认,对于简单地重载运算符是否足以创建 DSL 没有达成共识,尤其是当您遇到现有的优先规则和其他问题(例如 C++ 中 || 和 && 的短路评估语义)时。
  • 完全同意这一点。麻烦的是,你会发现很多人绝对肯定他们对什么是 DSL 有一个明确的定义,但没有一个人同意!在实践中,事情或多或少是 DSL-y,像 Ruby 和 Lisp 这样的语言鼓励这种风格,而像 Java 这样的语言让它几乎不可能。
  • 术语“DSL”在 Ruby 环境中被广泛滥用。 Ruby 的语法非常灵活,因此它允许人们编写表面上隐约类似于英语句子的 API。这通常被不恰当地称为“DSL”,但这不是严格技术意义上的 DSL,它只是一组用普通 Ruby 编写的巧妙命名的方法和变量。没有新的语法,因此没有开发新的“语言”。真正的 DSL 需要能够创建句法规则,例如使用解析器生成器或 Lisp 宏。
【解决方案3】:

Ruby 的诗歌模式和运算符重载的结合确实提供了同时具有合法 Ruby 语法和合理 DSL 的东西的可能性。

XML 的持续恶化确实表明,也许内置在所有这些配置文件中的简单 DSL 并没有完全被误导......

【讨论】:

    【解决方案4】:

    创建 DSL:

    • 向 Object 类添加新方法,以便您可以像调用内置语言结构一样调用它们。 (见耙子)

    • 在自定义对象或对象集上创建方法,然后让脚本文件在顶级对象的上下文中运行语句。 (见 capistrano)

    API 设计:

    • 在一个自定义对象或一组对象上创建方法,以便用户创建一个对象来使用这些方法。

    • 将方法创建为类方法,以便用户在所有方法前面加上类名前缀。

    • 将方法创建为用户在其自定义对象中包含或扩展以使用方法的 mixin。

    所以是的,他们之间的界限很细。通过添加一个在正确上下文中运行脚本文件的方法,将一组自定义对象转换为 DSL 很简单。

    【讨论】:

      【解决方案5】:

      对我而言,DSL 和 API 之间的区别在于,如果 DSL 不是由该领域的某个人编写为 Ruby 的子语言,那么它至少可以被理解(和验证)。

      例如,您可以让金融分析师在 Ruby DSL 中为股票交易应用程序编写规则,而他们永远不必知道他们正在使用 Ruby。

      【讨论】:

        【解决方案6】:

        事实上,它们是同一个东西。 DSL 通常是通过 Ruby 中的普通语言机制实现的,因此从技术上讲,它们都是 API。

        但是,为了让人们将某些东西识别为 DSL,通常最终会在现有类中添加看起来像声明性语句的东西。类似于 ActiveRecord 中的验证器和关系声明。

        class Foo << ActiveRecord::Base
          validates_uniqueness_of :name
          validates_numericality_of :number, :integer_only => true
        
        end
        

        看起来像 DSL,而以下不是:

        class Foo <<ActiveRecord::BAse
          def validate
            unless unique? name
              errors.add(:name, "must be unique")
            end
        
            unless number.to_s.match?(/^[-]?\d$/)
              errors.add(:number, "must be an integer")
            end
          end
        end
        

        它们都将由普通的 Ruby 代码实现。只是一个看起来你有很酷的新语言结构,而另一个看起来相当平淡(而且过于冗长等等)

        【讨论】:

          猜你喜欢
          • 2012-03-17
          • 2012-05-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多