class_eval()
- Module#class_eval()とObject#instance_eval()は全くの別物
- instance_eval()はselfに変更を加えるだけ
- class_eval()はselfとカレントクラスに変更を加える
- class()とclass_eval()も違う
- classは束縛を捨てて新しいスコープを作るがclass_eval()はフラットスコープをもつ
- classは定数を必要とするが、class_eval()はクラスを参照する変数なら何でも使える
def add_method_to(some_class)
some_class.class_eval do
def new_method
'Hello!'
end
end
end
add_method_to String
"foo".new_method
class MyClass
@my_var = 1
def self.read; @my_bar; end
def write; @my_var = 2; end
def read; @my_var; end
end
obj = MyClass.new
obj.write
obj.read
MyClass.read
- クラスインスタンス変数とクラス変数の違い
- クラス変数は、サブクラスやインスタンスメソッドからアクセスできる
- クラス変数はクラスに属していない(=Class階層に属している)
@@v = 1
class MyClass
@@v = 2
end
@@v
@@vはmainのコンテキストて定義されている(=Objectクラスに属している)ので、すべてのクラスでObjectクラスを継承している以上、全てのオブジェクトで@@vは共有されてしまう
定数に無名クラスを割り当てると、逆に無名クラスも定数を参照するようになる
c = Class.new(Array) do
def hogehoge
"fugafuga"
end
end
MyClass = c
c.name
str = "hoge"
def str.title?
self.upcase == self
end
str.title?
str.methods.grep(/title?/)
str.singleton_methods
class MyClass
def self.my_method; end
end
def MyClass.my_other_method; end
特異クラスをオープンしてメソッドを定義する
class MyClass
class << self
def my_method
end
end
module MyModule
def self.my_method; "hello"; end
end
class MyClass
include MyModule
end
MyClass.my_method
class MyClass
class << self
include MyModule
end
end
MyClass.my_method
- my_methodは、MyClassの特異クラスインスタンスメソッドであるといえる。つまり、my_methodはMyClassのクラスメソッドである。この技術をクラス拡張という。
- 同じくオブジェクトの場合はオブジェクト拡張という
Extend
- クラスやオブジェクトを拡張するのに特異クラスをオープンするのは自然なことではない。
- 代わりに用意されたのがextend
- レシーバの得意クラスにモジュールをインクルードするためのショートカットである
module MyModule
def my_method; 'Hello'; end
end
obj = Object.new
obj.extend MyModule
obj.my_method
class MyClass
extend MyModule
end
MyClass.my_method
- オブジェクトは一種類しかない。それが通常のオブジェクトかモジュールになる。
- モジュールは一種類しかない。それが通常のもモジュール、クラス、特異クラス、プロキシクラスのいずれかになる
- メソッドは一種類しかない。メソッドはモジュール(大半はクラス)にすんでいる
- すべてのオブジェクトはクラス含め、本物のクラスを持っている。それは、通常のクラスか特異クラスになる
- 全てのクラスはスーパークラスを持っている。ただし、Basic Objectにはスーパークラスはない。あらゆるクラスがBasicObjectに向かって一本の継承チェーンを持っている
- オブジェクトの特異クラスのスーパークラスは、オブジェクトのクラスである。クラスの特異クラスのスーパークラスはクラスのスーパークラスの特異クラスである。
- メソッドを呼び出すとき、Rubyはレシーバの本物のクラスに向かって右へ進み、継承チェーンを上へ進む。
クラスがモジュールをインクルードすると、モジュールのインスタンスメソッドが手に入る。クラスメソッドは入らない
- ライブラリなど直接編集すべきでないメソッドがある場合は、そのメソッドをラップして、機能を追加し、全てのクライアントが新しく追加した機能をを自動で使えるようにすればよい
alias :新しい名前 :古い名前
- aliasはキーワードであり、メソッドではいので二つの間にカンマはいらない
- 参照を向けるのではなく、コピーする。だから、aliasコマンドの後で元となるメソッドに変更が加えられても、aliasによって作成されたメソッドには影響がない