Ruby のクラスは Class クラスのインスタンスとして存在する。つまりクラスはオブジェクト。 オブジェクトとしてのクラスにとって Class クラスは klass となる
そしてクラス名は定数ということになる。 つまりスコープに定数がばら撒かれていて、そこにクラスオブジェクトが入っていると思っていい
なので
class Hoge end
この記法はクラスオブジェクトリテラル+定数設定ということになる。
class
キーワードに続きそのクラスの名前をつけて end で閉じればよい。メソッドは def
キーワードに続きブロックを作ればいい
class Hoge def hoge print "ほげ" end def piyo print "ぴよ" end end
class クラス名 def メソッド名 #処理内容 end end
Rubyのクラス名の命名規約はJavaと同じでパスカル方式
HogePiyo
全部小文字のハイフン繋ぎ。Rubyは複数のクラスを1個のファイルに記述できるが、そのなかでもインターフェースとなる主要なクラスをファイル名の元ネタとして使うのが一般的
hoge-piyo.rb
このように継承したいクラスを(例ならPiyo)リダイレクトで突っ込むように書く
class Hoge < Piyo def hoge print "ほげ" end end
クラスメソッドは self かクラス名をメソッドの頭につけることによって作れる。 通常はクラス名変更のリファクタを考慮するから self を使う
class Hoge def Hoge.hoge print "ほげ" end def self.piyo print "ぴよ" end end
つまり self はそのオブジェクト内ではオブジェクト自身を指すことになる。 なんでそうなるかといえば、Ruby にとって class は Classクラスのインスタンスになる。class Hoge~の記述は class 宣言ではなく、class インスタンスリテラルと捉えられる。
なので class ~ end 中の self は Class クラスのインスタンス自身を指すことになり、クラスメソッドに self をつけるのはそういう意味なのだ。
なのでそのクラスメソッド内部のselfもクラス自身を表すことになる
class Hoge def self.piyo print "ぴよ" end def self.fuga print self.piyo print "ふが" end end Hoge.fuga //=>"ぴよふが"
逆にインスタンスのメソッドを呼び出すときは内部のselfはオブジェクト=インスタンス自身となる。
コンストラクタは特別なメソッド initialize で定義する。
class Hoge def initialize(a) end end
Rubyには型が無いのでJavaのような引数の数と型による多態性は内部で自分で実装すれば実現できる。
RubyはJavaとかと違ってコード動作中で動的にクラスにメソッドを追加できる
class Hoge def hoge print "ほげ" end end if(true) class Hoge def piyo print "ぴよ" end end end aaa = Hoge.new() aaa.piyo() #=> "ぴよ"
こんな風に既に定義されているクラスでもう一度定義すると再定義ではなくて追加になる
オブジェクトの作られたタイミングと追加したメソッドの実行には関係が無い。だからこれもOK。
class Hoge def hoge print "ほげ" end end aaa = Hoge.new() if(true) class Hoge def piyo print "ぴよ" end end end aaa.piyo() #=> "ぴよ"
つまりメソッドは実行時にklassポインタをたどって検索されるという話
クラスメソッドを後付で追加するにはクラスオブジェクト自体の特異メソッドとして追加すれば実現できる。
class Hoge end class <<Hoge def hello puts "hello" end end Hoge.hello
Javascriptのように特定のオブジェクトのみにメソッドを追加できる
class Hoge def hoge print "ほげ" end end aaa = Hoge.new() #ここで追加 def aaa.piyo print "ぴよ" end aaa.piyo() #=> "ぴよ" bbb = Hoge.new() bbb.piyo() #=>エラー
特異メソッド的な機能をmoduleを使ってやることもできる。これにはextendメソッドを使う
#モジュール module Piyo def piyo print "ぴよ" end end #クラス class Hoge def hoge print "ほげ" end end a = Hoge.new() #ここでmix-in a.extend Piyo a.piyo() #=>"ぴよ" b = Hoge.new() b.piyo() #=>エラー
Ruby では Java のような同一メソッド名の引数によるシグネチャ違いをたくさん定義することができない。 その代わりにオプション引数とか rest 引数というものを駆使してやると同じようなことができる
つまりメソッドの引数は一番細かい粒度で作っておき、プリセットの値をオプションで埋めておくことで対応。
class Hoge def hoge(a, b=1, c=2) #何か処理 end end
同名のメソッドでメソッド追加してやるとメソッドの再定義になる
class Hoge def hello1 puts "hello1" end end class Hoge def hello1 puts "hello1+" end end Hoge.new.hello1 #=>"hello1+"
再定義したいんだけど、前の定義も利用したい場合は、このように既存のメソッドに別名をつけておいてポインタを掴んでおく。 そうした上で既存の名前を上書きする。
class Hoge def hello1 puts "hello1" end end class Hoge def hello1_plus hello1_inner #既存のメソッドを別名を利用して実行 puts "+" end alias_method :hello1_inner, :hello1 alias_method :hello1, :hello1_plus #既存のメソッドを上書き end Hoge.new.hello1
つまりこれは実行タイミングと定義タイミング、上書きタイミングをずらすためにaliasを使っている。
こちらもインスタンスメソッドと同様に同名でもう一度定義させれば再定義になる。
class Hoge def self.hello1 puts "hello1" end end class Hoge def self.hello1 puts "hello1+" end end Hoge.hello1 #=> "hello1+"
既存のクラスメソッド利用したい場合は特異メソッドの記法を用いて内部に「オブジェクト空間」のようなものを作ってそれに対して操作をかける事によって文法的に整合性をとりつつ、 既存のものを利用しつつ上書きできる。
class Hoge def self.hello1 puts "hello1" end end class Hoge class <<self def hello1_plus hello1_inner puts "+" end alias_method :hello1_inner, :hello1 alias_method :hello1, :hello1_plus end end Hoge.hello1
このことから特異メソッドの「«」の記法は他の言語で言う「with」のような効果があることがわかる。
Ruby はメソッドの実装だけ単独で借りてくることができる Mixin という機能がある
Ruby では self キーワードであらわす
Rubyでは演算子自体もメソッド呼び出しとして実装されている。 だがこいつのうまい使い方がいまいちわからんwww
class Hoge def +(a) print a end end a = Hoge.new() a + "がおー"
class Hoge attr_accessor :aaa def +@ print self.aaa end end a = Hoge.new() a.aaa = "がおー" +a
クラス定数は慣例的にスネークケースのアッパーで書く。class記述の直下にバンと書けばOK
class Hoge PIYO = "1" end
外部からのアクセス コロン2個のスコープ解決を使って書く
PIYO = "2" class Hoge PIYO = "1" end p Hoge::PIYO #=>"1"
クラスメソッドからのアクセスは何もつけずにOK・・・何かつけちゃだめ
PIYO = "2" class Hoge PIYO = "1" def self.piyo p PIYO end end Hoge.piyo #=>"1"
インスタンスメソッドは同じく何もつけずにOK・・・何かつけちゃだめ
PIYO = "2" class Hoge PIYO = "1" def piyo p PIYO end end Hoge.new.piyo #=>"1"