类 Object

Object 是所有 Ruby 对象的默认根类。 Object 继承自 BasicObject,这允许创建替代的对象层次结构。 Object 上的方法对所有类都可用,除非被明确覆盖。

Object 混合了 Kernel 模块,使内置的内核函数在全局范围内可用。尽管 Object 的实例方法是由 Kernel 模块定义的,但为了清晰起见,我们选择在这里记录它们。

在引用从 Object 继承的类中的常量时,您不需要使用完整的命名空间。例如,在 YourClass 中引用 File 将找到顶层的 File 类。

在 Object 方法的描述中,参数 symbol 指的是一个符号,它可以是一个带引号的字符串或一个 Symbol(例如 :name)。

内容

首先,看看其他地方。类 Object

这里,类 Object 提供了以下方法:

查询

实例变量

其他

常量

ARGF

ARGF 是一个流,专为处理作为命令行参数给出的文件或通过 STDIN 传入的文件的脚本而设计。

有关更多详细信息,请参阅 ARGF(类)。

ARGV

ARGV 包含用于运行 ruby 的命令行参数。

可以使用像 OptionParser 这样的库来处理命令行参数。

CROSS_COMPILING
DATA

DATA 是一个 File,其中包含执行文件的 data 部分。要创建 data 部分,请使用 __END__

$ cat t.rb
puts DATA.gets
__END__
hello world!

$ ruby t.rb
hello world!
ENV

ENV 是环境变量的类似 Hash 的访问器。

有关更多详细信息,请参阅 ENV(类)。

ruby 的版权字符串

RUBY_DESCRIPTION

完整的 ruby 版本字符串,例如 ruby -v 打印

RUBY_ENGINE

此 ruby 使用的引擎或解释器。

RUBY_ENGINE_VERSION

此 ruby 使用的引擎或解释器的版本。

RUBY_PATCHLEVEL

此 ruby 的补丁级别。如果这是 ruby 的开发版本,则补丁级别将为 -1

RUBY_PLATFORM

此 ruby 的平台

RUBY_RELEASE_DATE

此 ruby 发布的日期

RUBY_REVISION

此 ruby 的 GIT 提交哈希。

RUBY_VERSION

正在运行的 ruby 版本

Readline
RubyLex
STDERR

保存原始 stderr

STDIN

保存原始 stdin

STDOUT

保存原始 stdout

TOPLEVEL_BINDING

顶层作用域的 Binding

WIN32OLE_EVENT
WIN32OLE_METHOD
WIN32OLE_PARAM
WIN32OLE_RECORD
WIN32OLE_TYPE
WIN32OLE_TYPELIB
WIN32OLE_VARIABLE
WIN32OLE_VARIANT

公共类方法

yaml_tag(url) 点击切换源代码
# File ext/psych/lib/psych/core_ext.rb, line 3
def self.yaml_tag url
  Psych.add_tag(url, self)
end

公共实例方法

obj !~ other → true 或 false 点击切换源代码

如果两个对象不匹配(使用 =~ 方法),则返回 true,否则返回 false。

static VALUE
rb_obj_not_match(VALUE obj1, VALUE obj2)
{
    VALUE result = rb_funcall(obj1, id_match, 1, obj2);
    return rb_obj_not(result);
}
obj <=> other → 0 或 nil 点击切换源代码

如果 objother 是同一个对象或 obj == other,则返回 0,否则返回 nil。

The <=> 用于各种方法比较对象,例如 Enumerable#sortEnumerable#max 等。

您对 <=> 的实现应该返回以下值之一:-1、0、1 或 nil。-1 表示 self 小于 other。0 表示 self 等于 other。1 表示 self 大于 other。Nil 表示两个值无法比较。

当您定义 <=> 时,您可以包含 Comparable 以获得方法 <=、<、==、>=、> 和 between?

static VALUE
rb_obj_cmp(VALUE obj1, VALUE obj2)
{
    if (rb_equal(obj1, obj2))
        return INT2FIX(0);
    return Qnil;
}
true === other → true 或 false 点击切换源代码
false === other → true 或 false
nil === other → true 或 false

返回 truefalse

Object#== 类似,如果 objectObject 的实例(而不是其众多子类之一的实例)。

此方法通常被这些子类覆盖,以在 case 语句中提供有意义的语义。

#define case_equal rb_equal
CSV(*args, **options, &block) 点击切换源代码

args 传递给 CSV::instance

CSV("CSV,data").read
  #=> [["CSV", "data"]]

如果给定一个代码块,则将实例传递给代码块,并且返回值将成为代码块的返回值。

CSV("CSV,data") { |c|
  c.read.any? { |a| a.include?("data") }
} #=> true

CSV("CSV,data") { |c|
  c.read.any? { |a| a.include?("zombies") }
} #=> false

也可以给出 CSV 选项。

io = StringIO.new
CSV(io, col_sep: ";") { |csv| csv << ["a", "b", "c"] }

此 API 不支持 Ractor。

# File lib/csv.rb, line 2876
def CSV(*args, **options, &block)
  CSV.instance(*args, **options, &block)
end
DelegateClass(superclass, &block) 点击切换源代码

此库的主要接口。用于在定义类时设置委托。

class MyClass < DelegateClass(ClassToDelegateTo) # Step 1
  def initialize
    super(obj_of_ClassToDelegateTo)              # Step 2
  end
