2016-09-30 47 views
2

我与attr_accessor一类这样设置:继承attr_accessor内恒定

class Human 
    ATTRIBUTES = [:name] 
    attr_accessor *ATTRIBUTES 
end 

它就像一个魅力,让我保持内部属性属性不变。问题是我希望有一个类Student继承自Human类,而不需要每次都放置attr_accessor。 基本上我想有是这样的:

class Student < Human 
    ATTRIBUTES = [:name, :school] 
end 

不幸的是,当我做

Student.new.school 

我没有得到任何方法错误,因为attr_accessor从人,而不是一个学生装。我应该用什么构造来实现我的目标?

+0

这样的学生类没有attr_accessor,所以它不知道有学校属性。如果你想让学校认可,你应该在Student类中拥有attr_accessor,或者在Human类中声明学校attib。 – uday

+1

你甚至知道'attr_accessor'是什么吗?从我能理解你的问题,你不知道。这似乎是潜在的问题。 –

回答

2

那么,虽然我不需要保持数组中的属性,但Student类将继承其父类中定义的attr_accessor

例如:

class Human 
    attr_accessor :name, :gender 
end 

class Student < Human 
    attr_accessor :school 
end 

学生类现在有:姓名,性别和:学校attr_accessor的:

> Student.new.respond_to?(:name) 
=> true 
> Student.new.respond_to?(:name=) 
=> true 
> Student.new.respond_to?(:school) 
=> true 
> Student.new.respond_to?(:school=) 
=> true 

人也响应:name:gender

> Human.new.respond_to?(:name) 
=> true 
> Human.new.respond_to?(:gender) 
=> true 

但不去学校

> Human.new.respond_to?(:school) 
=> false 

它更清洁,它是红宝石的方式,更容易理解。

3

我个人同意@ lcguida的回答,但是如果你坚持遵循你提出的模式,我想出了一个小实验。其他答案已经涵盖了为什么你的解决方案不起作用,所以我没有在这里进入。

首先想到的是在父类的self.inherited回调上调用attr_accessor,但不幸的是,孩子的主体直到后来才加载。即便如此,有意愿的地方也有办法。如果您使用的是Ruby 2.0或更高版本,则以下实现将起作用。

module LazyAttrAccessorizer 
    def self.extended(obj) 
    TracePoint.trace(:end) do |t| 
     if obj == t.self 
     obj.send :attr_accessor, *obj::ATTRIBUTES 
     t.disable 
     end 
    end 
    end 
end 

class Human 
    extend LazyAttrAccessorizer 
    ATTRIBUTES = [:name] 
    def self.inherited(subclass) 
    subclass.extend LazyAttrAccessorizer 
    end 
end 

class Student < Human 
    ATTRIBUTES = [:name, :school] 
    # ATTRIBUTES = [:school] would also work as expected, but I think you'd like to be literal there. 
end 

> Student.new.respond_to?(:name) 
=> true 
> Student.new.respond_to?(:school) 
=> true 
+0

不错的一个!肯定+1! –