Rubyメタプログラミング-Week-4
沈小黒の菜園へようこそ~
クラス定義
「Rubyオブジェクトモデルの最も暗いコーナーに入る」...Javaとは異なり、Rubyでは定義クラスが実際にコードを実行しているという考えが1、クラスを修正できるクラスマクロ2、他の方法の前後に追加コードをカプセル化できるエイリアスを生み出した.もちろん、クラスは強化されたモジュールにすぎないので、これらの知識はモジュールにも適用できます.
現在のクラス
メソッドの属する判断は定義メソッドの所在selfによって判断されるので,親定義のメソッドは,サブクラスでm 2定義文が実行されてもm 2は親クラスに属する.
class_eval V.S classキーワード
クラスキーを使用してクラスを変更するにはクラス名を指定する必要がありますが、クラス名をパラメータとして動的に変更するには?このときModule#class_を使うことができます.eval(別名module_eval)メソッド.
またclassは役割ドメインゲートであり,クラス外の変数はクラス内では見えない.そしてclass_evalは、結局はメソッド呼び出しにすぎないため、フラットな役割ドメインを使用します.
classを見つけることができますevalとinstance_evalは似てるclassevalにもパラメータ付きclass_がありますexec.instance_evalのポイントは、オブジェクト内の変数の現在のselfを呼び出しで表示するように変更し、class_evalのポイントはクラスの変更です.
クラスのインスタンス変数
Rubyのインスタンス変数は現在のselfに属するため、クラス内のメソッド外で定義されたインスタンス変数はクラスのインスタンスではなくクラスというオブジェクトに属する.
インスタンス変数の帰属は現在のselfに基づいて判断されるため、サブクラス、インスタンスはクラスインスタンス変数にアクセスできません.この変数は「クラス」というオブジェクトのselfに属するためです.
注意@先頭のクラス変数とは異なり、現在のクラスとサブクラスまたはインスタンスによってアクセスできます.そのため、クラス変数をトップレベルの役割ドメインで定義すると、すべてのクラスがトップレベルの役割ドメインの上書き下にあるため、アクセスできます.
このような状況を避けるためには、できればクラス変数の使用を避け、クラスのインスタンス変数の使用を避けることが望ましい.
単品メソッド
Rubyは、単一オブジェクトへの追加方法をサポートします.
Javaでsingletonクラスが同じオブジェクトのみを生成できるという概念とは異なり、ここでのsingletonメソッドは、このメソッドが定義されたオブジェクトに属しているということです.
実際,クラスメソッドを定義する際のメソッド名のselfを連想するが,クラスメソッドはクラスオブジェクトの単品メソッドである.
クラスマクロ
Rubyオブジェクトには属性がないので、Javaのようなgetterとsetterを書いてから属性にアクセスまたは変更する必要があります.
でもこう書くのは煩わしくてクールじゃない~だからルビーはModule#attrを提供してくれたreader、Module#attr_writerとModule#attr_accessor
類似attr_accessorのような方法をクラスマクロと呼び、キーワードのように見えますが、実際にはクラスで使える方法にすぎません.
APIを更新し、古いメソッドをdeprecatedと宣言し、新しいメソッドに自動的に移動する必要があると仮定すると、次のようなコードを使用できます.
単品類
Rubyメソッドを検索するときは,受信者のクラスに入ってから上へ検索する.たとえば、MyClassクラスインスタンスobj呼び出しメソッドは、objのクラスMyClassに入ってメソッドを検索します.しかし、単品メソッドはクラスに含まれていないに違いありません.そうしないと、すべてのオブジェクトにこのメソッドがあります.オブジェクト自体はクラスではないのでobjにも入っていません.では、この方法はどこにあるのでしょうか.
単品類とは
オブジェクトのクラスを尋ねると,Rubyは実際に見たクラスではなく,オブジェクト特有の非表示クラスを返す.このクラスはこのオブジェクトの単品クラス、またはメタクラスと呼ばれます.
これにより、この単品クラスの参照(.classメソッドは単品クラスを隠すように包装される)を見ることができ、現在Rubyも提供している.singleton_classメソッドは、単一のクラスを返します.各オブジェクトには独自の単品クラスがあり、単品クラスにも1つのインスタンスしかない(そのインスタンスにも独自の単品クラスがある~ループ往復・・・ただしこの単品クラスの単品クラスの用途はまだ開発されていない).オブジェクトの単品メソッドは、対応する単品クラスに配置されます.
月曜日に学習した継承モデルを更新する必要があります:objが存在するクラスはobjの単品クラスで、単品クラスの親はMyClassで、MyClassクラスのオブジェクトの親はObjectです.
単品クラスと継承
次のようなクラス関係があると仮定すると,継承ツリーの出力を観察することによって彼らの構造関係を理解することができる.
クラス定義
「Rubyオブジェクトモデルの最も暗いコーナーに入る」...Javaとは異なり、Rubyでは定義クラスが実際にコードを実行しているという考えが1、クラスを修正できるクラスマクロ2、他の方法の前後に追加コードをカプセル化できるエイリアスを生み出した.もちろん、クラスは強化されたモジュールにすぎないので、これらの知識はモジュールにも適用できます.
現在のクラス
メソッドの属する判断は定義メソッドの所在selfによって判断されるので,親定義のメソッドは,サブクラスでm 2定義文が実行されてもm 2は親クラスに属する.
class C
def m1
def m2
end
end
end
p C.instance_methods(false) # => [:m1]
class D<C
end
D.new.m1
p C.instance_methods(false) # => [:m1, :m2]
p D.instance_methods(false) # => []
class_eval V.S classキーワード
クラスキーを使用してクラスを変更するにはクラス名を指定する必要がありますが、クラス名をパラメータとして動的に変更するには?このときModule#class_を使うことができます.eval(別名module_eval)メソッド.
def add_method_to(a_class)
a_class.class_eval do
def m
'Hello!'
end
end
end
add_method_to String
p "abc".m # => "Hello!"
またclassは役割ドメインゲートであり,クラス外の変数はクラス内では見えない.そしてclass_evalは、結局はメソッド呼び出しにすぎないため、フラットな役割ドメインを使用します.
classを見つけることができますevalとinstance_evalは似てるclassevalにもパラメータ付きclass_がありますexec.instance_evalのポイントは、オブジェクト内の変数の現在のselfを呼び出しで表示するように変更し、class_evalのポイントはクラスの変更です.
クラスのインスタンス変数
Rubyのインスタンス変数は現在のselfに属するため、クラス内のメソッド外で定義されたインスタンス変数はクラスのインスタンスではなくクラスというオブジェクトに属する.
class A
@var = 1
def read; @var; end
def write; @var = 2; end
def self.read; @var; end
end
class B<A
def self.read; @var; end
end
obj = A.new
p obj.read # => nil
p B.read # => nil
obj.write
p obj.read # => 2
p A.read # => 1
インスタンス変数の帰属は現在のselfに基づいて判断されるため、サブクラス、インスタンスはクラスインスタンス変数にアクセスできません.この変数は「クラス」というオブジェクトのselfに属するためです.
注意@先頭のクラス変数とは異なり、現在のクラスとサブクラスまたはインスタンスによってアクセスできます.そのため、クラス変数をトップレベルの役割ドメインで定義すると、すべてのクラスがトップレベルの役割ドメインの上書き下にあるため、アクセスできます.
@@var = 1
class A
@@var = 2
end
@@var = 2
このような状況を避けるためには、できればクラス変数の使用を避け、クラスのインスタンス変数の使用を避けることが望ましい.
単品メソッド
Rubyは、単一オブジェクトへの追加方法をサポートします.
str = "this is a string"
def str.title?
self.upcase == self
end
str.singleton_methods # => [:title?]
Javaでsingletonクラスが同じオブジェクトのみを生成できるという概念とは異なり、ここでのsingletonメソッドは、このメソッドが定義されたオブジェクトに属しているということです.
実際,クラスメソッドを定義する際のメソッド名のselfを連想するが,クラスメソッドはクラスオブジェクトの単品メソッドである.
クラスマクロ
Rubyオブジェクトには属性がないので、Javaのようなgetterとsetterを書いてから属性にアクセスまたは変更する必要があります.
class MyClass
def my_attribute=(value)
@my_attribute = value
end
def my_attribue
@my_attribute
end
end
obj = MyClass.new
obj.my_attribute = 1
obj.my_attribute # => 1
でもこう書くのは煩わしくてクールじゃない~だからルビーはModule#attrを提供してくれたreader、Module#attr_writerとModule#attr_accessor
class MyClass
attr_accessor :my_attribute
end
obj = MyClass.new
obj.my_attribute = 1
obj.my_attribute # => 1
類似attr_accessorのような方法をクラスマクロと呼び、キーワードのように見えますが、実際にはクラスで使える方法にすぎません.
APIを更新し、古いメソッドをdeprecatedと宣言し、新しいメソッドに自動的に移動する必要があると仮定すると、次のようなコードを使用できます.
class MyClass
def self.deprecate(old_method, new_method)
define_method(old_method) do |*args, &block|
warn "Warinig, #{old_method} is deprecated, use #{new_method} now!"
send(new_method,*args,&block)
end
end
def old_m
p "old"
end
def new_m
p "new"
end
deprecate :old_m, :new_m
end
obj = MyClass.new
obj.old_m
単品類
Rubyメソッドを検索するときは,受信者のクラスに入ってから上へ検索する.たとえば、MyClassクラスインスタンスobj呼び出しメソッドは、objのクラスMyClassに入ってメソッドを検索します.しかし、単品メソッドはクラスに含まれていないに違いありません.そうしないと、すべてのオブジェクトにこのメソッドがあります.オブジェクト自体はクラスではないのでobjにも入っていません.では、この方法はどこにあるのでしょうか.
単品類とは
オブジェクトのクラスを尋ねると,Rubyは実際に見たクラスではなく,オブジェクト特有の非表示クラスを返す.このクラスはこのオブジェクトの単品クラス、またはメタクラスと呼ばれます.
obj = Object.new
singleton_class = class << obj
self # => #>
end
p singleton_class
これにより、この単品クラスの参照(.classメソッドは単品クラスを隠すように包装される)を見ることができ、現在Rubyも提供している.singleton_classメソッドは、単一のクラスを返します.各オブジェクトには独自の単品クラスがあり、単品クラスにも1つのインスタンスしかない(そのインスタンスにも独自の単品クラスがある~ループ往復・・・ただしこの単品クラスの単品クラスの用途はまだ開発されていない).オブジェクトの単品メソッドは、対応する単品クラスに配置されます.
月曜日に学習した継承モデルを更新する必要があります:objが存在するクラスはobjの単品クラスで、単品クラスの親はMyClassで、MyClassクラスのオブジェクトの親はObjectです.
単品クラスと継承
次のようなクラス関係があると仮定すると,継承ツリーの出力を観察することによって彼らの構造関係を理解することができる.
class C
def self.claz_method
end
end
class D<C
end
obj = D.new
def obj.singleton_mtd
end
p C.singleton_class # => #
p D.singleton_class # => #
p D.singleton_class.superclass # => #
p C.singleton_class.superclass # => #