2014-02-16 36 views
3

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

鉴于以下代码:

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仍会nilMySuperclass.inherited称为那将是之前Class.new收率到其块并定义它的方法。

我知道一个类获取它的name时,它被分配给一个常量,但有没有办法设置Class#name“早”没有创建一个常量?

我准备了更多的verbose code example未通过测试,以说明预期。

+0

你有没有设法解决这个问题? –

+0

由Малъ-Скрылевъ(接受的答案)提供的代码实现了我想要完成的任务。我曾希望使用'继承的'回调来完成它,但唉,似乎不可能。 – carp

回答

1

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

def self.klass 
    @klass ||= (self.name || self.to_s).gsub(/Builder\z/, '') 
end 
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) 
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