用代码块收集参数
最近在为看rails源码做一些准备,其中必须要搞懂的东西除了Class,Module,Object,Kernel,eigenclass这类东西之外,还有一个比较重要的就是代码块了,虽然也了解了一些关于代码块的知识,但是对于代码块的运用还是比较少,代码块的基本知识不在本次简书中介绍了,这次先直接介绍我最近用代码块来干了些什么。
对于Sunspot#solr_search这个方法,大家一定很熟悉了,大家可以先回想一下,这个方法要接收什么参数,你想过之后会发现,我们在调用这个方法的时候并没有传什么参数,而是传了一大堆代码过去,恩,相信你已经明白了,对于一个方法,可以将一堆代码传过去作为参数,用{}来包裹他们,或者是从do 到 end, 这段代码会作为一个对象被传进这个方法,这就是代码块最基本的一个应用。下面我会教大家如何实现模仿solr_search的这种参数收集方式,纯自己捣鼓的,有不妥的地方欢迎指点。
首先我们要实现用with,把参数收集起来,就像solr_search那样,里面搜索的参数我们都是用with这个方法来做到的
class Peter
def my_method
options = {}
Kernel.module_eval do
define_method :with do |k,v|
options[k] = v
end
end
yield
undef :with
options
end
end
peter = Peter.new
peter.my_method do
with :first_val, 1
with :second_val, 2
end
#=> {:first_val => 1, :second_val => 2}
是不是还挺酷的?
来看看我做了什么,在我调用这个方法的时候,处在顶级作用域,也就是说当前的class是Object,然后Object这个类include了Kernel这个模块,也就是说在把方法写在Kernel中,任何对象都能调用到,因此我在我的方法里面打开了Kernel这个模块,在里面添加了with这个方法,这样在任何地方调用这个方法并使用with的时候都可以调用到!
接着我们模仿一下,all_of do,在代码块里传代码块,也是可以的!
class Peter
def my_method
options = {}
Kernel.module_eval do
define_method :all_of do |&block|
options[:my_block] = block
end
end
yield
options[:my_block].call('hello')
end
end
peter = Peter.new
peter.my_method do
all_of do |i|
"#{i} world!"
end
end
#=> 'hello world!'
方法参数不多的话,没有必要写成这样,但是一个方法接收七八个参数,那调用起来也很痛苦,试想一下solr_search这个方法不用代码块收集参数的话,得传多少个参数过去。