Inherit class-level instance variables in Ruby?

2019-01-26 03:44发布

I want a child class to inherit a class-level instance variable from its parent, but I can't seem to figure it out. Basically I'm looking for functionality like this:

class Alpha
  class_instance_inheritable_accessor :foo #
  @foo = [1, 2, 3]
end

class Beta < Alpha
  @foo << 4
  def self.bar
    @foo
  end
end

class Delta < Alpha
  @foo << 5
  def self.bar
    @foo
  end
end

class Gamma < Beta
  @foo << 'a'
  def self.bar
    @foo
  end
end

And then I want this to output like this:

> Alpha.bar
# [1, 2, 3]

> Beta.bar
# [1, 2, 3, 4]

> Delta.bar
# [1, 2, 3, 5]

> Gamma.bar
# [1, 2, 3, 4, 'a']

Obviously, this code doesn't work. Basically I want to define a default value for a class-level instance variables in the parent class, which its subclasses inherit. A change in a subclass will be the default value then for a sub-subclass. I want this all to happen without a change in one class's value affecting its parent or siblings. Class_inheritable_accessor gives exactly the behavior I want... but for a class variable.

I feel like I might be asking too much. Any ideas?

3条回答
放我归山
2楼-- · 2019-01-26 04:22

What I did in my project for using resque is to define a base

class ResqueBase
  def self.inherited base
    base.instance_variable_set(:@queue, :queuename)
  end
end

In the other child jobs, the queue instance will be set by default. Hope it can help.

查看更多
相关推荐>>
3楼-- · 2019-01-26 04:28

Use a mixin:

module ClassLevelInheritableAttributes
  def self.included(base)
    base.extend(ClassMethods)    
  end

  module ClassMethods
    def inheritable_attributes(*args)
      @inheritable_attributes ||= [:inheritable_attributes]
      @inheritable_attributes += args
      args.each do |arg|
        class_eval %(
          class << self; attr_accessor :#{arg} end
        )
      end
      @inheritable_attributes
    end

    def inherited(subclass)
      @inheritable_attributes.each do |inheritable_attribute|
        instance_var = "@#{inheritable_attribute}"
        subclass.instance_variable_set(instance_var, instance_variable_get(instance_var))
      end
    end
  end
end

Including this module in a class, gives it two class methods: inheritable_attributes and inherited.
The inherited class method works the same as the self.included method in the module shown. Whenever a class that includes this module gets subclassed, it sets a class level instance variable for each of declared class level inheritable instance variables (@inheritable_attributes).

查看更多
干净又极端
4楼-- · 2019-01-26 04:38

Rails has this built into the framework as a method called class_attribute. You could always check out the source for that method and make your own version or copy it verbatim. The only thing to watch out for is that you don't change the mutable items in place.

查看更多
登录 后发表回答