从单例类中检索Ruby对象?

时间:2019-02-05 09:32:56

标签: ruby metaprogramming

可以使用以下方法从Ruby对象访问singleton class

some_object.singleton_class

是否可以执行相反的操作:在单例类内部时访问原始对象?

class << some_object
  # how to reference some_object without actually typing some_object?
end

我想将此method烘干:

class Example
  PARENTS = []
  class << PARENTS
    FATHER = :father
    MOTHER = :mother
    PARENTS.push(FATHER, MOTHER)
  end
end

,并尝试用更通用的内容替换类中的PARENTS

3 个答案:

答案 0 :(得分:7)

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

class Object
  def define_instance_accessor(method_name = :instance)
    singleton_class.define_singleton_method(method_name, &method(:itself))
  end
end

用法:

obj = Object.new              #=> #<Object:0x00007ff58e8742f0>
obj.define_instance_accessor
obj.singleton_class.instance  #=> #<Object:0x00007ff58e8742f0>

在您的代码中:

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

在内部,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);
}

用法:

irb -r ./instance_accessor
> obj = Object.new
#=> #<Object:0x00007f94a11e1260>
> obj.singleton_class.instance
#=> #<Object:0x00007f94a11e1260>
>

答案 1 :(得分:1)

只是出于好奇(请不要在家里或学校使用)

object = []
class << object
  type, id = to_s[/(?<=:#<).*?(?=>)/].split(':')
  ObjectSpace.each_object(Kernel.const_get(type)).find do |e|
    e.__id__ == id.to_i(16) >> 1
  end << :father
end   
#⇒ [:father]

答案 2 :(得分:1)

我们可以按照以下步骤进行操作。

website.menu_id = Menu.search([('parent_id', '=', False), ('website_id', '=', website.id)], order='id', limit=1).id

在线救援是处理对象def singleton_class_to_object(sc) ObjectSpace.each_object(Object).find { |o| (o.singleton_class == sc) rescue false } end o = Object.new #=> #<Object:0x00005b52e502d030> singleton_class_to_object(o.singleton_class) #=> #<Object:0x00005b52e502d030> class C; end singleton_class_to_object(C.singleton_class) #=> C ,它们是直接对象,没有单例类。

在MRI v2.7.0中,

o
只是微不足道的。