Clojure

Contrib 使用指南

自述文件

Contrib 库的自述文件应该包含以下内容

  • 将库作为依赖项包含在 Maven / Leiningen 中的说明

  • 指向库在 Jenkins 和 JIRA 上页面的链接

  • 指向 Maven Central 和 oss.sonatype.org 上可用版本的链接

  • 指向生成的 API 文档的链接(如果适用)

  • 一般使用说明(应提及要使用/要求哪个命名空间)

  • 开发者信息:指向 GitHub 项目、Bug 追踪器、持续集成、兼容性测试矩阵的链接

  • 所有版本的变更日志(也可以在单独的文件中)

贡献者指南

如果您是 Clojure Contrib 贡献者,您应该做以下事情

  • 维护您的库并响应出现的任何问题/疑问

  • 在主分支上完成您的工作,或者(如果您正在处理一个您想暂时分开的大块工作)在您自己创建的特定于功能的分支上工作

  • 使用 GitHub 的“按需发布”操作来进行发布

  • 在更改其他贡献者的库之前与其他贡献者协调

  • 仅当其他人 签署了 CA 时才接受他们的贡献

需要避免的事项

  • 请不要推送到发布分支(名称如 1.2.x)

  • 不要接受非贡献者的补丁

  • 请不要接受来自贡献者的拉取请求。仅接受补丁。

  • 不要更改 pom.xml 中的版本号 - 使用上面提到的 Maven 发布流程

以下是成为贡献者的流程概述

  • 将您的 CA 归档

  • 加入 clojure-dev 邮件列表

  • 创建 JIRA 账户

  • 让 Clojure 核心团队知道您的 GitHub 用户名和 JIRA 用户名,以便他们可以设置正确的权限

  • Clojure 核心团队还需要在 build.clojure.org 上创建您的账户 - 请参见下文

将现有项目移入 contrib

  • 所有过去的贡献者必须

    • 提交 Clojure 贡献者协议

    • 向 clojure-dev 邮件列表发送一封电子邮件,授予许可,例如:"我,(NAME),授权根据 Clojure 贡献者协议发布我对 (PROJECT) 的贡献。"

设置新的 contrib 项目

  • 向 clojure-dev 邮件列表发送电子邮件,以获得新项目的批准以及 GitHub、Jira 和 Jenkins 中的管理员权限。

  • 在 clojure 组织 下请求一个新的 GitHub 仓库

    • 指定项目名称(必须经 Clojure 核心批准)

    • 指定描述

    • 合作者 - 添加团队:Contrib 贡献者,其中包括

      • clojure-build - 用于 Jenkins 标记版本、构建自动文档等

    • 禁用问题选项卡(我们使用 JIRA 代替)

    • 项目结构(请参阅现有项目以获取示例)

      • /README.md - 自述文件,请参见上文

      • /CHANGES.md - 变更日志

      • /CONTRIBUTING.md - 示例

      • /epl.html - EPL 许可证信息

      • /pom.xml - 按照 build.poms 说明 - 用于构建/部署

      • /src/main/clojure - Clojure 源代码

      • /src/test/clojure - Clojure 测试

      • /src/main/cljs - ClojureScript 源代码

      • /src/test/cljs - ClojureScript 测试

      • /src/main/java - Java 源代码(如果需要)

  • 创建一个新的 JIRA 项目(需要 JIRA 管理员权限)

    • 指定名称(与 GitHub 项目名称相同)

    • 指定键(由 Clojure 核心批准,从项目名称派生) - 通常应该由第一部分的首字母和第二部分最多 5 个字符组成 - TBENCH、DJSON 等。

    • 指定项目负责人的 JIRA 账户

    • 编辑项目以添加 URL 和描述(与 GitHub 项目相同)

    • 设置通知方案 - 通常为 "默认方案加通知项目负责人"

  • 设置构建(需要 Jenkins 管理员权限,但步骤 2 除外)

    • 为作者创建 Jenkins 用户账户

    • 编辑 build.ci 仓库中的 ci_data.clj 文件,添加新项目 / 更新作者(以便他们可以运行构建 / 发布版本)

    • 在 clojure-dev 邮件列表上请求运行 build.ci Jenkins 作业 - 这将重新创建所有 Jenkins 作业定义文件!

    • 强制 Jenkins 重新加载其配置文件

  • 自动文档

    • 进行中

  • 执行发布

    • 每次作业构建时(由任何源代码更改触发)都会自动创建快照版本

      • 要使用快照版本,请参阅 Maven 设置和仓库

    • 按照下面的“如何进行发布”部分中的说明进行发布

