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

13
クククククククククククククククク 2011/1/8 cuzic

Upload: tomoya-cuzic

Post on 30-Jun-2015

5.839 views

Category:

Technology


2 download

DESCRIPTION

Ruby勉強会@関西 #48 資料

TRANSCRIPT

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

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

2011/1/8

cuzic

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

Ruby 勉強会 第48回発表資料  「クラスのインスタンス変数について」

22自己紹介

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

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

Ruby 勉強会 第48回発表資料  「クラスのインスタンス変数について」

33Ruby の変数の種類と、インスタンス変数

Ruby の変数には下記の種類があるローカル変数      ・・・ 英小文字から始まるインスタンス変数    ・・・ @ から始まるクラス変数       ・・・ @@ から始まるグローバル変数     ・・・ $ から始まるその他 (擬似変数、 定数)

インスタンス変数とはあるオブジェクトに所属する変数同一の 「 @value 」という変数名でも所属するオブジェクトが異なれば、異なるオブジェクトを参照する。

class A   def initialize @value = “” end

def get return @value endend

a = A.newb = A.newp a.get.object_idp b.get.object_id(参考) クラス変数との違い

同一クラスのインスタンスメソッド、クラスメソッド、クラス定義内は クラス変数名が同一であれば同一のオブジェクトを参照している。

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

Ruby 勉強会 第48回発表資料  「クラスのインスタンス変数について」

44クラスのインスタンス変数とは

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 endend

v = A.valueA.setv2 = A.value2

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

Ruby 勉強会 第48回発表資料  「クラスのインスタンス変数について」

55クラスのインタンス変数の特徴

サブクラスから参照できないクラス B はクラス A とは異なるオブジェクトであるため、クラス B からクラス A のインスタンス変数は参照できない。

インスタンスメソッドから参照できないクラス A と クラス A のインスタンスは異なるオブジェクト。異なるオブジェクトであるため、インスタンスメソッドからクラスのインタンス変数にはアクセスできない

class A @value = []

def self.value return @value end

def instance_method return @value endend

class B<A p @value #=> nilend

p A.value #=> []p B.value #=> nilp A.new.instance_method #=> nil

(参考) クラス変数との違いクラス変数であれば、サブクラスやインスタンスメソッドから参照できる。

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

Ruby 勉強会 第48回発表資料  「クラスのインスタンス変数について」

クラスのインスタンス変数の長所 66

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 endend

クラスメソッドを定義することで、サブクラスで参照可能になる

インスタンスメソッドを定義することで、インスタンスメソッド内で参照可能になる

クラスのインスタンス変数は下位クラスから直接参照することができないため、参照性を制御しやすい

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

Ruby 勉強会 第48回発表資料  「クラスのインスタンス変数について」

継承があった場合 77

class Base def self.civar= val @civar = val end

def self.civar @civar endend

class Subclass < Baseend

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 は未定義

サブクラスはスーパークラスと異なるオブジェクトのため、同じ名前のインスタンス変数でも異なるオブジェクトを参照する

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

Ruby 勉強会 第48回発表資料  「クラスのインスタンス変数について」

(参考) クラス変数の参照性

サブクラスから参照可能

インスタンスメソッドから参照可能

サブクラスでの変更がグローバルに影響が及ぶ

クラスのインスタンス変数

×(アクセサメソッドが必要)

×(アクセサメソッドが

必要)

×(そもそも参照不可)

クラス変数 ○ ○ ○

ActiveSupport のclass_attribute(後述)

○(アクセサメソッド)

○(アクセサメソッド)(オプションで設定可

能)

×(破壊的変更を

行った場合を除く)

(参考) 定数 ○ ○

×(サブクラスでの定数

への代入文は新定数の定義となる)

88

Ruby のクラス変数は参照可能な範囲が限定されたグローバル変数

変更が全継承階層の同一名のクラス変数に影響する

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

Ruby 勉強会 第48回発表資料  「クラスのインスタンス変数について」

クラスのインスタンス変数の使用例 99

class Foo extend Exception2MessageMapper def_e2message ExsitingExceptionClass, “message …” def_exception :NewExceptionClass, “message …”end

Foo.Fail NewExceptionClass, arg …

Foo.Fail ExistingExceptionClass, arg …

Exception2MessageMapper例外クラスに特定のエラーメッセージ用

  フォーマットを関連付けるためのライブラリメッセージフォーマットを Module のインスタンス変数で保持

インスタンス変数のため、変数名重複の心配なしクラス変数の場合は、変数名重複の場合、誤動作が生じる。

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

Ruby 勉強会 第48回発表資料  「クラスのインスタンス変数について」

1010スーパークラスの値をデフォルト値にしたい!

ActiveSupport の class_attribute を使うと、継承時に、デフォルト値としてスーパークラスの値を利用可能

require “rubygems”require “active_support/core_ext/class”

class Base class_attribute :settingend

class Subclass < Baseend

Base.setting = truep Subclass.setting #=> trueSubclass.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 endend

class_eval

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

Ruby 勉強会 第48回発表資料  「クラスのインスタンス変数について」

1111class_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) endend

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

Ruby 勉強会 第48回発表資料  「クラスのインスタンス変数について」

class_attribute を利用した例(2)

ActiveRecord の場合大量のコールバックが利用可能

コールバックは主にクラスのインスタンス変数に保存

コールバックを管理するObserver もクラスのインスタンス変数に保存

1212コールバック タイミング

after_create 新規作成し、保存したあと

after_destroy 削除したあと

after_save 新規作成、更新したあと

after_update 更新したあと

after_validation バリデーションしたあと

before_create 新規作成する前

before_destroy 削除する前

before_save 新規作成、更新する前

before_update 更新する前

before_validation バリデーションする前

クラス内で共通だが、継承ツリー全体での共有はしたくない

設定はクラスのインスタンス変数を用いるとうまく実装できる

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

Ruby 勉強会 第48回発表資料  「クラスのインスタンス変数について」

まとめ

Ruby ではクラスもオブジェクトクラスもインスタンス変数を持つことができる

クラスのインスタンス変数は制御しやすいアクセサメソッドの定義によって制御可能クラス変数だと、サブクラスからでも変更可能

上位クラスも影響を受ける

Module 内でだけ有効な private なクラス変数としてModule 自身のインスタンス変数を使うこともできる継承したとき、スーパークラスの値をデフォルト値として使いたいときは、 class_attribute を用いる

1313