狠狠撸

狠狠撸Share a Scribd company logo
クラスのインスタンス変数について 2011/1/8 cuzic
自己紹介 cuzic  といいます きゅーじっく と読みます Ruby  暦は かれこれもう10年くらい Kindle  向けサーバサイドアプリを作成中 takibi   <http://www.github.com/cuzic/takibi> WEB 上の記事の  Scraping ? epub  作成を自動実行 4階層モデル( model  、 crawler 、 parser 、 formatter ) 安価な 共有 WEB ホスティングで動作できるよう工夫 デーモンの常駐不要。 Cron  で定期的に実行。 多数の日本語の  WEB 記事に対応 JBpress 、 Livedoor Blogos 、日経ビジネスオンライン、  etc
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 (参考) クラス変数との違い 同一クラスのインスタンスメソッド、クラスメソッド、クラス定義内 は  クラス変数名が同一であれば同一のオブジェクトを参照 している。
クラスのインスタンス変数とは 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
クラスのインタンス変数の特徴 サブクラスから参照できない クラス 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 (参考) クラス変数との違い クラス変数であれば、サブクラスやインスタンス メソッドから参照できる。
クラスのインスタンス変数の長所 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 クラスメソッドを定義することで、 サブクラスで参照可能になる インスタンスメソッドを定義することで、 インスタンスメソッド内で参照可能になる クラスのインスタンス変数は下位クラスから直接参照する ことができないため、参照性を制御しやすい
継承があった場合 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  は未定義 サブクラスはスーパークラスと異なるオブジェクトのため、 同じ名前のインスタンス変数でも異なるオブジェクトを参照する
(参考) クラス変数の参照性 Ruby  のクラス変数は参照可能な範囲が限定されたグローバル変数 変更が全継承階層の同一名のクラス変数に影響する サブクラスから参照可能 インスタンスメソッドから参照可能 サブクラスでの変更がグローバルに影響が及ぶ クラスの インスタンス変数 × (アクセサメソッドが必要) × (アクセサメソッドが必要) × (そもそも参照不可) クラス変数 ○ ○ ○ ActiveSupport  の class_attribute (後述) ○ (アクセサメソッド) ○ (アクセサメソッド) (オプションで設定可能) × (破壊的変更を 行った場合を除く) (参考) 定数 ○ ○ × (サブクラスでの定数 への代入文は新定数の定義となる)
クラスのインスタンス変数の使用例 Exception2MessageMapper 例外クラスに特定のエラーメッセージ用   フォーマットを関連付けるためのライブラリ メッセージフォーマットを Module のインスタンス変数で保持 インスタンス変数のため、変数名重複の心配なし クラス変数の場合は、変数名重複の場合、誤動作が生じる。 class Foo   extend Exception2MessageMapper   def_e2message ExsitingExceptionClass,   “message …”   def_exception :NewExceptionClass,    “message …” end Foo.Fail NewExceptionClass, arg … Foo.Fail ExistingExceptionClass, arg …
スーパークラスの値をデフォルト値にしたい! 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
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
class_attribute  を利用した例(2) ActiveRecord  の場合 大量のコールバック が利用可能 コールバックは主に クラスのインスタンス 変数に保存 コールバックを管理する Observer  もクラスの インスタンス変数に保存 クラス内で共通だが、継承ツリー全体での共有はしたくない 設定はクラスのインスタンス変数を用いるとうまく実装できる コールバック タイミング after_create 新規作成し、保存したあと after_destroy 削除したあと after_save 新規作成、更新したあと after_update 更新したあと after_validation バリデーションしたあと before_create 新規作成する前 before_destroy 削除する前 before_save 新規作成、更新する前 before_update 更新する前 before_validation バリデーションする前
まとめ Ruby  ではクラスもオブジェクト クラスもインスタンス変数を持つことができる クラスのインスタンス変数は制御しやすい アクセサメソッドの定義によって制御可能 クラス変数だと、サブクラスからでも変更可能 上位クラスも影響を受ける Module  内でだけ有効な  private  なクラス変数として Module  自身のインスタンス変数を使うこともできる 継承したとき、スーパークラスの値をデフォルト値として使いたいときは、 class_attribute  を用いる

More Related Content

クラスのインスタンス変数について

  • 2. 自己紹介 cuzic といいます きゅーじっく と読みます Ruby 暦は かれこれもう10年くらい Kindle 向けサーバサイドアプリを作成中 takibi   <http://www.github.com/cuzic/takibi> WEB 上の記事の Scraping ? epub 作成を自動実行 4階層モデル( model 、 crawler 、 parser 、 formatter ) 安価な 共有 WEB ホスティングで動作できるよう工夫 デーモンの常駐不要。 Cron で定期的に実行。 多数の日本語の WEB 記事に対応 JBpress 、 Livedoor Blogos 、日経ビジネスオンライン、 etc
  • 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 は未定義 サブクラスはスーパークラスと異なるオブジェクトのため、 同じ名前のインスタンス変数でも異なるオブジェクトを参照する
  • 8. (参考) クラス変数の参照性 Ruby のクラス変数は参照可能な範囲が限定されたグローバル変数 変更が全継承階層の同一名のクラス変数に影響する サブクラスから参照可能 インスタンスメソッドから参照可能 サブクラスでの変更がグローバルに影響が及ぶ クラスの インスタンス変数 × (アクセサメソッドが必要) × (アクセサメソッドが必要) × (そもそも参照不可) クラス変数 ○ ○ ○ ActiveSupport の class_attribute (後述) ○ (アクセサメソッド) ○ (アクセサメソッド) (オプションで設定可能) × (破壊的変更を 行った場合を除く) (参考) 定数 ○ ○ × (サブクラスでの定数 への代入文は新定数の定義となる)
  • 9. クラスのインスタンス変数の使用例 Exception2MessageMapper 例外クラスに特定のエラーメッセージ用   フォーマットを関連付けるためのライブラリ メッセージフォーマットを Module のインスタンス変数で保持 インスタンス変数のため、変数名重複の心配なし クラス変数の場合は、変数名重複の場合、誤動作が生じる。 class Foo extend Exception2MessageMapper def_e2message ExsitingExceptionClass, “message …” def_exception :NewExceptionClass, “message …” end Foo.Fail NewExceptionClass, arg … Foo.Fail ExistingExceptionClass, arg …
  • 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
  • 12. class_attribute を利用した例(2) ActiveRecord の場合 大量のコールバック が利用可能 コールバックは主に クラスのインスタンス 変数に保存 コールバックを管理する Observer もクラスの インスタンス変数に保存 クラス内で共通だが、継承ツリー全体での共有はしたくない 設定はクラスのインスタンス変数を用いるとうまく実装できる コールバック タイミング after_create 新規作成し、保存したあと after_destroy 削除したあと after_save 新規作成、更新したあと after_update 更新したあと after_validation バリデーションしたあと before_create 新規作成する前 before_destroy 削除する前 before_save 新規作成、更新する前 before_update 更新する前 before_validation バリデーションする前
  • 13. まとめ Ruby ではクラスもオブジェクト クラスもインスタンス変数を持つことができる クラスのインスタンス変数は制御しやすい アクセサメソッドの定義によって制御可能 クラス変数だと、サブクラスからでも変更可能 上位クラスも影響を受ける Module 内でだけ有効な private なクラス変数として Module 自身のインスタンス変数を使うこともできる 継承したとき、スーパークラスの値をデフォルト値として使いたいときは、 class_attribute を用いる