Before_filter的实现。

突然想起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,所以就没改,希望能对大家有帮助。

你可能感兴趣的:(filter)