我想要达到的效果是这样的
class Foo
redis_cache 10 do
def foo
'bar'
end
def bar
'foo'
end
end
end
被包裹在redis_cache里面的方法会在第一次执行后存入redis, 在第二次执行该方法的时候,去redis里面取,并且根据传入的秒数来设定缓存周期,以起到缓存的效果,老实讲是没什么必要这么弄,但是你们难道对如何实现不感兴趣吗?
感兴趣的同学往下看
思路
我们首先要熟悉ruby祖先链相关的知识,当一个实例执行一个方法的时候,是怎么样的一个流程,实例对象中没有方法,只有变量,实例执行方法的时候,先向右一步,到自己的类中找,假如没有找到,会继续往上,到该类的超类里面找,直到Object为止,还没找到的话,从一开始的类开始找名叫method_missing的方法,假如还是没有,会在Object这里找到一个内置的method_missing,这个方法没什么内容,就是抛出一个undifine_method xxx for xxx。。。
不过这一期的内容用不到这些知识
你们有没有想过,当一个类混入一个模块(include Foo)后,类里面的实例方法,和模块中同名的实例方法,哪个会被优先调用,答案是,优先执行类里面的,再是模块里面的,这个可以自己去做个试验,看到这里,如何实现这个简单的DSL就很明朗了,我们首先把redis_cache里面的block,拿到后跑到该类的超类中写一个方法,然后再在自己的类中建一个同名方法,用super来实现上下层的方法的交互,但是我们写进超类里面会有一个问题,方法有可能会被写进Object,这样会产生一个问题,其他的任何类都会拥有这个方法,这不是我们想要的效果,那利用我们刚说的第二点,把方法写进一个模块,然后include,就可以了
初步的代码是这样的
class Object
def redis_cache seconds=300, &block
top_mod = self.const_set(:TopMethods, Module.new)
top_mod.module_eval &block
include top_mod
top_mod.instance_methods.each do |m|
self.class_eval <<-CODE
def #{m}(*args)
puts 'in bottom'
super
end
CODE
end
end
end
class Foo
redis_cache do
def bar
'it works!'
end
end
end
aa = Foo.new
aa.bar
#=> in bottom
#=> 'it works!'
后面如何继续实现,相信大家都有思路了
网友评论