我想在其超类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的失败测试,以说明预期的内容。
答案 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