クラスが返却する値
クラスもメソッドのように最後に評価した値を返却する
class MyClass puts "Hello" end Hello
指定クラスにメソッドを追加
オープンしたいクラス名がわからない場合、classキーワードでは
メソッド追加できないため、class_eval
を用いる
def add_method_to(class_name) class_name.class_eval do def inc(x) self + x end end end add_method_to Fixnum 1.inc(1) # => 2
instance_eval()とclass_eval()
instance_eval() :self(オブジェクト)を変更
class_eval() :self(オブジェクト)とカレントクラスを変更
クラスインスタンス変数
インスタンス変数は2種類ある。
クラスに紐づくものとオブジェクトに紐づくもの
class MyClass @v1 = 1 # クラスメソッド。内部はクラススコープ def self.read @v1 end # インスタンスメソッド。オブジェクトスコープ def write @v1 = 2 end def read @v1 end end MyClass.read # => 1 クラスインスタンス変数を参照 obj = MyClass.new obj.write obj.read # =>2 objのインスタンス変数を参照
クラス変数の落とし穴
下記のような現象が起こるため、クラス変数ではなく、
クラスインスタンス変数を使う人が多い。
#トップレベル定義するとObject属するクラス変数となる @@v1 = 1 class MyClass #クラスすべてはObjectを継承し、クラス変数も継承(共有)される @@v1 = 2 end # 結果、MyClass内でトップレベルのクラス変数を変更できてしまう。 @@v1 # => 2
特異メソッド
特定オブジェクトにのみから呼び出せるメソッドのこと
str1 = "hello" def str1.hello? self == "hello" end str1.hello? # => true
クラスメソッドは特異メソッド
クラスメソッドはself(クラスオブジェクト)への特異メソッド定義らしい。
class Myclass # クラスオブジェクトにクラスメソッドを定義 def Myclass.my_method1 end # クラスオブジェクト(self)にクラスメソッドを定義 def self.my_method2 end end
クラスマクロ
クラス定義内で使用可能なクラスメソッド
Module#attr_*()のメソッドが代表的。
特異クラス
特異メソッドはどのクラスに所属しているか。
特異メソッドの定義クラスにおけるインスタンスメソッドだと全インスタンスに引き継がれてしまう。
Objectクラスだと全クラスに引き継がれてしまう。ではどこに所属しているのか。
特異クラスという特殊なクラスに所属している。
特異クラスのオープン
class << an_object #処理を記述 end
特異クラスの参照を取得
eigenclass = class << obj self end eigenclass.class # => Class
selfを使わず、クラスに属性定義をする
class MyClass # これだとインスタンスの属性定義になってしまう attr_accessor :a end MyClass.a # => NoMethodError: undefined method `c' for MyClass:Class mc = MyClass.new() mc.a = 1 mc.a # => 1
特異クラスを用いてクラス属性を追加します。
class MyClass # 特異クラスに属性追加することでクラスに属性追加 class << self # クラス属性の定義コンテキストで定義 attr_accessor :c end end MyClass.c = '属性定義' MyClass.c # => '属性定義'
クラス拡張
moduleのインスタンスメソッドをクラスメソッドとして定義させるとき
クラス拡張という方法で実現できる
module MyModule def my_method puts 1 end end class MyClass class << self # 特異クラス内でインスタンスメソッドを拡張させるとクラスメソッドとして定義可能 include MyModule end end MyClass.my_method # => 1
Object#extendを用いれば、もっとシンプルに定義可能
class MyClass extend MyModule end Myclass.my_method # => 1
エイリアス
aliasキーワードを用いて、Rubyメソッドへの別名をつけることができる。
class MyClass def my_method; "my_method()"; end # aliasはキーワードのため、二つのメソッド名の間にカンマ不要 alias :my_method2 :my_method end m = MyClass.new() m.my_method # => "my_method()" m.my_method2 # => "my_method()"
aliasの用途
元のメソッドを修正したいが、外部ライブラリなどで修正できない場合がある。
その場合は、元メソッドを別名定義し、元メソッド名でメソッドを再定義する。
その際、元メソッドを呼びながら、追加処理を記述できる。これをアラウンドエイリアスと呼ぶ
class MyClass def my_method puts "original" end # my_methodを別名定義 alias :org_my_method :my_method # my_methodを再定義 def my_method org_my_method puts "Redefinition" end end mc = MyClass.new() mc.my_method # => original Redefinition mc.org_my_method # => original
次はコードを記述するコード
メタプログラミング Ruby 第5章 コードを記述するコード - 気軽に楽しくプログラムと遊ぶ