LoginSignup
2
0

More than 3 years have passed since last update.

[Ruby] 継承可能なクラス属性を定義する

Last updated at Posted at 2019-11-25

やりたいこと

継承可能なクラス属性を定義したい。

class A
  self.x = :hoge
end

class B < A
end

class C < B
  self.x = :fuga
end

A.x #=> :hoge
B.x #=> :hoge (親の x を継承する。)
C.x #=> :fuga (再定義した場合はその値を使う。)

たったひとつの冴えたやり方

Active Support コア拡張の Class#class_attribute を使う。

require 'active_support/core_ext/class/attribute'

class A
  class_attribute :x

  self.x = :hoge
end

class B < A
end

class C < B
  self.x = :fuga
end

A.x #=> :hoge
B.x #=> :hoge
C.x #=> :fuga

他に考えた方法

:ng: クラス変数を使う (失敗)

クラス変数はサブクラスとも共有され、サブクラスで代入できるためこの用途に使えない。

class A
  @@x = :hoge
end

class B < A
end

class C < B
  @@x = :fuga
end

A.class_variable_get(:@@x) #=> :fuga 😭
B.class_variable_get(:@@x) #=> :fuga 😭
C.class_variable_get(:@@x) #=> :fuga

:ng: クラスインスタンス変数を使う (失敗)

クラスインスタンス変数はサブクラスとは共有されず、各クラスで独立している。しかし継承もしない。

class A
  @x = :hoge
end

class B < A
end

class C < B
  @x = :fuga
end

A.instance_variable_get(:@x) #=> :hoge
B.instance_variable_get(:@x) #=> nil 😭
C.instance_variable_get(:@x) #=> :fuga

:ok: クラスインスタンス変数を使い、継承時に親クラスの値を引き継ぐ (成功)

class A
  def self.inherited(subclass)
    subclass.instance_variable_set(:@x, @x)
  end

  @x = :hoge
end

class B < A
end

class C < B
  @x = :fuga
end

A.instance_variable_get(:@x) #=> :hoge
B.instance_variable_get(:@x) #=> :hoge
C.instance_variable_get(:@x) #=> :fuga

参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0