mcpField
G
gem-builder

gem-builder

github.com/majesticlabs-dev开发5052 次安装7 周前更新
代码仓库

关于 gem-builder

gem-builder 是供 Ruby 开发者创建和维护 Ruby gem 的参考技能,涵盖项目结构、配置、测试、文档、发布及 Rails 集成模式。

主要功能

  1. 01标准 gem 目录与入口模式
  2. 02gemspec 和依赖指导
  3. 03配置与错误处理模式
  4. 04Minitest 和 WebMock 测试设置
  5. 05YARD、README 与变更日志指导
  6. 06构建、发布及 Rails 集成实践

适用场景

  1. 01搭建 Ruby gem 项目结构
  2. 02设计 API 客户端 gem
  3. 03为公开 API 添加测试和文档
  4. 04准备 gem 发布

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/majesticlabs-dev/majestic-marketplace --skill gem-builder

安装后在 Claude Code 中输入/gem-builder确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
advanced-patterns.md
engine-migrations.md
templates.md

详细介绍

Gem Builder

核心理念

  • 依赖最少化:只添加真正需要的 gem
  • 单一职责:每个类/模块都只做好一件事
  • 语义化版本:严格遵循 SemVer(MAJOR.MINOR.PATCH)
  • 测试覆盖:为每个公共方法编写测试
  • 文档:提供 YARD 文档、README 和 CHANGELOG
  • 尽早失败:及早验证输入,并抛出描述清晰的错误

Gem 结构

my_gem/
├── lib/
│   ├── my_gem.rb              # Main entry point
│   ├── my_gem/
│   │   ├── version.rb         # VERSION constant
│   │   ├── config.rb          # Configuration class
│   │   ├── errors.rb          # Error hierarchy
│   │   └── [feature].rb       # Feature modules
├── test/                      # Test suite
├── my_gem.gemspec             # Gem specification
├── Gemfile                    # Development dependencies
├── Rakefile                   # Build tasks
├── README.md                  # User documentation
├── CHANGELOG.md               # Version history
└── LICENSE.txt                # License file
主入口点
# lib/my_gem.rb
require_relative "my_gem/version"
require_relative "my_gem/config"
require_relative "my_gem/errors"

module MyGem
  class << self
    def config
      @config ||= Config.new
    end

    def configure
      yield(config)
    end

    def reset_configuration!
      @config = nil
    end
  end
end

Gemspec 最佳实践

# my_gem.gemspec
require_relative "lib/my_gem/version"

Gem::Specification.new do |spec|
  spec.name          = "my_gem"
  spec.version       = MyGem::VERSION
  spec.authors       = ["Your Name"]
  spec.email         = ["[email protected]"]
  spec.summary       = "One-line description"
  spec.homepage      = "https://github.com/username/my_gem"
  spec.license       = "MIT"
  spec.required_ruby_version = ">= 3.2.0"

  spec.metadata["rubygems_mfa_required"] = "true"
  spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"

  # Exclude test/CI files
  spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls|
    ls.readlines("\x0", chomp: true).reject { |f| f.start_with?(*%w[bin/ test/ .github/]) }
  end
  spec.require_paths = ["lib"]
end

Gem 类型

类型主要特性
库纯 Ruby,不依赖外部服务
API 客户端采用资源模式的 HTTP 封装
CLI 工具spec.executables,设置 bindir
Rails 集成使用 ActiveSupport.on_load 的 Railtie
API 客户端模式
class Client
  def initialize(api_key: nil)
    @api_key = api_key || MyGem.config.api_key
    raise ArgumentError, "API key required" if @api_key.to_s.empty?
  end

  def users = @users ||= Resources::Users.new(self)
  def posts = @posts ||= Resources::Posts.new(self)
end
Rails 集成

切勿直接 require Rails。 使用延迟加载:

# lib/my_gem/railtie.rb
class Railtie < Rails::Railtie
  initializer "my_gem.configure" do
    ActiveSupport.on_load(:active_record) do
      extend MyGem::Model
    end
  end
end

# lib/my_gem.rb
require_relative "my_gem/railtie" if defined?(Rails)
类宏 DSL

searchkick、lockbox 使用的模式:

