[元编程系列] 邪恶
下面的一些代码,出自一个古老的库:evil.rb,你可以 gem install evil-ruby 来获得它。
如果想要兼容1.9的 evil-ruby,请用 Yugui
姐姐的修改版:
http://github.com/yugui/evil-ruby/tree/master
evil.rb 使用了核心库 Ruby/DL 来获得 C 层次的 Ruby 对象访问
不过……Yugui 姐姐你写的 DL,不仅大改 API,而且文档几乎为0……
作为实用主义者,先总结一下 API~ (源文件里注释写得很好,推荐直接看邪恶的源代码)
你可以暂停GC的运行:
- require 'evil'
- RubyInternal.critical do
- # GC暂停了!做坏事要打紧!
- end
- # critical 块和 RubyInternal 是下面很多方法实现的基础。
你还可以看看一个对象在内存中是个什么东西
:
- require 'pp'
- pp '12'.internal
可以获得地址……:
- '12'.internal_ptr.to_i # 47699480
- '12'.internal_ptr.to_i # 47667740,显示这两个'12'是不同的对象
可以获得内部类型在 C 中的定义数值:
- nil.internal_type # 在1.8是32,在1.9是16
还可以解冻对象~~(这个例子是作者举的):
- obj = "Hello World".freeze
- obj.frozen? # => true
- obj.unfreeze
- obj.frozen? # => false
解冻是超越安全等级的!
虽然在在高于 0 的安全等级用 unfreeze 时,会装模做样的弹出一个 Error,但是删掉 raise 那行就过去了……
通过 RubyInternal 操作 flag 和 mask,还可以解除 tainted 等状态 -___-
怪不得 Programing Ruby 里面讲安全等级的那章说:
教训就是:千万不要 eval 信不过的代码!
检查对象是否直接量(关于直接量和非直接量,请参考 JE 知识库里的 Ruby Hacking Guide):
- 12.direct_value? # => true
可以改变对象所属的类!
- class A;def 自白;puts '我是一个A';end;end
- class B;def 自白;puts '我是一个B';end;end
- a = A.new
- a.自白 # => 我是一个A
- a.class= B # 无敌的class=
- a.自白 # => 我是一个B
也可以改变继承关系!
- A.superclass = B
类,就是蜡烛一般弱的东西……噗~~~就没了~~~
一心同体……共享实例变量:
- class Body
- attr_accessor :heart
- end
- good_guy = Body.new
- good_guy.heart = 'good'
- bad_guy = Body.new
- bad_guy.share_instance_variables good_guy # 建立连接,同步率直线上升!
- puts bad_guy.heart # => kind
- bad_guy.heart = 'bad' # 一个修改,全部改变
- puts good_guy.heart # => bad
复制单例方法:
- a.grab_singleton_methods b
著名的 class to module:
- class A
- include Array.as_module # A可以当Array用了~
- end
Ruby不支持多重继承?当然支持了~
- class C
- inherit A, B # 后面的同名方法会覆盖前面的
- end
KernellessObject——更清洁干净的 BlankSlate 替代物,用来做基于 method_missing 的 DSL 载体非常合适。
在1.9里面返回一个 BasicObject。
- clean_obj = KernellessObject.new # 在irb里会弹出一堆错,因为它连inspect方法都没有,irb想偷窥都不行
UnboundedMethod#bind(obj) 原本要求 obj 属于该方法所在的类,不过 force_bind 超越了这个限制。
下面是作者给的例子,我无耻的copy出来了:
- foo_klass = Class.new do
- def greet; "#{self.inspect} says 'Hi!'"; end
- end
- obj = []
- greet = foo_klass.instance_method(:greet)
- greet.bind(obj).call # raises TypeError
- greet.force_bind(obj).call # => "[] says 'Hi!'"
还有两个简单的self的运用,其实现和C无关:
- class Object
- def meta_class
- class << self
- self
- end
- end
- end
- # meta_class(或者singleton_class,或者prototype)是一个class,
- # 但是对它的修改只影响该对象,不会影响对象的类。
- s = '不卫生'
- s.meta_class.class_eval do
- def xit
- 'xit'
- end
- end
- s.xit # => 'xit'
- '很卫生'.xit # => undefined method,String没有被改变
- class Proc
- def self
- eval 'self', self
- # eval的效果是——获得proc所在的对象,而直接用self只返回Proc本身
- end
- end
![](http://www.cnblogs.com/Emoticons/baimantou/202015934.gif)