MetricFu源码解析:Generator模板方法模式如何优雅驱动12种指标生成
MetricFu源码解析:Generator模板方法模式如何优雅驱动12种指标生成
【免费下载链接】metric_fuA fist full of code metrics项目地址: https://gitcode.com/gh_mirrors/met/metric_fu
MetricFu 是一款 Ruby 代码指标全家桶工具,一次运行即可产出复杂度、重复代码、代码异味等 12 类分析结果。本文将从源码层面拆解它的 Generator 模板方法模式,带你快速看懂「一套骨架驱动多种指标」的设计精髓。
为什么是「模板方法模式」?🎯
MetricFu 需要聚合 stats(代码行数)、flog(认知复杂度)、flay(重复代码)、reek(代码异味)、saikuro(圈复杂度)、churn(变更热点)、rcov(覆盖率)、cane(可维护性指数)、roodi(代码风格)、rails_best_practices(Rails 最佳实践)、hotspots(问题热点)等众多指标。如果每种指标各写一套流程,代码会迅速失控。
它的解法很经典:把「不变的流程」抽到父类,把「多变的细节」留给子类,这正是设计模式中教科书级别的模板方法模式(Template Method)。
核心骨架:Generator 基类
打开 lib/metric_fu/generator.rb,核心只有几十行:
def generate_result mf_debug "Executing #{metric}" emit analyze to_h endgenerate_result就是整个框架的「总调度」。它固定了emit → analyze → to_h三步流水线:
| 步骤 | 职责 | 子类要做什么 |
|---|---|---|
emit | 运行指标工具 | 调用具体工具(如 Flog、Reek)拿到原始输出 |
analyze | 解析原始输出 | 把输出整理成可程序化处理的结构 |
to_h | 序列化为 Hash | 产出可直接写入 YAML 的哈希结构 |
父类中这三个方法默认都抛NotImplementedError,相当于强制契约:子类不实现就立刻报错,新手看代码也能一眼知道「该补什么」。
一个真实例子:Flog 指标的实现
以认知复杂度指标为例,lib/metric_fu/metrics/flog/generator.rb 中的FlogGenerator完整演示了契约:
class FlogGenerator < Generator def self.metric :flog end def emit @flogger = FlogCLI.new(parse_options) @flogger.flog *files_to_flog end def analyze @flogger.each_by_score do |name, score, operators| # 按容器归类每个方法的得分…… end end def to_h { flog: { total: @flogger.total_score, average: @flogger.average, method_containers: sorted_containers.map(&:to_h) } } end end可以看到子类完全不用关心「何时运行、结果存到哪、如何输出报告」——这些由基类统一处理,子类只做三件事的填空。📝
自动注册:新指标「即插即用」
模板方法模式之外,MetricFu 还有一个精巧的设计:继承即注册。
在 lib/metric_fu/generator.rb 中:
def self.inherited(subclass) @generators << subclass end任何继承Generator的子类会自动进入全局注册表,框架通过get_generator(metric)按名字查找对应生成器。同样的思路也用在 lib/metric_fu/metric.rb 的Metric基类上——enabled_metrics会自动收集所有已启用并激活的指标实例。
这意味着:想扩展一个新指标,只需在lib/metric_fu/metrics/下新建目录,放入metric.rb+generator.rb(需要图表时再加grapher.rb),实现 emit/analyze/to_h 三个方法即可,无需修改任何核心代码。这就是开闭原则(对扩展开放、对修改封闭)的落地。
从启动到报告:完整流程一览 🔍
整条链路可以概括为:
- 加载:lib/metric_fu/loader.rb 扫描
metrics/**/metric.rb,注册全部可用指标 - 运行:lib/metric_fu/run.rb 的
Run#measure遍历enabled_metrics,逐个调用MetricFu.result.add(metric) - 生成:
Result内部通过注册表找到对应 Generator,调用模板方法generate_result - 汇报:lib/metric_fu/reporter.rb 的
Reporter以事件通知方式驱动各格式化器(HTML/YAML),产出最终报告
其中 lib/metric_fu/reporting/result.rb 是连接「运行编排」与「具体指标」的枢纽,值得重点阅读。
新手读码路线建议 ✨
| 顺序 | 文件 | 阅读目标 |
|---|---|---|
| 1 | lib/metric_fu/generator.rb | 理解模板方法骨架 |
| 2 | lib/metric_fu/metric.rb | 理解指标配置与注册机制 |
| 3 | lib/metric_fu/metrics/flog/generator.rb | 看一个「简单」的具体实现 |
| 4 | lib/metric_fu/metrics/reek/generator.rb | 看一个处理外部工具输出的实现 |
| 5 | lib/metric_fu/run.rb | 串起全局调用链 |
总结
MetricFu 用最朴素的模板方法模式解决了「多指标、同流程」的架构难题:基类锁定 emit → analyze → to_h 流水线,子类只填三个空,继承即注册。这套思路小到个人工具、大到企业级框架都适用,值得写 Ruby(或其他语言)插件化系统的人反复品味。
【免费下载链接】metric_fuA fist full of code metrics项目地址: https://gitcode.com/gh_mirrors/met/metric_fu
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
