Racket Package 创建与发布指南
本指南将带你从零开始创建一个 Racket 包并将其发布到官方包目录,适合没有包发布经验的新手。
前期准备
环境要求
确保你已安装:
- Racket 8.0 或更高版本
 - Git 版本控制工具
 - 文本编辑器(推荐 DrRacket、VS Code 或 Emacs)
 
验证环境
# 检查 Racket 版本
racket --version
# 检查包管理工具
raco --version
# 检查 Git
git --version
包结构设计
标准目录结构
创建一个新目录作为你的包根目录:
your-package-name/
├── main.rkt          # 主要实现文件
├── info.rkt          # 包元信息配置
├── your-package.scrbl # Scribble 文档
├── README.md         # 项目说明
├── LICENSE           # 开源协议
├── .gitignore        # Git 忽略文件
└── tests/            # 测试文件目录(可选)
    └── test-main.rkt
命名规范
- 包名:使用小写字母和连字符,如 
my-awesome-lib - 文件名:主文件可以命名为 
main.rkt或与包名相同 - 模块名:保持与包名一致
 
核心代码实现
1. 创建主实现文件(main.rkt)
#|
Package Name: my-math-utils
Description: A collection of mathematical utility functions
Author: Your Name <your.email@example.com>
License: MIT
|#
#lang racket/base
;; 导入需要的模块
(require racket/math
         racket/contract)
;; 导出公共接口
(provide square
         cube
         factorial
         (contract-out
          [prime? (-> exact-positive-integer? boolean?)]))
;; 测试模块
(module+ test
  (require rackunit))
;; 实现函数
(define (square x)
  (* x x))
(define (cube x)
  (* x x x))
(define (factorial n)
  (if (<= n 1)
      1
      (* n (factorial (- n 1)))))
