说在前面
这篇文章与这个系列的开篇文章隔了很久了,一直也没有能够整理出来,今天终于搞定一篇,希望尽早完成这个系列吧。上篇比较宏观地介绍了Ruby的元编程,从这篇开始,我们将进入Ruby的世界,探索哪些元编程特性。我们会先来介绍Ruby的对象模型和方法,对象模型是整个Ruby语言的基础,也为元编程带来了巨大的灵活性。而Ruby中的方法在对象模型的基础上提供了强大的动态操纵的能力,能够方便地进行元编程。
Object Model
先来看一张Ruby对象模型的图
Note:
- BasicObject类是Ruby类体系结构的根节点
- Object类是所有类的默认superclass
- 关于类为什么可以调用class方法,Class的superclass为什么是Module? 这些问题,可以参考另一篇文章《Ruby中那些不太容易理解的特性》
Module in Object Model
1 | # 查看祖先链 |
祖先链中Kernel是一个模块,为什么出现在这?Kernel其实是Object中include进来的一个Module,而Ruby底层会将引入的Module封装成一个匿名类插入到包含它的类的上方。
关于Kernel模块,值得一提的是,RubyGem就是在Kernel模块中定义了gem()方法,只要require这个包之后就能在任何地方使用这个方法了,还有proc和lambda方法也定义在Kernel模块中。
Open Class: 可以用来增强Ruby或者框架、类库提供的类4.
1 | > cat object_model.rb |
Namespace using Module: 可以用来防止命名冲突
1 | > cat namespace_example.rb |
Method in Ruby
方法的查找与执行
概念
. Receiver: 方法所在的对象
. Ancestors: 从Receiver对象所属的类开始到其父类自下而上的链条,以BasicObject为终点,其中也包括模块
方法查找就是从Receiver(接收者)开始沿着Ancestors(祖先链)查找,直到找到对应的方法,然后执行该方法。如果没有在Ancestors上找到对应的方法,解释器则会调用Kernel#method_missing()方法,并由它抛出NoMethodError。
self关键字表示当前对象,当一个方法被调用时,self就对应了receiver。
方法的动态操纵
利用方法的动态操纵能力可以避免重复代码,这些动态操纵的技术包括:
- Dynamic Dispatch
- Dynamic Method
- Ghost method
- Dynamic Proxies
方法的动态调用(利用Dynamic Dispatch技术)
Ruby方法调用的本质是向Receiver发送消息1
2
3
4
5
6
7
8
9
10
11> cat send_message.rb
# 利用send方法进行方法调用
class SendMessage
def my_method(arg)
puts arg * 5
end
end
obj = SendMessage.new
obj.my_method(2)
obj.send(:my_method, 2)
Dynamic Dispatch技术就利用了send方法,将方法名也作为参数,动态确定方法名,从而实现方法的动态调用。
1 | # 实例:Test::Unit |
方法的动态定义(利用Dynamic Method技术)
1 | > cat dynamic_method.rb |
创建幽灵方法(在method_missing内定义)
当无法找到调用的方法时,将会调用self的method_missing方法,可以利用这个特性创建一些Ghost method(幽灵方法),这些方法并不真正存在,但对用户来说,跟真实存在的方法没有区别。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22> cat ghost_method.rb
# 在method_missing中创建幽灵方法
class GhostMethod
def initialize
@attributes = {}
end
def method_missing(name, *args)
attribute = name.to_s
if attribute =~ /=$/
@attributes[attribute.chop] = args[0]
else
@attributes[attribute]
end
end
end
user = GhostMethod.new
user.name = "Warren"
user.job = "Programmer"
puts user.name
puts user.job
方法的转发(利用Dynamic Proxies技术创建封装对象,来封装另一个对象、Web服务或者其它语言代码)
1 | > cat http_wrapper.rb |
Conclusion
这里只是罗列了几个基本的元编程技术,将这些技术组合起来能够有效地消除重复代码。你是不是已经领略到了Ruby的神奇了?这还没结束下,期待下一篇吧。
Reference
Have Fun!
订阅我的微信公众号,您将即时收到新博客提醒!