News

利用 Kotlin DSL 的强大功能编写文档

Read this post in other languages:

本文最初发表于在阿姆斯特丹举办的 API The Docs 会议上,这项活动重点关注开发者成功以及 API 文档和开发者门户对企业的帮助。 我们向想要提升技术写作相关能力的读者强烈推荐这场会议。 所有演讲都很实用,信息丰富,并包括现场演示。

有时,几行代码就可以帮助您完成文档任务。 但是,文档不是代码,在编写文档时添加外部功能或自动化可能会更困难。 如果能像编写代码一样编写文档,完成特定任务,然后将代码转换回文档就好了!

在这篇博文中,我们将探讨如何使用 Kotlin DSL 编写文档来做到这一点。

DSL? 什么是 DSL?

我们来定义“领域专用语言”,即 DSL。

简单来说,它是一种专用于解决特定问题的编程语言。 这些语言的概念和规则特定于具体领域。

DSL 也称为小语言或面向问题的语言。 这些定义更好地描述了其本质 – DSL 专为解决特定问题而设计。

DSL 有两种类型。 外部 DSL 是独立语言,具有自己的语法、词法分析器和解析器。 SQL 就是这种语言的一个例子。 内部 DSL 则重用通用语言的语法和解析器,并利用该语言的可用扩展选项。

适用于文档的 Kotlin DSL 属于内部 DSL 类别。

使用 Kotlin,您可以构建具有外部 DSL 外观的内部 DSL。 因此,我们开发的是专为文档设计的内部 DSL。

JetBrains MPS 网站 上详细了解外部 DSL 与内部 DSL 之间的差异。

Kotlin DSL 的本质

适用于文档的 Kotlin DSL 是专为创建文档和静态网站而设计的框架。

框架是在基本文档元素上运行的类型安全构建器,额外功能作为用户代码或外部依赖项插入。 从特定源或输出格式到自然语言处理,依赖项可以提供任何类型的功能。

借助 Kotlin DSL,技术文档撰写人可以定义语义元素,例如章节、过程、表、列表等。 虽然 DSL 最初关注我们自己的标记,但其灵活性允许自定义扩展,因此理论上,我们可以将任何输入格式转换为任何输出格式。

在元素层面,用户可以将复杂逻辑封装在自定义元素中,然后像段落或列表一样简单使用。

Kotlin DSL 的一大显著优势是 IntelliJ IDEA 等集成式开发环境 (IDE) 已提供内置支持,包括错误检查、代码补全和重构。 这非常有助于提高书面内容的质量。

重复项检测运作方式示例

由于源是常规 Kotlin 代码,所有代码智能和语言支持功能均开箱即用。 需要浏览代码? 检测死代码和重复代码? 或者将另一种语言注入字符串文字? 这些 IDE 功能全都适用于 Kotlin DSL。 语言本身提供了显著好处,例如完整的静态类型和实用工具生态系统。

这篇博文展示了 DSL 如何生成自定义 XML 标记,但请注意,它也可以根据您的具体需求生成多种输出格式,例如 HTML 或 .docx。

此外,DSL 不仅可以在 IntelliJ IDEA 中使用,还可以在其他编辑器中甚至通过命令行使用。 它提供了与编写内容类似的体验,同时还利用了 Kotlin 编程语言的无限可能。

以下是我们标记的一些示例。

在第一个示例中,我们创建一个段落和一个包含两个列表条目的列表,并在这些元素内附加一些内容。

val content = StardustDslContentProvider {
   p { +"Hello, DSL"}
   list {
       li { +"List item 1" }
       li { +"List item 2" }
   }
   this
}

运行脚本后,结果如下:

在第二个示例中,我们创建一个包含两列的表。

