列出所有 Ruby 类 和方法

List all Ruby classes and methods

一段时间以来,我一直想要一种方法来检查加载特定模型时对给定 ruby 环境所做的所有更改。此外,能够比较和对比不同版本 ruby 和不同 Ruby 虚拟机中可用的方法和 classes。

我已经创建了一些使用元编程生成这样一个列表的代码:

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"))

列表的标准是它应该列出所有非继承的实例和 class 方法。常量用 :: 前缀表示,Class 方法用 MyClass::someMethod 表示,实例方法用如下方式表示:#<MyClass>.someMethod.

上面的脚本大部分都有效,但是它遗漏了 ObjectBasicObject。 IE。在创建的列表中,没有以 #<Object>.Object:: 为前缀的行。我是否遗漏了一些明显的东西?

我建议您为每个 Ruby 版本创建一个散列,然后将该散列或其内容保存到名称指示 Ruby 版本的文件中(例如,v_2-5-1.jsonv_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]

如您所见,ObjectBasicObject 是此散列中的两个键 (classes)。让我们看一下其中一个键的值: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 文档进行比较,我们发现 class Dir.

的结果是正确的

获取 class C 中定义的常量是有问题的。 C.constants,我在上面使用的包括继承的常量。如果我写的 C.constants - C.superclass.constants(注意 BasicObject.superclass #=> nil)不会报告在 C 中重新定义的继承常量(并且重新定义继承常量不会产生警告消息)。

而不是仅仅查看 classes,您可能希望检查所有模块 (ObjectSpace.each_object(Module)) 并将键 :is_class 添加到值为 true 的散列或false):

您可能还想将其他键添加到哈希中。 :superclass:included_modules (对于 classes )是我想到的两个; :nesting(对于非 class 模块)是另一个。参见 Module::nesting。我怀疑这些观察只是触及表面,对两个 Ruby 版本进行有意义的比较将非常复杂。