end

MyClass = DelegateClass(ClassToDelegateTo) do    # Step 1
  def initialize
    super(obj_of_ClassToDelegateTo)              # Step 2
  end
end

以下是从 Tempfile 中使用的示例,它实际上是一个 File 对象,但对存储位置和何时应删除 File 有几个特殊规则。这使得它成为使用委托的教科书式完美示例。

class Tempfile < DelegateClass(File)
  # constant and class member data initialization...

  def initialize(basename, tmpdir=Dir::tmpdir)
    # build up file path/name in var tmpname...

    @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)

    # ...

    super(@tmpfile)

    # below this point, all methods of File are supported...
  end

  # ...
end
调用超类方法
# File lib/delegate.rb, line 394
def DelegateClass(superclass, &block)
  klass = Class.new(Delegator)
  ignores = [*::Delegator.public_api, :to_s, :inspect, :=~, :!~, :===]
  protected_instance_methods = superclass.protected_instance_methods
  protected_instance_methods -= ignores
  public_instance_methods = superclass.public_instance_methods
  public_instance_methods -= ignores
  klass.module_eval do
    def __getobj__ # :nodoc:
      unless defined?(@delegate_dc_obj)
        return yield if block_given?
        __raise__ ::ArgumentError, "not delegated"
      end
      @delegate_dc_obj
    end
    def __setobj__(obj)  # :nodoc:
      __raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj)
      @delegate_dc_obj = obj
    end
    protected_instance_methods.each do |method|
      define_method(method, Delegator.delegating_block(method))
      protected method
    end
    public_instance_methods.each do |method|
      define_method(method, Delegator.delegating_block(method))
    end
  end
  klass.define_singleton_method :public_instance_methods do |all=true|
    super(all) | superclass.public_instance_methods
  end
  klass.define_singleton_method :protected_instance_methods do |all=true|
    super(all) | superclass.protected_instance_methods
  end
  klass.define_singleton_method :instance_methods do |all=true|
    super(all) | superclass.instance_methods
  end
  klass.define_singleton_method :public_instance_method do |name|
    super(name)
  rescue NameError
    raise unless self.public_instance_methods.include?(name)
    superclass.public_instance_method(name)
  end
  klass.define_singleton_method :instance_method do |name|
    super(name)
  rescue NameError
    raise unless self.instance_methods.include?(name)
    superclass.instance_method(name)
  end
  klass.module_eval(&block) if block
  return klass
end
Digest(name) → digest_subclass 点击切换源代码

以线程安全的方式通过 name 返回一个 Digest 子类,即使涉及按需加载。

require 'digest'

Digest("MD5")
# => Digest::MD5

Digest(:SHA256)
# => Digest::SHA256

Digest(:Foo)
# => LoadError: library not found for class Digest::Foo -- digest/foo
# File ext/digest/lib/digest.rb, line 110
def Digest(name)
  const = name.to_sym
  Digest::REQUIRE_MUTEX.synchronize {
    # Ignore autoload's because it is void when we have #const_missing
    Digest.const_missing(const)
  }
rescue LoadError
  # Constants do not necessarily rely on digest/*.
  if Digest.const_defined?(const)
    Digest.const_get(const)
  else
    raise
  end
end
define_singleton_method(symbol, method) → symbol 点击切换源代码
define_singleton_method(symbol) { block } → symbol

在接收者中定义一个公共单例方法。method 参数可以是 ProcMethodUnboundMethod 对象。如果指定了块,则将其用作方法体。如果块或方法具有参数,则将其用作方法参数。

class A
  class << self
    def class_name
      to_s
    end
  end
end
A.define_singleton_method(:who_am_i) do
  "I am: #{class_name}"
end
A.who_am_i   # ==> "I am: A"

guy = "Bob"
guy.define_singleton_method(:hello) { "#{self}: Hello there!" }
guy.hello    #=>  "Bob: Hello there!"

chris = "Chris"
chris.define_singleton_method(:greet) {|greeting| "#{greeting}, I'm Chris!" }
chris.greet("Hi") #=> "Hi, I'm Chris!"
static VALUE
rb_obj_define_method(int argc, VALUE *argv, VALUE obj)
{
    VALUE klass = rb_singleton_class(obj);
    const rb_scope_visibility_t scope_visi = {METHOD_VISI_PUBLIC, FALSE};

    return rb_mod_define_method_with_visibility(argc, argv, klass, &scope_visi);
}
display(port = $>) → nil 点击切换源代码

在给定端口上写入 self

1.display
"cat".display
[ 4, 5, 6 ].display
puts

输出

1cat[4, 5, 6]
static VALUE
rb_obj_display(int argc, VALUE *argv, VALUE self)
{
    VALUE out;

    out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
    rb_io_write(out, self);

    return Qnil;
}
dup → an_object 点击切换源代码

生成obj的浅拷贝——obj的实例变量被复制,但它们引用的对象没有被复制。

此方法可能具有特定于类的行为。如果是这样,该行为将在类的 #initialize_copy 方法下进行记录。

关于 dup 与 clone

通常,clonedup 在子类中可能具有不同的语义。虽然 clone 用于复制对象,包括其内部状态,但 dup 通常使用子类对象的类来创建新实例。

