#文档 #用户 #过程宏 #属性 #宏推导 #生成 #过程

user_doc

用于生成面向用户文档的属性和过程宏

4 个版本 (1 个稳定版本)

1.0.3 2023 年 7 月 4 日
0.1.2 2023 年 7 月 4 日
0.1.0 2021 年 11 月 7 日
0.0.1 2021 年 8 月 9 日

#1509开发工具

每月下载量 43 次
用于 user_doc-tests

Apache-2.0 OR MIT

48KB
915

  • 原因:停止在多个地方定义文档。
  • 方法:user_doc 将标记的 Rust 文档注释复制到可运行时访问的常量。

属性 user_doc_fn 和推导 user_doc_item 宏从注释中捕获文档,并在运行时提供内容。

每个宏调用填充一个包含在构建过程中捕获的所有文档的 DocDict 的节点。在运行时,编译时生成的全局树副本通过 RwLock 可在 DOCS 中访问。


宏选项

以下辅助属性(对于 user_doc_item)/ 参数(对于 user_doc_fn)可以轻松配置这些宏:

  • chapter_blurb:一个字符串字面量,将被添加到包含的章节中,以描述此文档。
  • chapter_name:一个字符串字面量,命名此章节。
  • chapter_name_slug:一个以逗号分隔的字符串字面量列表,命名章节路径。
  • chapter_num:一个与章节编号相对应的整数字面量。
  • chapter_num_slug:一个与章节路径相对应的整数字面量列表。

如何在函数定义中使用 user_doc_fn

假设函数 call_this_function 的文档应在运行时对用户可见。

#[user_doc_fn(
  chapter_num_slug(1, 3, 5),
  chapter_name_slug(
    "A Slaying in Luton",
    "The Trouble About Ipswich",
    "All Along the Weary M-5 Motorway",
  ),
)]
 
 
/// The parenchyma isn't as stiff as usual. It looks almost floppy.
/// I stick out a hand to touch it. It sucks my fingertips forward.
/// When I pull my hand back, a hanging bridge of sap follows.
pub fn call_this_function() -> bool { true }

注释行(从 "The parenchyma" 到 "sap follows.")将被捕获并分配在具有编号/命名节点的树层次结构中的位置

    1. "卢顿的杀戮"
    1. "伊普斯威奇的麻烦"
    1. "在疲惫的M-5高速公路上"

所以,在运行时

doc_data::load_global_docs(
  None, None
).expect("must load docs from path");
let docs = &*doc_data::DOCS;
let docs_read_lock = docs.read().expect("must get read guard on global docs");
 
 
 assert_eq!(
  docs_read_lock.get_entry_at_numeric_path(
    &[1,3,5] // corresponds to the `chapter_num_slug` argument in the macro call
  ).expect("must find test entry").1,
  " The parenchyma isn\\'t as stiff as usual. It looks almost floppy.\
    \n I stick out a hand to touch it. It sucks my fingertips forward.\
    \n When I pull my hand back, a hanging bridge of sap follows.",
);

文档注释已经插入到树结构中。哇。现在,它可以在运行时显示给用户。

如何在结构体或枚举定义上使用 user_doc_item

想象一下相同的用例,但这次,文档附加到了结构体或枚举定义上。
当与结构体或枚举一起工作时,外部属性注释不会被捕获。

#[derive(user_doc_item, Clone, Debug, PartialEq, Eq)]
/// This comment WILL NOT BE captured for user docs.
pub enum Idiot {
  #[chapter_num(23)] // should be overriden by slug
  #[chapter_num_slug(1, 3, 4)]
  #[chapter_name("The House of Almond Blossoms")]
  /// He took a look at the card I showed him. His brows scrunched up like he smelled something offensive.
  /// Could he tell it was fake? Everyone sweats in heat like this. If they don't, it means they're about to keel over from dehydration anyway. Still, I felt like I was sweating more than usual.
  /// We stood frozen for a moment. It seemed an eon. Then he mercifully broke the silence.
  /// "I can't read those. I'm just supposed to stand here and not let anyone pass."
  /// I considered. I didn't want to get him in trouble – he was clearly new. Still, it was me or him.
  /// "Oh," I said as casually as I could, "It says you're to let me through. But don't let anyone else through after me. It says that too.""
  Kid(u16),
}
 
 
let docs = &*user_doc::DOCS;
let docs_read_lock = docs.read().expect("must get read guard on global docs");
std::println!("docs_read_lock {:?} {:#?}", std::time::Instant::now(), *docs_read_lock );
assert_eq!(
  docs_read_lock.get_entry_at_numeric_path(&
    [1,3,4], // corresponds to the `chapter_num_slug` helper attribute in the macro call
  ).expect("must find test entry").0,
  String::from("The House of Almond Blossoms"),
);

在这里,chapter_num_slug 辅助属性覆盖了 chapter_num 属性。
Slug风格的(数字或名称)属性和参数将始终具有优先权。

如何为使用 mdbook 准备 DocDict

要将在 "tests/scratch/src" 路径处的全局文档存储库扩展到层次结构,请执行以下操作

user_doc::load_global_docs(
  None, None
).expect("must load docs from path");
let docs = &*user_doc::DOCS;
let docs_read_lock = docs.read().expect("must get read guard on global docs");
docs_read_lock.expand_into_mdbook_dirs_at_path(
   DirectoryNamingScheme::ChapterName,
   "tests/scratch/src",
).expect("must expand docs into dirs");

目录 tests/scratch/src 将填充与 mdbook 格式对应的文档。

如何在工作区项目中使用

在具有多个子项目的工作区中捕获文档数据时,只有一个全局文档捕获存储实例。因此,来自最后一个编译的子项目的文档通常会覆盖先前捕获的文档。

解决方案

只需使用 set_persistence_file_name 宏为每个捕获指定不同的文件名。然后,在运行时将提供的文件名传递给 load_global_docs 函数调用。

给定一个看起来像的项目树

some_workspace
  └ sub_package_a
      ┕ src/lib.rs
  └ sub_package_b
      ┕ src/lib.rs
  1. sub_package_a/src/lib.rs 中调用 set_persistence_file_name("docs_a_or_whatever")
  2. sub_package_b/src/lib.rs 中调用 set_persistence_file_name("docs_b_or_whatever")
  3. 在其他地方,加载来自两个包的文档到新的字典中
  let mut dict_a = DocDict::default();
  load_global_docs("docs_a_or_whatever", Some(&mut dict_a));
  let mut dict_b = DocDict::default();
  load_global_docs("docs_b_or_whatever", Some(&mut dict_b));

重要提示

这些宏使用临时目录从编译时到运行时持久化数据。
不要在这些宏捕获的文档注释中存储敏感信息(密钥、密码等)。

依赖项

~5MB
~96K SLoC