クラス
クラスは、新しいオブジェクトインスタンスを生成するときに使われる雛型です。例えば、前のgreetメソッドをクラスに入れるには、次のように記述します。
irb(main):001:0> class Manners
irb(main):002:1> def greet(name)
irb(main):003:2> puts "Hello, #{name}!"
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> m = Manners.nRew
=> #<Manners:0x404839c>
irb(main):007:0> m.greet "Reader"
Hello, Reader!
=> nil
このコードでは、Mannersという新しいクラスを作成し、そこにgreetメソッドを追加しています。その後、Mannersの新しいインスタンスを生成し、そのインスタンスを使って挨拶を表示しています。
Rubyのクラスはオブジェクトの生きた雛型であると考えてください。コンパイル時に定義される.NETのクラスと異なり、Rubyのクラスはいつでも拡張できます。クラスを拡張すると、そのクラスの既存のインスタンスにも直ちに新しい振る舞いが追加されます。別れの言葉(farewell)を表示しようとするとどのようなことが起きるか考えてみましょう。
irb(main):008:0> m.farewell "Reader"
NoMethodError: undefined method 'farewell' for
#<Manners:0x404839c>
from (irb):8
farewellを呼び出そうとすると、そのようなメソッドはないというメッセージが表示されます。そこで、Mannersクラスを拡張し、別れの言葉を表示する機能を追加します。
irb(main):009:0> class Manners
irb(main):010:1> def farewell(name)
irb(main):011:2> puts "Goodbye, #{name}!"
irb(main):012:2> end
irb(main):013:1> end
=> nil
irb(main):014:0> m.farewell "Reader"
Goodbye, Reader!
=> nil
Mannersクラスを拡張した後は、クラスの既存のインスタンスもfarewellを呼び出せるようになっています。
Mannersクラスには2つのメソッドがあり、どちらも名前(name)を引数として受け取ります。おそらく、生成時に名前を渡せるようにクラスを書き換えた方がいいでしょう。newに渡したすべての引数を使ってinitializeメソッドが呼び出されるようにします。変更後のMannersクラスは次のようになります。
irb(main):001:0> class Manners
irb(main):002:1> def initialize(name)
irb(main):003:2> @name = name
irb(main):004:2> end
irb(main):005:1> def greet
irb(main):006:2> puts "Hello, #{@name}!"
irb(main):007:2> end
irb(main):008:1> def farewell
irb(main):009:2> puts "Goodbye, #{@name}!"
irb(main):010:2> end
irb(main):011:1> end
=> nil
irb(main):012:0> m = Manners.new "Reader"
=> #<Manners:0x809fa08 @name="Reader">
irb(main):013:0> m.greet
Hello, Reader!
=> nil
irb(main):014:0> m.farewell
Goodbye, Reader!
=> nil
クラスは@nameというインスタンス変数に名前を格納します。また、インスタンスの内容表現(12行目の後に表示される結果)には、すべてのインスタンス変数の値が含まれます。
クラスの拡張性は、自分で定義したクラスだけにとどまりません。Rubyの組み込みクラスを拡張することもできます。
irb(main):001:0> class Array
irb(main):002:1> def print_tr
irb(main):003:2> puts "<tr>"
irb(main):004:2> each { |item|
irb(main):005:3* puts " <td>#{item}</td>"
irb(main):006:3> }
irb(main):007:2> puts "</tr>"
irb(main):008:2> end
irb(main):009:1> end
=> nil
Irb(main):010:0> ["hello","world!"].print_tr
<tr>
<td>hello</td>
<td>world!</td>
</tr>
=> nil
Railsの組み込みの型には、自然なインターフェイスを提供する多くの拡張が追加されています。例えば、5.days.from_nowのようなコードを書いて、タイムゾーンに対応した、今から5日後の日付を取得できます。
これまで定義してきたメソッドは、すべてインスタンスメソッドでした。つまり、クラスのインスタンスに対してのみ利用できるメソッドでした。Rubyには、静的メソッド(クラスメソッドも呼ばれます)もあります。実は、この記事でも既に静的メソッドをそれとは意識せずに呼び出しています。newメソッドのことです。
次のように、新しい静的メソッドを既存のクラスに追加できます。
irb(main):001:0> def String.concat(s1, s2) irb(main):002:1> s1 + ' ' + s2 irb(main):003:1> end => nil irb(main):004:0> String.concat 'hi', 'bye' => "hi bye"
また、「self」構文を使って、クラスを定義または拡張するコンテキストで静的メソッドを定義することもできます。
irb(main):001:0> class String irb(main):002:1> def self.concat(s1, s2) irb(main):003:2> s1 + ' ' + s2 irb(main):004:2> end irb(main):005:1> end => nil irb(main):006:0> String.concat 'hi', 'bye' => "hi bye"
