ruby-metaprogramming
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRuby Metaprogramming
Ruby元编程
Master Ruby's powerful metaprogramming capabilities to write code that writes code. Ruby's dynamic nature makes it exceptionally good at metaprogramming.
掌握Ruby强大的元编程能力,编写能生成代码的代码。Ruby的动态特性使其在元编程方面表现格外出色。
Dynamic Method Definition
动态方法定义
define_method
define_method
ruby
class Person
[:name, :age, :email].each do |attribute|
define_method(attribute) do
instance_variable_get("@#{attribute}")
end
define_method("#{attribute}=") do |value|
instance_variable_set("@#{attribute}", value)
end
end
end
person = Person.new
person.name = "Alice"
puts person.name # "Alice"ruby
class Person
[:name, :age, :email].each do |attribute|
define_method(attribute) do
instance_variable_get("@#{attribute}")
end
define_method("#{attribute}=") do |value|
instance_variable_set("@#{attribute}", value)
end
end
end
person = Person.new
person.name = "Alice"
puts person.name # "Alice"class_eval and instance_eval
class_eval 和 instance_eval
ruby
undefinedruby
undefinedclass_eval - Evaluates code in context of a class
class_eval - 在类的上下文中执行代码
class MyClass
end
MyClass.class_eval do
def hello
"Hello from class_eval"
end
end
puts MyClass.new.hello
class MyClass
end
MyClass.class_eval do
def hello
"Hello from class_eval"
end
end
puts MyClass.new.hello
instance_eval - Evaluates code in context of an instance
instance_eval - 在实例的上下文中执行代码
obj = Object.new
obj.instance_eval do
def greet
"Hello from instance_eval"
end
end
puts obj.greet
undefinedobj = Object.new
obj.instance_eval do
def greet
"Hello from instance_eval"
end
end
puts obj.greet
undefinedmodule_eval
module_eval
ruby
module MyModule
end
MyModule.module_eval do
def self.info
"Module metaprogramming"
end
end
puts MyModule.inforuby
module MyModule
end
MyModule.module_eval do
def self.info
"Module metaprogramming"
end
end
puts MyModule.infoMethod Missing
Method Missing
Basic method_missing
基础method_missing
ruby
class DynamicFinder
def initialize(data)
@data = data
end
def method_missing(method_name, *args)
if method_name.to_s.start_with?("find_by_")
attribute = method_name.to_s.sub("find_by_", "")
@data.find { |item| item[attribute.to_sym] == args.first }
else
super
end
end
def respond_to_missing?(method_name, include_private = false)
method_name.to_s.start_with?("find_by_") || super
end
end
users = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 }
]
finder = DynamicFinder.new(users)
puts finder.find_by_name("Alice") # {:name=>"Alice", :age=>30}ruby
class DynamicFinder
def initialize(data)
@data = data
end
def method_missing(method_name, *args)
if method_name.to_s.start_with?("find_by_")
attribute = method_name.to_s.sub("find_by_", "")
@data.find { |item| item[attribute.to_sym] == args.first }
else
super
end
end
def respond_to_missing?(method_name, include_private = false)
method_name.to_s.start_with?("find_by_") || super
end
end
users = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 }
]
finder = DynamicFinder.new(users)
puts finder.find_by_name("Alice") # {:name=>"Alice", :age=>30}Const Missing
Const Missing
ruby
class DynamicConstants
def self.const_missing(const_name)
puts "Constant #{const_name} not found, creating it..."
const_set(const_name, "Dynamic value for #{const_name}")
end
end
puts DynamicConstants::SOMETHING # "Dynamic value for SOMETHING"ruby
class DynamicConstants
def self.const_missing(const_name)
puts "Constant #{const_name} not found, creating it..."
const_set(const_name, "Dynamic value for #{const_name}")
end
end
puts DynamicConstants::SOMETHING # "Dynamic value for SOMETHING"send and public_send
send 和 public_send
ruby
class Calculator
def add(x, y)
x + y
end
private
def secret_method
"This is private"
end
end
calc = Calculator.newruby
class Calculator
def add(x, y)
x + y
end
private
def secret_method
"This is private"
end
end
calc = Calculator.newsend can call any method (including private)
send 可以调用任意方法(包括私有方法)
puts calc.send(:add, 3, 4) # 7
puts calc.send(:secret_method) # "This is private"
puts calc.send(:add, 3, 4) # 7
puts calc.send(:secret_method) # "This is private"
public_send only calls public methods
public_send 仅调用公共方法
puts calc.public_send(:add, 3, 4) # 7
puts calc.public_send(:add, 3, 4) # 7
calc.public_send(:secret_method) # NoMethodError
calc.public_send(:secret_method) # NoMethodError
undefinedundefinedClass Macros
类宏
ruby
class ActiveModel
def self.attr_with_history(attribute)
define_method(attribute) do
instance_variable_get("@#{attribute}")
end
define_method("#{attribute}=") do |value|
history = instance_variable_get("@#{attribute}_history") || []
history << value
instance_variable_set("@#{attribute}_history", history)
instance_variable_set("@#{attribute}", value)
end
define_method("#{attribute}_history") do
instance_variable_get("@#{attribute}_history") || []
end
end
end
class Person < ActiveModel
attr_with_history :name
end
person = Person.new
person.name = "Alice"
person.name = "Alicia"
puts person.name_history.inspect # ["Alice", "Alicia"]ruby
class ActiveModel
def self.attr_with_history(attribute)
define_method(attribute) do
instance_variable_get("@#{attribute}")
end
define_method("#{attribute}=") do |value|
history = instance_variable_get("@#{attribute}_history") || []
history << value
instance_variable_set("@#{attribute}_history", history)
instance_variable_set("@#{attribute}", value)
end
define_method("#{attribute}_history") do
instance_variable_get("@#{attribute}_history") || []
end
end
end
class Person < ActiveModel
attr_with_history :name
end
person = Person.new
person.name = "Alice"
person.name = "Alicia"
puts person.name_history.inspect # ["Alice", "Alicia"]Singleton Methods
单例方法
ruby
obj = "hello"ruby
obj = "hello"Define method on single instance
为单个实例定义方法
def obj.shout
self.upcase + "!!!"
end
puts obj.shout # "HELLO!!!"
def obj.shout
self.upcase + "!!!"
end
puts obj.shout # "HELLO!!!"
Using define_singleton_method
使用 define_singleton_method
obj.define_singleton_method(:whisper) do
self.downcase + "..."
end
puts obj.whisper # "hello..."
undefinedobj.define_singleton_method(:whisper) do
self.downcase + "..."
end
puts obj.whisper # "hello..."
undefinedEigenclass (Singleton Class)
Eigenclass(单例类)
ruby
class Person
def self.species
"Homo sapiens"
end
endruby
class Person
def self.species
"Homo sapiens"
end
endAccessing eigenclass
访问 eigenclass
eigenclass = class << Person
self
end
puts eigenclass # #Class:Person
eigenclass = class << Person
self
end
puts eigenclass # #Class:Person
Adding class methods via eigenclass
通过 eigenclass 添加类方法
class Person
class << self
def count
@@count ||= 0
end
def increment_count
@@count ||= 0
@@count += 1
endend
end
Person.increment_count
puts Person.count # 1
undefinedclass Person
class << self
def count
@@count ||= 0
end
def increment_count
@@count ||= 0
@@count += 1
endend
end
Person.increment_count
puts Person.count # 1
undefinedReflection and Introspection
反射与自省
Object Introspection
对象自省
ruby
class MyClass
def public_method; end
protected
def protected_method; end
private
def private_method; end
end
obj = MyClass.newruby
class MyClass
def public_method; end
protected
def protected_method; end
private
def private_method; end
end
obj = MyClass.newList methods
列出方法
puts obj.methods.include?(:public_method)
puts obj.private_methods.include?(:private_method)
puts obj.protected_methods.include?(:protected_method)
puts obj.methods.include?(:public_method)
puts obj.private_methods.include?(:private_method)
puts obj.protected_methods.include?(:protected_method)
Check method existence
检查方法是否存在
puts obj.respond_to?(:public_method) # true
puts obj.respond_to?(:private_method) # false
puts obj.respond_to?(:private_method, true) # true (include private)
puts obj.respond_to?(:public_method) # true
puts obj.respond_to?(:private_method) # false
puts obj.respond_to?(:private_method, true) # true (包含私有方法)
Get method object
获取方法对象
method = obj.method(:public_method)
puts method.class # Method
undefinedmethod = obj.method(:public_method)
puts method.class # Method
undefinedClass Introspection
类自省
ruby
class Parent
def parent_method; end
end
class Child < Parent
def child_method; end
endruby
class Parent
def parent_method; end
end
class Child < Parent
def child_method; end
endInheritance chain
继承链
puts Child.ancestors # [Child, Parent, Object, Kernel, BasicObject]
puts Child.ancestors # [Child, Parent, Object, Kernel, BasicObject]
Instance methods
实例方法
puts Child.instance_methods(false) # Only Child's methods
puts Child.instance_methods(false) # 仅Child的方法
Class variables and instance variables
类变量和实例变量
class Person
@@count = 0
def initialize(name)
@name = name
end
end
puts Person.class_variables # [:@@count]
person = Person.new("Alice")
puts person.instance_variables # [:@name]
undefinedclass Person
@@count = 0
def initialize(name)
@name = name
end
end
puts Person.class_variables # [:@@count]
person = Person.new("Alice")
puts person.instance_variables # [:@name]
undefinedHook Methods
钩子方法
Inheritance Hooks
继承钩子
ruby
class BaseClass
def self.inherited(subclass)
puts "#{subclass} inherited from #{self}"
subclass.instance_variable_set(:@inherited_at, Time.now)
end
end
class ChildClass < BaseClass
endruby
class BaseClass
def self.inherited(subclass)
puts "#{subclass} inherited from #{self}"
subclass.instance_variable_set(:@inherited_at, Time.now)
end
end
class ChildClass < BaseClass
endOutput: ChildClass inherited from BaseClass
输出: ChildClass inherited from BaseClass
undefinedundefinedMethod Hooks
方法钩子
ruby
module Monitored
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def method_added(method_name)
puts "Method #{method_name} was added to #{self}"
end
def method_removed(method_name)
puts "Method #{method_name} was removed from #{self}"
end
end
end
class MyClass
include Monitored
def my_method
end
# Output: Method my_method was added to MyClass
endruby
module Monitored
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def method_added(method_name)
puts "Method #{method_name} was added to #{self}"
end
def method_removed(method_name)
puts "Method #{method_name} was removed from #{self}"
end
end
end
class MyClass
include Monitored
def my_method
end
# 输出: Method my_method was added to MyClass
endincluded and extended
included 和 extended
ruby
module MyModule
def self.included(base)
puts "#{self} included in #{base}"
base.extend(ClassMethods)
end
def self.extended(base)
puts "#{self} extended by #{base}"
end
module ClassMethods
def class_method
"I'm a class method"
end
end
def instance_method
"I'm an instance method"
end
end
class MyClass
include MyModule # Adds instance_method as instance method
end
class AnotherClass
extend MyModule # Adds instance_method as class method
endruby
module MyModule
def self.included(base)
puts "#{self} included in #{base}"
base.extend(ClassMethods)
end
def self.extended(base)
puts "#{self} extended by #{base}"
end
module ClassMethods
def class_method
"I'm a class method"
end
end
def instance_method
"I'm an instance method"
end
end
class MyClass
include MyModule # 将instance_method添加为实例方法
end
class AnotherClass
extend MyModule # 将instance_method添加为类方法
endDSL Creation
DSL创建
ruby
class RouteBuilder
def initialize
@routes = {}
end
def get(path, &block)
@routes[path] = { method: :get, handler: block }
end
def post(path, &block)
@routes[path] = { method: :post, handler: block }
end
def routes
@routes
end
endruby
class RouteBuilder
def initialize
@routes = {}
end
def get(path, &block)
@routes[path] = { method: :get, handler: block }
end
def post(path, &block)
@routes[path] = { method: :post, handler: block }
end
def routes
@routes
end
endDSL usage
DSL使用示例
builder = RouteBuilder.new
builder.instance_eval do
get "/users" do
"List of users"
end
post "/users" do
"Create user"
end
end
puts builder.routes
undefinedbuilder = RouteBuilder.new
builder.instance_eval do
get "/users" do
"List of users"
end
post "/users" do
"Create user"
end
end
puts builder.routes
undefinedDynamic Class Creation
动态类创建
ruby
undefinedruby
undefinedCreate class dynamically
动态创建类
MyClass = Class.new do
define_method :greet do
"Hello from dynamic class"
end
end
puts MyClass.new.greet
MyClass = Class.new do
define_method :greet do
"Hello from dynamic class"
end
end
puts MyClass.new.greet
Create class with inheritance
创建带继承关系的类
Parent = Class.new do
def parent_method
"From parent"
end
end
Child = Class.new(Parent) do
def child_method
"From child"
end
end
child = Child.new
puts child.parent_method
puts child.child_method
undefinedParent = Class.new do
def parent_method
"From parent"
end
end
Child = Class.new(Parent) do
def child_method
"From child"
end
end
child = Child.new
puts child.parent_method
puts child.child_method
undefinedObject Extension
对象扩展
ruby
module Greetable
def greet
"Hello!"
end
end
obj = Object.new
obj.extend(Greetable)
puts obj.greet # "Hello!"ruby
module Greetable
def greet
"Hello!"
end
end
obj = Object.new
obj.extend(Greetable)
puts obj.greet # "Hello!"Only this instance has the method
只有这个实例拥有该方法
another_obj = Object.new
another_obj = Object.new
another_obj.greet # NoMethodError
another_obj.greet # NoMethodError
undefinedundefinedBinding and eval
Binding 和 eval
ruby
def get_binding(param)
local_var = "local value"
binding
end
b = get_binding("test")ruby
def get_binding(param)
local_var = "local value"
binding
end
b = get_binding("test")Evaluate code in the binding context
在binding上下文中执行代码
puts eval("param", b) # "test"
puts eval("local_var", b) # "local value"
puts eval("param", b) # "test"
puts eval("local_var", b) # "local value"
instance_eval with binding
结合binding使用instance_eval
class MyClass
def initialize
@value = 42
end
end
obj = MyClass.new
puts obj.instance_eval { @value } # 42
undefinedclass MyClass
def initialize
@value = 42
end
end
obj = MyClass.new
puts obj.instance_eval { @value } # 42
undefinedTracePoint
TracePoint
ruby
trace = TracePoint.new(:call, :return) do |tp|
puts "#{tp.event}: #{tp.method_id} in #{tp.defined_class}"
end
trace.enable
def my_method
"Hello"
end
my_method
trace.disableruby
trace = TracePoint.new(:call, :return) do |tp|
puts "#{tp.event}: #{tp.method_id} in #{tp.defined_class}"
end
trace.enable
def my_method
"Hello"
end
my_method
trace.disableBest Practices
最佳实践
- Use metaprogramming sparingly - it can make code hard to understand
- Always implement respond_to_missing? when using method_missing
- Prefer define_method over class_eval when possible
- Document metaprogramming heavily - it's not obvious what's happening
- Use public_send over send to respect visibility
- Cache metaprogrammed methods to avoid repeated definition
- Test metaprogrammed code thoroughly - bugs can be subtle
- 谨慎使用元编程 - 它会让代码难以理解
- 使用method_missing时务必实现respond_to_missing?
- 可能的话优先使用define_method而非class_eval
- 为元编程代码添加详细文档 - 其逻辑并不直观
- 优先使用public_send而非send 以遵循可见性规则
- 缓存元编程生成的方法 避免重复定义
- 全面测试元编程代码 - 潜在的bug可能很隐蔽
Anti-Patterns
反模式
❌ Don't overuse method_missing - it's slow and hard to debug
❌ Don't use eval with user input - major security risk
❌ Don't metaprogram when simple code works - clarity over cleverness
❌ Don't forget to call super in method_missing
❌ Don't create methods without documenting them - IDE support breaks
❌ 不要过度使用method_missing - 速度慢且难以调试
❌ 不要将eval与用户输入结合使用 - 存在重大安全风险
❌ 能用简单代码实现时不要用元编程 - 清晰胜于技巧
❌ 在method_missing中不要忘记调用super
❌ 不要在未文档化的情况下创建方法 - 会破坏IDE支持
Common Use Cases
常见用例
- ORMs (ActiveRecord) - Dynamic finders, associations
- DSLs - Route definitions, configurations
- Decorators - Method wrapping and enhancement
- Mocking/Stubbing - Test frameworks
- Attribute definition - Custom accessors with behavior
- ORM框架(如ActiveRecord)- 动态查找器、关联关系
- DSL - 路由定义、配置
- 装饰器 - 方法包装与增强
- Mock/Stub - 测试框架
- 属性定义 - 带自定义行为的访问器
Related Skills
相关技能
- ruby-oop - Understanding classes and modules
- ruby-blocks-procs-lambdas - For callbacks and dynamic behavior
- ruby-gems - Many gems use metaprogramming extensively
- ruby-oop - 理解类与模块
- ruby-blocks-procs-lambdas - 用于回调和动态行为
- ruby-gems - 许多gem都大量使用元编程