高级特性 #
原生扩展 #
许多 Gem 包含 C 扩展以提高性能。了解如何构建和分发原生扩展。
基本原生扩展 #
目录结构 #
text
mygem/
├── ext/
│ └── mygem/
│ ├── extconf.rb
│ ├── mygem.c
│ └── mygem.h
├── lib/
│ └── mygem.rb
└── mygem.gemspec
extconf.rb #
ruby
# ext/mygem/extconf.rb
require 'mkmf'
# 检查依赖库
have_header('stdio.h')
have_library('c')
# 创建 Makefile
create_makefile('mygem/mygem')
C 扩展代码 #
c
// ext/mygem/mygem.c
#include <ruby.h>
#include "mygem.h"
VALUE MygemModule = Qnil;
void Init_mygem(void) {
MygemModule = rb_define_module("Mygem");
rb_define_method(MygemModule, "hello", method_hello, 0);
}
VALUE method_hello(VALUE self) {
return rb_str_new_cstr("Hello from C!");
}
Ruby 接口 #
ruby
# lib/mygem.rb
require 'mygem/mygem'
module Mygem
class Error < StandardError; end
def self.greet
hello
end
end
gemspec 配置 #
ruby
# mygem.gemspec
Gem::Specification.new do |spec|
spec.name = "mygem"
spec.version = "0.1.0"
spec.extensions = ["ext/mygem/extconf.rb"]
spec.files = Dir["{ext,lib}/**/*"]
spec.require_paths = ["lib"]
# 开发依赖
spec.add_development_dependency "rake-compiler"
end
Rakefile 配置 #
ruby
# Rakefile
require "bundler/gem_tasks"
require "rake/extensiontask"
Rake::ExtensionTask.new("mygem") do |ext|
ext.lib_dir = "lib/mygem"
end
task default: :compile
跨平台编译 #
ruby
# Rakefile
require "rake/extensiontask"
Rake::ExtensionTask.new("mygem") do |ext|
ext.lib_dir = "lib/mygem"
ext.cross_compile = true
ext.cross_platform = %w[x86-mingw32 x64-mingw32]
end
预编译二进制 #
ruby
# 使用 rake-compiler-dock
# Rakefile
require "rake/extensiontask"
require "rake/compiler_dock"
Rake::ExtensionTask.new("mygem") do |ext|
ext.cross_compile = true
ext.cross_platform = %w[x86-mingw32 x64-mingw32]
end
namespace :gem do
desc "Build cross-compiled gems"
task :cross do
Rake::CompilerDock.sh "bundle exec rake gem:native"
end
end
平台支持 #
平台标识 #
| 平台 | 标识 |
|---|---|
| Linux x86_64 | x86_64-linux |
| Linux ARM | arm-linux |
| macOS x86_64 | x86_64-darwin |
| macOS ARM | arm64-darwin |
| Windows 32-bit | x86-mingw32 |
| Windows 64-bit | x64-mingw32 |
| Java | java |
平台特定代码 #
ruby
# lib/mygem.rb
module Mygem
if RUBY_PLATFORM =~ /darwin/
require 'mygem/platform/darwin'
elsif RUBY_PLATFORM =~ /linux/
require 'mygem/platform/linux'
elsif RUBY_PLATFORM =~ /mingw|mswin/
require 'mygem/platform/windows'
else
raise "Unsupported platform: #{RUBY_PLATFORM}"
end
end
Gemfile 平台配置 #
ruby
# Gemfile
platforms :ruby do
gem 'pg'
end
platforms :jruby do
gem 'activerecord-jdbcpostgresql-adapter'
end
platforms :mingw, :x64_mingw do
gem 'tzinfo-data'
end
Gem 签名 #
生成证书 #
bash
# 生成私钥
gem cert --build your@email.com
# 输出
# Private key: /Users/you/.gem/gem-private_key.pem
# Certificate: /Users/you/.gem/gem-public_cert.pem
签名 Gem #
ruby
# mygem.gemspec
Gem::Specification.new do |spec|
spec.name = "mygem"
spec.version = "0.1.0"
# 签名配置
spec.signing_key = File.expand_path("~/.gem/gem-private_key.pem")
spec.cert_chain = [File.expand_path("~/.gem/gem-public_cert.pem")]
end
构建签名 Gem #
bash
# 构建签名 Gem
gem build mygem.gemspec
# 验证签名
gem cert --verify mygem-0.1.0.gem
安装签名 Gem #
bash
# 添加信任证书
gem cert --add ~/.gem/gem-public_cert.pem
# 安装时验证签名
gem install mygem -P HighSecurity
安全级别 #
| 级别 | 描述 |
|---|---|
NoSecurity |
不验证签名 |
LowSecurity |
验证签名但不检查证书链 |
MediumSecurity |
验证签名和证书链 |
HighSecurity |
验证签名、证书链和信任度 |
私有源 #
搭建私有源 #
使用 Gemstash #
bash
# 安装 Gemstash
gem install gemstash
# 启动服务
gemstash start
# 默认地址
# http://localhost:9292
配置 Gemstash #
yaml
# ~/.gemstash/config.yml
:cache_type: memory
:base_path: ~/.gemstash
:db_adapter: sqlite3
:bind: tcp://0.0.0.0:9292
使用私有源 #
ruby
# Gemfile
source 'https://rubygems.org'
source 'http://localhost:9292/private' do
gem 'my_private_gem'
end
使用 Gemfury #
bash
# 安装 Gemfury CLI
gem install gemfury
# 推送 Gem
fury push mygem-0.1.0.gem --api-token YOUR_TOKEN
# 配置源
gem sources --add https://TOKEN@gem.fury.io/your-org/
使用 Nexus #
ruby
# Gemfile
source 'https://nexus.example.com/repository/rubygems/'
gem 'my_private_gem'
认证配置 #
bash
# 设置 API Key
gem config set https://gems.example.com api_key YOUR_API_KEY
# 或使用环境变量
export GEM_HOST_API_KEY=YOUR_API_KEY
插件系统 #
创建 Gem 插件 #
ruby
# lib/rubygems_plugin.rb
module Gem
class Commands::MyCommand < Gem::Command
def initialize
super 'mycommand', 'My custom gem command'
end
def execute
puts "Executing my custom command!"
end
end
end
Gem::CommandManager.instance.register_command :mycommand
插件安装钩子 #
ruby
# lib/rubygems_plugin.rb
Gem.post_install do |installer|
puts "Gem #{installer.spec.name} has been installed!"
end
Gem.pre_uninstall do |uninstaller|
puts "Gem #{uninstaller.spec.name} will be uninstalled!"
end
插件命令 #
ruby
# lib/rubygems_plugin.rb
module Gem
class Commands::AuditCommand < Gem::Command
def initialize
super 'audit', 'Audit installed gems for vulnerabilities'
add_option('--all', 'Audit all gems') do |value, options|
options[:all] = true
end
end
def execute
if options[:all]
audit_all_gems
else
audit_gem(get_one_gem_name)
end
end
private
def audit_all_gems
Gem::Specification.each do |spec|
puts "Auditing #{spec.name}..."
end
end
def audit_gem(name)
spec = Gem::Specification.find_by_name(name)
puts "Auditing #{spec.name} version #{spec.version}..."
end
end
end
Gem::CommandManager.instance.register_command :audit
Rake 任务 #
内置 Rake 任务 #
ruby
# Rakefile
require "bundler/gem_tasks"
require "rspec/core/rake_task"
RSpec::Core::RakeTask.new(:spec)
task default: :spec
# Bundler 提供的任务
# rake build - 构建 gem
# rake install - 安装 gem
# rake release - 发布 gem
自定义 Rake 任务 #
ruby
# Rakefile
namespace :gem do
desc "Build and push gem"
task :publish => [:build, :push]
task :build do
sh "gem build mygem.gemspec"
end
task :push do
sh "gem push mygem-*.gem"
end
desc "Clean build artifacts"
task :clean do
sh "rm -f *.gem"
end
end
namespace :docs do
desc "Generate YARD documentation"
task :generate do
sh "yard doc lib/**/*.rb"
end
desc "Start YARD server"
task :server do
sh "yard server"
end
end
Gem 规范高级字段 #
完整 gemspec 示例 #
ruby
# mygem.gemspec
# frozen_string_literal: true
Gem::Specification.new do |spec|
# 基本信息
spec.name = "mygem"
spec.version = "0.1.0"
spec.authors = ["Your Name"]
spec.email = ["your@email.com"]
spec.summary = "A short summary"
spec.description = "A longer description"
spec.homepage = "https://example.com"
spec.license = "MIT"
# Ruby 版本要求
spec.required_ruby_version = ">= 2.7.0"
spec.required_rubygems_version = ">= 3.0.0"
# 文件配置
spec.files = Dir["{lib,exe}/**/*", "LICENSE", "README.md"]
spec.bindir = "exe"
spec.executables = ["mygem"]
spec.require_paths = ["lib"]
# 原生扩展
spec.extensions = ["ext/mygem/extconf.rb"]
# 签名
spec.signing_key = File.expand_path("~/.gem/gem-private_key.pem")
spec.cert_chain = [File.expand_path("~/.gem/gem-public_cert.pem")]
# 元数据
spec.metadata = {
"homepage_uri" => "https://example.com",
"source_code_uri" => "https://github.com/user/mygem",
"changelog_uri" => "https://github.com/user/mygem/blob/main/CHANGELOG.md",
"bug_tracker_uri" => "https://github.com/user/mygem/issues",
"documentation_uri" => "https://docs.example.com",
"mailing_list_uri" => "https://groups.google.com/group/mygem",
"wiki_uri" => "https://wiki.example.com",
"funding_uri" => "https://patreon.com/user",
"rubygems_mfa_required" => "true"
}
# 运行时依赖
spec.add_dependency "nokogiri", "~> 1.14"
spec.add_dependency "json", ">= 2.6"
# 开发依赖
spec.add_development_dependency "rspec", "~> 3.12"
spec.add_development_dependency "rubocop", "~> 1.50"
spec.add_development_dependency "yard", "~> 0.9"
# 可选依赖
spec.add_optional_dependency "redis", "~> 5.0"
end
性能优化 #
延迟加载 #
ruby
# lib/mygem.rb
module Mygem
autoload :Client, 'mygem/client'
autoload :Request, 'mygem/request'
autoload :Response, 'mygem/response'
end
条件依赖 #
ruby
# lib/mygem.rb
module Mygem
def self.redis_available?
defined?(Redis)
end
def self.redis
@redis ||= Redis.new if redis_available?
end
end
缓存机制 #
ruby
# lib/mygem/cache.rb
module Mygem
class Cache
def initialize
@cache = {}
end
def fetch(key, &block)
@cache[key] ||= yield
end
def clear
@cache.clear
end
end
end
调试技巧 #
本地开发调试 #
ruby
# 使用 binding.irb
def debug_method
result = some_calculation
binding.irb # 打开交互式调试
result
end
日志记录 #
ruby
# lib/mygem/logger.rb
require 'logger'
module Mygem
class << self
attr_accessor :logger
def logger
@logger ||= Logger.new($stdout).tap do |log|
log.level = Logger::INFO
end
end
end
end
# 使用
Mygem.logger.debug "Debug message"
Mygem.logger.info "Info message"
错误处理 #
ruby
# lib/mygem/errors.rb
module Mygem
class Error < StandardError; end
class ConfigurationError < Error; end
class ConnectionError < Error; end
class TimeoutError < Error; end
class AuthenticationError < Error; end
class RateLimitError < Error; end
class << self
def with_error_handling
yield
rescue Timeout::Error => e
raise TimeoutError, "Request timed out: #{e.message}"
rescue SocketError => e
raise ConnectionError, "Connection failed: #{e.message}"
rescue => e
raise Error, "Unexpected error: #{e.message}"
end
end
end
多版本共存 #
版本选择 #
ruby
# lib/mygem.rb
module Mygem
module Version1
# 旧版本 API
end
module Version2
# 新版本 API
end
def self.use_version(version)
case version
when 1
include Version1
when 2
include Version2
else
raise "Unknown version: #{version}"
end
end
end
弃用警告 #
ruby
# lib/mygem/deprecated.rb
module Mygem
module Deprecated
def self.included(base)
warn "[DEPRECATION] #{base} is deprecated. Use #{base}V2 instead."
end
end
end
下一步 #
现在你已经掌握了 RubyGems 的高级特性,接下来学习 最佳实践 了解更多开发技巧!
最后更新:2026-03-28