val content = StardustDslContentProvider {
   table {
       tr {
           td {
               +"Parameter name"
           }
           td {
               +"Parameter type"
           }
       }
       tr {
           td {
               +"Value 1"
           }
           td {
               +"Value 2"
           }
       }
       this
   }

变为:

在第三个示例中,我们演示如何注入任何其他语言,例如 XML 或 Markdown。 在下面的示例中,我们注入一个包含三个步骤的过程:

xml("""
    <procedure title="Title">
        <step>Step 1</step>
        <step>Step 2</step>
        <step>Step 3</step>
    </procedure>
""")

结果如下:

包含 3 个步骤的过程

当然,仅用标记编写很难说是突破性成就。 那么,我们就来看一些更创新、更有趣的内容。

演示

首先,请注意,我们想展示的是方式,而不是具体实现。 以下演示使用我们的自定义 XML 标记执行,但我们可以桥接任何其他格式,例如 AsciiDoc、Markdown、reStructuredText、LaTeX 到 HTML,甚至是 .docx。

我们方式的三大关键优势

关注点分离

我们谈论了很多将内容与其表示分离的话题。 这种方式从 CSS 早期就存在于 Web 开发领域,后在轻量级标记语言中得到重新解释和强化。 这项技术涉及将文档的视觉和设计方面与其内容和结构分离。 这样一来,文档撰写人可以专注于内容,同时轻松调整其表示。

但我们可以更进一步,将数据与其表示分离。 文档可以基于数据本身生成,而不是基于与所述事物没有直接关系的标记。 我们可以从应用程序运行时获取数据,然后定义其表示。

此外,我们可以根据数据设计使表示具有条件。
例如,如果方法描述表明其已被弃用,则将其转换为警告元素。 在其他情况下,将其变为段落。

示例如下:

val descriptionTag = if (method.description.contains("DEPRECATED")) "warning" else "p"
xml(
   """
    <p>Method type: <b><font color="$font">${method.type.uppercase()}</font></b></p>
    <deflist>
        <def title="${method.summary}">
            <$descriptionTag>${method.description}</$descriptionTag>
        </def>
    </deflist>
   """
)

全新水平的文档即代码

我们经常谈论将文档视为代码,但我们通常指的是有限数量的工具和做法,例如使用轻量级标记编写、将文档置于版本控制之下,以及使用代码审查和 linter。 但是,我们可以从开发领域吸取更多。

借助 Kotlin DSL,文档成为代码的代名词,让文档撰写人可以利用开发者常用的做法。 部分做法包括:

  • 将内容的某些部分作为模块,然后将其作为许多文档集的依赖项导入,例如一些前端组件或者版权或许可协议等法律信息。
  • 在编程中使用函数组合,可以将复杂的标记结构和模式分解为更简单的结构和模式,使源更加精细并且易于维护和重用。
  • 将语义和前端组件视为类型,在需要的地方释放面向对象编程的优势。

可扩展性

DSL 的可扩展性将打破现有规则。 它不仅允许您添加自定义元素,还支持修改 DSL 本身,这开辟了无限可能。

您的想象力不会受到限制。 在计算机上可以实现的一切,都可以通过文档实现!

得益于与现有 JVM 库的无缝集成,您可以合并数据源、解析和丰富内容,甚至与 Selenium 和 Cucumber 等外部工具和框架集成。

Kotlin DSL 可扩展性选项示例如下:

  • 解析和集成任何数据格式,包括 XML、JSON、YAML、自定义序列化格式,甚至应用程序运行时的对象。
  • 添加映射并使用额外内容丰富文档。
  • 使用 Readability Analysis ToolApache OpenNLP 等库处理自然语言。
  • 为自动生成的部件应用测试和断言。

为什么选择 Kotlin?

先前已经有过从代码生成 HTML 的尝试,所以您可能想知道为什么我们选择 Kotlin 用于文档目的?

首先,Kotlin 具有一些高级功能,有助于创建强劲 DSL。

其次,Kotlin 以实用和对初学者友好而闻名。 它遵循简化日常任务的原则,确保新手能够快速轻松地掌握语言。

例如,在 Kotlin 中编写基本的“Hello, World!” 程序时,初学者不会被迫使用不理解的概念和关键字。

以下示例比较了 Java 与 Kotlin 中的“Hello, World!”程序:

Java:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

Kotlin:

fun main() = println("Hello, World!")

在 Kotlin 中,您不需要定义类或使用 public static void 签名。 main() 函数作为入口点,println() 可以直接用于输出所需消息。 这种简单性是 Kotlin 的主要优势之一,使编写基本程序更为轻松愉快。

如前所述,Kotlin 与 JVM 生态系统无缝集成。 Java 已诞生接近 30 周年,具有大量实用工具和库。 在构建脚本中添加一行,即可将这些工具合并到工作流中。

选择 Kotlin,我们优先考虑在简单性和强劲功能之间取得平衡的语言,确保愉快高效的开发者体验。

我需要成为程序员才能使用 Kotlin DSL 吗?

我们经常听到文档撰写人说:“我只是一个普通的技术文档撰写人,不是开发者也不是特别精通技术! 我该怎么用它? 我需要什么编程水平才能从中受益?”

要开始使用 DSL 元素作为标记,您不需要任何编码技能,也不需要了解 DSL 的运作方式。

只有在某些自动化相关任务上,您才需要对 Kotlin 有基本的了解。 JetBrains Academy 的 Kotlin Core 课程提供了所有必备知识。

但是,我们相信,学习 Kotlin DSL 从长远来看很有价值。 凭借其直观的语法和 IDE 支持,文档撰写人可以快速精通并更充分地利用强劲的文档工具。

将这种方式合并到文档工作流时,您可能需要学习一些编程知识。 将 Kotlin DSL 集成到工作中,您可以动手学习专门适用于文档职责的编程。 毕竟,技术文档撰写人可能会更喜欢文档相关任务,而不是假设课程的分数计算或基本计算器构建等综合练习。 此外,学习 Kotlin 还有助于理解其他语言和生态系统。

这种方式不一定适合所有技术文档撰写人,但对于撰写开发者工具内容的人员来说,这会非常有助于提升技能。

结论

适用于文档的 Kotlin DSL 引入了范式转变,使技术文档撰写人能够利用编程语言的强大功能轻松创作精彩内容。 利用 Kotlin 的优势、IDE 支持以及 DSL 固有的可扩展性,文档不再只是页面上的文字。 它成为开发流程中动态、集成的部分,增强协作并提供卓越结果。

快来为您的文档需求探索 Kotlin DSL 的无限可能吧! 

🚀 我们已经创建了一个示例项目,供您下载试用 Kotlin DSL。 如果您有任何疑问,请加入我们的 Slack,我们的专属频道是 #kotlin-dsl-for-docs。

拥抱代码的力量,将您的文档提升到全新高度。

祝您写作和编码快乐!

本博文英文原作者:

Sue

Svetlana Novikova

Sue

Igor Kulakov

image description