元编程的定义
- 元编程是能变现代码的代码
- 元编程是编写能在运行时操作语言构件的代码
基本概念
- 类的本质也是对象
- 对象就是一组实例变量外加一个指向其类的引用。对象的方法并不存在于对象本身,而是存在于对象的类中,即类的实例方法
- 类就是一个对象(Class类的一个实例)外加一组实例方法和一个对其超类的引用。Class类是Module类的子类,因此一个类也是一个模块
- 每个类都是一个模块,类就是带有三个方法(new,allocate,superclass)的增强模块,通过这三个方法可以组织类的继承结构,并创建对象
- Ruby的class关键字更像是一个作用域操作符,而不是类型声明语句。class关键字的核心任务是把你带到类的上下文中,让你可以在里面定义方法
- Ruby中的类和模块的概念十分接近,完全可以将二者相互替代,之所以同时保留二者的原因是为了保持代码的清晰性,让代码意图更加明确。使用原则: 希望把自己代码包含(include)到别的代码中,应该使用模块;希望某段代码被实例化或被继承,应该使用类
- 模块机制可以用来实现类似其它语言中的命名空间(Namespace)概念,如:
Rake::Task
,Rake就是用来充当常量容器的模块 - 任何以大写字母开头的引用(包括类名和模块名)都是常量, 而且可以修改常量的值, Ruby中常量和变量最大的区别在于作用域不同
- Ruby中常量的路径(作用域),类似与文件系统中的目录,通过::进行分割和访问,默认直接以::开头(例: :: Y)表示变量路径的根位置
- 不能通过明确指定接受者来调用私有方法。私有方法只能通过隐性的接受者self调用(Object#send是个例外)
- 调用一个方法时,接受者会扮演self角色 任何没有明确指定接受者的方法调用,都当做是调用self的方法 定义一个模块(或类)时,该模块(或类)会扮演self角色
类与对象与模块的关系
打开类,猴子补丁和细化
- 可以重新打开已经存在的类并对之进行动态修改,即使像String或者Array这样标准库的类也不例外。这种行为方式称之为打开类
- 如果你粗心地为某个类添加了新功能,同时覆盖了类原来的功能,进而影响到其他部分的代码,这样的patch称之为猴子补丁
- 细化是对打开类的全局修改的一种解决方法,在模块中使用
refine
指明需要修改,然后使用using
这个模块是其生效,细化就有了一个作用域,using后到模块结束或者文件结束
祖先链
- 祖先链用于描述Ruby对象的继承关系,因为类与模块是父子关系,所以祖先链中也可以包含模块
- 使用include方法,模块会被插入祖先链,当前类的正上方
- 使用prepend方法,模块也会被插入到祖先链,但位置其他却在当前类的正下方
- 查找方法的方式,向右一步,再向上
- 一个模块只会在一条祖先链中出现一次,故多次插入相同的模块,只有第一次生效
load与require方法的异同
load
和require
都用来导入外部的代码load
方法用来加载代码,如果不希望污染当前的命名空间,需要通过load('motd.rb',true)
显式的要求创建一个匿名模块来,接管motd.rb的常量;require
用于导入类库;- load方法每次调用都会再次运行所加载文件,require则对每个库文件只加载一次
一些方法和作用
obj.class
询问对象的类obj.class.instance_methods
,obj.methods
询问对象的类的实例方法obj.class.instance_methods(false)
不包括继承而来的方法obj.instance_variables
询问对象的实例变量Module#constants
(实例方法) 返回当前范围内的所有常量Module.constants
(类方法) 返回当前程序中所有顶层常量(包括类名)Module.nesting
获取当前代码所在路径obj.class.ancestors
查看当前类的祖先链