从单例类中检索Ruby对象?

Eri*_*nil 4 ruby metaprogramming

可以使用以下命令从Ruby对象访问单例类:

some_object.singleton_class
Run Code Online (Sandbox Code Playgroud)

是否可以执行反向操作:在单例类中访问原始对象?

class << some_object
  # how to reference some_object without actually typing some_object?
end
Run Code Online (Sandbox Code Playgroud)

我想干这个方法:

class Example
  PARENTS = []
  class << PARENTS
    FATHER = :father
    MOTHER = :mother
    PARENTS.push(FATHER, MOTHER)
  end
end
Run Code Online (Sandbox Code Playgroud)

并尝试PARENTS用更通用的东西替换类内部.

Ste*_*fan 7

我不知道任何内置方法或关键字,但您可以编写一个方法,将(单例)方法添加到对象的单例类,返回对象本身:

class Object
  def define_instance_accessor(method_name = :instance)
    singleton_class.define_singleton_method(method_name, &method(:itself))
  end
end
Run Code Online (Sandbox Code Playgroud)

用法:

obj = Object.new              #=> #<Object:0x00007ff58e8742f0>
obj.define_instance_accessor
obj.singleton_class.instance  #=> #<Object:0x00007ff58e8742f0>
Run Code Online (Sandbox Code Playgroud)

在你的代码中:

class Example
  PARENTS = []
  PARENTS.define_instance_accessor
  class << PARENTS
    FATHER = :father
    MOTHER = :mother
    instance.push(FATHER, MOTHER)
  end
end
Run Code Online (Sandbox Code Playgroud)

在内部,YARV将对象存储在名为的实例变量中__attached__.实例变量没有通常的@前缀,因此在Ruby中不可见或无法访问它.

这是一个小C扩展来暴露它:

#include <ruby.h>

static VALUE
instance_accessor(VALUE klass)
{
    return rb_ivar_get(klass, rb_intern("__attached__"));
}

void Init_instance_accessor()
{
    rb_define_method(rb_cClass, "instance", instance_accessor, 0);
}
Run Code Online (Sandbox Code Playgroud)

用法:

irb -r ./instance_accessor
> obj = Object.new
#=> #<Object:0x00007f94a11e1260>
> obj.singleton_class.instance
#=> #<Object:0x00007f94a11e1260>
>
Run Code Online (Sandbox Code Playgroud)


Mar*_*n13 2

类#attached_object (Ruby 3.2+)

从 开始Ruby 3.2,有一个Class#attached_object方法:

返回接收者是单例类的对象。 如果该类不是单例类,

则引发TypeError 。

例如:

class Foo; end

Foo.singleton_class.attached_object     #=> Foo
Foo.attached_object                     #=> TypeError: `Foo' is not a singleton class
Foo.new.singleton_class.attached_object #=> #<Foo:0x000000010491a370>
TrueClass.attached_object               #=> TypeError: `TrueClass' is not a singleton class
NilClass.attached_object                #=> TypeError: `NilClass' is not a singleton class
Run Code Online (Sandbox Code Playgroud)

资料来源: