Ruby钩子方法实战:常见运用场景与实例解析
时间:2026-08-18 | 作者:深海捕梦者 | 阅读:0在 Ruby 里,钩子方法(Hook Methods)就像一把手术刀,允许我们在类或模块的生命周期关键时刻精准介入。
用好它,代码的灵活性和可维护性都能上一个台阶。下面把这些生命周期相关的钩子方法梳理一下。
类与模块相关的钩子
Class#inherited—— 当子类被继承时触发Module#include—— 模块被混入时调用Module#prepended—— 模块被前置混入时触发Module#extend_object—— 对象被扩展时调用Module#method_added—— 实例方法被添加时触发Module#method_removed—— 实例方法被移除时触发Module#method_undefined—— 实例方法被置为 undefined 时触发
单件类相关的钩子
BasicObject#singleton_method_added—— 单件方法被添加时触发BasicObject#singleton_method_removed—— 单件方法被移除时触发BasicObject#singleton_method_undefined—— 单件方法被置为 undefined 时触发
示例代码
module M1
def self.included(othermod)
puts "M1 was included into #{othermod}"
end
end
module M2
def self.prepended(othermod)
puts "M2 was prepended to #{othermod}"
end
end
class C
include M1
include M2
end
# 输出
M1 was included into C
M2 was prepended to C
module M
def self.method_added(method)
puts "New method: M##{method}"
end
def my_method; end
end
# 输出
New method: M#my_method
除了上面列出的专用钩子,我们还可以通过重写父类方法来实现类似效果。
常见做法是先加入过滤逻辑,再用 super 调用原功能。环绕别名(Around Alias)也是一种常见的替代方案。
运用实例
任务描述:
写一个类似 attr_accessor 的类宏 attr_checked,用来对属性值做校验。使用方式如下:
class Person
include CheckedAttributes
attr_checked :age do |v|
v >= 18
end
end
me = Person.new
me.age = 39 # ok
me.age = 12 # 抛出异常
实施计划:
- 用 eval 方法编写一个
add_checked_attribute内核方法,为指定类添加经过简单校验的属性 - 重构该方法,去掉 eval,改用其他手段实现
- 添加代码块校验功能
- 修改方法名为
attr_checked,并使其对所有类都可用 - 通过引入模块的方式,只对引入该功能的类添加
attr_checked
Step 1
def add_checked_attribute(klass, attribute)
eval "
class #{klass}
def #{attribute}=(value)
raise 'Invalid attribute' unless value
@#{attribute} = value
end
def #{attribute}()
@#{attribute}
end
end
"
end
add_checked_attribute(String, :my_attr)
t = "hello,kitty"
t.my_attr = 100
puts t.my_attr
t.my_attr = false
puts t.my_attr
这一步直接用 eval 打开类并定义 get/set 方法。
set 方法会判断值是否为空(nil 或 false),否则抛出异常。虽然粗暴,但胜在直观。
Step 2
def add_checked_attribute(klass, attribute)
klass.class_eval do
define_method "#{attribute}=" do |value|
raise "Invalid attribute" unless value
instance_variable_set("@#{attribute}", value)
end
define_method attribute do
instance_variable_get "@#{attribute}"
end
end
end
这一步替换掉了 eval。
改用 class_eval 和 define_method。实例变量的读写也换成了 instance_variable_set 和 instance_variable_get。
功能完全一样,但实现更安全、更 Ruby 化。
Step 3
def add_checked_attribute(klass, attribute, &validation)
klass.class_eval do
define_method "#{attribute}=" do |value|
raise "Invalid attribute" unless validation.call(value)
instance_variable_set("@#{attribute}", value)
end
define_method attribute do
instance_variable_get "@#{attribute}"
end
end
end
add_checked_attribute(String, :my_attr){|v| v >= 180 }
t = "hello,kitty"
t.my_attr = 100 # Invalid attribute (RuntimeError)
puts t.my_attr
t.my_attr = 200
puts t.my_attr # 200
这一步增加了一个代码块参数,让校验逻辑更灵活。
不再局限于简单的非空判断,可以自定义任何条件。
Step 4
class Class
def attr_checked(attribute, &validation)
define_method "#{attribute}=" do |value|
raise "Invalid attribute" unless validation.call(value)
instance_variable_set("@#{attribute}", value)
end
define_method attribute do
instance_variable_get "@#{attribute}"
end
end
end
String.attr_checked(:my_attr){|v| v >= 180 }
t = "hello,kitty"
t.my_attr = 100 # Invalid attribute (RuntimeError)
puts t.my_attr
t.my_attr = 200
puts t.my_attr # 200
这一步把方法直接放到 Class 中,所有类都能调用。
因为在类内部 self 就是当前类,所以省去了 class_eval 和额外参数,方法名也改为 attr_checked。
Step 5
module CheckedAttributes
def self.included(base)
base.extend ClassMethods
end
end
module ClassMethods
def attr_checked(attribute, &validation)
define_method "#{attribute}=" do |value|
raise "Invalid attribute" unless validation.call(value)
instance_variable_set("@#{attribute}", value)
end
define_method attribute do
instance_variable_get "@#{attribute}"
end
end
end
class Person
include CheckedAttributes
attr_checked :age do |v|
v >= 18
end
end
最后一步,利用钩子方法 included,在模块被混入时自动扩展目标类,使其获得 attr_checked。
这样只对显式 include CheckedAttributes 的类生效,精确控制权限。
总结
到此,我们实现了一个类似 attr_accessor 的类宏 attr_checked,可以对属性值进行自定义校验。
整个过程展示了钩子方法在实际设计中的力量。
- 从
eval到define_method - 再到模块扩展
- 实现方式步步进化,越来越优雅
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- 使用RVM切换Ruby与Rails版本的实现方法
- 时间:2026-08-18
-
- Ruby语言是什么及入门使用方法
- 时间:2026-08-18
-
- Ruby on Rails网站项目搭建入门指南
- 时间:2026-08-18
-
- Ruby插入排序算法实现与二路插入排序代码示例
- 时间:2026-08-18
-
- Ruby图片滤镜算法实现代码与核心原理
- 时间:2026-08-18
-
- Ruby中Hash哈希结构基本操作方法详解
- 时间:2026-08-18
-
- Ruby面向对象编程:类方法与类扩展详解
- 时间:2026-08-18
-
- Ruby正则表达式语法详解与常用示例代码
- 时间:2026-08-18
精选合集
更多大家都在玩
大家都在看
更多-
- 糖尿病完全不能吃糖吗
- 时间:2026-09-15
-
- 蚂蚁庄园小课堂2026年9月16日最新题目答案
- 时间:2026-09-15
-
- 小鸡答题今天的答案是什么2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园每日答题答案2026年9月16日
- 时间:2026-09-15
-
- 以下哪种粮食是酿造绍兴黄酒的主要原料 蚂蚁庄园今日答案9月16日
- 时间:2026-09-15
-
- 劝学名句“及时当勉励,岁月不待人”出自哪位诗人 蚂蚁庄园今日答案9.16
- 时间:2026-09-15
-
- 蚂蚁庄园今天答题答案2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园答题今日答案2026年9月16日
- 时间:2026-09-15