使用 dup 时,不会复制对象已扩展的任何模块。

class Klass
  attr_accessor :str
end

module Foo
  def foo; 'foo'; end
end

s1 = Klass.new #=> #<Klass:0x401b3a38>
s1.extend(Foo) #=> #<Klass:0x401b3a38>
s1.foo #=> "foo"

s2 = s1.clone #=> #<Klass:0x401be280>
s2.foo #=> "foo"

s3 = s1.dup #=> #<Klass:0x401c1084>
s3.foo #=> NoMethodError: undefined method `foo' for #<Klass:0x401c1084>
VALUE
rb_obj_dup(VALUE obj)
{
    VALUE dup;

    if (special_object_p(obj)) {
        return obj;
    }
    dup = rb_obj_alloc(rb_obj_class(obj));
    return rb_obj_dup_setup(obj, dup);
}
enum_for(method = :each, *args) → enum
enum_for(method = :each, *args){|*args| block} → enum

创建一个新的 Enumerator,它将通过在 obj 上调用 method 来枚举,如果存在,则传递 args。方法yield的内容成为枚举器的值。

如果给定块,它将用于计算枚举器的大小,而无需迭代它(参见 Enumerator#size)。

示例

str = "xyz"

enum = str.enum_for(:each_byte)
enum.each { |b| puts b }
# => 120
# => 121
# => 122

# protect an array from being modified by some_method
a = [1, 2, 3]
some_method(a.to_enum)

# String#split in block form is more memory-effective:
very_large_string.split("|") { |chunk| return chunk if chunk.include?('DATE') }
# This could be rewritten more idiomatically with to_enum:
very_large_string.to_enum(:split, "|").lazy.grep(/DATE/).first

在为泛型 Enumerable 定义方法时,通常会在没有传递块的情况下调用 to_enum

以下是一个示例,包含参数传递和大小块

module Enumerable
  # a generic method to repeat the values of any enumerable
  def repeat(n)
    raise ArgumentError, "#{n} is negative!" if n < 0
    unless block_given?
      return to_enum(__method__, n) do # __method__ is :repeat here
        sz = size     # Call size and multiply by n...
        sz * n if sz  # but return nil if size itself is nil
      end
    end
    each do |*val|
      n.times { yield *val }
    end
  end
end

%i[hello world].repeat(2) { |w| puts w }
  # => Prints 'hello', 'hello', 'world', 'world'
enum = (1..14).repeat(3)
  # => returns an Enumerator when called without a block
enum.first(4) # => [1, 1, 1, 2]
enum.size # => 42
别名:to_enum
obj == other → true 或 false 点击切换源代码
equal?(other) → true 或 false
eql?(other) → true 或 false

相等性 - 在 Object 级别,== 仅当 objother 是同一个对象时才返回 true。通常,此方法在子类中被重写以提供特定于类的含义。

== 不同,equal? 方法不应被子类重写,因为它用于确定对象标识(即,a.equal?(b) 当且仅当 ab 是同一个对象时)。

obj = "a"
other = obj.dup

obj == other      #=> true
obj.equal? other  #=> false
obj.equal? obj    #=> true

eql? 方法如果 objother 指向同一个哈希键,则返回 true。这由 Hash 用于测试成员的相等性。对于任何一对 eql? 返回 true 的对象,这两个对象的 hash 值必须相等。因此,任何重写 eql? 的子类也应该相应地重写 hash

对于 Object 类的对象,eql? 等同于 ==。子类通常通过将 eql? 设为其重写的 == 方法的别名来延续这一传统,但也有例外。例如,Numeric 类型在 == 中执行类型转换,但在 eql? 中不执行类型转换,因此

1 == 1.0     #=> true
1.eql? 1.0   #=> false
VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
    return RBOOL(obj1 == obj2);
}
extend(module, ...) → obj 点击切换源代码

将参数中给出的每个模块的实例方法添加到obj中。

module Mod
  def hello
    "Hello from Mod.\n"
  end
end

class Klass
  def hello
    "Hello from Klass.\n"
  end
end

k = Klass.new
k.hello         #=> "Hello from Klass.\n"
k.extend(Mod)   #=> #<Klass:0x401b3bc8>
k.hello         #=> "Hello from Mod.\n"
static VALUE
rb_obj_extend(int argc, VALUE *argv, VALUE obj)
{
    int i;
    ID id_extend_object, id_extended;

    CONST_ID(id_extend_object, "extend_object");
    CONST_ID(id_extended, "extended");

    rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
    for (i = 0; i < argc; i++) {
        Check_Type(argv[i], T_MODULE);
        if (FL_TEST(argv[i], RMODULE_IS_REFINEMENT)) {
            rb_raise(rb_eTypeError, "Cannot extend object with refinement");
        }
    }
    while (argc--) {
        rb_funcall(argv[argc], id_extend_object, 1, obj);
        rb_funcall(argv[argc], id_extended, 1, obj);
    }
    return obj;
}
freeze → obj 点击切换源代码

阻止对obj的进一步修改。如果尝试修改,将引发 FrozenError。无法解冻已冻结的对象。另请参见 Object#frozen?

此方法返回自身。

a = [ "a", "b", "c" ]
a.freeze
a << "z"

产生

