整理中。
「特異」って言葉に慣れてないので想像しにくいのだけど、
1 特別に他とちがっていること。また、そのさま。「彼はこの会社では―な存在だ」
特異
2 特にすぐれていること。また、そのさま。「―な才能の持ち主」
マニュアルにある言葉をひっぱってくると
- 特異メソッドは特定のインスタンスに固有のメソッド
- 特異クラスはある特定のオブジェクトだけのための仮想的なクラス
- クラスメソッドはクラスの特異メソッド
モヤモヤ。
言葉の定義はモヤモヤするのだけど、 rails みたいに拡張しまくるプログラムを書くためには何がしたいかっていうと、
- 動的に、インスタンスにメソッドを追加したい
- 動的に、クラスにメソッドを追加したい
- 動的に、クラスにクラスメソッドを追加したい
になる。動的に追加するには、特異クラスを使うことが多い(のだと思う)。
class << self # 本文 end
上記のように定義文の中で宣言するか
sig = class << self ; self end
特異クラスを取り出して操作する。
さらに、特異クラスを取り出す(定義する)際のコンテキストも大事。インスタンスなのか、モジュールなのか。
実際にやってみる
動的に、インスタンスにメソッドを追加する
class A ; end a = A.new a.instance_eval do |obj| class << self define_method :hello , Proc.new{ 'world' } end end a.hello #=> world A.new.hello #=> undefined method
インスタンスのコンテキストで特異クラスを取り出してメソッドを定義する。インスタンス固有のメソッド定義になる。
以下のようにも書ける。
class A ; end a = A.new a.instance_eval do |obj| sig = class << self ; self end sig.send :define_method , :hello , Proc.new{ 'world' } end puts a.hello #=> world puts A.new.hello #=> undefined method
動的に、クラスにメソッドを追加する
全てのインスタンスで使えるメソッドを定義する。
class A ; end a = A.new a.class.module_eval do |mod| define_method :hello , Proc.new{ 'world' } end puts a.hello #=> world puts A.new.hello #=> world
モジュールのコンテキストでメソッドを定義する。クラス共通のメソッド定義になる。
動的に、クラスにクラスメソッドを追加する
class A ; end a = A.new a.class.module_eval do |mod| class << self define_method :hello , Proc.new{ 'world' } end end puts A.hello #=> world
モジュールのコンテキストで特異クラスを取り出してメソッドを定義するクラスメソッド定義になる。
以下のようにも書ける。
class A ; end a = A.new a.class.module_eval do |mod| sig = class << self ; self end sig.send :define_method , :hello , Proc.new{ 'world' } end puts A.hello #=> world
クラスメソッドはインスタンスから定義するシチュエーションが思い浮かばない・・・。rails っぽく(?) table 名をクラス変数としてアクセスできるようにするのはこんな感じだろうか。
class Z def self.set_table_name(table) @table = table end module_eval do |mod| sig = class << self ; self end sig.send :define_method , :table_name , Proc.new{ @table } end end class A < Z set_table_name :table_a end class B < Z set_table_name :table_b end puts A.table_name #=> table_a puts B.table_name #=> table_b
@table はクラスのインスタンス変数。でいいのかな。
またこんがらがってきた。
読み直すか。