关于 ruby
这项技能提供 Ruby 3.x 及更高版本的惯用写法与约定,面向开发者和编码 Agent,涵盖错误处理、现代语言特性、性能及代码组织。
主要功能
- 01异常与结果对象模式
- 02Ruby 3.x 语言特性
- 03注重性能的枚举处理
- 04安全的记忆化与字符串构建
- 05方法排序与文件布局
适用场景
- 01为预期失败选择处理约定
- 02使用现代 Ruby 语法和模式
- 03提升枚举与字符串构建效率
- 04组织 Ruby 类中的方法
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ midudev/ autoskills --skill ruby安装后在 Claude Code 中输入/ruby确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/error_handling.mdmethod_ordering.mdmodern_ruby.mdood-philosophy.mdperformance.md详细介绍
Ruby 语言技能
概述
一套注重实践的 Ruby 约定与惯用写法,用于编写符合 Ruby 3.x+ 惯例的代码。重点关注 Agent 默认容易忽略的模式——Weirich 的 raise/fail 区分、可安全处理 nil 的记忆化、预期失败时使用结果对象而非异常,以及注重性能的枚举方式。
错误处理约定
Weirich raise/fail 约定
首次抛出异常时使用 fail,仅在重新抛出时使用 raise:
def process(order)
fail ArgumentError, "Order cannot be nil" if order.nil?
begin
gateway.charge(order)
rescue PaymentError => e
logger.error("Payment failed: #{e.message}")
raise # re-raise with raise
end
end
自定义异常层次结构
将领域异常归入一个基类错误:
module MyApp
class Error < StandardError; end
class PaymentError < Error; end
class InsufficientFundsError < PaymentError; end
end
# Rescue at any granularity:
rescue MyApp::InsufficientFundsError # specific
rescue MyApp::PaymentError # category
rescue MyApp::Error # all app errors
使用结果对象处理预期失败
对于预期的失败路径,使用结果对象而非异常:
class Result
attr_reader :value, :error
def self.success(value) = new(value: value)
def self.failure(error) = new(error: error)
def initialize(value: nil, error: nil) = (@value, @error = value, error)
def success? = error.nil?
def failure? = !success?
end
由调用方提供备用处理方式
通过代码块让调用方定义错误处理方式:
def fetch_user(id, &fallback)
User.find(id)
rescue ActiveRecord::RecordNotFound => e
fallback ? fallback.call(e) : raise
end
user = fetch_user(999) { |_| User.new(name: "Guest") }
完整模式与重试策略请参阅 references/error_handling.md。
现代 Ruby(3.x+)
模式匹配
case response
in { status: 200, body: { users: [{ name: }, *] } }
"First user: #{name}"
in { status: (400..), error: message }
"Error: #{message}"
end
# Find pattern
case array
in [*, String => str, *]
"Found string: #{str}"
end
# Pin operator
expected = 200
case response
in { status: ^expected, body: }
process(body)
end
其他 3.x+ 特性
# Endless methods (3.0+)
def square(x) = x * x
def admin? = role == "admin"
# Numbered block parameters (2.7+)
[1, 2, 3].map { _1 * 2 }
# Data class - immutable value objects (3.2+)
Point = Data.define(:x, :y)
p = Point.new(x: 1, y: 2)
p.with(x: 3) # => Point(x: 3, y: 2)
# Hash#except (3.0+)
params.except(:password, :admin)
# filter_map (2.7+) - select + map in one pass
users.filter_map { |u| u.email if u.active? }
# tally (2.7+)
%w[a b a c b a].tally # => {"a"=>3, "b"=>2, "c"=>1}
Ractor、Fiber 调度器、RBS 类型和高级模式匹配请参阅 references/modern_ruby.md。
性能快速优化
冻结字符串字面量
# frozen_string_literal: true
# Add to top of every file. Prevents mutation, reduces allocations.
# When you need mutable: String.new("hello") or +"hello"
高效枚举
# each_with_object for building results (avoids intermediate arrays)
totals = items.each_with_object(Hash.new(0)) do |item, hash|
hash[item.category] += item.amount
end
# Lazy enumerables for large/infinite sequences
(1..Float::INFINITY).lazy.select(&:odd?).map { _1 ** 2 }.first(10)
记忆化的 nil/false 注意事项
# Simple (only works if result is truthy)
def users = @users ||= User.all.to_a
# Safe (handles nil/false results)
def feature_enabled?
return @feature_enabled if defined?(@feature_enabled)
@feature_enabled = expensive_check
end
字符串构建
# Bad: O(n^2) with +=
result = ""; items.each { |i| result += i.to_s }
# Good: O(n) with <<
result = String.new; items.each { |i| result << i.to_s }
# Best: join
items.map(&:to_s).join
YJIT、GC 调优、基准测试和性能分析工具请参阅 references/performance.md。
优先采用的 Ruby 惯用写法
守卫子句
def process(value)
return unless value
return unless value.valid?
# main logic here
end
字面量数组构造器
STATES = %w[draft published archived] # word array
FIELDS = %i[name email created_at] # symbol array
使用 Hash#fetch 获取必需键
config.fetch(:api_key) # raises KeyError if missing
config.fetch(:timeout, 30) # default value
config.fetch(:handler) { build_handler } # lazy default
安全导航
user&.profile&.avatar_url # returns nil if any link is nil
谓词与 Bang 约定
?后缀:返回布尔值(empty?、valid?、admin?)!后缀:危险版本——会修改接收者,或在失败时抛出异常(save!、sort!)- 定义 Bang 方法时,始终提供一个非 Bang 版本作为替代
方法排序与文件布局
按从上到下的顺序组织类,让读者每次只需深入一个抽象层级——即“逐步深入”/报纸式布局。元素顺序如下:
extend/include/prepend- 常量
attr_*读写方法与类宏(has_many、validates、scope)def initialize- 公有方法——从最高层级的入口开始
protectedprivate辅助方法——按抽象层级分组
在公有区块和私有区块内,均按抽象层级由广到窄排序,而不是按调用方进行深度优先排序。 将同一抽象层级的方法与其同级方法放在一起,然后排列它们调用的辅助方法,再排列这些辅助方法所调用的方法。将辅助方法紧接着唯一的调用方定义,会打散高层步骤,并将它们埋在细节之下。
# Good — breadth-first by altitude: stages cluster, then their helpers
def process; validate; charge; notify; end # altitude 1 (public entry)
private
def validate; end # altitude 2: stages together
def charge; end
def notify; end
def verify_customer; end # altitude 3: helpers together
def submit_payment; end
def write_audit_log; end
# Bad — depth-first by caller: altitudes 2 and 3 interleave, stages scatter
def validate; end
def verify_customer; end
def charge; end
def submit_payment; end
def notify; end
def write_audit_log; end
示例、逐步深入/SLAP 背景说明以及共享辅助方法的放置方式请参阅 references/method_ordering.md。
常见错误
| 错误 | 修正 |
|---|---|
对新异常使用 raise | 使用 fail;仅在重新抛出时使用 raise(Weirich 约定) |
结果可能为 nil/false 时使用 @var ||= compute | 改用 defined?(@var) 检查 |
在循环中使用 += 拼接字符串 | 使用 << 或 .join——+= 的复杂度为 O(n²) |
rescue Exception | 捕获 StandardError——Exception 也会捕获 SignalException、NoMemoryError |
过深的 &. 链(3 个或更多链接) | 提取为方法,或使用显式 nil 检查 |
缺少 # frozen_string_literal: true | 添加到每个文件的顶部 |
| 将辅助方法紧接着唯一的调用方定义(深度优先) | 按抽象层级对方法分组;采用由广到窄的布局(逐步深入规则) |
参考资料
references/modern_ruby.md- 模式匹配、Ractor、Fiber 调度器、RBS 类型references/error_handling.md- 异常层次结构、结果对象、重试模式references/performance.md- YJIT、GC 调优、基准测试、性能分析references/ood-philosophy.md- OOD 原则、命名、SOLID、TRUE 启发式、迪米特法则references/method_ordering.md- 文件布局顺序、逐步深入规则、由广到窄与深度优先的方法排序