prog.rb:3:in `<<': can't modify frozen Array (FrozenError)
 from prog.rb:3

以下类的对象始终被冻结:IntegerFloatSymbol

VALUE
rb_obj_freeze(VALUE obj)
{
    if (!OBJ_FROZEN(obj)) {
        OBJ_FREEZE(obj);
        if (SPECIAL_CONST_P(obj)) {
            rb_bug("special consts should be frozen.");
        }
    }
    return obj;
}
hash → integer 点击切换源代码

为该对象生成一个 Integer 哈希值。此函数必须具有以下属性:a.eql?(b) 意味着 a.hash == b.hash

哈希值与 eql? 一起由 Hash 类使用,以确定两个对象是否引用相同的哈希键。任何超过 Integer 容量的哈希值将在使用前被截断。

对象的哈希值可能在 Ruby 的调用或实现之间不相同。如果您需要跨 Ruby 调用和实现的稳定标识符,则需要使用自定义方法生成一个。

某些核心类(例如 Integer)使用内置的哈希计算,并且在用作哈希键时不会调用 hash 方法。

在基于多个值实现自己的 hash 时,最佳实践是使用数组的哈希码组合类和任何值

例如

def hash
  [self.class, a, b, c].hash
end

这样做的原因是 Array#hash 方法已经具有安全有效地组合多个哈希值的逻辑。

VALUE
rb_obj_hash(VALUE obj)
{
    long hnum = any_hash(obj, objid_hash);
    return ST2FIX(hnum);
}
inspect → string 点击切换源代码

返回一个包含obj的人类可读表示的字符串。默认的 inspect 显示对象的类名、其内存地址的编码以及实例变量及其值的列表(通过对每个实例变量调用 inspect)。用户定义的类应该覆盖此方法,以提供obj的更好表示。在覆盖此方法时,它应该返回一个编码与默认外部编码兼容的字符串。

[ 1, 2, 3..4, 'five' ].inspect   #=> "[1, 2, 3..4, \"five\"]"
Time.new.inspect                 #=> "2008-03-08 19:43:39 +0900"

class Foo
end
Foo.new.inspect                  #=> "#<Foo:0x0300c868>"

class Bar
  def initialize
    @bar = 1
  end
end
Bar.new.inspect                  #=> "#<Bar:0x0300c868 @bar=1>"
static VALUE
rb_obj_inspect(VALUE obj)
{
    if (rb_ivar_count(obj) > 0) {
        VALUE str;
        VALUE c = rb_class_name(CLASS_OF(obj));

        str = rb_sprintf("-<%"PRIsVALUE":%p", c, (void*)obj);
        return rb_exec_recursive(inspect_obj, obj, str);
    }
    else {
        return rb_any_to_s(obj);
    }
}
instance_of?(class) → true or false 点击切换源代码

如果obj是给定类的实例,则返回true。另请参见 Object#kind_of?

class A;     end
class B < A; end
class C < B; end

b = B.new
b.instance_of? A   #=> false
b.instance_of? B   #=> true
b.instance_of? C   #=> false
VALUE
rb_obj_is_instance_of(VALUE obj, VALUE c)
{
    c = class_or_module_required(c);
    return RBOOL(rb_obj_class(obj) == c);
}
instance_variable_defined?(symbol) → true 或 false 点击切换源代码
instance_variable_defined?(string) → true 或 false

如果给定的实例变量在 obj 中定义,则返回 trueString 参数将转换为符号。

class Fred
  def initialize(p1, p2)
    @a, @b = p1, p2
  end
end
fred = Fred.new('cat', 99)
fred.instance_variable_defined?(:@a)    #=> true
fred.instance_variable_defined?("@b")   #=> true
fred.instance_variable_defined?("@c")   #=> false
static VALUE
rb_obj_ivar_defined(VALUE obj, VALUE iv)
{
    ID id = id_for_var(obj, iv, instance);

    if (!id) {
        return Qfalse;
    }
    return rb_ivar_defined(obj, id);
}
instance_variable_get(symbol) → obj 点击切换源代码
instance_variable_get(string) → obj

返回给定实例变量的值,如果实例变量未设置,则返回 nil。 对于常规实例变量,应包含变量名称的 @ 部分。 如果提供的符号不是有效的实例变量名称,则会抛出 NameError 异常。 String 参数将转换为符号。

class Fred
  def initialize(p1, p2)
    @a, @b = p1, p2
  end
end
fred = Fred.new('cat', 99)
fred.instance_variable_get(:@a)    #=> "cat"
fred.instance_variable_get("@b")   #=> 99
static VALUE
rb_obj_ivar_get(VALUE obj, VALUE iv)
{
    ID id = id_for_var(obj, iv, instance);

    if (!id) {
        return Qnil;
    }
    return rb_ivar_get(obj, id);
}
instance_variable_set(symbol, obj) → obj 点击切换源代码
instance_variable_set(string, obj) → obj

symbol 指定的实例变量设置为给定的对象。 这可能会绕过类作者的封装意图,因此应谨慎使用。 变量不必在此调用之前存在。 如果实例变量名称作为字符串传递,则该字符串将转换为符号。

class Fred
  def initialize(p1, p2)
    @a, @b = p1, p2
  end
end
fred = Fred.new('cat', 99)
fred.instance_variable_set(:@a, 'dog')   #=> "dog"
fred.instance_variable_set(:@c, 'cat')   #=> "cat"
fred.inspect                             #=> "#<Fred:0x401b3da8 @a=\"dog\", @b=99, @c=\"cat\">"
static VALUE
rb_obj_ivar_set_m(VALUE obj, VALUE iv, VALUE val)
{
    ID id = id_for_var(obj, iv, instance);
    if (!id) id = rb_intern_str(iv);
    return rb_ivar_set(obj, id, val);
}
instance_variables → array 点击切换源代码

返回接收者的实例变量名称数组。 请注意,仅仅定义一个访问器不会创建相应的实例变量。

class Fred
  attr_accessor :a1
  def initialize
    @iv = 3
  end
end
Fred.new.instance_variables   #=> [:@iv]
VALUE
rb_obj_instance_variables(VALUE obj)
{
    VALUE ary;

    ary = rb_ary_new();
    rb_ivar_foreach(obj, ivar_i, ary);
    return ary;
}
is_a?(class) → true 或 false

如果 classobj 的类,或者 classobj 的超类之一或包含在 obj 中的模块,则返回 true

module M;    end
class A
  include M
end
class B < A; end
class C < B; end

b = B.new
b.is_a? A          #=> true
b.is_a? B          #=> true
b.is_a? C          #=> false
b.is_a? M          #=> true

b.kind_of? A       #=> true
b.kind_of? B       #=> true
b.kind_of? C       #=> false
b.kind_of? M       #=> true
别名:kind_of?
itself → obj 点击切换源代码

返回接收者。

string = "my string"
string.itself.object_id == string.object_id   #=> true
static VALUE
rb_obj_itself(VALUE obj)
{
    return obj;
}
kind_of?(class) → true 或 false 点击切换源代码

如果 classobj 的类,或者 classobj 的超类之一或包含在 obj 中的模块,则返回 true

module M;    end
class A
  include M
end
class B < A; end
class C < B; end

b = B.new
b.is_a? A          #=> true
b.is_a? B          #=> true
b.is_a? C          #=> false
b.is_a? M          #=> true

b.kind_of? A       #=> true
b.kind_of? B       #=> true
b.kind_of? C       #=> false
b.kind_of? M       #=> true
VALUE
rb_obj_is_kind_of(VALUE obj, VALUE c)
{
    VALUE cl = CLASS_OF(obj);

    RUBY_ASSERT(RB_TYPE_P(cl, T_CLASS));

    // Fastest path: If the object's class is an exact match we know `c` is a
    // class without checking type and can return immediately.
    if (cl == c) return Qtrue;

    // Note: YJIT needs this function to never allocate and never raise when
    // `c` is a class or a module.

    if (LIKELY(RB_TYPE_P(c, T_CLASS))) {
        // Fast path: Both are T_CLASS
        return class_search_class_ancestor(cl, c);
    }
    else if (RB_TYPE_P(c, T_ICLASS)) {
        // First check if we inherit the includer
        // If we do we can return true immediately
        VALUE includer = RCLASS_INCLUDER(c);
        if (cl == includer) return Qtrue;

        // Usually includer is a T_CLASS here, except when including into an
        // already included Module.
        // If it is a class, attempt the fast class-to-class check and return
        // true if there is a match.
        if (RB_TYPE_P(includer, T_CLASS) && class_search_class_ancestor(cl, includer))
            return Qtrue;

        // We don't include the ICLASS directly, so must check if we inherit
        // the module via another include
        return RBOOL(class_search_ancestor(cl, RCLASS_ORIGIN(c)));
    }
    else if (RB_TYPE_P(c, T_MODULE)) {
        // Slow path: check each ancestor in the linked list and its method table
        return RBOOL(class_search_ancestor(cl, RCLASS_ORIGIN(c)));
    }
    else {
        rb_raise(rb_eTypeError, "class or module required");
        UNREACHABLE_RETURN(Qfalse);
    }
}
也称为:is_a?
method(sym) → method 点击切换源代码

obj中查找名为方法的接收器,返回一个Method对象(或引发NameError)。Method对象在obj的对象实例中充当闭包,因此实例变量和self的值仍然可用。

class Demo
  def initialize(n)
    @iv = n
  end
  def hello()
    "Hello, @iv = #{@iv}"
  end
end

k = Demo.new(99)
m = k.method(:hello)
m.call   #=> "Hello, @iv = 99"

l = Demo.new('Fred')
m = l.method("hello")
m.call   #=> "Hello, @iv = Fred"

请注意,Method实现了to_proc方法,这意味着它可以与迭代器一起使用。

[ 1, 2, 3 ].each(&method(:puts)) # => prints 3 lines to stdout

out = File.open('test.txt', 'w')
[ 1, 2, 3 ].each(&out.method(:puts)) # => prints 3 lines to file

require 'date'
%w[2017-03-01 2017-03-02].collect(&Date.method(:parse))
#=> [#<Date: 2017-03-01 ((2457814j,0s,0n),+0s,2299161j)>, #<Date: 2017-03-02 ((2457815j,0s,0n),+0s,2299161j)>]
VALUE
rb_obj_method(VALUE obj, VALUE vid)
{
    return obj_method(obj, vid, FALSE);
}
methods(regular=true) → array click to toggle source

返回obj的公共和受保护方法的名称列表。这将包括obj的祖先中可访问的所有方法。如果可选参数为false,则返回obj的公共和受保护单例方法的数组,该数组不包括obj中包含的模块中的方法。

class Klass
  def klass_method()
  end
end
k = Klass.new
k.methods[0..9]    #=> [:klass_method, :nil?, :===,
                   #    :==~, :!, :eql?
                   #    :hash, :<=>, :class, :singleton_class]
k.methods.length   #=> 56

k.methods(false)   #=> []
def k.singleton_method; end
k.methods(false)   #=> [:singleton_method]

module M123; def m123; end end
k.extend M123
k.methods(false)   #=> [:singleton_method]
VALUE
rb_obj_methods(int argc, const VALUE *argv, VALUE obj)
{
    rb_check_arity(argc, 0, 1);
    if (argc > 0 && !RTEST(argv[0])) {
        return rb_obj_singleton_methods(argc, argv, obj);
    }
    return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_i);
}
nil? → true or false click to toggle source

只有nil对象对nil?响应true

Object.new.nil?   #=> false
nil.nil?          #=> true
VALUE
rb_false(VALUE obj)
{
    return Qfalse;
}
__id__ → integer click to toggle source
object_id → integer

返回obj的整数标识符。

对于给定对象,对object_id的所有调用都将返回相同的数字,并且没有两个活动对象将共享一个id。

注意:为了优化,某些内置类对象会被重复使用。对于立即值和冻结字符串文字来说就是这样。

BasicObject实现了__id__Kernel实现了object_id

立即值不是通过引用传递,而是通过值传递:niltruefalse、Fixnums、Symbols和一些Floats。

Object.new.object_id  == Object.new.object_id  # => false
(21 * 2).object_id    == (21 * 2).object_id    # => true
"hello".object_id     == "hello".object_id     # => false
"hi".freeze.object_id == "hi".freeze.object_id # => true
VALUE
rb_obj_id(VALUE obj)
{
    /*
     *                32-bit VALUE space
     *          MSB ------------------------ LSB
     *  false   00000000000000000000000000000000
     *  true    00000000000000000000000000000010
     *  nil     00000000000000000000000000000100
     *  undef   00000000000000000000000000000110
     *  symbol  ssssssssssssssssssssssss00001110
     *  object  oooooooooooooooooooooooooooooo00        = 0 (mod sizeof(RVALUE))
     *  fixnum  fffffffffffffffffffffffffffffff1
     *
     *                    object_id space
     *                                       LSB
     *  false   00000000000000000000000000000000
     *  true    00000000000000000000000000000010
     *  nil     00000000000000000000000000000100
     *  undef   00000000000000000000000000000110
     *  symbol   000SSSSSSSSSSSSSSSSSSSSSSSSSSS0        S...S % A = 4 (S...S = s...s * A + 4)
     *  object   oooooooooooooooooooooooooooooo0        o...o % A = 0
     *  fixnum  fffffffffffffffffffffffffffffff1        bignum if required
     *
     *  where A = sizeof(RVALUE)/4
     *
     *  sizeof(RVALUE) is
     *  20 if 32-bit, double is 4-byte aligned
     *  24 if 32-bit, double is 8-byte aligned
     *  40 if 64-bit
     */

    return rb_find_object_id(obj, cached_object_id);
}
private_methods(all=true) → array click to toggle source

返回obj可访问的私有方法列表。如果all参数设置为false,则只列出接收器中的那些方法。

VALUE
rb_obj_private_methods(int argc, const VALUE *argv, VALUE obj)
{
    return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_priv_i);
}
protected_methods(all=true) → array click to toggle source

返回obj可访问的受保护方法列表。如果all参数设置为false,则只列出接收器中的那些方法。

VALUE
rb_obj_protected_methods(int argc, const VALUE *argv, VALUE obj)
{
    return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_prot_i);
}
public_method(sym) → method 点击切换源代码

类似于 method,仅搜索公共方法。

VALUE
rb_obj_public_method(VALUE obj, VALUE vid)
{
    return obj_method(obj, vid, TRUE);
}
public_methods(all=true) → array 点击切换源代码

返回 obj 可访问的公共方法列表。如果 all 参数设置为 false,则只列出接收器中的方法。

VALUE
rb_obj_public_methods(int argc, const VALUE *argv, VALUE obj)
{
    return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_pub_i);
}
public_send(symbol [, args...]) → obj 点击切换源代码
public_send(string [, args...]) → obj

调用由 symbol 标识的方法,并将任何指定的参数传递给它。与 send 不同,public_send 仅调用公共方法。当方法由字符串标识时,字符串将转换为符号。

1.public_send(:puts, "hello")  # causes NoMethodError
static VALUE
rb_f_public_send(int argc, VALUE *argv, VALUE recv)
{
    return send_internal_kw(argc, argv, recv, CALL_PUBLIC);
}
remove_instance_variable(symbol) → obj 点击切换源代码
remove_instance_variable(string) → obj

obj 中删除命名的实例变量,并返回该变量的值。 String 参数将转换为符号。

class Dummy
  attr_reader :var
  def initialize
    @var = 99
  end
  def remove
    remove_instance_variable(:@var)
  end
end
d = Dummy.new
d.var      #=> 99
d.remove   #=> 99
d.var      #=> nil
VALUE
rb_obj_remove_instance_variable(VALUE obj, VALUE name)
{
    const ID id = id_for_var(obj, name, an, instance);

    // Frozen check comes here because it's expected that we raise a
    // NameError (from the id_for_var check) before we raise a FrozenError
    rb_check_frozen(obj);

    if (id) {
        VALUE val = rb_ivar_delete(obj, id, Qundef);

        if (val != Qundef) return val;
    }

    rb_name_err_raise("instance variable %1$s not defined",
                      obj, name);
    UNREACHABLE_RETURN(Qnil);
}
respond_to?(symbol, include_all=false) → true or false 点击切换源代码
respond_to?(string, include_all=false) → true or false

如果 obj 响应给定方法,则返回 true。只有当可选的第二个参数计算结果为 true 时,私有和受保护的方法才会包含在搜索中。

如果方法未实现,例如 Windows 上的 Process.fork,GNU/Linux 上的 File.lchmod 等,则返回 false。

如果方法未定义,则调用 respond_to_missing? 方法并返回结果。

当方法名称参数以字符串形式给出时,字符串将转换为符号。

static VALUE
obj_respond_to(int argc, VALUE *argv, VALUE obj)
{
    VALUE mid, priv;
    ID id;
    rb_execution_context_t *ec = GET_EC();

    rb_scan_args(argc, argv, "11", &mid, &priv);
    if (!(id = rb_check_id(&mid))) {
        VALUE ret = basic_obj_respond_to_missing(ec, CLASS_OF(obj), obj,
                                                 rb_to_symbol(mid), priv);
        if (UNDEF_P(ret)) ret = Qfalse;
        return ret;
    }
    return  RBOOL(basic_obj_respond_to(ec, obj, id, !RTEST(priv)));
}
respond_to_missing?(symbol, include_all) → true or false 点击切换源代码
respond_to_missing?(string, include_all) → true or false

不要直接使用此方法。

挂钩方法,用于返回 obj 是否可以响应 id 方法。

当方法名称参数以字符串形式给出时,字符串将转换为符号。

参见 respond_to?BasicObject 的示例。

static VALUE
obj_respond_to_missing(VALUE obj, VALUE mid, VALUE priv)
{
    return Qfalse;
}
send(symbol [, args...]) → obj 点击切换源代码
__send__(symbol [, args...]) → obj
send(string [, args...]) → obj
__send__(string [, args...]) → obj

调用由symbol标识的方法,并将指定的任何参数传递给它。当方法由字符串标识时,字符串将被转换为符号。

BasicObject 实现 __send__Kernel 实现 send。当obj具有与Socket相同的名称时,__send__send 更安全。另请参见 public_send

class Klass
  def hello(*args)
    "Hello " + args.join(' ')
  end
end
k = Klass.new
k.send :hello, "gentle", "readers"   #=> "Hello gentle readers"
VALUE
rb_f_send(int argc, VALUE *argv, VALUE recv)
{
    return send_internal_kw(argc, argv, recv, CALL_FCALL);
}
singleton_class → class 点击切换源代码

返回obj的单例类。如果obj没有单例类,此方法将创建一个新的单例类。

如果objniltruefalse,它将分别返回NilClassTrueClassFalseClass。如果objIntegerFloatSymbol,它将引发TypeError

Object.new.singleton_class  #=> #<Class:#<Object:0xb7ce1e24>>
String.singleton_class      #=> #<Class:String>
nil.singleton_class         #=> NilClass
static VALUE
rb_obj_singleton_class(VALUE obj)
{
    return rb_singleton_class(obj);
}
singleton_method(sym) → method 点击切换源代码

类似于method,仅搜索单例方法。

class Demo
  def initialize(n)
    @iv = n
  end
  def hello()
    "Hello, @iv = #{@iv}"
  end
end

k = Demo.new(99)
def k.hi
  "Hi, @iv = #{@iv}"
end
m = k.singleton_method(:hi)
m.call   #=> "Hi, @iv = 99"
m = k.singleton_method(:hello) #=> NameError
VALUE
rb_obj_singleton_method(VALUE obj, VALUE vid)
{
    VALUE klass = rb_singleton_class_get(obj);
    ID id = rb_check_id(&vid);

    if (NIL_P(klass) ||
        NIL_P(klass = RCLASS_ORIGIN(klass)) ||
        !NIL_P(rb_special_singleton_class(obj))) {
        /* goto undef; */
    }
    else if (! id) {
        VALUE m = mnew_missing_by_name(klass, obj, &vid, FALSE, rb_cMethod);
        if (m) return m;
        /* else goto undef; */
    }
    else {
        const rb_method_entry_t *me = rb_method_entry_at(klass, id);
        vid = ID2SYM(id);

        if (UNDEFINED_METHOD_ENTRY_P(me)) {
            /* goto undef; */
        }
        else if (UNDEFINED_REFINED_METHOD_P(me->def)) {
            /* goto undef; */
        }
        else {
            return mnew_from_me(me, klass, klass, obj, id, rb_cMethod, FALSE);
        }
    }

  /* undef: */
    rb_name_err_raise("undefined singleton method `%1$s' for `%2$s'",
                      obj, vid);
    UNREACHABLE_RETURN(Qundef);
}
singleton_methods(all=true) → array 点击切换源代码