如何进行发布

准备工作

  • 您的项目必须有一个 pom.xml 文件,其中包含 -SNAPSHOT 版本

  • pom.xml 文件必须指定一个父级,即 pom.contrib 的最新发布版本,位于 build.poms

如何进行 -SNAPSHOT 发布

  • 您的项目必须有一个 pom.xml 文件,其中包含 -SNAPSHOT 版本

  • 推送到 GitHub 的 "master" 分支

  • Jenkins 会轮询 GitHub 并自动构建

  • 或者您也可以在项目页面上点击 "立即构建"

  • Jenkins 会构建并上传一个唯一编号的 JAR 文件到 Sonatype OSS 快照仓库

如何进行编号发布

  • GitHub 中的 "master" 分支必须有一个 pom.xml 文件,其中包含 -SNAPSHOT 版本,而不是一个裸的版本号

  • 登录 Jenkins

  • 导航到您的项目的作业

  • 点击左侧的 "执行 Maven 发布" 链接

  • 在 "执行 Maven 发布" 页面上

    • 选择 "为所有模块指定一个版本"

    • 在 "发布版本" 字段中,输入该版本的项目版本号

      • 这通常是当前开发版本,删除了 "-SNAPSHOT" 后缀

    • 在 "开发版本" 字段中,输入项目后续开发版本的版本号

      • 这将以 "-SNAPSHOT" 结尾

    • 点击 "计划 Maven 发布构建"

  • 构建成功完成后

    • 在您的开发机器上执行 git pull 以获取新的发布标签

    • 发布的 JAR 文件将上传到 Sonatype OSS 暂存仓库

    • 发布将在 24 小时内(通常在 15 分钟内)自动复制到 Maven Central 仓库

  • 不要忘记更新项目的自述文件,如果它向用户推荐了一个版本。

Contrib 版本编号策略

  • 主版本.次版本.修订版本

  • 尽可能遵循累积和固定的原则,而不是破坏性的原则

编码规范

免责声明

  • 规则是为了打破而制定的。了解标准,但不要将它们视为绝对真理。

