更多内容请访问 rubyonrails.org:

API 文档指南

本指南介绍了 Ruby on Rails API 文档指南。

阅读本指南后,您将了解

  • 如何为文档目的撰写有效的散文。
  • 记录不同类型的 Ruby 代码的风格指南。

1 RDoc

使用 Rails API 文档 是用 RDoc 生成的。若要生成它,请确保您在 rails 根目录中,运行 bundle install 并执行

$ bundle exec rake rdoc

生成的 HTML 文件可以在 ./doc/rdoc 目录中找到。

请参考 RDoc 标记参考 以获得语法方面的帮助。

Rails API 文档不适合在 GitHub 上查看,因此链接应该使用 RDoc 链接标记 相对于当前 API 的标记。

这是由于 GitHub Markdown 和发布在 api.rubyonrails.orgedgeapi.rubyonrails.org 上的生成的 RDoc 之间的差异。

例如,我们使用 [link:classes/ActiveRecord/Base.html] 来创建指向由 RDoc 生成的 ActiveRecord::Base 类。

这优于绝对 URL,例如 [https://api.rubyonrails.net.cn/classes/ActiveRecord/Base.html],后者会将读者带离他们当前的文档版本(例如 edgeapi.rubyonrails.org)。

3 措辞

使用简单、陈述性的句子。简洁就是优点。言简意赅。

# BAD
# Caching may interfere with being able to see the results
# of code changes.

# GOOD
# Caching interferes with seeing the results of code changes.

使用现在时

# BAD
# Returned a hash that...
# Will return a hash that...
# Return a hash that...

# GOOD
# Returns a hash that...

以大写字母开头注释。遵循标点符号规则

# BAD
# declares an attribute reader backed by an internally-named
# instance variable

# GOOD
# Declares an attribute reader backed by an internally-named
# instance variable.

向读者传达当前的做事方式,无论显式还是隐式。使用 edge 中推荐的习语。如果需要,重新排序部分以突出显示首选方法,等等。文档应该是最佳实践和规范的现代 Rails 用法的典范。

# BAD
# Book.where('name = ?', "Where the Wild Things Are")
# Book.where('year_published < ?', 50.years.ago)

# GOOD
# Book.where(name: "Where the Wild Things Are")
# Book.where(year_published: ...50.years.ago)

文档必须简短但全面。探索和记录边缘情况。如果模块是匿名的会发生什么?如果集合为空会发生什么?如果参数是 nil 会发生什么?

3.1 命名

Rails 组件的正确名称在单词之间有一个空格,例如“Active Support”。ActiveRecord 是一个 Ruby 模块,而 Active Record 是一种 ORM。所有 Rails 文档应始终使用其正确名称来引用 Rails 组件。

# GOOD
# Active Record classes can be created by inheriting from
# ActiveRecord::Base.

当引用“Rails 应用程序”时,而不是“引擎”或“插件”,始终使用“应用程序”。Rails 应用程序不是“服务”,除非专门讨论面向服务的架构。

# BAD
# Production services can report their status upstream.
# Devise is a Rails authentication application.

# GOOD
# Production applications can report their status upstream.
# Devise is a Rails authentication engine.

正确拼写软件名称。如有疑问,请参考一些权威来源,例如其官方文档。

# GOOD
# Arel
# ERB
# Hotwire
# HTML
# JavaScript
# minitest
# MySQL
# npm
# PostgreSQL
# RSpec

对“SQL”使用冠词“an”

# BAD
# Creates a SQL statement.
# Starts a SQLite database.

# GOOD
# Creates an SQL statement.
# Starts an SQLite database.

3.2 代词

避免使用“你”和“你的”。

# BAD
# If you need to use +return+ statements in your callbacks, it is
# recommended that you explicitly define them as methods.

# GOOD
# If +return+ is needed, it is recommended to explicitly define a
# method.

也就是说,当使用代词来指代假设的人时,例如“具有会话 cookie 的用户”,应该使用中性代词(他们/他们的/他们)。不要使用

  • 他或她... 使用他们。
  • 他或她... 使用他们。
  • 他或她的... 使用他们的。
  • 他或她的... 使用他们的。
  • 他自己或她自己... 使用他们自己。

3.3 美式英语

请使用美式英语(colorcentermodularize 等)。参见 此处列出的美式英语和英式英语拼写差异

3.4 牛津逗号

请使用 牛津逗号(“red, white, and blue”,而不是“red, white and blue”)。

4 示例代码

选择有意义的示例来描述和涵盖基础知识以及有趣的要点或陷阱。

为了正确渲染,请从左边缘缩进代码两个空格。示例本身应使用 Rails 代码规范

简短的文档不需要显式的“示例”标签来介绍代码段;它们只是在段落之后。

# Converts a collection of elements into a formatted string by
# calling +to_s+ on all elements and joining them.
#
#   Blog.all.to_fs # => "First PostSecond PostThird Post"

另一方面,大量的结构化文档可能有一个单独的“示例”部分。

# ==== Examples
#
#   Person.exists?(5)
#   Person.exists?('5')
#   Person.exists?(name: "David")
#   Person.exists?(['name LIKE ?', "%#{query}%"])

表达式的结果在它们之后,并由“# => ”引入,垂直对齐。

# For checking if an integer is even or odd.
#
#   1.even? # => false
#   1.odd?  # => true
#   2.even? # => true
#   2.odd?  # => false

如果一行太长,注释可以放在下一行。

#   label(:article, :title)
#   # => <label for="article_title">Title</label>
#
#   label(:article, :title, "A short title")
#   # => <label for="article_title">A short title</label>
#
#   label(:article, :title, "A short title", class: "title_label")
#   # => <label for="article_title" class="title_label">A short title</label>

避免使用任何打印方法,例如 putsp 来实现此目的。

另一方面,普通注释不使用箭头。

#   polymorphic_url(record)  # same as comment_url(record)

4.1 SQL

当记录 SQL 语句时,结果不应在输出之前有 =>

例如,

#   User.where(name: 'Oscar').to_sql
#   # SELECT "users".* FROM "users"  WHERE "users"."name" = 'Oscar'

4.2 IRB

当记录 IRB(Ruby 的交互式 REPL)的行为时,始终使用 irb> 作为命令前缀。输出应该以 => 作为前缀。

例如,

# Find the customer with primary key (id) 10.
#   irb> customer = Customer.find(10)
#   # => #<Customer id: 10, first_name: "Ryan">

4.3 Bash / 命令行

对于命令行示例,始终使用 $ 作为命令前缀。输出不需要任何前缀。

# Run the following command:
#   $ bin/rails new zomg
#   ...

5 布尔值

对于谓词和标志,优先记录布尔语义而不是精确值。

当“true”或“false”在 Ruby 中被定义为使用时,使用常规字体。单例 truefalse 需要使用固定宽度字体。请避免使用诸如“truthy”之类的术语。Ruby 定义了语言中什么是真和假,因此这些词具有技术意义,不需要替代品。

一般来说,除非绝对必要,否则不要记录单例。这样可以防止诸如 !! 或三元运算符之类的构造,允许重构,并且代码不需要依赖于方法在实现中返回的精确值。

例如

# +config.action_mailer.perform_deliveries+ specifies whether mail
# will actually be delivered and is true by default

用户不需要知道标志的实际默认值是什么,因此我们只记录其布尔语义。

带有谓词的示例

# Returns true if the collection is empty.
#
# If the collection has been loaded it is equivalent to
# +collection.size.zero?+. If the collection has not been loaded,
# it is equivalent to +!collection.exists?+. If the collection has
# not already been loaded and you are going to fetch the records
# anyway, it is better to check +collection.length.zero?+.
def empty?
  if loaded?
    size.zero?
  else
    @target.blank? && !scope.exists?
  end
end

API 谨慎避免承诺任何特定值,方法具有谓词语义,这已经足够了。

6 文件名

一般来说,使用相对于应用程序根目录的文件名:config/routes.rb 而不是 routes.rbRAILS_ROOT/config/routes.rb

7 字体

7.1 固定宽度字体

对以下内容使用固定宽度字体

  • 常量,特别是类和模块名称
  • 方法名称
  • 文字,例如 nilfalsetrueself
  • 符号
  • 方法参数
  • 文件名
  • HTML 标签和属性
  • CSS 选择器、属性和值
class Array
  # Calls +to_param+ on all its elements and joins the result with
  # slashes. This is used by +url_for+ in Action Pack.
  def to_param
    collect { |e| e.to_param }.join "/"
  end
end

使用 +...+ 用于固定宽度字体仅适用于简单的内容,例如普通类、模块、方法名称、符号、路径(使用正斜杠)等。对于其他所有内容,请使用 <tt>...</tt>

您可以使用以下命令快速测试 RDoc 输出

$ echo "+:to_param+" | rdoc --pipe
# => <p><code>:to_param</code></p>

例如,包含空格或引号的代码应使用 <tt>...</tt> 形式。

7.2 常规字体

当“true”和“false”是英文单词而不是 Ruby 关键字时,请使用常规字体

# Runs all the validations within the specified context.
# Returns true if no errors are found, false otherwise.
#
# If the argument is false (default is +nil+), the context is
# set to <tt>:create</tt> if <tt>new_record?</tt> is true,
# and to <tt>:update</tt> if it is not.
#
# Validations with no <tt>:on</tt> option will run no
# matter the context. Validations with # some <tt>:on</tt>
# option will only run in the specified context.
def valid?(context = nil)
  # ...
end

8 描述列表

在选项、参数等的列表中,在项目及其描述之间使用连字符(读起来比冒号好,因为通常选项是符号)

# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.

描述以大写字母开头,并以句号结尾——这是标准的英语。

当您想要提供更多细节和示例时,另一种方法是使用选项部分样式。

ActiveSupport::MessageEncryptor#encrypt_and_sign 是一个很好的例子。

# ==== Options
#
# [+:expires_at+]
#   The datetime at which the message expires. After this datetime,
#   verification of the message will fail.
#
#     message = encryptor.encrypt_and_sign("hello", expires_at: Time.now.tomorrow)
#     encryptor.decrypt_and_verify(message) # => "hello"
#     # 24 hours later...
#     encryptor.decrypt_and_verify(message) # => nil

9 动态生成的 methods

使用 (module|class)_eval(STRING) 创建的 methods 在其旁边有一个注释,其中包含生成的代码实例。该注释与模板相距 2 个空格。

(module|class)_eval(STRING) code comments

如果结果行太宽,例如 200 列或更多列,请将注释放在调用上方

# def self.find_by_login_and_activated(*args)
#   options = args.extract_options!
#   ...
# end
self.class_eval %{
  def self.#{method_id}(*args)
    options = args.extract_options!
    ...
  end
}, __FILE__, __LINE__

10 method 可见性

在编写 Rails 文档时,区分用户界面 API 和内部 API 至关重要。

Ruby 私有范围内的所有方法都将从用户界面 API 中排除。然而,某些内部 API 方法必须位于 Ruby 的公共范围内,以便它们可以在框架中的其他地方调用。要从用户界面 API 中排除此类方法,请使用 RDoc 的 :nodoc: 指令。

例如,ActiveRecord::Core::ClassMethods#arel_table

module ActiveRecord::Core::ClassMethods
  def arel_table # :nodoc:
    # do some magic..
  end
end

虽然它是一个公共方法,但用户不应该依赖它。此方法的名称可能会改变,或者返回值可能会改变,或者此方法可能会完全删除。通过使用 :nodoc: 标记它,它将从用户界面 API 文档中删除。

作为贡献者,重要的是考虑 API 应该是用户界面还是内部的。Rails 团队致力于在没有经过完整的弃用周期的情况下,不进行对用户界面 API 的重大更改。因此,您应该将 :nodoc: 添加到任何内部方法或模块,除非它们已经是私有的。(将 :nodoc: 添加到模块或类表示所有方法都是内部 API,并且应该从用户界面 API 文档中删除。)

11 关于 Rails 栈

在记录 Rails API 的部分时,请务必注意整个 Rails 栈。您正在记录的方法或类的行为可能会根据上下文而改变。

其中一个例子是 ActionView::Helpers::AssetTagHelper#image_tag

# image_tag("icon.png")
#   # => <img src="/assets/icon.png" />

孤立地,image_tag 将返回 /images/icon.png。但是,当我们考虑到完整的 Rails 栈,包括 Asset Pipeline 时,我们可能会看到上述结果。

我们想要记录框架的行为,而不仅仅是孤立的方法。我们关心的是用户使用完整的默认 Rails 栈时所经历的行为。

如果您对 Rails 团队如何处理某些 API 有疑问,请随时打开一个问题或向 问题跟踪器 发送补丁。



返回顶部