一段时间以来,我一直希望有一种方法可以检查在加载特定模型时对给定红宝石环境所做的所有更改。此外,还可以比较和对比不同版本的ruby和不同的Ruby VM中可用的方法和类。
我创建了一些使用元编程生成这样的列表的代码:
arr = []
arr << "Ruby version " + ::RUBY_VERSION
arr << ""
Module.constants.each do |const|
if ::Module.const_defined? const
#If for whatever reason const_get fails, then rescue.
begin
obj = Module.const_get(const)
if obj
if obj.is_a? Class
# Class methods
arr << (obj.singleton_methods).sort.map do |method_sym|
obj.to_s + "::" + method_sym.to_s
end
# Instance methods
arr << (obj.instance_methods - (obj.superclass ? obj.superclass.instance_methods : []) - Object.methods).sort.map do |method_sym|
"#<" + obj.to_s + ">." + method_sym.to_s
end
elsif obj.is_a? Module
arr << (obj.methods - Module.methods).sort.map do |method_sym|
obj.to_s + "::" + method_sym.to_s
end
else
# Methods
arr << "::" + const.to_s
end
end
rescue
end
end
end
File.new("D:\\methods_#{::RUBY_VERSION}.txt","w").write(arr.flatten.sort.join("\n"))
该列表的标准是它应列出所有非继承的实例和类方法。常量用前缀::
表示,类方法表示为MyClass::someMethod
,实例方法表示为:#<MyClass>.someMethod
。
上面的脚本大部分都起作用,但是它错过了Object
和BasicObject
。即在创建的列表中,没有以#<Object>.
或Object::
为前缀的行。我缺少明显的东西吗?
答案 0 :(得分:3)
我建议您为每个Ruby版本创建一个哈希,然后将该哈希或其内容保存到名称指示Ruby版本的文件中(例如v_2-5-1.json
或v_2-5-1.txt
)
尽管我不完全理解这个问题,但您可能会发现这里的方法ObjectSpace::each_object很有帮助。例如,
h = ObjectSpace.each_object(Class).with_object({}) do |c,h|
h[c] = { cm: c.methods(false).sort, im: c.instance_methods(false).sort,
con: c.constants.sort }
end
h.keys && [Object, BasicObject]
# [Object, BasicObject]
您看到Object
和BasicObject
是此哈希中的两个键(类)。让我们看一下其中一个键的值:Dir
。
h[Dir]
#=> {:cm=>[:[], :chdir, :children, :chroot, :delete, :each_child, :empty?,
# :entries, :exist?, :exists?, :foreach, :getwd, :glob, :home,
# :mkdir, :open, :pwd, :rmdir, :unlink],
# :im=>[:close, :each, :fileno, :inspect, :path, :pos, :pos=, :read,
# :rewind, :seek, :tell, :to_path],
# :con=>[]}
这是
RUBY_VERSION
#=> "2.5.1"
将此哈希的内容与v2.5.1的Dir的文档进行比较,我们发现结果对于类Dir
是正确的。
获得在类C
中定义的常量是有问题的。我上面使用的C.constants
包含继承的常量。我是在写C.constants - C.superclass.constants
时(谨记BasicObject.superclass #=> nil
)不会报告继承的常量,而是在C
中进行了重新定义(并且重新定义继承的常量不会产生警告消息)。
您可能希望检查所有模块(ObjectSpace.each_object(Module)
),然后将键:is_class
添加到具有值true
或false
的哈希中,而不是仅查看类:
您可能希望将其他键添加到哈希中。 :superclass
和:included_modules
(对于class)是我想到的两个。 :nesting
(对于非类模块)是另一个。参见Module::nesting。我怀疑这些观察只是表面上的事情,两个Ruby版本的有意义的比较会非常复杂。