标准

  • 确保名称和签名正确。Rich 深刻尊重 Java 对不破坏现有代码的承诺。在实践中,这意味着我们可以永远调整实现,但一旦我们发布了一个名称和签名,我们就需要坚持使用它。(在实践中我认为这意味着我们希望许多人审查名称和签名,即使他们没有审查实现细节。)

  • 对可能在关键代码中的函数使用类型提示;否则保持代码简单,不使用提示。

    • 只使用有意义的类型提示。如果您不确定类型提示是否有帮助,请不要添加它。

  • 使用良好的名称,不要害怕与其他命名空间中的名称冲突。这就是灵活的命名空间支持存在的意义。

    • 另一方面,使用相同的名称但具有不同的签名或语义,就让人怀疑其中一个是否不够理想。

  • 明确且最小化地依赖其他包。(优先使用 :require :refer 而不是 :use)

  • 如果函数可以完成任务,请不要使用宏。如果宏对于易用性很重要,也请公开函数版本。

  • 如果您确定在编译时拥有所有信息,请在可以提高性能敏感代码的情况下使用宏。

  • 提供库级文档字符串。

  • 提供自动测试。

  • 对谓词使用 '?' 后缀,并返回布尔值。

  • 对解构目标和将被当前代码忽略其值的正式参数名使用 '_'。

  • 包含文档字符串。

  • 如有疑问,请公开高性能版本。Clojure 做出了巨大的努力,以便在您需要时能够实现性能,库也应该如此。(这就是为什么我们在核心代码中没有多方法 + 的原因,例如)。用户始终可以在自己的代码中创建更多多态 API,如果他们愿意,可以劫持符号。

  • 如果您使用了一个与核心代码冲突的良好名称,请确保您的语义是平行的(可能不包括惰性)。字符串函数的良好示例,它们与核心代码的 seq 函数冲突。

  • 使用 assert 以及前置条件和后置条件。

  • 尽可能使用惰性。

  • 遵循 clojure.core 的示例,使用诸如 pred 和 coll 之类的惯用名称。

    • 在函数中

      • f、g、h - 函数输入

      • n - 整数输入,通常是一个大小

      • index - 整数索引

      • x、y - 数字

      • s - 字符串输入

      • coll - 集合

      • pred - 谓词闭包

      • &更多 - 可变参数输入

    • 在宏中

      • expr - 表达式

      • body - 宏体

      • binding - 宏绑定向量

  • 不要遵循 clojure.core 的序言代码中的惯例。该代码在有限的环境中运行,因为 Clojure 尚未启动。

  • 分解组件。如果您不是 Rich,请不要编写与 doseq 的定义一样长的形式。

  • 使用关键字优先语法访问对象上的属性:(:property object-like-map)

  • 使用集合优先语法从集合中提取值(或者如果集合可能为 nil,则使用 get):(collection-like-map key)(get collection-like-map key)。请注意,并非所有集合都以关键字为键。

  • 惯用代码大量使用解构。但是,只有当您想将子结构作为调用者契约的一部分进行传达时,才应该在参数列表中进行解构。否则,请在第一行的 let 中进行解构。

  • 优先使用更新而不是设置。原因很多:统一的更新模型提供了一种简单标准的方式来执行此操作。帮助您发现可交换操作。减少了您对要更新的对象所做的假设的范围。

  • 不要在错误的集合类型上进行操作。如果您的算法仅在随机访问的情况下有效,则需要一个具有随机访问权限的参数。

  • 仅将 *earmuffs* 用于旨在重新绑定的内容。不要使用特殊符号表示常量;除非另有说明,否则所有内容都被认为是常量。

  • 仅将感叹号用于在 STM 事务中不安全的项目。

  • 优先使用序列库组合而不是显式循环/递归。

  • 可重新绑定的变量应与作用域宏配对,例如 in 和 with-in-str。

  • 延迟序列应公开为仅保存最少状态的函数,即“放下头”。让调用者决定要使用多少本地内存。

  • 使用 Klass/staticField、(Klass/staticMethod)、(Klass.) 和 (.method obj) 交互样式,唯一的例外是在代码生成代码中,其中较旧的 (. obj method) 样式可能更容易生成。

  • 如果您提供一个通过动态绑定隐式传递参数的接口(例如 sql 中的 db),也提供一个相同的接口,但参数显式传递。

  • 在为 cond 提供默认情况时,使用关键字 :else 作为条件而不是 true。

  • 要访问私有变量(例如用于测试),请使用 @#'some.ns/var 形式。

  • 协议

    • 只有当您拥有类型或协议时,才能将协议扩展到类型。

    • 如果违反了前面的规则,则应准备好撤回,如果实现者提供定义,则应做好准备。

    • 如果协议随 Clojure 自身提供,请避免将其扩展到您不拥有的类型,尤其是例如 java.lang.String 和其他核心 Java 接口。请放心,如果协议应该扩展到它,它就会扩展,否则请游说它。

      • 正如 Rich Hickey 所说,其动机是防止“人们将协议扩展到对它们没有意义的类型,例如,协议作者考虑过但拒绝了实现,因为语义不匹配”。“不会有任何扩展(通过设计),并且缺乏足够理解/技能的人可能会用错误的想法填补空白。”