オブジェクトに処理を行わせる、何らかの命令を定義する時に メソッドを使う。
メソッドには種類があって、インスタンスメソッド、クラスメソッド、関数的メソッド、特異メソッド、モジュールメソッドがある。
インスタンスメソッド はレシーバをつけて呼び出すメソッドである。レシーバはどこかのクラスのインスタンスである
class Cat
def siro
"siro"
end
end
a = Cat.new
a.siro
# => "siro"
"aa".length
# => 2
クラスメソッド はレシーバがクラス名つまり、定数で指定して呼び出せるメソッドである
class Zoo
def self.gorira
"gorira"
end
end
Zoo.gorira
# => "gorira"
関数的メソッドはレシーバ省略形式で呼ばれるメソッドのことである
irbを起動してみると
> puts "a"
> p "a"
aというメッセージが返ってくる、
また、クラス定義の中でprivateで指定したメソッドのこと。クラス定義の中でprivateでメソッドを指定すればそのメソッドはレシーバを省略した形でしか使えないメソッドになる
class Cat
def tunakan
secret_tunakan
end
private
def secret_tunakan
"delicious"
end
end
a = Cat.new
a.tunakan
# => "delicious"
Cat.ancestors #クラスの継承関係を表示するメソッド
=> [Cat, Object, Kernel, BasicObject]
ちなみにp, print, putsはObjectクラスのPrivateなメソッドでクラスを定義するとObject、Kernel、BasicObjectが継承関係に取り込まれるからレシーバを省略できる。
> Object.private_methods.grep(/p/)
=> [:prepended, :initialize_copy, :public, :protected, :private, :initialize_dup, :sprintf, :loop, :respond_to_missing?, :open, :printf, :print, :putc, :puts, :p, :trap, :spawn, :sleep, :proc, :Complex]
モジュールメソッドは特殊なクラスメソッドだと思えばいいかもしれない、
module Panda
def self.panda
"panda"
end
end
class Zoo
include Panda
def self.gorira
"gorira"
end
end
Panda.panda
# => "panda"
最後に 特異メソッドであるがこれはメソッドを特定のオブジェクトに追加する方法である
a = [1,2,3,4,5]
b = [1,2,3,4,5]
def a.jijyou
self.map { |b| b * b }
end
a.jijyou
=> [1, 4, 9, 16, 25]
b.jijyou
=> NoMethodError: undefined method `jijyou' for [1, 2, 3, 4, 5]:Array
上記の例ではオブジェクトが違うため変数bはエラーがでた、このように特定のオブジェクトに紐づくのが特異メソッドである、
オブジェクトにはクラス名の定数も含まれるから クラスメソッドとはクラスの特異メソッドであるという事実に気づく、非常にややこしいけど、慣れるしかない。
特異メソッドは下記の例からobjectの部分はオブジェクトの参照、クラス名の定数、リテラル表記、selfが入る。
def object.method # オブジェクトの参照 or クラス名の定数 or リテラル表記 or self
# 処理の中身
end
オブジェクトの概念 Rubyの章でオブジェクトはクラスへの参照とインスタンス変数をもっていて、メソッドは持たないと書いたが、特異メソッドは特定のオブジェクトに紐づいていてそれってオブジェクト自身がメソッドをもっていることにはならないか?疑問に思わないだろうか、、特異メソッドはインスタンメソッドでもない、 コマンドを打ってみてクラスに問い合わせても特異メソッドは見つからない
a = "nyaaa"
def a.dog
"wanwan"
end
a.dog
# => "wanwan"
a.class.instance_methods(false).grep(/dog/)
# => [] #空っぽ
a.class.superclass.instance_methods(false).grep(/dog/)
# => []
Stringクラスには定義されていないという解答が返ってきた、
実はクラスメソッドの場合も同様であるがRubyは裏で特別なクラスを持っていて、 特異クラス と呼ばれているクラスを持っている
特異クラスとは特異メソッドのためにあるクラスである
obj = "singleton_class"
singleton_class = class << obj
self
end
singleton_class.class
=> Class
変った構文で特異クラスの正体を見つけることができる、上記の例から特異クラスもクラスの一員であることが分かる
def obj.won_won
"gau!!!"
end
singleton_class.instance_methods.grep(/won/)
# => [:won_won]
特異メソッドは特異クラスに住んでいていることが分かる、特異メソッドはインスタンスを1つしか持てなくて、シングルトンクラスとも呼ばれている
class Object
def eigenclass
class << self
self
end
end
end
obj.eigenclass
=> #<Class:#<String:0x007ff8416d03f8>>
obj.eigenclass.superclass
=> String
Objectクラスに特異クラスを返すメソッドを定義する、
上記の例からobj.eigenclassを呼び出すことによってobjの特異クラスはStringクラスであり、その親もStringクラスであることが分かる。
前者を特異クラスのStringクラスとして、後者を通常のメソッドの探索に含まれるStringクラスと思ってもらって良い
また、Rubyのプログラムは最初に特異クラスにメソッドがあるか問い合わせてその後に通常のクラスに問い合わせる
さらに下記の例を使ってクラスと特異クラスの関係を探ってみる
class Animal
class << self
def mammal
"cat"
end
end
end
class Cat < Animal
end
Animal.eigenclass
=> #<Class:Animal>
Cat.eigenclass
=> #<Class:Cat>
Animal.eigenclass.superclass
=> #<Class:Object>
Cat.eigenclass.superclass
=> #<Class:Animal>
Animalクラスの特異クラスは特異クラスAnimalであり、特異クラスAnimalの親は特異クラスObjectである、またCatクラスの特異クラスは特異クラスCatであり、その親は特異クラスAnimalである
複雑で分かりにくいがこの仕組みのおかげでAnimalクラスで定義したクラスメソッドがつまり特異メソッドが子のCatクラスでも使えるのだ
Cat.mammal
=> "cat"
##まとめ
メソッド探索:メソッドを探す時Rubyはまずそのオブジェクトの所属するクラスに問い合わせる、見つからなければ上へ上へ向かってメソッドを探していく
インスタンスメソッド はレシーバをつけて呼び出すメソッドである
クラスメソッド はレシーバがクラス名つまり、定数で指定して呼び出せるメソッドである
関数的メソッドはレシーバ省略形式で呼ばれるメソッドのことである
モジュールメソッドは特殊なクラスメソッド
特異メソッドはメソッドを特定のオブジェクトに追加する方法である、クラスメソッドも特異メソッドの一種である
特異クラスは特異メソッドやクラスメソッドをもっていて、インスタンスは1つしか持てない、特異メソッドは特異クラスのインスタンスメソッドである
続く、、、、