返回obj的单例方法名称数组。如果可选的all参数为true,则列表将包含包含在obj中的模块中的方法。仅返回公共和受保护的单例方法。

module Other
  def three() end
end

class Single
  def Single.four() end
end

a = Single.new

def a.one()
end

class << a
  include Other
  def two()
  end
end

Single.singleton_methods    #=> [:four]
a.singleton_methods(false)  #=> [:two, :one]
a.singleton_methods         #=> [:two, :one, :three]
VALUE
rb_obj_singleton_methods(int argc, const VALUE *argv, VALUE obj)
{
    VALUE ary, klass, origin;
    struct method_entry_arg me_arg;
    struct rb_id_table *mtbl;
    int recur = TRUE;

    if (rb_check_arity(argc, 0, 1)) recur = RTEST(argv[0]);
    if (RB_TYPE_P(obj, T_CLASS) && FL_TEST(obj, FL_SINGLETON)) {
        rb_singleton_class(obj);
    }
    klass = CLASS_OF(obj);
    origin = RCLASS_ORIGIN(klass);
    me_arg.list = st_init_numtable();
    me_arg.recur = recur;
    if (klass && FL_TEST(klass, FL_SINGLETON)) {
        if ((mtbl = RCLASS_M_TBL(origin)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg);
        klass = RCLASS_SUPER(klass);
    }
    if (recur) {
        while (klass && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) {
            if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg);
            klass = RCLASS_SUPER(klass);
        }
    }
    ary = rb_ary_new2(me_arg.list->num_entries);
    st_foreach(me_arg.list, ins_methods_i, ary);
    st_free_table(me_arg.list);

    return ary;
}
to_enum(method = :each, *args) → enum 点击切换源代码
to_enum(method = :each, *args) {|*args| block} → enum

