有同学表示第九章元编程的例程不好理解。先道歉,因为能力不足于游刃有余地表达元编程的方方面面,所以我选择了只演示最简单的元编程,而不展开解释。
下面给出例程的一点注释,不保证你能理解。对于入门,知道Ruby长于元编程就可以了。
ruby 代码
- class MetaPerson
- def MetaPerson.method_missing(methodName, *args) #重新定义Ruby内置的方法method_missing
- name = methodName.to_s
- begin
- #调用Ruby内置的方法 class_eval 自动生成一个新方法
- class_eval(%Q[
- def #{name}
- puts '#{name}, #{name}, #{name}...'
- end
- ])
- rescue
- #出现异常的时候,执行Ruby原有的method_missing(methodName, *args)
- super(methodName, *args)
- end
- end
- def method_missing(methodName, *args)
- MetaPerson.method_missing(methodName, *args) #实例method_missing调用类方法method_missing
- send(methodName) #使用Ruby内置的send方法,来呼叫前面自动生成的新方法
- end
- #下面代码类似于上面---------
- def MetaPerson.modify_method(methodName, methodBody)
- class_eval(%Q[
- def #{methodName}
- #{methodBody}
- end
- ])
- end
- def modify_method(methodName, methodBody)
- MetaPerson.modify_method(methodName, methodBody)
- end
- #---------------------------
- end #结束MetaPerson 类的定义
- class Person < MetaPerson
- end
- person1 = Person.new
- person2 = Person.new
- person1.sleep #=> sleep, sleep, sleep...
- person1.running #=> running, running, running...
- person1.modify_method("sleep", "puts 'ZZZ...'") #修改方法sleep
- person1.sleep #=> ZZZ...
- person2.sleep #=> ZZZ...
这个例程有什么用呢?
假设《机械公敌》中的某一个ND5型机器人,在执行“保护人类计划”的过程中,发现微笑是很好的沟通行为,于是smile。虽然在这之前,ND5型机器人是不会smile的,但是就在某一个ND5型机器人试着smile的一瞬间,所有的ND5型机器人都可以smile了。当然,在以后的时间里,任何一个ND5型机器人都可以不断演化smile,并让其它的ND5型机器人共享smile的演化结果。
也许你不希望每一个ND5型机器人都会smile,你喜欢某一个实例对象有特立独行的行为,比如桑尼,桑尼确实与众不同,坚强,机智,谦逊(请允许我把这几个形容词用在一个机器人身上)。
为了达到你的要求,试试下面这个程序吧。
ruby 代码
- class Person
- def method_missing(methodName, *args)
- name = methodName.to_s
- obj = self.inspect
- begin
- self.instance_eval(%Q[
- def #{name}
- puts '#{obj}, #{name} '
- end
- ])
- send(methodName)
- rescue
- super(methodName, *args)
- end
- end
- def modify_method(methodName, methodBody)
- self.instance_eval(%Q[
- def #{methodName}
- #{methodBody}
- end
- ])
- end
- end
- p1=Person.new
- p2=Person.new
- p1.sleep #=> #<person:0x296cb14>, sleep
- p1.modify_method(:sleep, "puts 'This is p1 ZZZ...'")
- p1.sleep #=> This is p1 ZZZ...
- p2.sleep #=> #<person:0x296c998>, sleep
- p2.modify_method(:sleep, "puts 'This is p2 ZZZ...'")
- p2.sleep #=> This is p2 ZZZ...