关于 simplifying-ruby-code
用于 Ruby 代码审查与重构的 Skill,着重简化结构并保留有意义的行为。它提供替换冗余类、分离决策与 I/O,以及删除代码前检查调用方的模式。
主要功能
- 01将无状态命令对象改为函数
- 02按需选用 Hash、Struct 或 Data
- 03以组合替代深层继承
- 04分离纯决策与 I/O
- 05删除类前检查调用方
- 06指导审查和分步重构
适用场景
- 01审查 Ruby 代码的简化机会
- 02重构 Rails 服务对象和 Concern
- 03规划安全删除类
- 04分离计算与数据库或文件操作
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ bostonaholic/ skills --skill simplifying-ruby-code安装后在 Claude Code 中输入/simplifying-ruby-code确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlreferences/review-findings.mdscripts/find-callers.sh详细介绍
简化 Ruby 代码
优先使用普通数据(Hash、Array、Struct、Data)和纯函数,而不是添加状态或行为的类。将决策与副作用分开:决策接收数据并返回数据;副作用执行 I/O(数据库、网络、文件、时间)。将它们放在不同的方法或模块中,这样测试决策时就不需要使用模拟对象。
用户要求审查时,只报告发现的问题,除非用户要求,否则不要编辑任何内容。通过编号(“Pattern 1”)或反模式名称引用相关模式。
模式
-
将命令对象改为模块函数。 如果某个类唯一的公共方法是
call、perform、run或execute,且除了构造函数参数外不持有任何内容,就可以改为直接调用或模块函数(UserCreator.new(params).call可改为User.create(params))。如果对象会在多次调用间持有状态、执行值得命名的多步骤算法,或必须序列化(例如后台任务),则保留对象。 -
将值对象改为 Data、Struct 或 Hash。 如果某个类只存储属性,包含手写的
initialize、读取器或==,且没有行为或验证:使用方式 适用情况 Hash 临时数据、键不固定、JSON 输入或输出 Struct 属性固定,允许修改 Data 属性固定且不可变(检查 ruby -v>= 3.2)自定义类 验证、不变量或真正的领域行为 -
将仅含类方法的类改为模块。 如果某个类从未被实例化,且只定义
self.方法,就将其改为带有module_function的模块。 -
用组合替代深层继承。 继承层级超过 2 层(只计算项目自身的类;
ApplicationRecord或StandardError等框架和标准库基类不计入),或存在只有一个子类的抽象基类时,考虑改用组合。 -
缺少 Ruby 协议。 如果调用方需要手动拆解类似集合或值的类,而该类没有实现
each和Enumerable、to_h、<=>和Comparable,或hash和eql?,就应补上相应协议。 -
混合决策与副作用。 如果测试需要大量模拟对象,或某个方法在同一段代码中计算并写入数据,就将计算提取为纯函数,并保留一个精简的方法来处理 I/O。
Rails 反模式
- 服务对象: 单方法、无状态的服务应放在模型方法或模块函数中(模式 1)。复杂的编排可以保留为服务,但要将决策与副作用分开(模式 6)。任务是合理的对象,因为它们需要序列化。
- 模型: ActiveRecord 模型应保留为类;将业务计算移入纯函数。
- Concern: Concern 用于在多个模型间共享行为;如果某个 Concern 被用作单个模型的杂物箱,则应指出。
- Helper: 仅用于视图格式化;业务规则应放在模块中。
- 重新实现 Rails: 自定义 DSL 或基类若重复实现 scopes、validations、callbacks、enums 或
ActiveModel,就应避免。
纯 Ruby 反模式
- 模板方法: 基类使用钩子方法,而代码块即可实现。
- 构建器: 对于可通过关键字参数或
Data.define直接构建的对象。 - 包装器: 包装 Array、Hash、Set 或其他标准库类型,并转发大多数调用的类。
- 元编程: 使用
method_missing、define_method或instance_eval构建 DSL,而普通方法即可实现。 - 依赖: 为了几行标准库代码而引入 gem。
在 gem 中,每个公共常量都是其他项目可能调用的 API。
移除或内联类之前
- 对每个类运行
bash <skill-dir>/scripts/find-callers.sh <Constant> <project>。 - 退出码为 0:处理每个
reference和require命中项,并判断每个dynamic命中项构造出的名称是否可能是该类;这需要阅读代码,因此由你负责。 - 退出码为 1:未找到调用方。退出码为 2:修正参数。退出码为 3:安装指定工具。退出码为 4:报告 grep 错误。
- 控制器还会通过
config/routes.rb中的 snake_case 资源名被调用;脚本不会搜索这种情况,因此请阅读该文件。 - 在评审中,如果无法确认某个发现的调用方情况,请删除或降低该发现的优先级。
评审发现
报告评审结果时,请阅读评审发现,了解分组方式、每条发现包含的字段以及结尾顺序。
重构
先确保测试基线全部通过。一次应用一种模式,并在每次之后运行测试套件;如果失败,请先修复或回退该步骤,再继续。更新那些模拟已移除层的测试,让它们改为调用纯函数或直接 API。