Introspection and ObjectSpace: Examining Data and Methods at Runtime
Ruby提供了很多方法用来在运行时查找对象。还有访问实例变量对象方法。使用他们的时候要当心,因为这些方法
破坏了封装。
class C
def initialize
@ivar = 1
end
end
c = C.new
c.instance_variables # => ["@ivar"]
c.instance_variable_get(:@ivar) # => 1
c.instance_variable_set(:@ivar, 3) # => 3
c.instance_variable_get(:@ivar) # => 3
Object#methods方法返回实例方法的一个数组,包含了定义在接受者上的单例方法。如果这个方法的第一个参数是
false,则只返回对象的单例方法。
class C
def inst_method
end
def self.cls_method
end
end
c = C.new
class << c
def singleton_method
end
end
c.methods - Object.methods # => ["inst_method", "singleton_method"]
c.methods(false) # => ["singleton_method"]
Module#instance_methods返回了类或者模块的实例方法。instance_methods是被class调用而methods是被实例调
用。给instance_methods传递一个false跳过了父类的方法:
C.instance_methods(false) # => ["inst_method"]
也可以用Metaid的metaclass来检查C的类方法:
C.metaclass.instance_methods(false) # => ["new", "allocate", "cls_method",
"superclass"]
In my experience, most of the value from these methods is in satisfying curiosity. With the
exception of a few well-established idioms, there is rarely a need in production code to reflect on
an object's methods. Far more often, these techniques can be used at a console prompt to find
methods available on an object—it's usually quicker than reaching for a reference book:
Array.instance_methods.grep /sort/ # => ["sort!", "sort", "sort_by"]
ObjectSpace
ObjectSpace是一个用来和Ruby的对象系统交互的模块。它有几个很有用的可以使底层hacking更轻松的模块方法:
Garbage-collection methods: define_finalizer (sets up a callback to be called just before an object is destroyed), undefine_finalizer (removes those call-backs), and garbage_collect (starts garbage collection).
_id2ref converts an object's ID to a reference to that Ruby object.
each_object iterates through all objects (or all objects of a certain class) and yields them to a block.
尽管这些方法很有用,但是也很危险。慎重的使用他们。
在Ruby的Test::Unit框架里有个恰当的使用Objectspace的例子。代码用了ObjectSpace.each_object来列举所有存在的继承自Test::Unit::TestCase类。
test_classes = []
ObjectSpace.each_object(Class) {
| klass |
test_classes << klass if (Test::Unit::TestCase > klass)
}
不行的是,ObjectSpace是Ruby的虚拟机更加复杂化。特别是打开ObjectSpace打开的时候Jruby的性能受损很严重,因为Ruby的解析器不能直接的检查在JVM的内部数据的存在的对象。相反的,JRuby必须保持手工的跟踪对象,这将增加很多的消耗。相同的技巧可以在像Module.extended和Class.inherited的方法得到,这些不会有ObjectSpace更切实。