# Usage: mygemname word_start: [:name]
module Model
  def mygemname(**options)
    unknown = options.keys - KNOWN_OPTIONS
    raise ArgumentError, "Unknown: #{unknown.join(", ")}" if unknown.any?

    mod = Module.new
    mod.module_eval { define_method(:some_method) { options[:key] } }
    include mod
    class_variable_set(:@@mygemname_options, options.dup)
  end
end

配置模式

# lib/my_gem/config.rb
class Config
  attr_accessor :api_key, :base_url, :timeout
  attr_writer :logger

  def initialize
    @api_key = ENV.fetch("MY_GEM_API_KEY", nil)
    @base_url = ENV.fetch("MY_GEM_BASE_URL", "https://api.example.com")
    @timeout = Integer(ENV.fetch("MY_GEM_TIMEOUT", 30)) rescue 30
  end

  def logger
    @logger ||= defined?(Rails) ? Rails.logger : Logger.new($stderr)
  end
end

用法:

MyGem.configure do |config|
  config.api_key = "secret"
end

错误处理

# lib/my_gem/errors.rb
module MyGem
  class Error < StandardError
    attr_reader :status, :body

    def initialize(message = nil, status: nil, body: nil)
      super(message)
      @status, @body = status, body
    end
  end

  class ConfigurationError < Error; end
  class AuthenticationError < Error; end  # 401
  class ClientError < Error; end          # 4xx
  class ServerError < Error; end          # 5xx
  class NetworkError < Error; end         # Connection failures
end

测试设置

# test/test_helper.rb
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
require "my_gem"
require "minitest/autorun"
require "webmock/minitest"

module TestConfig
  def setup_config
    WebMock.reset!
    MyGem.reset_configuration!
    MyGem.configure { |c| c.api_key = "test-key" }
  end

  def teardown_config
    WebMock.reset!
    MyGem.reset_configuration!
  end
end
class ClientTest < Minitest::Test
  include TestConfig
  def setup = setup_config
  def teardown = teardown_config

  def test_requires_api_key
    MyGem.config.api_key = nil
    assert_raises(ArgumentError) { MyGem::Client.new }
  end
end

文档

YARD 设置(.yardopts)
--markup markdown
--no-private
lib/**/*.rb
- README.md
README 章节

安装、快速入门、配置、功能、开发、许可证。

CHANGELOG(遵循 Keep a Changelog)
## [1.0.0] - 2025-01-15
### Added
- Initial release

构建与发布

Rakefile
require "bundler/gem_tasks"
require "minitest/test_task"
Minitest::TestTask.create

require "rubocop/rake_task"
RuboCop::RakeTask.new

task default: %i[test rubocop]
发布工作流
# 1. Update lib/my_gem/version.rb
# 2. Update CHANGELOG.md
# 3. Commit and release
git commit -am "Release v1.0.0"
bundle exec rake release

反模式

避免使用替代方案
method_missingdefine_method
@@class_variables使用实例变量的 class << self
直接 require RailsActiveSupport.on_load
过多的运行时依赖优先使用标准库
提交 Gemfile.lock仅在应用中锁定依赖
过于复杂的 DSL使用显式 Ruby 代码
autoloadrequire_relative

最佳实践检查清单

结构:

  • 标准目录布局
  • 版本号只在一处定义
  • 冻结字符串字面量

Gemspec:

  • 填写所有元数据
  • rubygems_mfa_required = true
  • 尽量减少运行时依赖

配置:

  • 环境变量回退值
  • 基于代码块的 DSL
  • 便于测试的重置方法

错误处理:

  • 自定义错误层级
  • 描述清晰的消息
  • 保留状态码/响应正文

测试:

  • 测试之间相互隔离
  • 使用 WebMock 测试 HTTP
  • 覆盖成功和失败场景

文档:

  • 为公共方法编写 YARD 文档
  • README 包含快速入门
  • 提供 CHANGELOG

Rails(如适用):

  • 通过 if defined?(Rails) 实现可选集成
  • 使用隔离的命名空间
  • 使用 ActiveSupport.on_load 钩子

参考资料

  • references/templates.md - 可直接复制粘贴的模板(CI、gemspec、README)
  • references/advanced-patterns.md - 数据库适配器、多版本测试
  • references/engine-migrations.md - 在 Rails 引擎中保留迁移文件

评论

支持 Markdown