在超类'self.inherited中访问匿名类的名称

时间:2014-02-16 12:55:06

标签: ruby inheritance anonymous-class

我想在其超类MySuperclass'self.inherited方法中访问类的名称。它适用于class Foo < MySuperclass; end定义的具体类,但在使用匿名类时失败。我倾向于避免在测试中创建(类)常量;我希望它能与匿名课程一起使用。

给出以下代码:

class MySuperclass
  def self.inherited(subclass)
    super
    # work with subclass' name
  end
end

klass = Class.new(MySuperclass) do
  def self.name
    'FooBar'
  end
end
调用klass#name

nil仍为MySuperclass.inherited,因为在 Class.new产生其块并定义其方法之前将是

我理解一个类在分配给常量时得到它的name,但是有没有办法在不创建常量的情况下“早期”设置Class#name

我准备了更多verbose code example的失败测试,​​以说明预期的内容。

3 个答案:

答案 0 :(得分:1)

#yield被调用之后可能发生了::inherited,我看到了与类定义类似的行为。但是,您可以使用::klass单例方法而不是::inherited回调来避免它。

def self.klass
   @klass ||= (self.name || self.to_s).gsub(/Builder\z/, '')
end

答案 1 :(得分:1)

我试图理解能够通过您创建后分配给它的名称来引用匿名类的好处。我想我可以通过提供一些你可以看到的代码然后告诉我们你想要做的不同来改变对话:

class MySuperclass
  def self.inherited(subclass)
    # Create a class method for the subclass
    subclass.instance_eval do
      def sub_class() puts "sub_class here" end
    end
    # Create an instance method for the subclass
    subclass.class_eval do
      def sub_instance() puts "sub_instance here" end
    end  
  end
end

klass = Class.new(MySuperclass) do
  def self.name=(name)
    @name = Object.const_set(name, self)
  end
  def self.name
    @name
  end
end

klass.sub_class        #=> "sub_class here"
klass.new.sub_instance #=> "sub_instance here"

klass.name = 'Fido'    #=> "Fido"
kn = klass.name        #=> Fido

kn.sub_class           #=> "sub_class here"
kn.new.sub_instance    #=> "sub_instance here"

klass.name = 'Woof'    #=> "Woof"
kn = klass.name        #=> Fido (cannot change)

答案 2 :(得分:1)

纯Ruby中没有办法在不将其赋值给常量的情况下设置类名。

如果您正在使用MRI并希望自己编写一个非常小的C扩展,它看起来像这样:

VALUE
force_class_name (VALUE klass, VALUE symbol_name)
{
    rb_name_class(klass, SYM2ID(symbol_name));
    return klass;
}

void
Init_my_extension ()
{
    rb_define_method(rb_cClass, "force_class_name", force_class_name, 1);
}

这是解决问题的一个非常重要的方法。即使它有效,也不能保证可以跨多种版本的ruby工作,因为它依赖于非API C函数rb_name_class。我也不确定一旦Ruby在之后运行自己的类命名挂钩后会发生什么行为。

您的用例的代码段如下所示:

require 'my_extension'

class MySuperclass
  def self.inherited(subclass)
    super
    subclass.force_class_name(:FooBar)
    # work with subclass' name
  end
end