ブロック
先ほどRubyにはデータとメソッドがあると説明しました。実はRubyにはメソッドのような実行できる処理をもデータと同じように他のメソッドに渡すことができる「ブロック」という仕組みがあります。「ブロック」はRubyの柔軟性を生み出している要素の1つです。
繰り返し処理
ブロックの典型的な活用例がRubyの繰り返し処理です。Rubyでは「イテレータ」と呼びます。では、さっそくirbで試してみましょう(リスト8)。
「do」から「end」までがブロックとなります。これを配列arrayのeachメソッドへ渡しています。eachでは配列の要素1つ1つに対して渡されたブロックを実行しています。この例ではputsを実行して要素を表示しています。
ブロックを活用することによって外側から自由に実行させたい処理の断片を渡すことができるのです。他にもファイルのオープン、クローズなどブロックを活用することが多くあります。
宣言的な記法
Dogクラスには名前を返すメソッド「name」を定義しました。このようにインスタンス変数を参照したり代入したりするメソッドを「アクセサメソッド」と呼び、Rubyではインスタンス変数の都度定義しなくても簡単なメソッドの呼び出しで定義することができます。
アクセサメソッドには次の3種類があり、「attr_accessor」は読み書き可能、「attr_reader」は読み出し専用、「attr_writer」は書き込み専用となっています。
実際にCatクラスでアクセサメソッドを作ってみましょう。nameを読み出し専用としてageを読み書き可能としてみます(リスト9)。
リスト8:ブロックの定義
irb(main):050:0> array = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
irb(main):051:0> array.each do |e| # <- ブロック開始
irb(main):052:1* puts e # |
irb(main):053:2> end # <- ブロック終端
1
2
3
4
5
=> [1, 2, 3, 4, 5]
リスト9:アクセサメソッドの定義
irb(main):060:0> class Cat
irb(main):061:1> attr_reader :name
irb(main):062:1> attr_accessor :age
irb(main):063:1> def initialize(name, age)
irb(main):064:2> @name = name
irb(main):065:2> @age = age
irb(main):066:2> end
irb(main):067:1> end
=> nil
リスト10:アクセサメソッドの実行
irb(main):070:0> tama = Cat.new("tama", 10)
irb(main):071:0> tama.name
=> "tama"
irb(main):072:0> tama.age
=> 10
irb(main):073:0> tama.age = 11
=> 11
リスト11:すべてがオブジェクト
irb(main):080:0> 1.to_s # 数値を文字列に変換します
=> "1"
irb(main):081:0> 1.class # クラスを表示
=> Fixnum
irb(main):082:0> "Hello".class
=> String
irb(main):083:0> tama.class
=> Cat
irb(main):084:0> 3.times do
irb(main):085:1* puts "Hello"
irb(main):086:1> end
Hello
Hello
Hello
=> 3
アクセサメソッドを使ってみます。Catクラスをインスタンス化してtama変数に代入します(リスト10)。
インスタンス変数へ簡単にアクセスできるようになりました。クラスに宣言するように書くだけでメソッドが追加されます。他にも便利なメソッドが用意されています。リファレンスマニュアルのModuleの項を参照してみてください。
実習3
読み出し専用属性に書き込んだり、書き込み専用属性を読み込んだりエラーが出るか確かめてみてください。
すべてがオブジェクト
Rubyでは今まで作成したDogやCatのような手作りのクラスだけでなく、システムが用意しているシステムクラスや、単なる数値、文字列に至るまですべてがオブジェクトとして扱えます。数値や文字列もメソッドを持っているのです。それではirbで試してみましょう(リスト11)。
実行環境がオブジェクト
今まで画面に文字列を表示するための命令として「puts」を使ってきました。レシーバ無しで呼び出しているputsは、どのクラスのメソッドなのでしょうか。
実はObjectクラスというRubyのすべてのクラスのベースになるクラスのメソッドです。レシーバ無しで呼んだメソッドは、自分のクラスに該当するメソッドが無ければ、最終的にベースのObjectクラスに定義されたメソッドを呼び出します。そのためObjectクラスに定義されたメソッドはどこからでも呼び出すことができるのです。
オープンクラス
irbを使って少しづつDogクラスのメソッドを増やしていったり、定義を拡張していきました。Rubyではこのように完全なクラスを一度に書かなくても、後から足したり書き換えたりして定義できます。これはRubyの動的な特徴の1つですね。
同じようにRubyが標準で提供する各種クラスライブラリも書き換えたり拡張したりすることができます。ユーザ自身が作ったユーザクラスとシステムが提供するシステムクラスとの区別が無いことを「オープンクラス」と呼びます。
オープンクラスのRubyではシステムクラスやサードパーティから提供されたライブラリを自分の好きな形にカスタマイズすることも可能です。しかし多くのシステムで使われているシステムクラスを安易に書き換えると、Ruby全体に影響がおよぶため十分なテストが必要となりますので注意してください。
まとめ
Rubyとオブジェクト指向プログラミングへの入り口をirbで確かめながら解説してきました。オブジェクト指向は奥が深いですが、オブジェクト指向の理解が進むことでRubyの背景にある設計の意味がわかってきます。Rubyを活用するためにぜひオブジェクト指向プログラミングに親しんでみてください。