Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 在常量内继承attr\u访问器_Ruby - Fatal编程技术网

Ruby 在常量内继承attr\u访问器

Ruby 在常量内继承attr\u访问器,ruby,Ruby,我有一个类,其attr_访问器设置如下: class Human ATTRIBUTES = [:name] attr_accessor *ATTRIBUTES end 它就像一个符咒,让我保持属性内属性不变。问题是我希望有一个类学生从人类类继承,而不需要每次都放置attr_访问器。 基本上我想要的是: class Student < Human ATTRIBUTES = [:name, :school] end 我没有得到方法错误,因为attr_访问器是从人而不

我有一个类,其attr_访问器设置如下:

class Human
    ATTRIBUTES = [:name]
    attr_accessor *ATTRIBUTES
end
它就像一个符咒,让我保持属性内属性不变。问题是我希望有一个类学生从人类类继承,而不需要每次都放置attr_访问器。 基本上我想要的是:

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

我没有得到方法错误,因为attr_访问器是从人而不是学生加载的。我应该使用什么构造来实现我的目标?

好吧,虽然我不需要将属性保存在数组中,
Student
类已经继承了父类中定义的
attr\u访问器

例如:

class Human
  attr_accessor :name, :gender
end

class Student < Human
  attr_accessor :school
end
人类也对
:姓名
:性别

> Human.new.respond_to?(:name)
=> true
> Human.new.respond_to?(:gender)
=> true
但不是去学校

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

它更干净,是ruby方式,更容易理解

我个人同意@lcguida的答案,但如果你坚持按照你提出的模式行事,我提出了一个小小的实验。其他答案已经涵盖了为什么你的解决方案不起作用,所以我这里不讨论这个问题

首先想到的是调用父类上的
self.inherited
回调上的
attr\u 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
模块懒散附加器
def自扩展(obj)
跟踪点。跟踪(:end)do | t|
如果obj==t.self
obj.send:attr_访问器,*obj::ATTRIBUTES
t、 禁用
结束
结束
结束
结束
阶级人
扩展懒散附加器
属性=[:名称]
def self.inherited(子类)
子类.extend lazyattr附加器
结束
结束
班级学生<人
属性=[:名称,:学校]
#ATTRIBUTES=[:school]也会像预期的那样工作,但我认为您希望在这里使用文字。
结束
>学生。新。回复?(:姓名)
=>正确
>学生。新。回复:(:学校)
=>正确

Student类本身没有attr\u访问器,因此它不知道school有一个属性。如果你想让学校被识别,你应该在学生班上有attr_访问器,或者在人类班上声明学校阁楼。你知道attr_访问器的作用吗?从我对你问题的理解来看,你没有。这似乎是潜在的问题。很好!绝对是+1!
> Human.new.respond_to?(:school)
=> false
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