Before_filter的实现。

本文介绍了一种在Ruby中模仿Rails框架before_filter功能的方法。通过使用method_added钩子,作者实现了在方法调用前后分别执行特定函数的功能。这种方式可用于执行如用户验证等前置操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

突然想起rails有before_filter,想了一下怎么实现(看源码太费劲,机器上也没rails),就动手试了一下。

简单介绍一下before_filter:

比如以下代码:

class Person

before :bef
after :aft

def initialize name
@name = name
end

def make_new_friend
puts "Nice to see you"
end

def introduce_self
puts "Bla Bla Bla..."
end

def bef
puts "Hi, I'm #{@name}"
end

def aft
puts "Bye, contact me, I'm #{@name}"
end

end

p =Person.new('Xiao Ping')

p.make_new_friend
p.introduce_self


我想每次运行Person的某个方法前,都自动执行一下bef方法(在第3行声明过,在18行定义),运行方法后执行aft方法。(例如rails中可以在bef方法中写验证用户是否有效),既方法make_new_friend
虽然目前看只输出Nice to see you,但是我实际要输出
Hi, I'm Xiao Ping
Nice to see you
Bye, contact me, I'm Xiao Ping

bef
make_new_friend
aft
三个方法的组合。

实现的方式我目前猜测了几种,并自己写了一种供大家分享。
原理很简单,就是通过method_added这个钩子方法hack新添加的方法

class Base

def self.method_added m
m_name = m.to_s
# 下面几个判断都是过滤掉不需要hack的方法。
@@registered_methods ||= []
unless m_name =~ /original/ || m_name == 'initialize'
unless protected_instance_methods.include?(m)
unless @@registered_methods.include?(m_name)

# 保存原来的方法
alias_method "original_#{m_name}".to_sym, m_name.to_sym
@@registered_methods << m_name
self.class_eval do
parameters = public_instance_method(m).parameters.collect {|i| i[1]}

# 创建新的同名方法
define_method m do |*parameters|
self.class.class_variable_get(:@@before).each do |m|
__send__(m)
end
rtn = __send__("original_#{m_name}".to_sym, *parameters)
self.class.class_variable_get(:@@after).each do |m|
__send__(m)
end
rtn
end
end
end
end
end
end

def self.before *methods
@@before ||= []
methods.each do |m|
@@before << m unless @@before.include?(m)
end
end

def self.after *methods
@@after ||= []
methods.each do |m|
@@after << m unless @@after.include?(m)
end
end

end

class Person < Base

before :bef
after :aft

def initialize name
@name = name
end

def make_new_friend
puts "Nice to see you"
end

def introduce_self
puts "Bla Bla Bla..."
end


protected
def bef
puts "Hi, I'm #{@name}"
end

def aft
puts "Bye, contact me, I'm #{@name}"
end

end

p =Person.new('Xiao Ping')

p.make_new_friend
p.introduce_self


有点瑕疵,改了之后容易让人confused,所以就没改,希望能对大家有帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值