
后端【免费下载链接】nokogiriNokogiri (鋸) makes it easy and painless to work with XML and HTML from Ruby.项目地址https://gitcode.com/gh_mirrors/no/nokogiri点击查看免费下载Nokogiri鋸是 Ruby 生态中最常用的 XML / HTML 解析库其仓库同时维护 CRuby基于 libxml2/libxslt、libgumbo与 JRuby基于 Xerces/NekoHTML/Saxon两套原生实现。本文以仓库根目录的 CONTRIBUTING.md 为骨架系统梳理 Nokogiri 的贡献规范、开发环境搭建、全套测试矩阵、代码风格、CI 与 OSS-Fuzz 配置以及从打包到发布的完整流程并结合仓库源码与配置逐条给出可验证的实操依据。读完本文你将掌握向 Nokogiri 提交高质量 Pull Request、运行各种测试级别、定位内存问题乃至亲手完成一次版本发布的全套方法。项目定位与核心指导原则在动手写代码之前先理解 Nokogiri 项目自我约束的两条最高原则源自 README.md在 CONTRIBUTING.md 中被再次强调安全默认secure-by-default默认把所有文档视为**不可信untrusted**输入来解析。薄封装thin-as-reasonable layer在底层解析器之上只做合理程度内最薄的一层不试图抹平不同解析器之间的行为差异。由此衍生出几条二级原则只要可能CRuby 与 JRuby 应实现同样的功能只要可能共享行为应写成共享的 Ruby 代码即原生代码越少越好测试尽量不写平台相关用例若必须写用skip并附上解释。值得注意的一点虽然各解析器都符合标准但 CRuby 与 JRuby 底层解析器之间天然存在行为不一致Nokogiri不会也不应去消除这些差异。处理方式是当差异具有语义重要性时在测试套件中显式暴露它否则刻意让测试只依赖关键的语义部分例如在匹配结果的 regex 中忽略空白字符。Nokogiri 在 Ruby 生态中被广泛使用因此维护者非常谨慎地避免引入破坏性变更。如果你要修改公开 API请先阅读官方文档中的Semantic Versioning Policy弄清楚哪些改动会被视为 breaking change。另一个需要尊重的事实是维护者都是志愿者请友善沟通、避免提出无理要求行为准则全文见 CODE_OF_CONDUCT.md。从哪里开始选择切入点如果你刚加入社区官方推荐从Issues 上标记为 Help Wanted的任务入手在仓库的 GitHub Issues 页面用标签过滤即可找到。此外文档改进类的 Pull Request 永远受欢迎——文档是项目最容易产生价值也最容易被忽略的部分详见下文文档风格小节。提交 Pull Request 的硬性规则所有 PR 必须以main为合并基线merge base分支管理细节见下一节。引入行为变更的 PR 必须包含一个测试用来演示该行为被引入、修复或改变。测试应尽量向维护者传达你要解决的问题如果维护者看不懂会向你追问澄清。如果 PR 包含功能或 bugfix请在 CHANGELOG.md 的unreleased 区段添加条目。请勿提交纯外观性改动风格、命名等。维护者认可代码永远可以改进但更希望你把精力放在有实际影响力的贡献上。鼓励提前推送 work in progress PR 以利用 CI 反馈但请用 GitHub 的Draft Pull Request功能标记它尚未完成。分支管理与版本发布管理Nokogiri 遵循 SemVer。开发工作全部在main上进行此时main上的版本号被设置为下一个 minor 版本的开发版本号。例如本仓库 lib/nokogiri/version/constant.rb 当前即为module Nokogiri # The version of Nokogiri you are using VERSION 1.20.0.dev end版本号带.dev后缀意味着当前main处于下一个版本如 1.20.0的开发中状态。所有 PR 以main为合并基线即与此对应。补丁patch版本发布的做法是从main上挑选cherry-pick所需提交到对应的发布分支如v1.13.x并以标签为backport的 PR 形式合并。本地开发环境搭建基础步骤git clone --recurse-submodules https://github.com/sparklemotion/nokogiri cd nokogiri bundle install注意--recurse-submodules仓库以 submodule 形式引用了 html5lib 测试集test/html5lib-tests后续测试会用到。进阶建议安装最新或上一个版本的 CRuby截至文档写作时为 4.0 或 3.4以及较新的 JRuby推荐使用rbenv测试脚本需要多 Ruby 环境时会用到它。安装系统版的 libxml2/libxslt这样你能同时针对打包的库和系统库两种构建方式运行测试。尽量安装valgrind主要用于内存调试非必需注意 valgrind 在 macOS 上可能不太好装。如果计划发布预编译的原生 gem确保docker已安装且工作正常下文打包环节会用到。运行测试从一条命令到整套内存调试矩阵首先要理解一个设计意图rake test不会编译原生扩展这是故意的——这样可以用已安装的 gem 直接跑测试套件。如果你在改扩展代码请确保每次跑测试前都重新编译以免测的是旧代码。最短路径bundle exec rake compile test聚焦单测与指定文件用 Minitest 的TESTOPTS按测试名过滤bundle exec rake compile test TESTOPTS-n/test_last_element_child/用TESTGLOB按文件匹配默认是test/**/test_*.rb见 rakelib/test.rake 中nokogiri_test_case_configurationbundle exec rake compile test TESTGLOBtest/**/test_*node*rb并行编译与并行测试测试并行度由环境变量NCPU控制编译并行度由MAKEFLAGS控制可写进.bashrcexport NCPU8 export MAKEFLAGS-j8 bundle exec rake compile test在 test/helper.rb 中可以看到当NCPU 1且非 JRuby 时会加载minitest/parallel_fork实现并行测试。CRuby 高级用法使用系统库而不是打包库跑测试先清理再用--enable-system-libraries重新编译bundle exec rake clean # 清掉用打包库构建的产物 bundle exec rake compile test -- --enable-system-libraries其余高级任务全部注册在namespace test下可对照 rakelib/test.rake 的实现# 性能基准测试 bundle exec rake compile test:bench # valgrind 内存检查 bundle exec rake compile test:valgrind # 调试器内运行gdb / lldb bundle exec rake compile test:gdb bundle exec rake compile test:lldb # ruby_memcheck valgrind 查找内存泄漏 bundle exec rake compile test:memcheck # 基于 RSS 和线性插值的内存泄漏测试 bundle exec rake compile test:memory_suite # 在 valgrind 下对每个测试循环寻找内存错误 bundle exec rake compile test:memory_suite:valgrind几个 rake 任务的实现细节值得注意ValgrindTestTask会强制NCPUnilvalgrind 不能并行跑并注入--num-callers50 --error-limitno --partial-loads-okyes --undef-value-errorsno --error-exitcode42 --gen-suppressionsall等选项它会根据当前 Ruby 版本如ruby-3.4.x自动匹配suppressions/目录下的.supp文件MemorySuiteTestTask会设置NOKOGIRI_MEMORY_SUITEt和NOKOGIRI_TEST_GC_LEVELmajor只有安装了ruby_memcheckgem 时memcheck任务才可用见 rakelib/test.rake 顶部的require ruby_memcheck及其rescue LoadError。通过环境变量控制 GC 行为测试套件支持多种 GC 行为用于定位特定类别的内存 bug实现细节见 test/helper.rb 的nokogiri_test_gc_level与 setup/teardown 逻辑# 普通 GC 行为默认 NOKOGIRI_TEST_GC_LEVELnormal bundle exec rake compile test # 每个测试后执行一次 minor GC NOKOGIRI_TEST_GC_LEVELminor bundle exec rake compile test # 每个测试后执行一次 major GC NOKOGIRI_TEST_GC_LEVELmajor bundle exec rake compile test # 每个测试后 major GC每 20 个测试后做一次 GC compaction NOKOGIRI_TEST_GC_LEVELcompact bundle exec rake compile test # 每 20 个测试后校验 compaction 后的引用GC.verify_compaction_references NOKOGIRI_TEST_GC_LEVELverify bundle exec rake compile test # 开启 GC.stress 模式 NOKOGIRI_TEST_GC_LEVELstress bundle exec rake compile test其中compact与verify依赖平台对GC.compact的支持不支持时会自动回退到normal见 test/helper.rb 的initialize_nokogiri_test_gc_level。针对 libxml2 / libxslt 的深度调试如果你想基于修改过的 libxml2 或 libxslt构建 Nokogiri做法是把两个库克隆为同级目录../libxml2与../libxslt然后运行仓库脚本scripts/compile-against-libxml2-source该脚本会就地make install两个库到$HOME/tmp/libxml2导出LD_LIBRARY_PATH、CFLAGS、LDFLAGS并以--enable-system-libraries重新编译 Nokogiri见 scripts/compile-against-libxml2-source。它还接受一个可选命令在设好环境变量后用本地 libxml2 执行对git bisect定位 libxml2/libxslt 的回归非常有用scripts/compile-against-libxml2-source bundle exec rake test如果只是临时用源码目录构建不做 bisect 或改库更轻量的替代方案是bundle exec rake compile -- \ --with-xslt-source-dir$(pwd)/../libxslt \ --with-xml2-source-dir$(pwd)/../libxml2针对 libgumboHTML5 解析器的开发与模糊测试跑 HTML5 解析器测试bundle exec rake gumbo另外Nokogiri 的 HTML5 解析器还有一批 html5lib 测试放在submodule中没有检出时先执行git submodule update --init # 检出 test/html5lib-tests bundle exec rake compile test快速迭代编译 libgumbo如果正在改 libgumbo 源码rake clean compile test的反馈太慢。用--gumbo-dev模式可以让后续每次rake compile只增量重编译被改动的文件并重链接nokogiri.sobundle exec rake clean compile -- --gumbo-dev # 改完任意 gumbo 文件后 bundle exec rake compile # 立即增量编译并重链接用 libFuzzer 模糊测试 gumbo 改动修改或新增gumbo-parser功能时官方建议用 libFuzzer 配合各种 sanitizer 做模糊测试。仓库已内置 fuzz 工程见 gumbo-parser/fuzzer构建方式cd gumbo-parser make fuzzers构建完成后进入gumbo-parser/fuzzer/build目录可选的可执行文件有parse_fuzzer无 sanitizer 的标准 fuzzerparse_fuzzer-asan基于 ASANAddressSanitizer构建parse_fuzzer-msan基于 MSANMemorySanitizer构建parse_fuzzer-ubsan基于 UBSANUndefinedBehaviorSanitizer构建。为提高效率可同时使用仓库提供的字典与语料库./parse_fuzzer -dict../gumbo.dict ../gumbo_corpus正常运行时终端会持续输出 libFuzzer 的覆盖率统计例如INFO: Seed: 4156947595 INFO: Loaded 1 modules (7149 inline 8-bit counters): 7149 0x58a462, 0x58c04f, INFO: Loaded 1 PC tables (7149 PCs): 7149 0x53beb0,0x557d80, INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes #732 NEW cov: 188 ft: 279 corp: 8/78b lim: 11 exec/s: 0 rss: 24Mb NEW_FUNC[1/1]: 0x441de0 in gumbo_token_destroy (...)一旦 fuzzer 发现 crash说明找到了 bug会停止并写出一个可复现的最小输入文件31511 ERROR: libFuzzer: deadly signal ... artifact_prefix./; Test unit written to ./crash-b13e8756b13a00cf168300179061fb4b91fefbed把该文件重新喂给 fuzzer 即可稳定复现parse_fuzzer crash-b13e8756b13a00cf168300179061fb4b91fefbed样式指南文档与代码文档风格Nokogiri 用rdoc构建文档运行rake rdoc会在./html目录生成文档rdoc 相关任务见 rakelib/rdoc.rake。文档字符串默认使用RDoc::Markup格式简单 docstring 也可以声明:markup: markdown后用 Markdown。仓库曾尝试转向yard但该工作已停止。文档改进 PR 会被维护者乐意合并并在 CHANGELOG 中署名。具体规范示例可参考 lib/nokogiri/xml/node.rb 与 ext/nokogiri/xml/node.c:call-seq:用法尽量标注返回类型如:call-seq: upcase(name) → String列出方法的所有别名说明方法的 block/yield 用法。简要说明方法用途、返回值及副作用。方法签名[Parameters]段以项目符号列表描述位置参数参数名后用括号标注类型描述末尾标注默认值例如- options (Nokogiri::XML::ParseOptions) The parser options. (default ParseOptions::DEFAULT_XML)关键字参数使用独立的[Optional Keyword Arguments]段格式相同[Returns]段标注返回类型[Yields]段标注 block 参数类型声明尽量用 RBS 语法例如联合类型(String | IO)。提示符号约定️用于安全相关说明⚠️用于警告 tricky 用法用于提醒其他重要事项。示例偏好用代码示例展示微妙行为而不是用文字解释用*Example:* 简短说明行来命名并分隔示例代码块缩进两个额外空格。元数据See also:用于关联相关方法Since用于标注代码引入的版本。代码风格Ruby 代码使用Standard风格standardrbC 与 Java 使用astyle配置集中在 rakelib/format.rake。一键格式化rake format从 rakelib/format.rake 可以看到它串联了format:c、format:java、format:ruby、format:toc四个子任务。C 语言的 astyle 参数包括2 空格缩进、1TBS 括号风格、--pad-oper/--pad-comma空格策略、--align-pointername、--max-code-length120等。另外用rake format:toc可以重新生成文档如 CONTRIBUTING.md的目录。仓库还有一些待处理的 Rubocop 规则记录在.rubocop_todo.yml中修复它们同样欢迎提交 PR。C 代码命名规范C 代码命名目前尚未完全统一但维护者正逐步推进一套能让栈回溯更可读的规范绑定到 Ruby 方法的函数以noko_开头后接 snake_case 的类/模块名单例方法用_s_分隔方法名noko_xml_sax_parser_context_s_io对应Nokogiri::XML::SAX::ParserContext.io实例方法用__分隔noko_xml_sax_parser_context__line对应Nokogiri::XML::SAX::ParserContext#line属性 setter 加_set后缀noko_xml_sax_parser_context__recovery_set对应Nokogiri::XML::SAX::ParserContext#recovery谓词加_eh后缀noko_xml_node__blank_eh对应Nokogiri::XML::Node#blank?。公开的 C 函数以noko_开头合适时后接类/模块名与描述名如noko_xml_node_wrap_node_set_result否则用__加描述如noko__structured_error_func_save。这些规范在源码中均有实例例如 ext/nokogiri/xml_node_set.c 定义了noko_xml_node_wrap_node_set_resultext/nokogiri/nokogiri.h 声明了noko__structured_error_func_save等函数ext/nokogiri/html4_sax_push_parser.c 调用noko__structured_error_func_save_and_set。未绑定的 static C 函数以_noko_开头后接类/模块名与描述名如_noko_xml_xpath_context_dfree。CI 是如何配置的CI 主体自 2021 年 5 月起运行在 GitHub Actions 上此外32 位 Windows当时 GA 不支持在 Appveyor 上跑测试。目前已知的覆盖缺口是arm64-darwin 原生 gem 测试缺失。ci.yml 管线基础安全检查与格式检查Rubocop在 vanilla ubuntu 上用系统库跑快速暴露明显失败在 ubuntu、macos、windows 上跑 Gumbo 解析器测试在所有受支持的 CRuby 版本上各跑三遍一次用打包库一次用系统库一次在 valgrind 下查内存 bug用 ruby_memcheck 跑套件寻找新内存泄漏跑 JRuby跑 TruffleRuby在 MuslAlpine系统上对系统库跑用打包库 valgrind 跑加载 libxml-ruby 跑因为它可能与 libxml2 产生冲突对系统库用打包库 valgrind构建 ruby 平台 gem并在 linux、macos、windows 上安装测试构建原生 gem并对所有受支持 CRuby 版本以及多种 linux/macos/windows 系统安装测试构建 jruby gem 并安装测试。upstream.yml 管线针对 libxml2 与 libxslt 的 headlinux跑含 valgrind 检查针对 CRuby headlinux、windows、macos跑含 valgrind 检查针对 JRuby head 跑运行 html5lib-tests 项目origin/master的测试。downstream.yml 管线针对一批重要的下游依赖项目用 Nokogirimain跑它们的测试。generate-ci-images.yml 管线每周构建一次其他管线用到的容器主要优化是确保系统包如libxml2-dev、valgrind已预装。容器内容见 oci-images/nokogiri-test/。Valgrind 与 ruby_memcheck项目重度依赖 Valgrind 与ruby_memcheck来抓内存 bug并与每个 CRuby 版本组合运行。suppressions 文件主要用于压制已知的小内存泄漏或特定 Ruby 版本的怪癖相关文件在 suppressions/ 目录装载逻辑见 rakelib/test.rake 的ValgrindTestTask它会按当前 Ruby 引擎与版本号匹配如ruby-3.4、ruby等 suppressions 文件。Benchmark / 性能测试test:bench是独立套件用于守住若干性能预期目前规模不大会持续扩充在 CI 的 CRuby 与 JRuby 上都会跑。基准测试类需继承Nokogiri::TestBenchmark定义于 test/helper.rb文件需匹配test/**/bench_*.rb见 rakelib/test.rake 的nokogiri_test_bench_configuration。写新 CI job 时的提示检出源码时务必包含 submodulehtml5lib 测试依赖它测试打包库而非系统库时缓存ports/已编译的库或ports/archives/仅 tarball注意libgumbo构建在ports/之外正是为了允许这种安全缓存。OSS-Fuzz 配置OSS-Fuzz 是面向开源库的持续模糊测试服务。Nokogiri 的 libgumbo 已接入 OSS-Fuzz相关配置维护在 OSS-Fuzz 项目内通知邮件发送到nokogiri-oss-fuzzgooglegroups.com。仓库内与之配套的本地 fuzz 工程位于 gumbo-parser/fuzzer包含 parse_fuzzer.cc、词典 gumbo.dict 与语料库 gumbo_corpus.zip。打包发布Precompiled Native Gems打包原生预编译gem 的前提是docker已正确安装。运行仓库脚本scripts/build-gems它会为所有受支持平台打包 gem并依次调用以下脚本做基本健全性测试scripts/test-gem-setscripts/test-gem-file-contentsscripts/test-gem-installation具体发布检查清单见下文发布流程。其他实用工具脚本scripts/test-exported-symbols检查编译出的nokogiri.so是否有意外导出的符号该脚本大概率只在 Linux 上可用。scripts/files-modified-by-open-prs查看当前所有 open PR 中提议改动过的文件。当你打算大刀阔斧改某个文件时先跑一下它有助于预判可能产生的 merge conflict。项目根目录还有一个Vagrantfile用于在非 Linux 系统如 OpenBSD上复现问题但维护不积极使用效果因人而异YMMV。升级 Java 依赖JRuby 平台的.jar依赖全部以随 gem 打包的方式管理位于lib/nokogiri/jruby/下实际清单见 lib/nokogiri/jruby/nokogiri_jars.rb包含 Xerces 2.12.2、NekoHTML 2.63.0、Saxon-HE 12.7、jing 20200702VNU、xmlresolver 5.3.3、isorelax 20030108、xalan 2.7.3 等。开发依赖使用jar-dependencies管理注意 NekoDTD 用的是项目自维护的 fork。要修改或新增一个依赖需要四处保持同步nokogiri.gemspec 的spec.requirements声明 Maven groupId、artifactId 与版本nokogiri.gemspec 的spec.files把 jar 文件列入文件清单gitlib/nokogiri/jruby/下的 jar 文件必须提交进 gitlib/nokogiri/jruby/nokogiri_jars.rb包含所有 jar 的 require 与JAR_DEPENDENCIES哈希。对开发者而言实际操作流程是# 1. 在 gemspec 的 requirements 中编辑坐标 # 2. 更新 lib/nokogiri/jruby 下的所有产物 bundle exec rake vendor_jars # 3. 检查 manifest必要时更新 gemspec 的 files bundle exec rake check_manifest # 4. 把 lib/nokogiri/jruby 下所有内容含 jar提交进 gitRake 任务的组织方式仓库的Rakefile曾经是一坨巨大的烂摊子现已拆分为 rakelib/ 下的一组小文件如 rakelib/test.rake、rakelib/format.rake、rakelib/rdoc.rake、rakelib/extensions.rake、rakelib/package.rake、rakelib/clean.rake、rakelib/docker.rake、rakelib/css-generate.rake、rakelib/gumbo.rake、rakelib/rubocop.rake、rakelib/debug.rake 等。如果你要新增 rake 任务请判断它该放进哪个既有领域或是否有必要新建一个文件没有充分理由不要直接往Rakefile里加任务。发布流程Release Checklist发布 Nokogiri 的完整清单来自 CONTRIBUTING.md括号内为仓库内对应实现预检确保 CI 全绿更新 CHANGELOG.md 与 lib/nokogiri/version/constant.rb提交并打 git tag运行scripts/build-gems确认全部完成且所有测试通过内部调用scripts/test-gem-set、scripts/test-gem-file-contents、scripts/test-gem-installation做健全性检查。发布git push git push --tagsfor g in gems/*.gem ; do gem push $g ; done在 GitHub Releases 页面创建 release并附上 sha2 校验和。如果该版本含安全修复发布 GHSAGitHub Security Advisory发送邮件至ruby-security-anngooglegroups.com与ruby-talkruby-lang.org。发布后更新 nokogiri.org 站点内容将 lib/nokogiri/version/constant.rb 提升为预发布版本号如v1.14.0.dev与当前仓库的1.20.0.dev模式一致让main重新进入下一个版本的开发状态。小结Nokogiri 的贡献流程可以概括为一条清晰的链路以main为基线、带测试提交 PR → 本地用rake compile test起步、用TESTOPTS/TESTGLOB聚焦、用test:valgrind/test:memcheck/NOKOGIRI_TEST_GC_LEVEL排查内存问题 → 按文档与代码风格规范rdoc:call-seq:、Standard、astyle、noko_命名体系打磨 → 由 CI 三套管线ci/upstream/downstream与 OSS-Fuzz 守门 → 最后由scripts/build-gems与发布清单完成交付。无论是首次提交文档改进的新人还是深入 libxml2、libgumbo 或 JRuby 依赖的资深维护者本文梳理的环境、命令与源码证据都能作为一份可随时查阅的操作手册。赞分享后端【免费下载链接】nokogiriNokogiri (鋸) makes it easy and painless to work with XML and HTML from Ruby.项目地址https://gitcode.com/gh_mirrors/no/nokogiri点击查看免费下载相关推荐Trippy 贡献与发布完全指南从开发环境搭建到 0.xx.0 版本发布Trippy 贡献与发布完全指南从开发环境搭建到 0.xx.0 版本发布 本篇技术指南围绕 Trippy一个用 Rust 编写的网络诊断工具工作区由 tr网络CLI运维node-fetch 贡献指南从环境搭建、测试驱动开发到 semantic-release 自动发布全流程node fetch 贡献指南从环境搭建、测试驱动开发到 semantic release 自动发布全流程 node fetch 是一个把 WHATWG Fe后端Slate 贡献指南从环境搭建、测试验证到版本发布的完整开发实践Slate 贡献指南从环境搭建、测试验证到版本发布的完整开发实践 本文是围绕开源富文本编辑器框架 Slate当前处于 beta 阶段仓库编写的贡献指南系前端富文本UI组件上一篇Rawdog 革命性 CLI 助手如何用 AI 自动生成和执行 Python 脚本下一篇js2flowchart与AWS云服务代码可视化最佳实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考