创建一个新的 Enumerator,它将通过在 obj 上调用 method 来枚举,如果存在,则传递 args。方法yield的内容成为枚举器的值。

如果给定块,它将用于计算枚举器的大小,而无需迭代它(参见 Enumerator#size)。

示例

str = "xyz"

enum = str.enum_for(:each_byte)
enum.each { |b| puts b }
# => 120
# => 121
# => 122

# protect an array from being modified by some_method
a = [1, 2, 3]
some_method(a.to_enum)

# String#split in block form is more memory-effective:
very_large_string.split("|") { |chunk| return chunk if chunk.include?('DATE') }
# This could be rewritten more idiomatically with to_enum:
very_large_string.to_enum(:split, "|").lazy.grep(/DATE/).first

在为泛型 Enumerable 定义方法时,通常会在没有传递块的情况下调用 to_enum

以下是一个示例,包含参数传递和大小块

module Enumerable
  # a generic method to repeat the values of any enumerable
  def repeat(n)
    raise ArgumentError, "#{n} is negative!" if n < 0
    unless block_given?
      return to_enum(__method__, n) do # __method__ is :repeat here
        sz = size     # Call size and multiply by n...
        sz * n if sz  # but return nil if size itself is nil
      end
    end
    each do |*val|
      n.times { yield *val }
    end
  end
end

%i[hello world].repeat(2) { |w| puts w }
  # => Prints 'hello', 'hello', 'world', 'world'
enum = (1..14).repeat(3)
  # => returns an Enumerator when called without a block
enum.first(4) # => [1, 1, 1, 2]
enum.size # => 42
static VALUE
obj_to_enum(int argc, VALUE *argv, VALUE obj)
{
    VALUE enumerator, meth = sym_each;

    if (argc > 0) {
        --argc;
        meth = *argv++;
    }
    enumerator = rb_enumeratorize_with_size(obj, meth, argc, argv, 0);
    if (rb_block_given_p()) {
        RB_OBJ_WRITE(enumerator, &enumerator_ptr(enumerator)->size, rb_block_proc());
    }
    return enumerator;
}
也称为:enum_for
to_s → string 点击切换源代码

返回表示obj的字符串。默认的to_s 打印对象的类和对象 ID 的编码。作为特殊情况,作为 Ruby 程序初始执行上下文的顶级对象返回“main”。

VALUE
rb_any_to_s(VALUE obj)
{
    VALUE str;
    VALUE cname = rb_class_name(CLASS_OF(obj));

    str = rb_sprintf("#<%"PRIsVALUE":%p>", cname, (void*)obj);

    return str;
}
to_yaml(options = {}) 点击切换源代码

将对象转换为YAML。有关可用options的更多信息,请参见Psych.dump

# File ext/psych/lib/psych/core_ext.rb, line 12
def to_yaml options = {}
  Psych.dump self, options
end
xmp(exps, bind = nil) 点击切换源代码

仅在您需要 IRB::XMP 标准库时才可用的便捷方法。

创建一个新的 XMP 对象,使用给定的表达式作为 exps 参数,可选绑定作为 bind 或使用顶层绑定。然后使用 :XMP 提示模式评估给定的表达式。

例如

require 'irb/xmp'
ctx = binding
xmp 'foo = "bar"', ctx
#=> foo = "bar"
  #==>"bar"
ctx.eval 'foo'
#=> "bar"

有关更多信息,请参见 XMP.new

# File lib/irb/xmp.rb, line 159
def xmp(exps, bind = nil)
  bind = IRB::Frame.top(1) unless bind
  xmp = XMP.new(bind)
  xmp.puts exps
  xmp
end