为什么要贡献新的学习资料?
正如 Heather Miller 所写,为 docs.scala-lang.org 做出贡献对于让 Scala 对新手、经验丰富的程序员和任何好奇的人来说都是至关重要的。对于任何习惯使用 Scala 但可能不想使用编译器等复杂工具的人来说,这也是一种做出贡献的绝佳方式。
架构
此文档网站由一个开源的 GitHub 存储库 支持,并且始终可以贡献。
内容
目前,此存储库中支持的文档类型是
- 指南/概述/书籍:特定语言功能的权威指南/概述。通常是篇幅较长、内容详尽的文档,通常由 Scala 团队成员编写。一个示例是 集合 概述。
- 参考:由 Scala 团队成员编写的语言功能规范参考。这些内容提供了确切的规范,以便理解语言的更微妙方面。一个示例是 Scala 3 参考。
- 教程:篇幅短小、示例丰富且简洁的文章,旨在让开发人员快速上手。
- 备忘单:Scala 语法和行为的快速参考。
实施
该网站是使用 Markdown 源代码通过 Jekyll 静态生成的,并托管在 GitHub Pages 上。选择此工作流是为了帮助贡献者专注于编写有用的内容,而不是配置和样板。它还有助于在中心位置发布静态站点。
正在使用的 Markdown 语法支持 Maruku 扩展,并具有自动语法高亮功能,无需任何标记。
此外,mdoc 在拉取请求期间用于验证 Scala 代码块。要使用此功能,您必须使用 mdoc 记录的重音符符号,请参阅此处 了解示例。
注意:仅由 mdoc 完成代码验证,并且不会生成额外的输出。
提交文档
要提交新文档,您应首先 分叉 存储库,然后使用 Markdown 编写您的文章(如下面的示例),最后提交拉取请求。在经过一些编辑和讨论后,您的文档将 docs.scala-lang.org 上线。
---
layout: singlepage-overview
title: My Awesome Title
---
## An h2 Header in Markdown
And a paragraph, with a [link](https://scala-lang.org.cn).
目录将自动生成在您的文档的侧边栏中,并提供语法高亮。
文档被接受的标准
此文档存储库的目标是经过精心策划,而不是像 wiki 等其他社区驱动的文档平台的方法。因此,要包含在 docs.scala-lang.org 中,文档必须
- “适合”该存储库(即,它不应是另一篇文章的完全副本),
- 经过完善,即它必须全面、完整、正确且有条理;作为一篇文章编写,以便许多用户理解。
- 维护,如果文档可能需要不时进行修订,请做好随时更新的准备,或指定某人负责。
如果您有想要贡献的内容,或正在考虑撰写内容以进行贡献,我们很乐意考虑!请随时在 GitHub 问题和请求拉取以及 #scala-contributors
房间 Discord 中提出任何问题、疑虑、澄清等。
代码块
各种文档通常需要代码示例。您可以通过以下方式在 Markdown 文档中贡献代码
- 内联,在代码周围加上反引号,
- 用三个反引号包围,
- 或缩进 4 个空格,例如
inline example: `val x = 23`
block example:
```scala
println("hello")
```
indented example:
case class Foo(x: Int)
Scala 2 与 Scala 3
我们的目标是拥有一个统一的文档,涵盖 Scala 2 和 Scala 3。在许多情况下,Scala 2 和 Scala 3 中的代码示例是相同的,但有时会有一些语法差异。在一些不太常见的情况下,页面可能会解释 Scala 3 中的新概念,而在 Scala 2 中没有等效概念,或者解释 Scala 3 中已删除的概念。在所有情况下,文档都应清楚地“标记”代码示例,以便读者知道它们在哪些版本的 Scala 中有效。
以下部分解释了如何正确“标记”代码示例。
标记 Scala 2 和 Scala 3 中都可用的概念的页面中的代码片段
当页面的内容不特定于 Scala 2 或 Scala 3 时,例如我们的 Hello World Scala Book 章节,代码片段应显示 Scala 2 和 Scala 3 语法。我们通过根据以下规则在选项卡中标记代码片段来实现此目的
- 如果 Scala 2 和 Scala 3 中的惯用语法不同,我们会创建两个选项卡,“Scala 2”和“Scala 3”,显示相应的语法
- 如果代码片段在 Scala 2 和 Scala 3 中都是惯用的,我们会创建一个选项卡,“Scala 2 和 3”
- 如果代码片段仅在 Scala 2 或 Scala 3 中有效,我们会创建一个选项卡,“仅限 Scala 2”或“仅限 Scala 3”
以下是如何使用 tabs
指令和类 tabs-scala-version
在 Markdown 中生成此类选项卡的示例
{% tabs hello-world-demo class=tabs-scala-version %}
{% tab 'Scala 2' %}
```scala
object hello extends App {
println("Hello, World!")
}
```
{% endtab %}
{% tab 'Scala 3' %}
```scala
@main def hello() = println("Hello, World!")
```
{% endtab %}
{% endtabs %}
至关重要的是,您使用 tabs-scala-version
类,以受益于一些很酷的用户交互
- 同一页面上的所有其他 Scala 版本选项卡也会切换到当前选项卡,只要其中一个发生更改。
- 选中的选项卡将在整个网站中记住,并且当用户在一段时间后返回该页面时,该选项卡也将被记住。
对于在 Scala 2 和 Scala 3 中都有效的代码片段,请使用一个标记为 'Scala 2 and 3'
的选项卡(请注意,tabs-scala-version
类也被删除了)。
{% tabs scala-2-and-3-demo %}
{% tab 'Scala 2 and 3' %}
```scala
List(1, 2, 3).map(x => x + 1).sum
```
{% endtab %}
{% endtabs %}
对于仅适用于 Scala 2 或 Scala 3 中的一个的示例,请使用选项卡 'Scala 2 Only'
和 'Scala 3 Only'
。
如果您有一个特别长的选项卡,为了可读性,您可以使用参数 for=tab-group
指出它所属的选项卡组,如下例所示
{% tabs my-tab-group class=tabs-scala-version %}
...
{% tab 'Scala 3' for=my-tab-group %}
...
标记一个记录特定于 Scala 版本的概念的完整页面
当页面内容解释了一个在 Scala 3 中是新的且在 Scala 2 中没有等效项的概念(例如 TASTy),或在 Scala 3 中已被删除的概念时,我们标记整个页面,而不是标记每个代码示例。
我们通过在 Markdown 文件的 YAML 前置内容 中设置几个属性来实现这一点。例如,对于特定于 Scala 3 的页面
scala3: true
versionSpecific: true
或者,对于特定于 Scala 2 的页面
scala2: true
versionSpecific: true
请注意,当整个页面被标记时,其代码示例不需要有选项卡。
类型检查示例
网站构建过程使用 mdoc 对 markdown 中的代码片段进行类型检查。这是一个确保您包含的代码片段进行类型检查并且有效的好方法。以下是一些快速入门提示
首先,在创建代码块时,在 scala
之后添加 mdoc
。这里的 mdoc
修饰符将确保 mdoc
运行代码片段并确保其有效。
```scala mdoc
val a = 1
```
如果您有一个您希望失败的片段,您还可以使用 mdoc:fail
来解决编译错误,mdoc:crash
来解决运行时错误。
```scala mdoc:fail
val b: String = 3 // won't compile
```
请记住,单个文件全部编译为一个单元,因此你无法重新定义在其他代码片段中上面定义的变量。然而,有几种方法可以解决这个问题。首先,你可以使用 mdoc:nest
修饰符,它将用 scala.Predef.locally{...}
包装代码片段。这实际上会将代码片段“隐藏”起来。解决此问题的另一种方法是使用 mdoc:reset
修饰符,它会重置并忘记上面的一切。下面是使用各种修饰符的一个示例。
```scala mdoc
import java.time.Instant
def now() = Instant.now()
object Foo {}
```
```scala mdoc:nest
case class Foo(a: Int) // conflicts with Foo above, but it's nested so it's fine
```
```scala mdoc
val a = s"The time is ${now()}" // still have access to the now method from above
```
```scala mdoc:reset
case class Foo(a: String) // forget the previous Foo's and start fresh
```
```scala mdoc
val myFoo = Foo("hi") // now we only have access to the last Foo
```
文档模板
指南/概述
可以逻辑地放在一个 Markdown 页面上的指南或概述应放在目录 _overviews/RELEVANT-CATEGORY/
中。它应具有标题
---
layout: singlepage-overview
title: YOUR TITLE
---
文档的其余部分将以 Markdown 语法编写。
你可以用任何相关的目录替换 RELEVANT-CATEGORY
,或者如果找不到合适的目录,则创建一个新的目录。
如果你的指南/概述包含多个页面,例如 集合 概述,则必须指定顺序,方法是在标题中使用 num
标记按逻辑顺序对文档编号,并使用 partof
标记为页面集合分配一个名称。例如,以下标题可用于集合概述中的文档
---
layout: multipage-overview
title: YOUR TITLE
partof: collections
num: 10
---
集合中的至少一个文档必须在标题中包含一个标记 outof
,该标记指示大型概述中的文档总数。通常最好将它放在概述的最后一页上
---
layout: multipage-overview
title: YOUR TITLE
partof: collections
num: 15
outof: 15
---
索引页面(例如 docs.scala-lang.org/overviews/index.html)是通过读取配置文件(例如 _data/overviews.yml
)中的数据生成的,因此你的概述应放在那里的一个类别中。
教程
教程不同于指南,它们应该以更简洁、面向任务的风格编写,通常在一页上。
与指南类似,教程也使用相同的 Markdown 标题。
编写完教程后,为了帮助用户导航,必须将他们的链接添加到 /tutorials.md
的元数据中。例如,它可能如下所示
---
layout: root-index-layout
title: Tutorials
tutorials:
...
- title: My New Tutorial
url: "/tutorials/my-new-tutorial.html"
description: "Learn How To Do This Specific Task"
icon: code
---
还必须将教程添加到导航栏中的下拉列表中。为此,请向 _data/doc-nav-header.yml
中添加一个额外的条目。即
---
- title: Getting Started
url: "/getting-started/index.html"
- title: Learn
...
- title: Tutorials
url: "#"
submenu:
...
- title: My New Tutorial
url: "/tutorials/my-new-tutorial.html"
...
---
备忘单
备忘单具有特殊的布局,并且内容应为 Markdown 表格。要提供备忘单,应使用以下格式
---
layout: cheatsheet
title: YOUR TITLE
by: YOUR NAME
about: SOME TEXT ABOUT THE CHEAT SHEET.
---
| Title A | Title B |
|---------|---------|
| content | more |