【问题标题】:How do you list the currently available objects in the current scope in ruby?如何在 ruby​​ 中列出当前范围内的当前可用对象?
【发布时间】:2010-09-18 17:21:53
【问题描述】:

我是 ruby​​ 新手,我正在玩 IRB。

我发现我可以使用“.methods”方法列出对象的方法,而 self.methods 可以满足我的需求(类似于 Python 的 dir(builtins)?) ,但是如何找到我通过 include 和 require 加载的库/模块的方法?

irb(main):036:0* self.methods
=> ["irb_pop_binding", "inspect", "taguri", "irb_chws", "clone", "irb_pushws", "public_methods", "taguri=", "irb_pwws",
"public", "display", "irb_require", "irb_exit", "instance_variable_defined?", "irb_cb", "equal?", "freeze", "irb_context
", "irb_pop_workspace", "irb_cwb", "irb_jobs", "irb_bindings", "methods", "irb_current_working_workspace", "respond_to?"
, "irb_popb", "irb_cws", "fg", "pushws", "conf", "dup", "cwws", "instance_variables", "source", "cb", "kill", "help", "_
_id__", "method", "eql?", "irb_pwb", "id", "bindings", "send", "singleton_methods", "popb", "irb_kill", "chws", "taint",
 "irb_push_binding", "instance_variable_get", "frozen?", "irb_source", "pwws", "private", "instance_of?", "__send__", "i
rb_workspaces", "to_a", "irb_quit", "to_yaml_style", "irb_popws", "irb_change_workspace", "jobs", "type", "install_alias
_method", "irb_push_workspace", "require_gem", "object_id", "instance_eval", "protected_methods", "irb_print_working_wor
kspace", "irb_load", "require", "==", "cws", "===", "irb_pushb", "instance_variable_set", "irb_current_working_binding",
 "extend", "kind_of?", "context", "gem", "to_yaml_properties", "quit", "popws", "irb", "to_s", "to_yaml", "irb_fg", "cla
ss", "hash", "private_methods", "=~", "tainted?", "include", "irb_cwws", "irb_change_binding", "irb_help", "untaint", "n
il?", "pushb", "exit", "irb_print_working_binding", "is_a?", "workspaces"]
irb(main):037:0>

我习惯了python,在这里我使用 dir() 函数来完成同样的事情:

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']
>>>

【问题讨论】:

    标签: ruby introspection irb


    【解决方案1】:

    我不完全确定您所说的“当前对象”是什么意思。正如已经提到的,您可以遍历 ObjectSpace。但这里有一些其他方法。

    local_variables
    instance_variables
    global_variables
    
    class_variables
    constants
    

    有一个问题。必须在正确的范围内调用它们。所以就在 IRB 中,或者在对象实例中或在类范围内(基本上到处都是),您可以调用前 3 个。

    local_variables #=> ["_"]
    foo = "bar"
    local_variables #=> ["_", "foo"]
    # Note: the _ variable in IRB contains the last value evaluated
    _ #=> "bar"
    
    instance_variables  #=> []
    @inst_var = 42
    instance_variables  #=> ["@inst_var"]
    
    global_variables    #=> ["$-d", "$\"", "$$", "$<", "$_", ...]
    $"                  #=> ["e2mmap.rb", "irb/init.rb", "irb/workspace.rb", ...]
    

    但是,嗯,如果您希望您的程序实际评估它们而不需要您多次键入它们怎么办?诀窍是评估。

    eval "@inst_var" #=> 42
    global_variables.each do |v|
      puts eval(v)
    end
    

    开头提到的 5 个中的最后 2 个必须在模块级别进行评估(类是模块的后代,因此有效)。

    Object.class_variables #=> []
    Object.constants #=> ["IO", "Duration", "UNIXserver", "Binding", ...]
    
    class MyClass
      A_CONST = 'pshh'
      class InnerClass
      end
      def initialize
        @@meh = "class_var"
      end
    end
    
    MyClass.constants           #=> ["A_CONST", "InnerClass"]
    MyClass.class_variables     #=> []
    mc = MyClass.new
    MyClass.class_variables     #=> ["@@meh"]
    MyClass.class_eval "@@meh"  #=> "class_var"
    

    这里还有一些技巧可以从不同的方向探索

    "".class            #=> String
    "".class.ancestors  #=> [String, Enumerable, Comparable, ...]
    String.ancestors    #=> [String, Enumerable, Comparable, ...]
    
    def trace
      return caller
    end
    trace #=> ["(irb):67:in `irb_binding'", "/System/Library/Frameworks/Ruby...", ...]
    

    【讨论】:

      【解决方案2】:

      ObjectSpace.each_object 可能就是您要找的。​​p>

      要获取包含的模块列表,您可以使用Module.included_modules

      您还可以使用object.respond_to?逐个检查对象是否响应方法。

      【讨论】:

        【解决方案3】:

        dir() 方法是 not clearly defined...

        注意:因为提供了dir() 主要是为了方便使用 一个交互式提示,它试图 提供一组有趣的名称 不仅仅是它试图提供一个 严格或一致定义的集合 名称及其详细行为 可能会因版本而异。

        ...但是我们可以在 Ruby 中创建一个近似值。让我们创建一个方法,该方法将返回由包含模块添加到我们范围内的所有方法的排序列表。我们可以通过included_modules方法获取已经包含的模块列表。

        dir(),我们想忽略“默认”方法(如print),我们还想关注“有趣”的名称集。因此,我们将忽略Kernel 中的方法,并且我们只会返回直接在模块中定义的方法,而忽略继承的方法。我们可以通过将false 传递给methods() 方法来完成后者。综上所述,我们得到...

        def included_methods(object=self)
          object = object.class if object.class != Class
          modules = (object.included_modules-[Kernel])
          modules.collect{ |mod| mod.methods(false)}.flatten.sort
        end
        

        您可以向它传递一个类、一个对象或什么都不传递(它默认为当前范围)。让我们试一试...

        irb(main):006:0> included_methods
        => []
        irb(main):007:0> include Math
        => Object
        irb(main):008:0> included_methods
        => ["acos", "acosh", "asin", "asinh", "atan", "atan2", "atanh", "cos", "cosh", "erf", "erfc", "exp", "frexp", "hypot", "ldexp", "log", "log10", "sin", "sinh", "sqrt", "tan", "tanh"]
        

        dir() 还包括本地定义的变量,这很容易。只要打电话...

        local_variables
        

        ...不幸的是,我们不能只将local_variables 调用添加到included_methods,因为它会给我们提供included_methods 方法的本地变量,这不会很有用。因此,如果您希望包含在 included_methods 中的局部变量,只需调用...

         (included_methods + local_variables).sort
        

        【讨论】:

        • 好的,我在慢慢学习。这就引出了我的下一个问题,“include”和“require”有什么区别?我会去阅读,但是如何查看通过“require”加载的方法?
        • 一个包含会将常量、方法和模块变量添加到当前范围。它通常用于向类添加功能。一个 require 加载另一个 ruby​​ 文件(如果它还没有被加载)。如果您想加载它(即使它已经加载),请改用“加载”方法。
        • 通常需要的文件会加载一个类。例如 require 'foo' 将加载 Foo 类。因此,您可以通过执行 Foo.methods(false) 来获取该类中的方法列表。如果需要的文件只是一堆方法: orig = Object.private_methods;需要'foo'; p Object.private_methods - 原始
        【解决方案4】:

        我为此写了一个 gem:

        $ gem install method_info
        $ rvm use 1.8.7 # (1.8.6 works but can be very slow for an object with a lot of methods)
        $ irb
        > require 'method_info'
        > 5.method_info
        ::: Fixnum :::
        %, &, *, **, +, -, -@, /, <, <<, <=, <=>, ==, >, >=, >>, [], ^, abs,
        div, divmod, even?, fdiv, id2name, modulo, odd?, power!, quo, rdiv,
        rpower, size, to_f, to_s, to_sym, zero?, |, ~
        ::: Integer :::
        ceil, chr, denominator, downto, floor, gcd, gcdlcm, integer?, lcm,
        next, numerator, ord, pred, round, succ, taguri, taguri=, times, to_i,
        to_int, to_r, to_yaml, truncate, upto
        ::: Precision :::
        prec, prec_f, prec_i
        ::: Numeric :::
        +@, coerce, eql?, nonzero?, pretty_print, pretty_print_cycle,
        remainder, singleton_method_added, step
        ::: Comparable :::
        between?
        ::: Object :::
        clone, to_yaml_properties, to_yaml_style, what?
        ::: MethodInfo::ObjectMethod :::
        method_info
        ::: Kernel :::
        ===, =~, __clone__, __id__, __send__, class, display, dup, enum_for,
        equal?, extend, freeze, frozen?, hash, id, inspect, instance_eval,
        instance_exec, instance_of?, instance_variable_defined?,
        instance_variable_get, instance_variable_set, instance_variables,
        is_a?, kind_of?, method, methods, nil?, object_id, pretty_inspect,
        private_methods, protected_methods, public_methods, respond_to?, ri,
        send, singleton_methods, taint, tainted?, tap, to_a, to_enum, type,
        untaint
         => nil
        

        我正在改进传递选项和设置默认值,但现在我建议您将以下内容添加到您的 .irbrc 文件中:

        require 'method_info'
        MethodInfo::OptionHandler.default_options = {
         :ancestors_to_exclude => [Object],
         :enable_colors => true
        }
        

        这会启用颜色并隐藏每个对象具有的方法,因为您通常对这些不感兴趣。

        【讨论】:

        • 我猜这不是问题的真正意义,但哦,jeebus 这就是我需要的 irb。 mixin 的广泛使用导致方法太多,使得 ruby​​ 库比 python 库更难探索,但这应该非常有助于解决这个问题。现在我只需要一个同样好的 help() 替代品。
        【解决方案5】:

        怎么样:

        Object.constants.select{|x| eval(x.to_s).class == Class}
        

        这为我列出了可用的课程。我不是红宝石专家,我被丢在红宝石控制台上,不知道手头有什么课程。一个班轮是一个开始。

        【讨论】:

        • 这让我很开心。谢谢。
        【解决方案6】:

        要访问 ruby​​ 中的所有对象实例,请使用 ObjectSpace

        http://www.ruby-doc.org/core-1.8.7/classes/ObjectSpace.html#M000928

        但是,这被认为很慢(即使对于 ruby​​),并且可能无法在某些解释器中启用(例如,jRuby 可以禁用 ObjectSpace,因为它在 jvm 中用于 gc 的速度要快得多,而无需在 jRuby 中跟踪这些东西)。

        【讨论】:

          【解决方案7】:

          您甚至可以在加载之前将 .methods 消息传递给库/模块,以查看所有可用的方法。执行self.methods 只会返回 Object 对象包含的所有方法。你可以通过self.class 看到这一点。因此,假设您想查看 File 模块中的所有方法。您只需执行File.methods,您将获得文件模块中存在的所有方法的列表。这也许不是您想要的,但它应该会有所帮助。

          【讨论】:

            猜你喜欢
            • 2022-10-04
            • 1970-01-01
            • 2017-07-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-07
            • 1970-01-01
            相关资源
            最近更新 更多