代码之家  ›  专栏  ›  技术社区  ›  Sancarn

列出所有Ruby类和方法

  •  0
  • Sancarn  · 技术社区  · 6 年前

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

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

    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:: . 我是否遗漏了一些明显的东西?

    1 回复  |  直到 6 年前
        1
  •  3
  •   Cary Swoveland    6 年前

    我建议您为每个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"
    

    将此哈希的内容与的文档进行比较 Dir 对于v2.5.1,我们看到结果对于类是正确的。 迪尔 .

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

    您可能希望检查所有模块,而不只是查看类。( ObjectSpace.each_object(Module) )并添加一个键 :is_class 到具有值的哈希 true false ):

    您可能希望将其他密钥添加到哈希中。 :superclass :included_modules (对于课堂)是两个浮现在脑海中的概念; :nesting (对于非类模块)是另一个。见 Module::nesting . 我怀疑这些观察只是表面现象,对两个Ruby版本进行有意义的比较是非常复杂的。