3. Ruby の変数の種類と、インスタンス変数 Ruby の変数には下記の種類がある ローカル変数 ??? 英小文字から始まる インスタンス変数 ??? @ から始まる クラス変数 ??? @@ から始まる グローバル変数 ??? $ から始まる その他 (擬似変数、 定数) インスタンス変数とは あるオブジェクトに所属する変数 同一の 「 @value 」という変数名でも 所属するオブ ジェクトが異なれば、異なるオブジェクトを参照する。 class A def initialize @value = “” end def get return @value end end a = A.new b = A.new p a.get.object_id p b.get.object_id (参考) クラス変数との違い 同一クラスのインスタンスメソッド、クラスメソッド、クラス定義内 は クラス変数名が同一であれば同一のオブジェクトを参照 している。
4. クラスのインスタンス変数とは Ruby はすべてがオブジェクト クラスもオブジェクト ( Class クラスのインスタンス) ? クラスも通常のオブジェクトと同様、所属する インスタンス変数を持つことができる クラスのインスタンス変数の利用 @value の初期化 クラス定義内で、クラスのインスタンス 変数を初期化 @value2 の初期化 クラスメソッド(=クラスの特異メソッド) の中でクラスのインスタンス変数を定義 @value 、 @value2 の参照 クラスメソッドから参照している class A @value = Object.new def self.value return @value end def self.set @value2 = 2 end def self.value2 @value2 end end v = A.value A.set v2 = A.value2
5. クラスのインタンス変数の特徴 サブクラスから参照できない クラス B はクラス A とは異なる オブジェクトであるため、 クラス B からクラス A のインスタンス 変数は参照できない。 インスタンスメソッドから参照できない クラス A と クラス A のインスタンスは 異なるオブジェクト。 異なるオブジェクトであるため、 インスタンスメソッドからクラスの インタンス変数にはアクセスできない class A @value = [] def self.value return @value end def instance_method return @value end end class B<A p @value #=> nil end p A.value #=> [] p B.value #=> nil p A.new.instance_method #=> nil (参考) クラス変数との違い クラス変数であれば、サブクラスやインスタンス メソッドから参照できる。
6. クラスのインスタンス変数の長所 class Base def self.civar= val @civar = val end def self.civar @civar end def civar= val self.class.civar = val end def civar self.class.civar end end クラスメソッドを定義することで、 サブクラスで参照可能になる インスタンスメソッドを定義することで、 インスタンスメソッド内で参照可能になる クラスのインスタンス変数は下位クラスから直接参照する ことができないため、参照性を制御しやすい
7. 継承があった場合 class Base def self.civar= val @civar = val end def self.civar @civar end end class Subclass < Base end Base.civar = 1 p Subclass.civar #=> nil Subclass.civar = 2 p Base.civar #=> 1 この行で 1 と表示させたいときは、 後述の class_attribute を利用する ① : Subclass.civar の呼び出し ② : 存在しないので、 Base.civar の呼び出し ③ : インスタンス変数 @civar の 値を返す。このとき self は Subclass のため @civar は未定義 サブクラスはスーパークラスと異なるオブジェクトのため、 同じ名前のインスタンス変数でも異なるオブジェクトを参照する
10. スーパークラスの値をデフォルト値にしたい! ActiveSupport の class_attribute を使うと、 継承時に、デフォルト値としてスーパークラスの値を利用可能 require “rubygems” require “active_support/core_ext/class” class Base class_attribute :setting end class Subclass < Base end Base.setting = true p Subclass.setting #=> true Subclass.setting = false p Subclass.setting #=> false P Base.setting #=> true class Base def self.setting= val class << self self end.class_eval do define_method :setting do val end end end end class_eval
11. class_attribute を利用した例(1) ActiveSupport::Rescuable 例外処理を rescue_from で体系的に行うためのモジュール 例外処理のコールバックをクラスのインスタンス変数に格納 継承したとき、デフォルトで親のコールバックを利用するように、 前のスライドの class_attribute を利用 ActiveSupport::Rescuable のように、クラスに対して新たな機能を付加するモジュールを作成するときは、クラス変数が役立つときがある。 class ApplicationController < ActionController::Base # include ActiveSupport::Rescuable # すでに include している rescue_from ActiveRecord::RecordInvalid do |exception| render :action => (exception.record.new_record? ? :new : :edit) end end