关于 andrew-kane-gem-writer
Andrew Kane Gem Writer 是一项指导 Ruby gem 结构与实现模式的技能。它强调显式 Ruby、尽量减少运行时依赖、通过钩子条件式集成 Rails,以及使用 Minitest。
主要功能
- 01组织 gem 入口与模块
- 02采用类宏 DSL 模式
- 03通过 ActiveSupport 钩子集成 Rails
- 04定义简洁的配置与错误体系
- 05规范 Minitest 和 gemspec
适用场景
- 01搭建 Ruby gem 结构
- 02添加可选的 Rails 集成
- 03检查 gem 依赖与测试
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ everyinc/ compound-engineering-plugin --skill andrew-kane-gem-writer安装后在 Claude Code 中输入/andrew-kane-gem-writer确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/database-adapters.mdmodule-organization.mdrails-integration.mdresources.mdtesting-patterns.md详细介绍
Andrew Kane Gem 编写指南
遵循 Andrew Kane 久经实战检验的模式编写 Ruby gem。他的 100 多个 gem(包括 Searchkick、PgHero、Chartkick、Strong Migrations、Lockbox、Ahoy、Blazer、Groupdate、Neighbor、Blind Index)累计下载量超过 3.74 亿次。
核心理念
简单胜于巧妙。 零依赖或尽量少用依赖。使用显式代码,而非元编程。集成 Rails,但不与 Rails 耦合。每种模式都服务于生产环境的实际需求。
入口文件结构
每个 gem 的 lib/gemname.rb 都遵循以下精确模式:
# 1. Dependencies (stdlib preferred)
require "forwardable"
# 2. Internal modules
require_relative "gemname/model"
require_relative "gemname/version"
# 3. Conditional Rails (CRITICAL - never require Rails directly)
require_relative "gemname/railtie" if defined?(Rails)
# 4. Module with config and errors
module GemName
class Error < StandardError; end
class InvalidConfigError < Error; end
class << self
attr_accessor :timeout, :logger
attr_writer :client
end
self.timeout = 10 # Defaults set immediately
end
类宏 DSL 模式
Kane 的标志性模式——一次方法调用即可完成所有配置:
# Usage
class Product < ApplicationRecord
searchkick word_start: [:name]
end
# Implementation
module GemName
module Model
def gemname(**options)
unknown = options.keys - KNOWN_KEYWORDS
raise ArgumentError, "unknown keywords: #{unknown.join(", ")}" if unknown.any?
mod = Module.new
mod.module_eval do
define_method :some_method do
# implementation
end unless method_defined?(:some_method)
end
include mod
class_eval do
cattr_reader :gemname_options, instance_reader: false
class_variable_set :@@gemname_options, options.dup
end
end
end
end
Rails 集成
始终使用 ActiveSupport.on_load,绝不直接 require Rails gem:
# WRONG
require "active_record"
ActiveRecord::Base.include(MyGem::Model)
# CORRECT
ActiveSupport.on_load(:active_record) do
extend GemName::Model
end
# Use prepend for behavior modification
ActiveSupport.on_load(:active_record) do
ActiveRecord::Migration.prepend(GemName::Migration)
end
配置模式
使用 class << self 和 attr_accessor,而非 Configuration 对象:
module GemName
class << self
attr_accessor :timeout, :logger
attr_writer :master_key
end
def self.master_key
@master_key ||= ENV["GEMNAME_MASTER_KEY"]
end
self.timeout = 10
self.logger = nil
end
错误处理
使用简单的层级结构,并提供信息丰富的消息:
module GemName
class Error < StandardError; end
class ConfigError < Error; end
class ValidationError < Error; end
end
# Validate early with ArgumentError
def initialize(key:)
raise ArgumentError, "Key must be 32 bytes" unless key&.bytesize == 32
end
测试(仅限 Minitest)
# test/test_helper.rb
require "bundler/setup"
Bundler.require(:default)
require "minitest/autorun"
require "minitest/pride"
# test/model_test.rb
class ModelTest < Minitest::Test
def test_basic_functionality
assert_equal expected, actual
end
end
Gemspec 模式
尽可能不添加运行时依赖:
Gem::Specification.new do |spec|
spec.name = "gemname"
spec.version = GemName::VERSION
spec.required_ruby_version = ">= 3.1"
spec.files = Dir["*.{md,txt}", "{lib}/**/*"]
spec.require_path = "lib"
# NO add_dependency lines - dev deps go in Gemfile
end
应避免的反模式
method_missing(改用define_method)- Configuration 对象(改用类访问器)
@@class_variables(改用class << self)- 直接 require Rails gem
- 过多的运行时依赖
- 在 gem 中提交 Gemfile.lock
- RSpec(改用 Minitest)
- 繁重的 DSL(优先使用显式 Ruby 代码)
参考文件
如需了解更深入的模式,请参阅:
references/module-organization.md- 目录布局、方法拆分references/rails-integration.md- Railtie、Engine、on_load 模式references/database-adapters.md- 多数据库支持模式references/testing-patterns.md- 多版本测试、CI 设置references/resources.md- Kane 的代码库和文章链接
评论
支持 Markdown