(define (prime? n)
  (cond
    [(<= n 1) #f]
    [(<= n 3) #t]
    [(or (= 0 (modulo n 2)) (= 0 (modulo n 3))) #f]
    [else
     (let loop ([i 5])
       (cond
         [(> (* i i) n) #t]
         [(or (= 0 (modulo n i)) (= 0 (modulo n (+ i 2)))) #f]
         [else (loop (+ i 6))]))]))
;; 单元测试
(module+ test
  (test-case "square function"
    (check-equal? (square 0) 0)
    (check-equal? (square 3) 9)
    (check-equal? (square -4) 16))
  
  (test-case "cube function"
    (check-equal? (cube 0) 0)
    (check-equal? (cube 3) 27)
    (check-equal? (cube -2) -8))
  
  (test-case "factorial function"
    (check-equal? (factorial 0) 1)
    (check-equal? (factorial 1) 1)
    (check-equal? (factorial 5) 120))
  
  (test-case "prime? function"
    (check-false (prime? 1))
    (check-true (prime? 2))
    (check-true (prime? 17))
    (check-false (prime? 15))))
2. 代码组织最佳实践
- 使用合约:为公共函数添加类型合约
 - 模块化测试:使用 
(module+ test ...)内联测试 - 文档字符串:为复杂函数添加说明
 - 错误处理:适当处理边界情况和错误
 
包信息配置
创建 info.rkt
#lang info
;; 包的基本信息
(define collection "my-math-utils")
(define pkg-desc "A collection of mathematical utility functions")
(define version "1.0.0")
(define pkg-authors '("Your Name"))
;; 依赖管理
(define deps '("base"))  ; 运行时依赖
(define build-deps '("scribble-lib" "racket-doc" "rackunit-lib"))  ; 构建时依赖
;; 文档配置
(define scribblings '(("my-math-utils.scrbl" ())))
;; 许可证
(define license 'MIT)
;; 包的分类标签
(define tags '("math" "utilities" "library"))
;; 编译器设置
(define compile-omit-paths '("tests"))
info.rkt 字段说明
collection:集合名称,通常与包名相同deps:运行时依赖包列表build-deps:文档构建和测试所需的依赖scribblings:文档文件配置compile-omit-paths:编译时忽略的路径
编写文档
创建 Scribble 文档(my-math-utils.scrbl)
#lang scribble/manual
@require[@for-label[my-math-utils
                    racket/base
                    racket/contract]]
@title{My Math Utils}
@author{Your Name}
@defmodule[my-math-utils]
This package provides a collection of mathematical utility functions
for common operations.
@section{Basic Operations}
@defproc[(square [x number?]) number?]{
  Returns the square of @racket[x].
  
  @examples[#:eval (make-base-eval)
    (require my-math-utils)
    (square 5)
    (square -3)
    (square 2.5)
  ]
}
@defproc[(cube [x number?]) number?]{
  Returns the cube of @racket[x].
  
  @examples[#:eval (make-base-eval)
    (require my-math-utils)
    (cube 3)
    (cube -2)
  ]
}
@defproc[(factorial [n exact-nonnegative-integer?]) exact-nonnegative-integer?]{
  Computes the factorial of @racket[n].
  
  @examples[#:eval (make-base-eval)
    (require my-math-utils)
    (factorial 5)
    (factorial 0)
  ]
}
@section{Number Theory}
@defproc[(prime? [n exact-positive-integer?]) boolean?]{
  Returns @racket[#t] if @racket[n] is prime, @racket[#f] otherwise.
  
  @examples[#:eval (make-base-eval)
    (require my-math-utils)
    (prime? 17)
    (prime? 15)
    (prime? 2)
  ]
}
@section{Installation}
@codeblock|{
raco pkg install my-math-utils
}|
@section{License}
This package is distributed under the MIT License.
创建 README.md
# My Math Utils
A Racket package providing mathematical utility functions.
## Installation
```bash
raco pkg install my-math-utils
Usage
#lang racket
(require my-math-utils)
(square 5)      ; => 25
(cube 3)        ; => 27
(factorial 5)   ; => 120
(prime? 17)     ; => #t
API
square- Compute the square of a numbercube- Compute the cube of a numberfactorial- Compute factorialprime?- Test if a number is prime
Documentation
Full documentation is available at: https://docs.racket-lang.org/my-math-utils/
Testing
raco test main.rkt
License
MIT License
## 测试与验证
### 运行测试
```bash
# 运行内联测试
raco test main.rkt
# 运行所有测试
raco test .
# 详细输出
raco test -v main.rkt
本地安装测试
# 以链接方式安装(开发期间)
raco pkg install --link .
# 测试导入
racket -e "(require my-math-utils) (square 5)"
# 构建文档
raco setup --doc-index my-math-utils
# 卸载本地包
raco pkg remove my-math-utils
验证清单
版本控制设置
创建 .gitignore
# Racket 编译文件
compiled/
*.zo
# 文档构建产物
doc/
# 编辑器临时文件
*~
.#*
\#*#
.DS_Store
# 平台相关文件
Thumbs.db
ehthumbs.db
Git 初始化和提交
# 初始化仓库
git init
# 添加文件
git add .
# 首次提交
git commit -m "Initial commit: Add my-math-utils package"
# 创建 GitHub 仓库后
git remote add origin https://github.com/yourusername/my-math-utils.git
git branch -M main
git push -u origin main
# 创建版本标签
git tag v1.0.0
git push origin v1.0.0
发布到包目录
1. 在 GitHub 上创建仓库
- 访问 GitHub
 - 创建新仓库,命名为 
my-math-utils - 设置为公开仓库
 - 推送代码到仓库
 
2. 注册到 Racket 包目录
- 访问 Racket Package Catalog
 - 点击右上角登录/注册
 - 登录后点击 "Add Your Own Package"
 - 填写表单:
- Package Name: 
my-math-utils - Source: 
https://github.com/yourusername/my-math-utils.git - Source Type: 
git - Description: 包的简短描述
 
 - Package Name: 
 
3. 提交审核
提交后,系统会自动:
- 克隆你的代码仓库
 - 验证包结构和依赖
 - 运行测试
 - 构建文档
 - 检查许可证信息
 
4. 处理审核反馈
如果有问题,修复后:
- 在本地修复问题
 - 提交并推送到 GitHub
 - 包目录会自动重新检查
 
5. 发布成功
审核通过后,用户可以通过以下方式安装:
raco pkg install my-math-utils
维护与更新
版本更新流程
- 修改代码
 - 更新版本号(在 
info.rkt中) - 更新文档
 - 运行测试
 - 提交更改
 - 创建新标签
 
# 更新版本
git add .
git commit -m "Version 1.1.0: Add new functions"
git tag v1.1.0
git push origin main
git push origin v1.1.0
语义化版本控制
遵循 SemVer 规范:
- 主版本号(1.x.x):不兼容的API变更
 - 次版本号(x.1.x):向后兼容的功能增加
 - 修订版本号(x.x.1):向后兼容的问题修复
 
处理问题反馈
- GitHub Issues:鼓励用户报告问题
 - 快速响应:及时回复和修复
 - 文档更新:根据反馈改进文档
 - 兼容性:谨慎处理破坏性变更
 
最佳实践
代码质量
- 一致的代码风格:使用统一的缩进和命名
 - 充分的测试覆盖:确保所有功能都有测试
 - 清晰的错误消息:提供有用的错误信息
 - 性能考虑:合理使用内联和优化
 
文档完善
- 示例丰富:为每个函数提供使用示例
 - 边界情况说明:明确函数的使用限制
 - 安装说明:提供清晰的安装步骤
 - 更新日志:维护版本变更记录
 
社区友好
- 响应式维护:及时回复问题和 PR
 - 贡献指南:如果接受贡献,提供指南
 - 许可证明确:选择合适的开源许可证
 - 感谢贡献者:在 README 中感谢贡献者
 
依赖管理
- 最少依赖原则:只依赖必要的包
 - 版本兼容性:测试不同版本的兼容性
 - 依赖更新:定期检查依赖的安全更新
 - 可选依赖:合理使用可选功能
 
常见问题解答
Q: 如何选择包名?
A: 包名应该:
- 具有描述性
 - 避免与现有包冲突
 - 使用小写字母和连字符
 - 不要过长或过于简单
 
Q: 什么时候需要更新主版本号?
A: 当发生以下变化时:
- 删除或重命名公共函数
 - 改变函数签名
 - 修改函数行为(不向后兼容)
 - 改变数据结构格式
 
Q: 如何处理大型包?
A: 对于复杂项目:
- 拆分为多个子模块
 - 使用 
provide精确控制导出 - 考虑拆分为多个相关包
 - 提供不同层次的API
 
Q: 测试失败怎么办?
A: 检查以下方面:
- 测试用例是否正确
 - 依赖是否完整
 - 路径配置是否正确
 - Racket 版本兼容性
 
总结
创建和发布 Racket 包是一个系统性的过程,需要注意代码质量、测试完整性、文档清晰度和社区友好性。遵循本指南,你可以创建出专业、可靠的 Racket 包,为 Racket 生态系统做出贡献。
记住,好的包不仅仅是功能正确,更重要的是易用、可维护,并且有完善的文档支持。持续改进和响应用户反馈是成功开源项目的关键。