JQ Blog

クラス定義②

特異クラス

特異メソッドはどのクラスに所属しているのか。
特異メソッドの定義クラスにおけるインスタンスメソッドだと全インスタンスに引き継がれてしまう。
Objectクラスだと全クラスに引き継がれてしまう。ではどこに所属しているのか。 特異クラスという特殊なクラスに所属している。

特異クラスのオープン

1
2
3
class << an_object
 #処理を記述
end

特異クラスの参照を取得

1
2
3
4
5
eigenclass = class << obj
  self
end

eigenclass.class # => Class

特異クラスの特別なところ

  • インスタンスを1つしか持てない(だからシングルトンクラスとも呼ばれる)
  • 継承ができない
  • 特異クラスはオブジェクトの特異メソッドが住んでいる場所

クラスメソッドの構文

この前の記事でクラスメソッドを定義する方法の2つを書いてたけど、もう1つがある。

1
2
3
4
5
6
7
8
class MyClass
  class << self
    def my_method; puts "Hello!" end
  end
end

MyClass.my_method # => "Hello!"
end

クラスの属性を定義する

1
2
3
4
5
6
7
8
9
class MyClass
  # これだとインスタンスの属性定義になってしまう
  attr_accessor :a
end

MyClass.a # => NoMethodError: undefined method `a' for MyClass:Class
obj = MyClass.new
obj.a = 1
obj.a # => 1
1
2
3
4
5
6
7
8
class MyClass
  class << self
    attr_accessor :c
  end
end

MyClass.c = 'It works!'
MyClass.c # => "It works!"

クラス拡張

moduleのインスタンスメソッドをクラスメソッドとして定義させるとき
クラス拡張という方法で実現できる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module MyModule
  def my_method
    puts 1
  end
end

class MyClass
  class << self
    # 特異クラス内でインスタンスメソッドを拡張させるとクラスメソッドとして定義可能
    include MyModule
  end
end

MyClass.my_method # => 1

Object#extendを用いれば、もっとシンプルに定義できる。

1
2
3
4
5
class MyClass
  extend MyModule
end

Myclass.my_method # => 1

エイリアス

1
alias :新しい名前 :古い名前
  • aliasはキーワードであり、メソッドではいので二つの間にカンマはいらない
  • 参照を向けるのではなく、コピーする。だから、aliasコマンドの後で元となるメソッドに変更が加えられても、aliasによって作成されたメソッドには影響がない
1
2
3
4
5
6
7
8
class MyClass
  def my_method; "my_method()"; end
  alias :my_method2 :my_method
end

m = MyClass.new()
m.my_method # =>  "my_method()"
m.my_method2 # =>  "my_method()"

のように使える。

aliasの用途

元のメソッドを修正したいが、外部ライブラリなどで修正できない場合がある。
その場合は、元メソッドを別名定義し、元メソッド名でメソッドを再定義する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass
  def my_method
    puts "original"
  end

  alias :my_method2 :my_method

  def my_method
    puts "changed"
  end
end

mc = MyClass.new
mc.my_method # => changed
mc.my_method2 # => original

参照

http://tamata78.hatenablog.com/entry/2015/09/16/205224